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