root / ase / gui / nanoparticle.py @ 15
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()
|