Statistiques
| Révision :

root / ase / gui / scaling.py @ 3

Historique | Voir | Annoter | Télécharger (14,54 ko)

1 1 tkerber
# encoding: utf-8
2 1 tkerber
3 1 tkerber
"Module for homogeneous deformation and calculations of elastic constants."
4 1 tkerber
5 1 tkerber
import gtk
6 1 tkerber
from ase.gui.simulation import Simulation
7 1 tkerber
from ase.gui.minimize import MinimizeMixin
8 1 tkerber
from ase.gui.energyforces import OutputFieldMixin
9 1 tkerber
from ase.gui.widgets import oops, pack, AseGuiCancelException
10 1 tkerber
import ase
11 1 tkerber
import numpy as np
12 1 tkerber
13 1 tkerber
scaling_txt = """\
14 1 tkerber
This module is intended for calculating elastic constants by homogeneously
15 1 tkerber
deforming a system."""
16 1 tkerber
17 1 tkerber
class HomogeneousDeformation(Simulation, MinimizeMixin, OutputFieldMixin):
18 1 tkerber
    "Window for homogeneous deformation and elastic constants."
19 1 tkerber
20 1 tkerber
    def __init__(self, gui):
21 1 tkerber
        Simulation.__init__(self, gui)
22 1 tkerber
        self.set_title("Homogeneous scaling")
23 1 tkerber
        vbox = gtk.VBox()
24 1 tkerber
        self.packtext(vbox, scaling_txt)
25 1 tkerber
        self.packimageselection(vbox, txt1="", txt2="")
26 1 tkerber
        self.start_radio_nth.set_active(True)
27 1 tkerber
        pack(vbox, gtk.Label(""))
28 1 tkerber
29 1 tkerber
        # Radio buttons for choosing deformation mode.
30 1 tkerber
        tbl = gtk.Table(4,3)
31 1 tkerber
        for i, l in enumerate(('3D', '2D', '1D')):
32 1 tkerber
            l = l + " deformation   "
33 1 tkerber
            lbl = gtk.Label(l)
34 1 tkerber
            tbl.attach(lbl, i, i+1, 0, 1)
35 1 tkerber
        self.radio_bulk = gtk.RadioButton(None, "Bulk")
36 1 tkerber
        tbl.attach(self.radio_bulk, 0, 1, 1, 2)
37 1 tkerber
        self.radio_xy = gtk.RadioButton(self.radio_bulk, "xy-plane")
38 1 tkerber
        tbl.attach(self.radio_xy, 1, 2, 1, 2)
39 1 tkerber
        self.radio_xz = gtk.RadioButton(self.radio_bulk, "xz-plane")
40 1 tkerber
        tbl.attach(self.radio_xz, 1, 2, 2, 3)
41 1 tkerber
        self.radio_yz = gtk.RadioButton(self.radio_bulk, "yz-plane")
42 1 tkerber
        tbl.attach(self.radio_yz, 1, 2, 3, 4)
43 1 tkerber
        self.radio_x = gtk.RadioButton(self.radio_bulk, "x-axis")
44 1 tkerber
        tbl.attach(self.radio_x, 2, 3, 1, 2)
45 1 tkerber
        self.radio_y = gtk.RadioButton(self.radio_bulk, "y-axis")
46 1 tkerber
        tbl.attach(self.radio_y, 2, 3, 2, 3)
47 1 tkerber
        self.radio_z = gtk.RadioButton(self.radio_bulk, "z-axis")
48 1 tkerber
        tbl.attach(self.radio_z, 2, 3, 3, 4)
49 1 tkerber
        tbl.show_all()
50 1 tkerber
        pack(vbox, [tbl])
51 1 tkerber
        self.deformtable = [
52 1 tkerber
            (self.radio_bulk, (1,1,1)),
53 1 tkerber
            (self.radio_xy, (1,1,0)),
54 1 tkerber
            (self.radio_xz, (1,0,1)),
55 1 tkerber
            (self.radio_yz, (0,1,1)),
56 1 tkerber
            (self.radio_x, (1,0,0)),
57 1 tkerber
            (self.radio_y, (0,1,0)),
58 1 tkerber
            (self.radio_z, (0,0,1))]
59 1 tkerber
        self.deform_label = gtk.Label("")
60 1 tkerber
        pack(vbox, [self.deform_label])
61 1 tkerber
        self.choose_possible_deformations(first=True)
62 1 tkerber
63 1 tkerber
        # Parameters for the deformation
64 1 tkerber
        framedef = gtk.Frame("Deformation:")
65 1 tkerber
        vbox2 = gtk.VBox()
66 1 tkerber
        vbox2.show()
67 1 tkerber
        framedef.add(vbox2)
68 1 tkerber
        self.max_scale = gtk.Adjustment(0.010, 0.001, 10.0, 0.001)
69 1 tkerber
        max_scale_spin = gtk.SpinButton(self.max_scale, 10.0, 3)
70 1 tkerber
        pack(vbox2, [gtk.Label("Maximal scale factor: "), max_scale_spin])
71 1 tkerber
        self.scale_offset = gtk.Adjustment(0.0, -10.0, 10.0, 0.001)
72 1 tkerber
        scale_offset_spin = gtk.SpinButton(self.scale_offset, 10.0, 3)
73 1 tkerber
        pack(vbox2, [gtk.Label("Scale offset: "), scale_offset_spin])
74 1 tkerber
        self.nsteps = gtk.Adjustment(5, 3, 100, 1)
75 1 tkerber
        nsteps_spin = gtk.SpinButton(self.nsteps, 1, 0)
76 1 tkerber
        pack(vbox2, [gtk.Label("Number of steps: "), nsteps_spin])
77 1 tkerber
78 1 tkerber
        # Atomic relaxations
79 1 tkerber
        framerel = gtk.Frame("Atomic relaxations:")
80 1 tkerber
        vbox2 = gtk.VBox()
81 1 tkerber
        vbox2.show()
82 1 tkerber
        framerel.add(vbox2)
83 1 tkerber
        self.radio_relax_on = gtk.RadioButton(None, "On   ")
84 1 tkerber
        self.radio_relax_off = gtk.RadioButton(self.radio_relax_on, "Off")
85 1 tkerber
        self.radio_relax_off.set_active(True)
86 1 tkerber
        pack(vbox2, [self.radio_relax_on, self.radio_relax_off])
87 1 tkerber
        self.make_minimize_gui(vbox2)
88 1 tkerber
        for r in (self.radio_relax_on, self.radio_relax_off):
89 1 tkerber
            r.connect("toggled", self.relax_toggled)
90 1 tkerber
        self.relax_toggled()
91 1 tkerber
        pack(vbox, [framedef, gtk.Label(" "), framerel])
92 1 tkerber
        pack(vbox, gtk.Label(""))
93 1 tkerber
94 1 tkerber
        # Results
95 1 tkerber
        pack(vbox, [gtk.Label("Results:")])
96 1 tkerber
        self.radio_results_optimal = gtk.RadioButton(
97 1 tkerber
            None, "Load optimal configuration")
98 1 tkerber
        self.radio_results_all =  gtk.RadioButton(
99 1 tkerber
            self.radio_results_optimal, "Load all configurations")
100 1 tkerber
        self.radio_results_optimal.set_active(True)
101 1 tkerber
        pack(vbox, [self.radio_results_optimal])
102 1 tkerber
        pack(vbox, [self.radio_results_all])
103 1 tkerber
104 1 tkerber
        # Output field
105 1 tkerber
        outframe = self.makeoutputfield(None)
106 1 tkerber
        fitframe = gtk.Frame("Fit:")
107 1 tkerber
        vbox2 = gtk.VBox()
108 1 tkerber
        vbox2.show()
109 1 tkerber
        fitframe.add(vbox2)
110 1 tkerber
        self.radio_fit_2 = gtk.RadioButton(None, "2nd")
111 1 tkerber
        self.radio_fit_3 = gtk.RadioButton(self.radio_fit_2, "3rd")
112 1 tkerber
        self.radio_fit_2.connect("toggled", self.change_fit)
113 1 tkerber
        self.radio_fit_3.connect("toggled", self.change_fit)
114 1 tkerber
        self.radio_fit_3.set_active(True)
115 1 tkerber
        pack(vbox2, [gtk.Label("Order of fit: "), self.radio_fit_2,
116 1 tkerber
                     self.radio_fit_3])
117 1 tkerber
        pack(vbox2, [gtk.Label("")])
118 1 tkerber
        scrwin = gtk.ScrolledWindow()
119 1 tkerber
        scrwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
120 1 tkerber
        self.fit_output = gtk.TextBuffer()
121 1 tkerber
        txtview = gtk.TextView(self.fit_output)
122 1 tkerber
        txtview.set_editable(False)
123 1 tkerber
        scrwin.add(txtview)
124 1 tkerber
        scrwin.show_all()
125 1 tkerber
        self.fit_win = scrwin
126 1 tkerber
        print "SIZE RQ:", scrwin.size_request()
127 1 tkerber
        vbox2.pack_start(scrwin, True, True, 0)
128 1 tkerber
        hbox = gtk.HBox(homogeneous=True)
129 1 tkerber
        for w in [outframe, fitframe]:
130 1 tkerber
            hbox.pack_start(w)
131 1 tkerber
            w.show()
132 1 tkerber
        pack(vbox, hbox)
133 1 tkerber
        pack(vbox, gtk.Label(""))
134 1 tkerber
135 1 tkerber
        # Status field
136 1 tkerber
        self.status_label = gtk.Label("")
137 1 tkerber
        pack(vbox, [self.status_label])
138 1 tkerber
139 1 tkerber
        # Run buttons etc.
140 1 tkerber
        self.makebutbox(vbox)
141 1 tkerber
        vbox.show()
142 1 tkerber
        self.add(vbox)
143 1 tkerber
        self.show()
144 1 tkerber
        self.gui.register_vulnerable(self)
145 1 tkerber
146 1 tkerber
    def choose_possible_deformations(self, first=False):
147 1 tkerber
        """Turn on sensible radio buttons.
148 1 tkerber

149 1 tkerber
        Only radio buttons corresponding to deformations in directions
150 1 tkerber
        with periodic boundary conditions should be turned on.
151 1 tkerber
        """
152 1 tkerber
        if self.setup_atoms():
153 1 tkerber
            pbc = self.atoms.get_pbc()
154 1 tkerber
        else:
155 1 tkerber
            pbc = [False, False, False]
156 1 tkerber
        for radio, requirement in self.deformtable:
157 1 tkerber
            ok = True
158 1 tkerber
            for i in range(3):
159 1 tkerber
                if requirement[i] and not pbc[i]:
160 1 tkerber
                    ok = False
161 1 tkerber
            radio.set_sensitive(ok)
162 1 tkerber
            if first and ok:
163 1 tkerber
                # The first acceptable choice, choose it to prevent
164 1 tkerber
                # inconsistent state.
165 1 tkerber
                radio.set_active(True)
166 1 tkerber
                first = False
167 1 tkerber
168 1 tkerber
    def relax_toggled(self, *args):
169 1 tkerber
        "Turn minimization widgets on or off."
170 1 tkerber
        state = self.radio_relax_on.get_active()
171 1 tkerber
        for widget in (self.algo, self.fmax_spin, self.steps_spin):
172 1 tkerber
            widget.set_sensitive(state)
173 1 tkerber
174 1 tkerber
    def notify_atoms_changed(self):
175 1 tkerber
        "When atoms have changed, check for the number of images."
176 1 tkerber
        self.setupimageselection()
177 1 tkerber
        self.choose_possible_deformations()
178 1 tkerber
179 1 tkerber
    def get_deformation_axes(self):
180 1 tkerber
        """Return which axes the user wants to deform along."""
181 1 tkerber
        for but, deform in self.deformtable:
182 1 tkerber
            if but.get_active():
183 1 tkerber
                return np.array(deform)
184 1 tkerber
        # No deformation chosen!
185 1 tkerber
        oops("No deformation chosen: Please choose a deformation mode.")
186 1 tkerber
        return False
187 1 tkerber
188 1 tkerber
    def run(self, *args):
189 1 tkerber
        """Make the deformation."""
190 1 tkerber
        self.output.set_text("")
191 1 tkerber
        if not self.setup_atoms():
192 1 tkerber
            return
193 1 tkerber
        deform_axes = self.get_deformation_axes()
194 1 tkerber
        if deform_axes is False:
195 1 tkerber
            return  #Nothing to do!
196 1 tkerber
197 1 tkerber
        # Prepare progress bar
198 1 tkerber
        if self.radio_relax_on.get_active():
199 1 tkerber
            fmax = self.fmax.value
200 1 tkerber
            mininame = self.minimizers[self.algo.get_active()]
201 1 tkerber
            self.begin(mode="scale/min", algo=mininame, fmax=fmax,
202 1 tkerber
                       steps=self.steps.value, scalesteps=self.nsteps.value)
203 1 tkerber
        else:
204 1 tkerber
            self.begin(mode="scale", scalesteps=self.nsteps.value)
205 1 tkerber
        try:
206 1 tkerber
            logger_func = self.gui.simulation['progress'].get_logger_stream
207 1 tkerber
        except (KeyError, AttributeError):
208 1 tkerber
            logger = None
209 1 tkerber
        else:
210 1 tkerber
            logger = logger_func()  # Don't catch errors in the function.
211 1 tkerber
212 1 tkerber
        # Display status message
213 1 tkerber
        self.status_label.set_text("Running ...")
214 1 tkerber
        self.status_label.modify_fg(gtk.STATE_NORMAL,
215 1 tkerber
                                    gtk.gdk.color_parse('#AA0000'))
216 1 tkerber
        while gtk.events_pending():
217 1 tkerber
            gtk.main_iteration()
218 1 tkerber
219 1 tkerber
        # Do the scaling
220 1 tkerber
        scale = self.max_scale.value
221 1 tkerber
        steps = np.linspace(-scale, scale, self.nsteps.value)
222 1 tkerber
        steps += self.scale_offset.value
223 1 tkerber
        undef_cell = self.atoms.get_cell()
224 1 tkerber
        results = []
225 1 tkerber
        txt = "Strain\t\tEnergy [eV]\n"
226 1 tkerber
        # If we load all configurations, prepare it.
227 1 tkerber
        if self.radio_results_all.get_active():
228 1 tkerber
            self.prepare_store_atoms()
229 1 tkerber
230 1 tkerber
        try:
231 1 tkerber
            # Now, do the deformation
232 1 tkerber
            for i, d in enumerate(steps):
233 1 tkerber
                deformation = np.diag(1.0 + d * deform_axes)
234 1 tkerber
                self.atoms.set_cell(np.dot(undef_cell, deformation),
235 1 tkerber
                                    scale_atoms=True)
236 1 tkerber
                if self.gui.simulation.has_key('progress'):
237 1 tkerber
                    self.gui.simulation['progress'].set_scale_progress(i)
238 1 tkerber
                if self.radio_relax_on.get_active():
239 1 tkerber
                    algo = getattr(ase.optimize, mininame)
240 1 tkerber
                    minimizer = algo(self.atoms, logfile=logger)
241 1 tkerber
                    minimizer.run(fmax=fmax, steps=self.steps.value)
242 1 tkerber
                e = self.atoms.get_potential_energy()
243 1 tkerber
                results.append((d, e))
244 1 tkerber
                txt = txt + ("%.3f\t\t%.3f\n" % (d, e))
245 1 tkerber
                self.output.set_text(txt)
246 1 tkerber
                if self.radio_results_all.get_active():
247 1 tkerber
                    self.store_atoms()
248 1 tkerber
        except AseGuiCancelException:
249 1 tkerber
            # Update display to reflect cancellation of simulation.
250 1 tkerber
            self.status_label.set_text("Calculation CANCELLED.")
251 1 tkerber
            self.status_label.modify_fg(gtk.STATE_NORMAL,
252 1 tkerber
                                        gtk.gdk.color_parse('#AA4000'))
253 1 tkerber
        except MemoryError:
254 1 tkerber
            self.status_label.set_text("Out of memory, consider using LBFGS instead")
255 1 tkerber
            self.status_label.modify_fg(gtk.STATE_NORMAL,
256 1 tkerber
                                        gtk.gdk.color_parse('#AA4000'))
257 1 tkerber
258 1 tkerber
        else:
259 1 tkerber
            # Update display to reflect succesful end of simulation.
260 1 tkerber
            self.status_label.set_text("Calculation completed.")
261 1 tkerber
            self.status_label.modify_fg(gtk.STATE_NORMAL,
262 1 tkerber
                                        gtk.gdk.color_parse('#007700'))
263 1 tkerber
264 1 tkerber
        if results:
265 1 tkerber
            self.do_fit(np.array(results))
266 1 tkerber
            if self.radio_results_optimal.get_active():
267 1 tkerber
                if self.minimum_ok:
268 1 tkerber
                    deformation = np.diag(1.0 + self.x0 * deform_axes)
269 1 tkerber
                    self.atoms.set_cell(np.dot(undef_cell, deformation),
270 1 tkerber
                                        scale_atoms=True)
271 1 tkerber
                    if self.radio_relax_on.get_active():
272 1 tkerber
                        if self.gui.simulation.has_key('progress'):
273 1 tkerber
                            self.gui.simulation['progress'].set_scale_progress(
274 1 tkerber
                                len(steps))
275 1 tkerber
                        algo = getattr(ase.optimize, mininame)
276 1 tkerber
                        minimizer = algo(self.atoms, logfile=logger)
277 1 tkerber
                        minimizer.run(fmax=fmax, steps=self.steps.value)
278 1 tkerber
                    # Store the optimal configuration.
279 1 tkerber
                    self.prepare_store_atoms()
280 1 tkerber
                    self.store_atoms()
281 1 tkerber
                else:
282 1 tkerber
                    oops("No trustworthy minimum: Old configuration kept.")
283 1 tkerber
            self.activate_output()
284 1 tkerber
            self.gui.notify_vulnerable()
285 1 tkerber
        self.end()
286 1 tkerber
287 1 tkerber
        # If we store all configurations: Open movie window and energy graph
288 1 tkerber
        if self.gui.images.nimages > 1:
289 1 tkerber
            self.gui.movie()
290 1 tkerber
            assert not np.isnan(self.gui.images.E[0])
291 1 tkerber
            if not self.gui.plot_graphs_newatoms():
292 1 tkerber
                expr = 'i, e - E[-1]'
293 1 tkerber
                self.gui.plot_graphs(expr=expr)
294 1 tkerber
            # Continuations should use the best image
295 1 tkerber
            nbest = np.argmin(np.array(results)[:,1])
296 1 tkerber
            self.start_nth_adj.value = nbest
297 1 tkerber
298 1 tkerber
299 1 tkerber
    def change_fit(self, widget):
300 1 tkerber
        "Repeat the fitting if the order is changed."
301 1 tkerber
        # It may be called both for the button being turned on and the
302 1 tkerber
        # one being turned off.  But we only want to call do_fit once.
303 1 tkerber
        # And only if there are already cached results (ie. if the
304 1 tkerber
        # order is changed AFTER the calculation is done).
305 1 tkerber
        if widget.get_active() and getattr(self, "results", None) is not None:
306 1 tkerber
            self.do_fit(None)
307 1 tkerber
308 1 tkerber
    def do_fit(self, results):
309 1 tkerber
        "Fit the results to a polynomial"
310 1 tkerber
        if results is None:
311 1 tkerber
            results = self.results  # Use cached results
312 1 tkerber
        else:
313 1 tkerber
            self.results = results  # Keep for next time
314 1 tkerber
        self.minimum_ok = False
315 1 tkerber
        if self.radio_fit_3.get_active():
316 1 tkerber
            order = 3
317 1 tkerber
        else:
318 1 tkerber
            order = 2
319 1 tkerber
320 1 tkerber
        if len(results) < 3:
321 1 tkerber
            txt = ("Insufficent data for a fit\n(only %i data points)\n"
322 1 tkerber
                   % (len(results),) )
323 1 tkerber
            order = 0
324 1 tkerber
        elif len(results) == 3 and order == 3:
325 1 tkerber
            txt = "REVERTING TO 2ND ORDER FIT\n(only 3 data points)\n\n"
326 1 tkerber
            order = 2
327 1 tkerber
        else:
328 1 tkerber
            txt = ""
329 1 tkerber
330 1 tkerber
        if order > 0:
331 1 tkerber
            fit0 = np.poly1d(np.polyfit(results[:,0], results[:,1], order))
332 1 tkerber
            fit1 = np.polyder(fit0, 1)
333 1 tkerber
            fit2 = np.polyder(fit1, 1)
334 1 tkerber
335 1 tkerber
            x0 = None
336 1 tkerber
            for t in np.roots(fit1):
337 1 tkerber
                if fit2(t) > 0:
338 1 tkerber
                    x0 = t
339 1 tkerber
                    break
340 1 tkerber
            if x0 is None:
341 1 tkerber
                txt = txt + "No minimum found!"
342 1 tkerber
            else:
343 1 tkerber
                e0 = fit0(x0)
344 1 tkerber
                e2 = fit2(x0)
345 1 tkerber
                txt += "E = "
346 1 tkerber
                if order == 3:
347 1 tkerber
                    txt += "A(x - x0)³ + "
348 1 tkerber
                txt += "B(x - x0)² + C\n\n"
349 1 tkerber
                txt += "B = %.5g eV\n" % (e2,)
350 1 tkerber
                txt += "C = %.5g eV\n" % (e0,)
351 1 tkerber
                txt += "x0 = %.5g\n" % (x0,)
352 1 tkerber
                lowest = self.scale_offset.value - self.max_scale.value
353 1 tkerber
                highest = self.scale_offset.value + self.max_scale.value
354 1 tkerber
                if x0 < lowest or x0 > highest:
355 1 tkerber
                    txt += "\nWARNING: Minimum is outside interval\n"
356 1 tkerber
                    txt += "It is UNRELIABLE!\n"
357 1 tkerber
                else:
358 1 tkerber
                    self.minimum_ok = True
359 1 tkerber
                    self.x0 = x0
360 1 tkerber
        self.fit_output.set_text(txt)