Statistiques
| Révision :

root / ase / gui / nanoparticle.py @ 11

Historique | Voir | Annoter | Télécharger (17,65 ko)

1 1 tkerber
# encoding: utf-8
2 1 tkerber
"""nanoparticle.py - Window for setting up crystalline nanoparticles.
3 1 tkerber
"""
4 1 tkerber
5 1 tkerber
import gtk
6 1 tkerber
from ase.gui.widgets import pack, cancel_apply_ok, oops
7 1 tkerber
from ase.gui.setupwindow import SetupWindow
8 1 tkerber
from ase.gui.pybutton import PyButton
9 1 tkerber
import ase
10 1 tkerber
import numpy as np
11 1 tkerber
# Delayed imports:
12 1 tkerber
# ase.cluster.data
13 1 tkerber
14 1 tkerber
introtext = """\
15 1 tkerber
You specify the size of the particle by specifying the number of atomic layers
16 1 tkerber
in the different low-index crystal directions.  Often, the number of layers is
17 1 tkerber
specified for a family of directions, but they can be given individually.
18 1 tkerber

19 1 tkerber
When the particle is created, the actual numbers of layers are printed, they
20 1 tkerber
may be less than specified if a surface is cut of by other surfaces."""
21 1 tkerber
22 1 tkerber
py_template = """
23 1 tkerber
from ase.cluster import Cluster
24 1 tkerber
import ase
25 1 tkerber

26 1 tkerber
layers = %(layers)s
27 1 tkerber
atoms = Cluster(symbol='%(element)s', layers=layers, latticeconstant=%(a).5f,
28 1 tkerber
                symmetry='%(structure)s')
29 1 tkerber

30 1 tkerber
# OPTIONAL: Cast to ase.Atoms object, discarding extra information:
31 1 tkerber
# atoms = ase.Atoms(atoms)
32 1 tkerber
"""
33 1 tkerber
34 1 tkerber
class attribute_collection:
35 1 tkerber
    pass
36 1 tkerber
37 1 tkerber
class SetupNanoparticle(SetupWindow):
38 1 tkerber
    "Window for setting up a nanoparticle."
39 1 tkerber
    families = {'fcc': [(0,0,1), (0,1,1), (1,1,1)]}
40 1 tkerber
    defaults = {'fcc': [6, 9, 5]}
41 1 tkerber
42 1 tkerber
    def __init__(self, gui):
43 1 tkerber
        SetupWindow.__init__(self)
44 1 tkerber
        self.set_title("Nanoparticle")
45 1 tkerber
        self.atoms = None
46 1 tkerber
        import ase.cluster.data
47 1 tkerber
        self.data_module = ase.cluster.data
48 1 tkerber
        import ase.cluster
49 1 tkerber
        self.Cluster = ase.cluster.Cluster
50 1 tkerber
        self.wulffconstruction = ase.cluster.wulff_construction
51 1 tkerber
        self.no_update = True
52 1 tkerber
53 1 tkerber
        vbox = gtk.VBox()
54 1 tkerber
55 1 tkerber
        # Intoductory text
56 1 tkerber
        self.packtext(vbox, introtext)
57 1 tkerber
58 1 tkerber
        # Choose the element
59 1 tkerber
        label = gtk.Label("Element: ")
60 1 tkerber
        label.set_alignment(0.0, 0.2)
61 1 tkerber
        element = gtk.Entry(max=3)
62 1 tkerber
        self.element = element
63 1 tkerber
        lattice_button = gtk.Button("Get structure")
64 1 tkerber
        lattice_button.connect('clicked', self.get_structure)
65 1 tkerber
        self.elementinfo = gtk.Label(" ")
66 1 tkerber
        pack(vbox, [label, element, self.elementinfo, lattice_button], end=True)
67 1 tkerber
        self.element.connect('activate', self.update)
68 1 tkerber
        self.legal_element = False
69 1 tkerber
70 1 tkerber
        # The structure and lattice constant
71 1 tkerber
        label = gtk.Label("Structure: ")
72 1 tkerber
        self.structure = gtk.combo_box_new_text()
73 1 tkerber
        self.allowed_structures = ('fcc',)
74 1 tkerber
        for struct in self.allowed_structures:
75 1 tkerber
            self.structure.append_text(struct)
76 1 tkerber
        self.structure.set_active(0)
77 1 tkerber
        self.structure.connect('changed', self.update)
78 1 tkerber
79 1 tkerber
        label2 = gtk.Label("   Lattice constant: ")
80 1 tkerber
        self.lattice_const = gtk.Adjustment(3.0, 0.0, 1000.0, 0.01)
81 1 tkerber
        lattice_box = gtk.SpinButton(self.lattice_const, 10.0, 3)
82 1 tkerber
        lattice_box.numeric = True
83 1 tkerber
        pack(vbox, [label, self.structure, label2, lattice_box])
84 1 tkerber
        self.lattice_const.connect('value-changed', self.update)
85 1 tkerber
86 1 tkerber
        # Choose specification method
87 1 tkerber
        label = gtk.Label("Method: ")
88 1 tkerber
        self.method = gtk.combo_box_new_text()
89 1 tkerber
        for meth in ("Layer specification", "Wulff construction"):
90 1 tkerber
            self.method.append_text(meth)
91 1 tkerber
        self.method.set_active(0)
92 1 tkerber
        self.method.connect('changed', self.update_gui)
93 1 tkerber
        pack(vbox, [label, self.method])
94 1 tkerber
        pack(vbox, gtk.Label(""))
95 1 tkerber
96 1 tkerber
        # The number of layers
97 1 tkerber
        self.layerbox = gtk.VBox()
98 1 tkerber
        self.layerdata = attribute_collection()
99 1 tkerber
        pack(vbox, self.layerbox)
100 1 tkerber
        self.make_layer_gui(self.layerbox, self.layerdata, 0)
101 1 tkerber
102 1 tkerber
        # The Wulff construction
103 1 tkerber
        self.wulffbox = gtk.VBox()
104 1 tkerber
        self.wulffdata = attribute_collection()
105 1 tkerber
        pack(vbox, self.wulffbox)
106 1 tkerber
        self.make_layer_gui(self.wulffbox, self.wulffdata, 1)
107 1 tkerber
        label = gtk.Label("Particle size: ")
108 1 tkerber
        self.size_n_radio = gtk.RadioButton(None, "Number of atoms: ")
109 1 tkerber
        self.size_n_radio.set_active(True)
110 1 tkerber
        self.size_n_adj = gtk.Adjustment(100, 1, 100000, 1)
111 1 tkerber
        self.size_n_spin = gtk.SpinButton(self.size_n_adj, 0, 0)
112 1 tkerber
        self.size_dia_radio = gtk.RadioButton(self.size_n_radio,
113 1 tkerber
                                              "Volume: ")
114 1 tkerber
        self.size_dia_adj = gtk.Adjustment(1.0, 0, 100.0, 0.1)
115 1 tkerber
        self.size_dia_spin = gtk.SpinButton(self.size_dia_adj, 10.0, 2)
116 1 tkerber
        pack(self.wulffbox, [label, self.size_n_radio, self.size_n_spin,
117 1 tkerber
                    gtk.Label("   "), self.size_dia_radio, self.size_dia_spin,
118 1 tkerber
                    gtk.Label("ų")])
119 1 tkerber
        self.size_n_radio.connect("toggled", self.update_gui)
120 1 tkerber
        self.size_dia_radio.connect("toggled", self.update_gui)
121 1 tkerber
        self.size_n_adj.connect("value-changed", self.update_size_n)
122 1 tkerber
        self.size_dia_adj.connect("value-changed", self.update_size_dia)
123 1 tkerber
        self.update_size_n()
124 1 tkerber
        label = gtk.Label(
125 1 tkerber
            "Rounding: If exact size is not possible, choose the size")
126 1 tkerber
        pack(self.wulffbox, [label])
127 1 tkerber
        self.round_above = gtk.RadioButton(None, "above  ")
128 1 tkerber
        self.round_below = gtk.RadioButton(self.round_above, "below  ")
129 1 tkerber
        self.round_closest = gtk.RadioButton(self.round_above, "closest  ")
130 1 tkerber
        self.round_closest.set_active(True)
131 1 tkerber
        buts = [self.round_above, self.round_below, self.round_closest]
132 1 tkerber
        pack(self.wulffbox, buts)
133 1 tkerber
        for b in buts:
134 1 tkerber
            b.connect("toggled", self.update)
135 1 tkerber
136 1 tkerber
        # Information
137 1 tkerber
        pack(vbox, gtk.Label(""))
138 1 tkerber
        infobox = gtk.VBox()
139 1 tkerber
        label1 = gtk.Label("Number of atoms: ")
140 1 tkerber
        self.natoms_label = gtk.Label("-")
141 1 tkerber
        label2 = gtk.Label("   Approx. diameter: ")
142 1 tkerber
        self.dia1_label = gtk.Label("-")
143 1 tkerber
        pack(infobox, [label1, self.natoms_label, label2, self.dia1_label])
144 1 tkerber
        pack(infobox, gtk.Label(""))
145 1 tkerber
        infoframe = gtk.Frame("Information about the created cluster:")
146 1 tkerber
        infoframe.add(infobox)
147 1 tkerber
        infobox.show()
148 1 tkerber
        pack(vbox, infoframe)
149 1 tkerber
150 1 tkerber
        # Buttons
151 1 tkerber
        self.pybut = PyButton("Creating a nanoparticle.")
152 1 tkerber
        self.pybut.connect('clicked', self.makeatoms)
153 1 tkerber
        buts = cancel_apply_ok(cancel=lambda widget: self.destroy(),
154 1 tkerber
                               apply=self.apply,
155 1 tkerber
                               ok=self.ok)
156 1 tkerber
        pack(vbox, [self.pybut, buts], end=True, bottom=True)
157 1 tkerber
        self.auto = gtk.CheckButton("Automatic Apply")
158 1 tkerber
        fr = gtk.Frame()
159 1 tkerber
        fr.add(self.auto)
160 1 tkerber
        fr.show_all()
161 1 tkerber
        pack(vbox, [fr], end=True, bottom=True)
162 1 tkerber
163 1 tkerber
        # Finalize setup
164 1 tkerber
        self.update_gui()
165 1 tkerber
        self.add(vbox)
166 1 tkerber
        vbox.show()
167 1 tkerber
        self.show()
168 1 tkerber
        self.gui = gui
169 1 tkerber
        self.no_update = False
170 1 tkerber
171 1 tkerber
    def update_gui(self, widget=None):
172 1 tkerber
        method = self.method.get_active()
173 1 tkerber
        if method == 0:
174 1 tkerber
            self.wulffbox.hide()
175 1 tkerber
            self.layerbox.show()
176 1 tkerber
        elif method == 1:
177 1 tkerber
            self.layerbox.hide()
178 1 tkerber
            self.wulffbox.show()
179 1 tkerber
            self.size_n_spin.set_sensitive(self.size_n_radio.get_active())
180 1 tkerber
            self.size_dia_spin.set_sensitive(self.size_dia_radio.get_active())
181 1 tkerber
182 1 tkerber
    def update_size_n(self, widget=None):
183 1 tkerber
        if not self.size_n_radio.get_active():
184 1 tkerber
            return
185 1 tkerber
        at_vol = self.get_atomic_volume()
186 1 tkerber
        dia = 2.0 * (3 * self.size_n_adj.value * at_vol / (4 * np.pi))**(1.0/3)
187 1 tkerber
        self.size_dia_adj.value = dia
188 1 tkerber
        self.update()
189 1 tkerber
190 1 tkerber
    def update_size_dia(self, widget=None):
191 1 tkerber
        if not self.size_dia_radio.get_active():
192 1 tkerber
            return
193 1 tkerber
        at_vol = self.get_atomic_volume()
194 1 tkerber
        n = round(np.pi / 6 * self.size_dia_adj.value**3 / at_vol)
195 1 tkerber
        self.size_n_adj.value = n
196 1 tkerber
        self.update()
197 1 tkerber
198 1 tkerber
    def update(self, *args):
199 1 tkerber
        if self.no_update:
200 1 tkerber
            return
201 1 tkerber
        self.update_gui()
202 1 tkerber
        self.update_element()
203 1 tkerber
        if self.auto.get_active():
204 1 tkerber
            self.makeatoms()
205 1 tkerber
            if self.atoms is not None:
206 1 tkerber
                self.gui.new_atoms(self.atoms)
207 1 tkerber
        else:
208 1 tkerber
            self.clearatoms()
209 1 tkerber
        self.makeinfo()
210 1 tkerber
211 1 tkerber
    def get_structure(self, *args):
212 1 tkerber
        if not self.update_element():
213 1 tkerber
            oops("Invalid element.")
214 1 tkerber
            return
215 1 tkerber
        z = ase.atomic_numbers[self.legal_element]
216 1 tkerber
        ref = ase.data.reference_states[z]
217 1 tkerber
        if ref is None:
218 1 tkerber
            structure = None
219 1 tkerber
        else:
220 1 tkerber
            structure = ref['symmetry'].lower()
221 1 tkerber
222 1 tkerber
        if ref is None or not structure in self.allowed_structures:
223 1 tkerber
            oops("Unsupported or unknown structure",
224 1 tkerber
                 "Element = %s,  structure = %s" % (self.legal_element,
225 1 tkerber
                                                    structure))
226 1 tkerber
            return
227 1 tkerber
        for i, s in enumerate(self.allowed_structures):
228 1 tkerber
            if structure == s:
229 1 tkerber
                self.structure.set_active(i)
230 1 tkerber
        a = ref['a']
231 1 tkerber
        self.lattice_const.set_value(a)
232 1 tkerber
233 1 tkerber
    def make_layer_gui(self, box, data, method):
234 1 tkerber
        "Make the part of the gui specifying the layers of the particle"
235 1 tkerber
        assert method in (0,1)
236 1 tkerber
237 1 tkerber
        # Clear the box
238 1 tkerber
        children = box.get_children()
239 1 tkerber
        for c in children:
240 1 tkerber
            box.remove(c)
241 1 tkerber
        del children
242 1 tkerber
243 1 tkerber
        # Make the label
244 1 tkerber
        if method == 0:
245 1 tkerber
            txt = "Number of layers:"
246 1 tkerber
        else:
247 1 tkerber
            txt = "Surface energies (unit: energy/area, i.e. J/m<sup>2</sup> or eV/nm<sup>2</sup>, <i>not</i> eV/atom):"
248 1 tkerber
        label = gtk.Label()
249 1 tkerber
        label.set_markup(txt)
250 1 tkerber
        pack(box, [label])
251 1 tkerber
252 1 tkerber
        # Get the crystal structure
253 1 tkerber
        struct = self.structure.get_active_text()
254 1 tkerber
        # Get the surfaces in the order the ase.cluster module expects
255 1 tkerber
        surfaces = self.data_module.lattice[struct]['surface_names']
256 1 tkerber
        # Get the surface families
257 1 tkerber
        families = self.families[struct]
258 1 tkerber
        if method == 0:
259 1 tkerber
            defaults = self.defaults[struct]
260 1 tkerber
        else:
261 1 tkerber
            defaults = [1.0] * len(self.defaults[struct])
262 1 tkerber
263 1 tkerber
        # Empty array for the gtk.Adjustments for the layer numbers
264 1 tkerber
        data.layers = [None] * len(surfaces)
265 1 tkerber
        data.layer_lbl = [None] * len(surfaces)
266 1 tkerber
        data.layer_spin = [None] * len(surfaces)
267 1 tkerber
        data.layer_owner = [None] * len(surfaces)
268 1 tkerber
        data.layer_label = [None] * len(surfaces)
269 1 tkerber
        data.famlayers = [None] * len(families)
270 1 tkerber
        data.infamily = [None] * len(families)
271 1 tkerber
        data.family_label = [None] * len(families)
272 1 tkerber
273 1 tkerber
        # Now, make a box for each family of surfaces
274 1 tkerber
        frames = []
275 1 tkerber
        for i in range(len(families)):
276 1 tkerber
            family = families[i]
277 1 tkerber
            default = defaults[i]
278 1 tkerber
            frames.append(self.make_layer_family(data, i, family, surfaces,
279 1 tkerber
                                                 default, method))
280 1 tkerber
        for a in data.layers:
281 1 tkerber
            assert a is not None
282 1 tkerber
283 1 tkerber
        pack(box, frames)
284 1 tkerber
        box.show_all()
285 1 tkerber
286 1 tkerber
    def make_layer_family(self, data, n, family, surfaces, default, method):
287 1 tkerber
        """Make a frame box for a single family of surfaces.
288 1 tkerber

289 1 tkerber
        The layout is a frame containing a table.  For example
290 1 tkerber

291 1 tkerber
        {0,0,1}, SPIN, EMPTY, EMPTY
292 1 tkerber
        -- empty line --
293 1 tkerber
        (0,0,1), SPIN, Label(actual), Checkbox
294 1 tkerber
        ...
295 1 tkerber
        """
296 1 tkerber
        tbl = gtk.Table(2, 4)
297 1 tkerber
        lbl = gtk.Label("{%i,%i,%i}: " % family)
298 1 tkerber
        lbl.set_alignment(1, 0.5)
299 1 tkerber
        tbl.attach(lbl, 0, 1, 0, 1)
300 1 tkerber
        if method == 0:
301 1 tkerber
            famlayers = gtk.Adjustment(default, 1, 100, 1)
302 1 tkerber
            sbut = gtk.SpinButton(famlayers, 0, 0)
303 1 tkerber
        else:
304 1 tkerber
            flimit = 1000.0
305 1 tkerber
            famlayers = gtk.Adjustment(default, 0.0, flimit, 0.1)
306 1 tkerber
            sbut = gtk.SpinButton(famlayers, 10.0, 3)
307 1 tkerber
        tbl.attach(sbut, 2, 3, 0, 1)
308 1 tkerber
        tbl.attach(gtk.Label(" "), 0, 1, 1, 2)
309 1 tkerber
        assert data.famlayers[n] is None
310 1 tkerber
        data.famlayers[n] = famlayers
311 1 tkerber
        data.infamily[n] = []
312 1 tkerber
        data.family_label[n] = gtk.Label("")
313 1 tkerber
        tbl.attach(data.family_label[n], 1, 2, 0, 1)
314 1 tkerber
        row = 2
315 1 tkerber
        myspin = []
316 1 tkerber
        for i, s in enumerate(surfaces):
317 1 tkerber
            s2 = [abs(x) for x in s]
318 1 tkerber
            s2.sort()
319 1 tkerber
            if tuple(s2) == family:
320 1 tkerber
                data.infamily[n].append(i)
321 1 tkerber
                tbl.resize(row+1, 4)
322 1 tkerber
                lbl = gtk.Label("(%i,%i,%i): " % s)
323 1 tkerber
                lbl.set_alignment(1, 0.5)
324 1 tkerber
                tbl.attach(lbl, 0, 1, row, row+1)
325 1 tkerber
                label = gtk.Label("    ")
326 1 tkerber
                tbl.attach(label, 1, 2, row, row+1)
327 1 tkerber
                data.layer_label[i] = label
328 1 tkerber
                if method == 0:
329 1 tkerber
                    lay = gtk.Adjustment(default, -100, 100, 1)
330 1 tkerber
                    spin = gtk.SpinButton(lay, 0, 0)
331 1 tkerber
                else:
332 1 tkerber
                    lay = gtk.Adjustment(default, -flimit, flimit, 0.1)
333 1 tkerber
                    spin = gtk.SpinButton(lay, 10.0, 3)
334 1 tkerber
                lay.connect('value-changed', self.update)
335 1 tkerber
                spin.set_sensitive(False)
336 1 tkerber
                tbl.attach(spin, 2, 3, row, row+1)
337 1 tkerber
                assert data.layers[i] is None
338 1 tkerber
                data.layers[i] = lay
339 1 tkerber
                data.layer_lbl[i] = lbl
340 1 tkerber
                data.layer_spin[i] = spin
341 1 tkerber
                data.layer_owner[i] = n
342 1 tkerber
                myspin.append(spin)
343 1 tkerber
                chkbut = gtk.CheckButton()
344 1 tkerber
                tbl.attach(chkbut, 3, 4, row, row+1)
345 1 tkerber
                chkbut.connect("toggled", self.toggle_surface, i)
346 1 tkerber
                row += 1
347 1 tkerber
        famlayers.connect('value-changed', self.changed_family_layers, myspin)
348 1 tkerber
        vbox = gtk.VBox()
349 1 tkerber
        vbox.pack_start(tbl, False, False, 0)
350 1 tkerber
        fr = gtk.Frame()
351 1 tkerber
        fr.add(vbox)
352 1 tkerber
        fr.show_all()
353 1 tkerber
        return fr
354 1 tkerber
355 1 tkerber
    def toggle_surface(self, widget, number):
356 1 tkerber
        "Toggle whether a layer in a family can be specified."
357 1 tkerber
        active = widget.get_active()
358 1 tkerber
        data = self.get_data()
359 1 tkerber
        data.layer_spin[number].set_sensitive(active)
360 1 tkerber
        if not active:
361 1 tkerber
            data.layers[number].value = \
362 1 tkerber
                data.famlayers[data.layer_owner[number]].value
363 1 tkerber
364 1 tkerber
    def changed_family_layers(self, widget, myspin):
365 1 tkerber
        "Change the number of layers in inactive members of a family."
366 1 tkerber
        self.no_update = True
367 1 tkerber
        x = widget.value
368 1 tkerber
        for s in myspin:
369 1 tkerber
            if s.state == gtk.STATE_INSENSITIVE:
370 1 tkerber
                adj = s.get_adjustment()
371 1 tkerber
                if adj.value != x:
372 1 tkerber
                    adj.value = x
373 1 tkerber
        self.no_update = False
374 1 tkerber
        self.update()
375 1 tkerber
376 1 tkerber
    def get_data(self):
377 1 tkerber
        return self.layerdata
378 1 tkerber
379 1 tkerber
    def makeatoms(self, *args):
380 1 tkerber
        "Make the atoms according to the current specification."
381 1 tkerber
        if not self.update_element():
382 1 tkerber
            self.clearatoms()
383 1 tkerber
            self.makeinfo()
384 1 tkerber
            return False
385 1 tkerber
        assert self.legal_element is not None
386 1 tkerber
        struct = self.structure.get_active_text()
387 1 tkerber
        lc = self.lattice_const.value
388 1 tkerber
        if self.method.get_active() == 0:
389 1 tkerber
            # Layer-by-layer specification
390 1 tkerber
            layers = [int(x.value) for x in self.layerdata.layers]
391 1 tkerber
            self.atoms = self.Cluster(self.legal_element, layers=layers,
392 1 tkerber
                                      latticeconstant=lc, symmetry=struct)
393 1 tkerber
            self.pybut.python = py_template % {'element': self.legal_element,
394 1 tkerber
                                               'layers': str(layers),
395 1 tkerber
                                               'structure': struct,
396 1 tkerber
                                               'a': lc}
397 1 tkerber
        else:
398 1 tkerber
            # Wulff construction
399 1 tkerber
            assert self.method.get_active() == 1
400 1 tkerber
            surfaceenergies = [x.value for x in self.wulffdata.layers]
401 1 tkerber
            self.update_size_dia()
402 1 tkerber
            if self.round_above.get_active():
403 1 tkerber
                rounding = "above"
404 1 tkerber
            elif self.round_below.get_active():
405 1 tkerber
                rounding = "below"
406 1 tkerber
            elif self.round_closest.get_active():
407 1 tkerber
                rounding = "closest"
408 1 tkerber
            else:
409 1 tkerber
                raise RuntimeError("No rounding!")
410 1 tkerber
            self.atoms = self.wulffconstruction(self.legal_element,
411 1 tkerber
                                                surfaceenergies,
412 1 tkerber
                                                self.size_n_adj.value,
413 1 tkerber
                                                rounding, struct, lc)
414 1 tkerber
415 1 tkerber
        self.makeinfo()
416 1 tkerber
417 1 tkerber
    def clearatoms(self):
418 1 tkerber
        self.atoms = None
419 1 tkerber
        self.pybut.python = None
420 1 tkerber
421 1 tkerber
    def get_atomic_volume(self):
422 1 tkerber
        s = self.structure.get_active_text()
423 1 tkerber
        a = self.lattice_const.value
424 1 tkerber
        if s == 'fcc':
425 1 tkerber
            return a**3 / 4
426 1 tkerber
        else:
427 1 tkerber
            raise RuntimeError("Unknown structure: "+s)
428 1 tkerber
429 1 tkerber
    def makeinfo(self):
430 1 tkerber
        "Fill in information field about the atoms."
431 1 tkerber
        #data = self.get_data()
432 1 tkerber
        if self.atoms is None:
433 1 tkerber
            self.natoms_label.set_label("-")
434 1 tkerber
            self.dia1_label.set_label("-")
435 1 tkerber
            for d in (self.layerdata, self.wulffdata):
436 1 tkerber
                for label in d.layer_label+d.family_label:
437 1 tkerber
                    label.set_text("    ")
438 1 tkerber
        else:
439 1 tkerber
            self.natoms_label.set_label(str(len(self.atoms)))
440 1 tkerber
            at_vol = self.get_atomic_volume()
441 1 tkerber
            dia = 2 * (3 * len(self.atoms) * at_vol / (4 * np.pi))**(1.0/3.0)
442 1 tkerber
            self.dia1_label.set_label("%.1f Å" % (dia,))
443 1 tkerber
            actual = self.atoms.get_layers()
444 1 tkerber
            for i, a in enumerate(actual):
445 1 tkerber
                self.layerdata.layer_label[i].set_text("%2i " % (a,))
446 1 tkerber
                self.wulffdata.layer_label[i].set_text("%2i " % (a,))
447 1 tkerber
            for d in (self.layerdata, self.wulffdata):
448 1 tkerber
                for i, label in enumerate(d.family_label):
449 1 tkerber
                    relevant = actual[d.infamily[i]]
450 1 tkerber
                    if relevant.min() == relevant.max():
451 1 tkerber
                        label.set_text("%2i " % (relevant[0]))
452 1 tkerber
                    else:
453 1 tkerber
                        label.set_text("-- ")
454 1 tkerber
455 1 tkerber
    def apply(self, *args):
456 1 tkerber
        self.makeatoms()
457 1 tkerber
        if self.atoms is not None:
458 1 tkerber
            self.gui.new_atoms(self.atoms)
459 1 tkerber
            return True
460 1 tkerber
        else:
461 1 tkerber
            oops("No valid atoms.",
462 1 tkerber
                 "You have not (yet) specified a consistent set of parameters.")
463 1 tkerber
            return False
464 1 tkerber
465 1 tkerber
    def ok(self, *args):
466 1 tkerber
        if self.apply():
467 1 tkerber
            self.destroy()