Statistiques
| Révision :

root / ase / gui / surfaceslab.py @ 11

Historique | Voir | Annoter | Télécharger (9,28 ko)

1 1 tkerber
# encoding: utf-8
2 1 tkerber
"""surfaceslab.py - Window for setting up surfaces
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.pybutton import PyButton
8 1 tkerber
from ase.gui.setupwindow import SetupWindow
9 1 tkerber
import ase.lattice.surface as _surf
10 1 tkerber
import ase
11 1 tkerber
import numpy as np
12 1 tkerber
13 1 tkerber
introtext = """\
14 1 tkerber
  Use this dialog to create surface slabs.  Select the element by
15 1 tkerber
writing the chemical symbol or the atomic number in the box.  Then
16 1 tkerber
select the desired surface structure.  Note that some structures can
17 1 tkerber
be created with an othogonal or a non-orthogonal unit cell, in these
18 1 tkerber
cases the non-orthogonal unit cell will contain fewer atoms.
19 1 tkerber

20 1 tkerber
  If the structure matches the experimental crystal structure, you can
21 1 tkerber
look up the lattice constant, otherwise you have to specify it
22 1 tkerber
yourself."""
23 1 tkerber
24 1 tkerber
# Name, structure, orthogonal, support-nonorthogonal, function
25 1 tkerber
surfaces = [('FCC(100)', 'fcc', True, False, _surf.fcc100),
26 1 tkerber
            ('FCC(110)', 'fcc', True, False, _surf.fcc110),
27 1 tkerber
            ('FCC(111) non-orthogonal', 'fcc', False, True, _surf.fcc111),
28 1 tkerber
            ('FCC(111) orthogonal', 'fcc', True, True, _surf.fcc111),
29 1 tkerber
            ('BCC(100)', 'bcc', True, False, _surf.bcc100),
30 1 tkerber
            ('BCC(110) non-orthogonal', 'bcc', False, True, _surf.bcc110),
31 1 tkerber
            ('BCC(110) orthogonal', 'bcc', True, True, _surf.bcc110),
32 1 tkerber
            ('BCC(111) non-orthogonal', 'bcc', False, True, _surf.bcc111),
33 1 tkerber
            ('BCC(111) orthogonal', 'bcc', True, True, _surf.bcc111),
34 1 tkerber
            ('HCP(0001) non-orthogonal', 'hcp', False, True, _surf.hcp0001),
35 1 tkerber
            ('HCP(0001) orthogonal', 'hcp', True, True, _surf.hcp0001),
36 1 tkerber
            ]
37 1 tkerber
38 1 tkerber
py_template = """
39 1 tkerber
from ase.lattice.surface import %(func)s
40 1 tkerber

41 1 tkerber
atoms = %(func)s(symbol='%(symbol)s', size=%(size)s,
42 1 tkerber
    a=%(a).3f, vacuum=%(vacuum).3f%(orthoarg)s)
43 1 tkerber
"""
44 1 tkerber
45 1 tkerber
class SetupSurfaceSlab(SetupWindow):
46 1 tkerber
    """Window for setting up a surface."""
47 1 tkerber
    def __init__(self, gui):
48 1 tkerber
        SetupWindow.__init__(self)
49 1 tkerber
        self.set_title("Surface")
50 1 tkerber
        self.atoms = None
51 1 tkerber
52 1 tkerber
        vbox = gtk.VBox()
53 1 tkerber
54 1 tkerber
        # Intoductory text
55 1 tkerber
        self.packtext(vbox, introtext)
56 1 tkerber
57 1 tkerber
        # Choose the element
58 1 tkerber
        label = gtk.Label("Element: ")
59 1 tkerber
        element = gtk.Entry(max=3)
60 1 tkerber
        self.element = element
61 1 tkerber
        self.elementinfo = gtk.Label("")
62 1 tkerber
        pack(vbox, [label, element, self.elementinfo])
63 1 tkerber
        self.element.connect('activate', self.update)
64 1 tkerber
        self.legal_element = False
65 1 tkerber
66 1 tkerber
        # Choose the surface structure
67 1 tkerber
        label = gtk.Label("Structure: ")
68 1 tkerber
        self.structchoice = gtk.combo_box_new_text()
69 1 tkerber
        self.surfinfo = {}
70 1 tkerber
        for s in surfaces:
71 1 tkerber
            assert len(s) == 5
72 1 tkerber
            self.structchoice.append_text(s[0])
73 1 tkerber
            self.surfinfo[s[0]] = s
74 1 tkerber
        pack(vbox, [label, self.structchoice])
75 1 tkerber
        self.structchoice.connect('changed', self.update)
76 1 tkerber
77 1 tkerber
        # Choose the lattice constant
78 1 tkerber
        tbl = gtk.Table(2, 3)
79 1 tkerber
        label = gtk.Label("Lattice constant: ")
80 1 tkerber
        tbl.attach(label, 0, 1, 0, 1)
81 1 tkerber
        vbox2 = gtk.VBox()          # For the non-HCP stuff
82 1 tkerber
        self.vbox_hcp = gtk.VBox()  # For the HCP stuff.
83 1 tkerber
        self.lattice_const = gtk.Adjustment(3.0, 0.0, 1000.0, 0.01)
84 1 tkerber
        lattice_box = gtk.SpinButton(self.lattice_const, 10.0, 3)
85 1 tkerber
        lattice_box.numeric = True
86 1 tkerber
        pack(vbox2, [gtk.Label("a:"), lattice_box, gtk.Label("Å")])
87 1 tkerber
        tbl.attach(vbox2, 1, 2, 0, 1)
88 1 tkerber
        lattice_button = gtk.Button("Get from database")
89 1 tkerber
        tbl.attach(lattice_button, 2, 3, 0, 1)
90 1 tkerber
        # HCP stuff
91 1 tkerber
        self.hcp_ideal = (8.0/3)**(1.0/3)
92 1 tkerber
        self.lattice_const_c = gtk.Adjustment(self.lattice_const.value * self.hcp_ideal,
93 1 tkerber
                                              0.0, 1000.0, 0.01)
94 1 tkerber
        lattice_box_c = gtk.SpinButton(self.lattice_const_c, 10.0, 3)
95 1 tkerber
        lattice_box_c.numeric = True
96 1 tkerber
        pack(self.vbox_hcp, [gtk.Label("c:"), lattice_box_c, gtk.Label("Å")])
97 1 tkerber
        self.hcp_c_over_a_format = "c/a: %.3f (%.1f %% of ideal)"
98 1 tkerber
        self.hcp_c_over_a_label = gtk.Label(self.hcp_c_over_a_format % (self.hcp_ideal,
99 1 tkerber
                                                                        100.0))
100 1 tkerber
        pack(self.vbox_hcp, [self.hcp_c_over_a_label])
101 1 tkerber
        tbl.attach(self.vbox_hcp, 1, 2, 1, 2)
102 1 tkerber
        tbl.show_all()
103 1 tkerber
        pack(vbox, [tbl])
104 1 tkerber
        self.lattice_const.connect('value-changed', self.update)
105 1 tkerber
        self.lattice_const_c.connect('value-changed', self.update)
106 1 tkerber
        lattice_button.connect('clicked', self.get_lattice_const)
107 1 tkerber
        pack(vbox, gtk.Label(""))
108 1 tkerber
109 1 tkerber
        # System size
110 1 tkerber
        self.size = [gtk.Adjustment(1, 1, 100, 1) for i in range(3)]
111 1 tkerber
        buttons = [gtk.SpinButton(s, 0, 0) for s in self.size]
112 1 tkerber
        self.vacuum = gtk.Adjustment(10.0, 0, 100.0, 0.1)
113 1 tkerber
        vacuum_box = gtk.SpinButton(self.vacuum, 0.0, 1)
114 1 tkerber
        pack(vbox, [gtk.Label("Size: \tx: "), buttons[0],
115 1 tkerber
                    gtk.Label(" unit cells")])
116 1 tkerber
        pack(vbox, [gtk.Label("\t\ty: "), buttons[1],
117 1 tkerber
                    gtk.Label(" unit cells")])
118 1 tkerber
        pack(vbox, [gtk.Label("      \t\tz: "), buttons[2],
119 1 tkerber
                    gtk.Label(" layers,  "),
120 1 tkerber
                    vacuum_box, gtk.Label(" Å vacuum")])
121 1 tkerber
        self.nosize = "\t\tNo size information yet."
122 1 tkerber
        self.sizelabel = gtk.Label(self.nosize)
123 1 tkerber
        pack(vbox, [self.sizelabel])
124 1 tkerber
        for s in self.size:
125 1 tkerber
            s.connect('value-changed', self.update)
126 1 tkerber
        self.vacuum.connect('value-changed', self.update)
127 1 tkerber
        pack(vbox, gtk.Label(""))
128 1 tkerber
129 1 tkerber
        # Buttons
130 1 tkerber
        self.pybut = PyButton("Creating a surface slab.")
131 1 tkerber
        self.pybut.connect('clicked', self.update)
132 1 tkerber
        buts = cancel_apply_ok(cancel=lambda widget: self.destroy(),
133 1 tkerber
                               apply=self.apply,
134 1 tkerber
                               ok=self.ok)
135 1 tkerber
        pack(vbox, [self.pybut, buts], end=True, bottom=True)
136 1 tkerber
137 1 tkerber
        self.add(vbox)
138 1 tkerber
        vbox.show()
139 1 tkerber
        self.show()
140 1 tkerber
        self.gui = gui
141 1 tkerber
142 1 tkerber
        # Hide the HCP stuff to begin with.
143 1 tkerber
        self.vbox_hcp.hide_all()
144 1 tkerber
145 1 tkerber
    # update_element inherited from SetupWindow
146 1 tkerber
147 1 tkerber
    def update(self, *args):
148 1 tkerber
        "Called when something has changed."
149 1 tkerber
        struct = self.structchoice.get_active_text()
150 1 tkerber
        if struct:
151 1 tkerber
            structinfo = self.surfinfo[struct]
152 1 tkerber
            if structinfo[1] == 'hcp':
153 1 tkerber
                self.vbox_hcp.show_all()
154 1 tkerber
                ca = self.lattice_const_c.value / self.lattice_const.value
155 1 tkerber
                self.hcp_c_over_a_label.set_text(self.hcp_c_over_a_format %
156 1 tkerber
                                                 (ca, 100 * ca / self.hcp_ideal))
157 1 tkerber
            else:
158 1 tkerber
                self.vbox_hcp.hide_all()
159 1 tkerber
        # Abort if element or structure is invalid
160 1 tkerber
        if not (self.update_element() and struct):
161 1 tkerber
            self.sizelabel.set_text(self.nosize)
162 1 tkerber
            self.atoms = None
163 1 tkerber
            self.pybut.python = None
164 1 tkerber
            return False
165 1 tkerber
        # Make the atoms
166 1 tkerber
        assert self.legal_element
167 1 tkerber
        kw = {}
168 1 tkerber
        kw2 = {}
169 1 tkerber
        if structinfo[3]:  # Support othogonal keyword?
170 1 tkerber
            kw['orthogonal'] = structinfo[2]
171 1 tkerber
            kw2['orthoarg'] = ', orthogonal='+str(kw['orthogonal'])
172 1 tkerber
        else:
173 1 tkerber
            kw2['orthoarg'] = ''
174 1 tkerber
        kw2['func'] = structinfo[4].__name__
175 1 tkerber
        kw['symbol'] = self.legal_element
176 1 tkerber
        kw['size'] = [int(s.value) for s in self.size]
177 1 tkerber
        kw['a'] = self.lattice_const.value
178 1 tkerber
        kw['vacuum'] = self.vacuum.value
179 1 tkerber
        # Now create the atoms
180 1 tkerber
        try:
181 1 tkerber
            self.atoms = structinfo[4](**kw)
182 1 tkerber
        except ValueError, e:
183 1 tkerber
            # The values were illegal - for example some size
184 1 tkerber
            # constants must be even for some structures.
185 1 tkerber
            self.pybut.python = None
186 1 tkerber
            self.atoms = None
187 1 tkerber
            self.sizelabel.set_text(str(e).replace(".  ", ".\n"))
188 1 tkerber
            return False
189 1 tkerber
        kw2.update(kw)
190 1 tkerber
        self.pybut.python = py_template % kw2
191 1 tkerber
        # Find the heights of the unit cell
192 1 tkerber
        h = np.zeros(3)
193 1 tkerber
        uc = self.atoms.get_cell()
194 1 tkerber
        for i in range(3):
195 1 tkerber
            norm = np.cross(uc[i-1], uc[i-2])
196 1 tkerber
            norm /= np.sqrt(np.dot(norm, norm))
197 1 tkerber
            h[i] = np.abs(np.dot(norm, uc[i]))
198 1 tkerber
        natoms = len(self.atoms)
199 1 tkerber
        txt = ("\t\t%.2f Å x %.2f Å x %.2f Å,  %i atoms."
200 1 tkerber
               % (h[0], h[1], h[2], natoms))
201 1 tkerber
        self.sizelabel.set_text(txt)
202 1 tkerber
        return True
203 1 tkerber
204 1 tkerber
    def get_lattice_const(self, *args):
205 1 tkerber
        if not self.update_element():
206 1 tkerber
            oops("Invalid element.")
207 1 tkerber
            return
208 1 tkerber
        z = ase.atomic_numbers[self.legal_element]
209 1 tkerber
        ref = ase.data.reference_states[z]
210 1 tkerber
        surface = self.structchoice.get_active_text()
211 1 tkerber
        if not surface:
212 1 tkerber
            oops("No structure specified!")
213 1 tkerber
            return
214 1 tkerber
        struct = self.surfinfo[surface][1]
215 1 tkerber
        if ref is None or ref['symmetry'].lower() != struct:
216 1 tkerber
            oops(struct.upper() + " lattice constant unknown for "
217 1 tkerber
                      + self.legal_element + ".")
218 1 tkerber
            return
219 1 tkerber
        a = ref['a']
220 1 tkerber
        self.lattice_const.set_value(a)
221 1 tkerber
        if struct == 'hcp':
222 1 tkerber
            c = ref['c/a'] * a
223 1 tkerber
            self.lattice_const_c.set_value(c)
224 1 tkerber
225 1 tkerber
    def apply(self, *args):
226 1 tkerber
        self.update()
227 1 tkerber
        if self.atoms is not None:
228 1 tkerber
            self.gui.new_atoms(self.atoms)
229 1 tkerber
            return True
230 1 tkerber
        else:
231 1 tkerber
            oops("No valid atoms.",
232 1 tkerber
                 "You have not (yet) specified a consistent set of parameters.")
233 1 tkerber
            return False
234 1 tkerber
235 1 tkerber
    def ok(self, *args):
236 1 tkerber
        if self.apply():
237 1 tkerber
            self.destroy()
238 1 tkerber
239 1 tkerber