root / ase / gui / progress.py @ 15
Historique | Voir | Annoter | Télécharger (12,33 ko)
1 |
# encoding: utf-8
|
---|---|
2 |
|
3 |
import gtk |
4 |
import numpy as np |
5 |
from ase.gui.widgets import pack, oops, AseGuiCancelException |
6 |
import sys |
7 |
import re |
8 |
import time |
9 |
|
10 |
|
11 |
class DummyProgressIndicator: |
12 |
def begin(self, **kwargs): |
13 |
pass
|
14 |
|
15 |
def end(self): |
16 |
pass
|
17 |
|
18 |
class DefaultProgressIndicator(gtk.Window): |
19 |
"Window for reporting progress."
|
20 |
waittime = 3 # Time (in sec) after which a progress bar appears. |
21 |
def __init__(self): |
22 |
gtk.Window.__init__(self)
|
23 |
self.set_title("Progress") |
24 |
self.globalbox = gtk.VBox()
|
25 |
|
26 |
# Scaling deformation progress frame
|
27 |
self.scalebox = gtk.VBox()
|
28 |
self.scaleframe = gtk.Frame("Scaling deformation:") |
29 |
vbox = gtk.VBox() |
30 |
self.scaleframe.add(vbox)
|
31 |
pack(self.scalebox, [self.scaleframe]) |
32 |
pack(self.scalebox, gtk.Label("")) |
33 |
|
34 |
self.label_scale_stepno_format = "Step number %s of %s." |
35 |
self.label_scale_stepno = gtk.Label(
|
36 |
self.label_scale_stepno_format % ("-" , "-")) |
37 |
pack(vbox, [self.label_scale_stepno])
|
38 |
self.scale_progress = gtk.ProgressBar()
|
39 |
self.scale_progress.modify_bg(gtk.STATE_PRELIGHT,
|
40 |
gtk.gdk.color_parse('#00AA00'))
|
41 |
pack(vbox, [self.scale_progress])
|
42 |
|
43 |
vbox.show() |
44 |
self.scaleframe.show()
|
45 |
self.globalbox.pack_start(self.scalebox) |
46 |
|
47 |
# Minimization progress frame
|
48 |
self.minbox = gtk.VBox() # Box containing frame and spacing |
49 |
self.minframe = gtk.Frame("Energy minimization:") |
50 |
vbox = gtk.VBox() # Box containing the frames content.
|
51 |
self.minframe.add(vbox)
|
52 |
pack(self.minbox, [self.minframe]) |
53 |
pack(self.minbox, gtk.Label("")) |
54 |
|
55 |
self.label_min_stepno = gtk.Label("-") |
56 |
pack(vbox, [gtk.Label("Step number: "), self.label_min_stepno]) |
57 |
lbl = gtk.Label() |
58 |
lbl.set_markup("F<sub>max</sub>: ")
|
59 |
self.minimize_progress = gtk.ProgressBar()
|
60 |
pack(vbox, [lbl, self.minimize_progress])
|
61 |
self.label_min_fmax = gtk.Label("-") |
62 |
lbl = gtk.Label() |
63 |
lbl.set_markup("Convergence criterion: F<sub>max</sub> = ")
|
64 |
pack(vbox, [lbl, self.label_min_fmax])
|
65 |
self.label_min_maxsteps = gtk.Label("-") |
66 |
pack(vbox, [gtk.Label("Max. number of steps: "),
|
67 |
self.label_min_maxsteps])
|
68 |
|
69 |
vbox.show() |
70 |
self.minframe.show()
|
71 |
self.globalbox.pack_start(self.minbox) |
72 |
self.globalbox.show()
|
73 |
self.add(self.globalbox) |
74 |
|
75 |
# Make the cancel button
|
76 |
self.cancelbut = gtk.Button(stock=gtk.STOCK_CANCEL)
|
77 |
self.cancelbut.connect('clicked', self.cancel) |
78 |
pack(self.globalbox, [self.cancelbut], end=True, bottom=True) |
79 |
|
80 |
def begin(self, mode=None, algo=None, fmax=None, steps=None, |
81 |
scalesteps=None):
|
82 |
self.mode = mode
|
83 |
# Hide all mode-specific boxes
|
84 |
self.scalebox.hide()
|
85 |
self.minbox.hide()
|
86 |
# Activate any relevant box
|
87 |
if mode == "scale" or mode == "scale/min": |
88 |
self.scalesteps = int(scalesteps) |
89 |
self.scalebox.show()
|
90 |
self.set_scale_progress(0, init=True) |
91 |
if mode == "min" or mode == "scale/min": |
92 |
# It is a minimization.
|
93 |
self.minbox.show()
|
94 |
self.label_min_stepno.set_text("-") |
95 |
self.label_min_fmax.set_text("%.3f" % (fmax,)) |
96 |
self.label_min_maxsteps.set_text(str(steps)) |
97 |
self.minimize_progress.set_fraction(0) |
98 |
self.minimize_progress.set_text("unknown") |
99 |
# Record starting time
|
100 |
self.starttime = time.time()
|
101 |
self.active = None # Becoming active |
102 |
self.raisecancelexception = False |
103 |
|
104 |
def end(self): |
105 |
self.hide()
|
106 |
self.active = False |
107 |
|
108 |
def activity(self): |
109 |
"Register that activity occurred."
|
110 |
if self.active is None and time.time() > self.starttime + self.waittime: |
111 |
# This has taken so long that a progress bar is needed.
|
112 |
self.show()
|
113 |
self.active = True |
114 |
# Allow GTK to update display
|
115 |
while gtk.events_pending():
|
116 |
gtk.main_iteration() |
117 |
if self.raisecancelexception: |
118 |
self.cancelbut.set_sensitive(True) |
119 |
raise AseGuiCancelException
|
120 |
|
121 |
def cancel(self, widget): |
122 |
print "CANCEL pressed." |
123 |
# We cannot raise the exception here, as this function is
|
124 |
# called by the GTK main loop.
|
125 |
self.raisecancelexception = True |
126 |
self.cancelbut.set_sensitive(False) |
127 |
|
128 |
def set_scale_progress(self, step, init=False): |
129 |
"Set the step number in scaling deformation."
|
130 |
self.label_scale_stepno.set_text(
|
131 |
self.label_scale_stepno_format % (step, self.scalesteps)) |
132 |
percent = 1.0 * step / self.scalesteps |
133 |
self.scale_progress.set_fraction(percent)
|
134 |
self.scale_progress.set_text("%i%%" % (round(100*percent),)) |
135 |
if not init: |
136 |
self.activity()
|
137 |
|
138 |
def logger_write(self, line): |
139 |
if self.mode == "min" or self.mode == "scale/min": |
140 |
# Update the minimization progress bar.
|
141 |
w = line.split() |
142 |
fmax = float(w[-1]) |
143 |
step = w[1]
|
144 |
self.minimize_progress.set_fraction(fmax / 1.0) |
145 |
self.minimize_progress.set_text(w[-1]) |
146 |
self.label_min_stepno.set_text(step)
|
147 |
else:
|
148 |
raise RuntimeError( |
149 |
"ProgressIndicator.logger_write called unexpectedly")
|
150 |
self.activity()
|
151 |
|
152 |
def get_logger_stream(self): |
153 |
return LoggerStream(self) |
154 |
|
155 |
|
156 |
class GpawProgressIndicator(DefaultProgressIndicator): |
157 |
"Window for reporting GPAW progress."
|
158 |
|
159 |
def __init__(self): |
160 |
DefaultProgressIndicator.__init__(self)
|
161 |
|
162 |
# GPAW progress frame
|
163 |
self.gpawframe = gtk.Frame("GPAW progress:") |
164 |
vbox = self.gpawvbox = gtk.VBox()
|
165 |
self.gpawframe.add(vbox)
|
166 |
self.table = gtk.Table(1, 2) |
167 |
self.tablerows = 0 |
168 |
pack(vbox, self.table)
|
169 |
self.status = gtk.Label("-") |
170 |
self.tablepack([gtk.Label("Status: "), self.status]) |
171 |
self.iteration = gtk.Label("-") |
172 |
self.tablepack([gtk.Label("Iteration: "), self.iteration]) |
173 |
self.tablepack([gtk.Label("")]) |
174 |
lbl = gtk.Label() |
175 |
lbl.set_markup("log<sub>10</sub>(change):")
|
176 |
self.tablepack([gtk.Label(""), lbl]) |
177 |
self.wfs_progress = gtk.ProgressBar()
|
178 |
self.tablepack([gtk.Label("Wave functions: "), self.wfs_progress]) |
179 |
self.dens_progress = gtk.ProgressBar()
|
180 |
self.tablepack([gtk.Label("Density: "), self.dens_progress]) |
181 |
self.energy_progress = gtk.ProgressBar()
|
182 |
self.tablepack([gtk.Label("Energy: "), self.energy_progress]) |
183 |
self.tablepack([gtk.Label("")]) |
184 |
self.versionlabel = gtk.Label("") |
185 |
self.tablepack([gtk.Label("GPAW version: "), self.versionlabel]) |
186 |
self.natomslabel = gtk.Label("") |
187 |
self.tablepack([gtk.Label("Number of atoms: "), self.natomslabel]) |
188 |
self.memorylabel = gtk.Label("N/A") |
189 |
self.tablepack([gtk.Label("Memory estimate: "), self.memorylabel]) |
190 |
self.globalbox.pack_start(self.gpawframe) |
191 |
self.gpawframe.show()
|
192 |
|
193 |
vbox.show() |
194 |
self.active = False |
195 |
|
196 |
def tablepack(self, widgets): |
197 |
self.tablerows += 1 |
198 |
self.table.resize(self.tablerows, 2) |
199 |
for i, w in enumerate(widgets): |
200 |
self.table.attach(w, i, i+1, self.tablerows-1, self.tablerows) |
201 |
if hasattr(w, "set_alignment"): |
202 |
w.set_alignment(0, 0.5) |
203 |
w.show() |
204 |
|
205 |
def begin(self, **kwargs): |
206 |
DefaultProgressIndicator.begin(self, **kwargs)
|
207 |
# Set GPAW specific stuff.
|
208 |
self.active = True |
209 |
self.oldenergy = None |
210 |
self.poscount = None |
211 |
self.reset_gpaw_bars()
|
212 |
# With GPAW, all calculations are slow: Show progress window
|
213 |
# immediately.
|
214 |
self.show()
|
215 |
while gtk.events_pending():
|
216 |
gtk.main_iteration() |
217 |
|
218 |
def reset_gpaw_bars(self): |
219 |
for lbl in (self.status, self.iteration): |
220 |
lbl.set_text("-")
|
221 |
for bar in (self.wfs_progress, self.dens_progress, |
222 |
self.energy_progress):
|
223 |
bar.set_fraction(0.0)
|
224 |
bar.set_text("No info")
|
225 |
|
226 |
def gpaw_write(self, txt): |
227 |
#if not self.active:
|
228 |
# self.begin()
|
229 |
sys.stdout.write(txt) |
230 |
versearch = re.search("\|[ |_.]+([0-9]+\.[0-9]+\.[0-9]+)", txt)
|
231 |
if versearch:
|
232 |
# Starting a gpaw calculation.
|
233 |
self.versionlabel.set_text(versearch.group(1)) |
234 |
self.status.set_text("Initializing") |
235 |
elif txt.startswith("Positions:"): |
236 |
# Start counting atoms
|
237 |
self.poscount = True |
238 |
self.reset_gpaw_bars()
|
239 |
self.status.set_text("Starting calculation") |
240 |
self.oldenergy = None |
241 |
elif txt.strip() == "": |
242 |
# Stop counting atoms
|
243 |
self.poscount = False |
244 |
elif self.poscount: |
245 |
# Count atoms.
|
246 |
w = txt.split() |
247 |
assert(len(w) == 5) |
248 |
self.natoms = int(w[0]) + 1 |
249 |
self.natomslabel.set_text(str(self.natoms)) |
250 |
elif txt.startswith("iter:"): |
251 |
# Found iteration line.
|
252 |
wfs = txt[self.wfs_idx:self.density_idx].strip() |
253 |
dens = txt[self.density_idx:self.energy_idx].strip() |
254 |
energy = txt[self.energy_idx:self.fermi_idx].strip() |
255 |
if wfs:
|
256 |
p = fraction(float(wfs), -9.0) |
257 |
self.wfs_progress.set_fraction(p)
|
258 |
self.wfs_progress.set_text(wfs)
|
259 |
if dens:
|
260 |
p = fraction(float(dens), -4.0) |
261 |
self.dens_progress.set_fraction(p)
|
262 |
self.dens_progress.set_text(dens)
|
263 |
if energy:
|
264 |
if self.oldenergy is None: |
265 |
self.oldenergy = float(energy) |
266 |
else:
|
267 |
de = abs(self.oldenergy - float(energy)) |
268 |
self.oldenergy = float(energy) |
269 |
if de > 1e-10: |
270 |
de = np.log10(de/self.natoms)
|
271 |
p = fraction(de, -3.0)
|
272 |
self.energy_progress.set_fraction(p)
|
273 |
self.energy_progress.set_text("%.1f" % de) |
274 |
else:
|
275 |
self.energy_progress.set_fraction(1) |
276 |
self.energy_progress.set_text("unchanged") |
277 |
words = txt.split() |
278 |
self.iteration.set_text(words[1]) |
279 |
elif (-1 < txt.find("WFS") < txt.find("Density") < txt.find("Energy") |
280 |
< txt.find("Fermi")):
|
281 |
# Found header of convergence table
|
282 |
self.wfs_idx = txt.find("WFS") |
283 |
self.density_idx = txt.find("Density") |
284 |
self.energy_idx = txt.find("Energy") |
285 |
self.fermi_idx = txt.find("Fermi") |
286 |
self.status.set_text("Self-consistency loop") |
287 |
self.iteration.set_text("0") |
288 |
elif txt.find("Converged After") != -1: |
289 |
# SCF loop has converged.
|
290 |
words = txt.split() |
291 |
self.status.set_text("Calculating forces") |
292 |
self.iteration.set_text(words[2]+" (converged)") |
293 |
elif -1 < txt.find("Calculator") < txt.find("MiB"): |
294 |
# Memory estimate
|
295 |
words = txt.split() |
296 |
self.memorylabel.set_text(words[1]+" "+words[2]) |
297 |
self.activity()
|
298 |
|
299 |
def get_gpaw_stream(self): |
300 |
return GpawStream(self) |
301 |
|
302 |
|
303 |
|
304 |
class LoggerStream: |
305 |
"A file-like object feeding minimizer logs to GpawProgressWindow."
|
306 |
def __init__(self, progresswindow): |
307 |
self.window = progresswindow
|
308 |
|
309 |
def write(self, txt): |
310 |
self.window.logger_write(txt)
|
311 |
|
312 |
def flush(self): |
313 |
pass
|
314 |
|
315 |
|
316 |
class GpawStream: |
317 |
"A file-like object feeding GPAWs txt file to GpawProgressWindow."
|
318 |
def __init__(self, progresswindow): |
319 |
self.window = progresswindow
|
320 |
|
321 |
def write(self, txt): |
322 |
if txt == "": |
323 |
return
|
324 |
endline = txt[-1] == '\n' |
325 |
if endline:
|
326 |
txt = txt[:-1]
|
327 |
lines = txt.split("\n")
|
328 |
if endline:
|
329 |
for l in lines: |
330 |
self.window.gpaw_write(l+'\n') |
331 |
else:
|
332 |
for l in lines[:-1]: |
333 |
self.window.gpaw_write(l+'\n') |
334 |
self.window.gpaw_write(lines[-1]) |
335 |
|
336 |
def flush(self): |
337 |
pass
|
338 |
|
339 |
def fraction(value, maximum): |
340 |
p = value/maximum |
341 |
if p < 0.0: |
342 |
return 0.0 |
343 |
elif p > 1.0: |
344 |
return 1.0 |
345 |
else:
|
346 |
return p
|
347 |
|
348 |
|