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