root / ase / gui / progress.py @ 4
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 |
|