Statistiques
| Révision :

root / ase / gui / surfaceslab.py @ 13

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

1
# encoding: utf-8
2
"""surfaceslab.py - Window for setting up surfaces
3
"""
4

    
5
import gtk
6
from ase.gui.widgets import pack, cancel_apply_ok, oops
7
from ase.gui.pybutton import PyButton
8
from ase.gui.setupwindow import SetupWindow
9
import ase.lattice.surface as _surf
10
import ase
11
import numpy as np
12

    
13
introtext = """\
14
  Use this dialog to create surface slabs.  Select the element by
15
writing the chemical symbol or the atomic number in the box.  Then
16
select the desired surface structure.  Note that some structures can
17
be created with an othogonal or a non-orthogonal unit cell, in these
18
cases the non-orthogonal unit cell will contain fewer atoms.
19

20
  If the structure matches the experimental crystal structure, you can
21
look up the lattice constant, otherwise you have to specify it
22
yourself."""
23

    
24
# Name, structure, orthogonal, support-nonorthogonal, function
25
surfaces = [('FCC(100)', 'fcc', True, False, _surf.fcc100),
26
            ('FCC(110)', 'fcc', True, False, _surf.fcc110),
27
            ('FCC(111) non-orthogonal', 'fcc', False, True, _surf.fcc111),
28
            ('FCC(111) orthogonal', 'fcc', True, True, _surf.fcc111),
29
            ('BCC(100)', 'bcc', True, False, _surf.bcc100),
30
            ('BCC(110) non-orthogonal', 'bcc', False, True, _surf.bcc110),
31
            ('BCC(110) orthogonal', 'bcc', True, True, _surf.bcc110),
32
            ('BCC(111) non-orthogonal', 'bcc', False, True, _surf.bcc111),
33
            ('BCC(111) orthogonal', 'bcc', True, True, _surf.bcc111),
34
            ('HCP(0001) non-orthogonal', 'hcp', False, True, _surf.hcp0001),
35
            ('HCP(0001) orthogonal', 'hcp', True, True, _surf.hcp0001),
36
            ]
37

    
38
py_template = """
39
from ase.lattice.surface import %(func)s
40

41
atoms = %(func)s(symbol='%(symbol)s', size=%(size)s,
42
    a=%(a).3f, vacuum=%(vacuum).3f%(orthoarg)s)
43
"""
44

    
45
class SetupSurfaceSlab(SetupWindow):
46
    """Window for setting up a surface."""
47
    def __init__(self, gui):
48
        SetupWindow.__init__(self)
49
        self.set_title("Surface")
50
        self.atoms = None
51

    
52
        vbox = gtk.VBox()
53

    
54
        # Intoductory text
55
        self.packtext(vbox, introtext)
56
             
57
        # Choose the element
58
        label = gtk.Label("Element: ")
59
        element = gtk.Entry(max=3)
60
        self.element = element
61
        self.elementinfo = gtk.Label("")
62
        pack(vbox, [label, element, self.elementinfo])
63
        self.element.connect('activate', self.update)
64
        self.legal_element = False
65
        
66
        # Choose the surface structure
67
        label = gtk.Label("Structure: ")
68
        self.structchoice = gtk.combo_box_new_text()
69
        self.surfinfo = {}
70
        for s in surfaces:
71
            assert len(s) == 5
72
            self.structchoice.append_text(s[0])
73
            self.surfinfo[s[0]] = s
74
        pack(vbox, [label, self.structchoice])
75
        self.structchoice.connect('changed', self.update)
76

    
77
        # Choose the lattice constant
78
        tbl = gtk.Table(2, 3)
79
        label = gtk.Label("Lattice constant: ")
80
        tbl.attach(label, 0, 1, 0, 1)
81
        vbox2 = gtk.VBox()          # For the non-HCP stuff
82
        self.vbox_hcp = gtk.VBox()  # For the HCP stuff.
83
        self.lattice_const = gtk.Adjustment(3.0, 0.0, 1000.0, 0.01)
84
        lattice_box = gtk.SpinButton(self.lattice_const, 10.0, 3)
85
        lattice_box.numeric = True
86
        pack(vbox2, [gtk.Label("a:"), lattice_box, gtk.Label("Å")])
87
        tbl.attach(vbox2, 1, 2, 0, 1)
88
        lattice_button = gtk.Button("Get from database")
89
        tbl.attach(lattice_button, 2, 3, 0, 1)
90
        # HCP stuff
91
        self.hcp_ideal = (8.0/3)**(1.0/3)
92
        self.lattice_const_c = gtk.Adjustment(self.lattice_const.value * self.hcp_ideal,
93
                                              0.0, 1000.0, 0.01)
94
        lattice_box_c = gtk.SpinButton(self.lattice_const_c, 10.0, 3)
95
        lattice_box_c.numeric = True
96
        pack(self.vbox_hcp, [gtk.Label("c:"), lattice_box_c, gtk.Label("Å")])
97
        self.hcp_c_over_a_format = "c/a: %.3f (%.1f %% of ideal)"
98
        self.hcp_c_over_a_label = gtk.Label(self.hcp_c_over_a_format % (self.hcp_ideal,
99
                                                                        100.0))
100
        pack(self.vbox_hcp, [self.hcp_c_over_a_label])
101
        tbl.attach(self.vbox_hcp, 1, 2, 1, 2)
102
        tbl.show_all()
103
        pack(vbox, [tbl])
104
        self.lattice_const.connect('value-changed', self.update)
105
        self.lattice_const_c.connect('value-changed', self.update)
106
        lattice_button.connect('clicked', self.get_lattice_const)
107
        pack(vbox, gtk.Label(""))
108

    
109
        # System size
110
        self.size = [gtk.Adjustment(1, 1, 100, 1) for i in range(3)]
111
        buttons = [gtk.SpinButton(s, 0, 0) for s in self.size]
112
        self.vacuum = gtk.Adjustment(10.0, 0, 100.0, 0.1)
113
        vacuum_box = gtk.SpinButton(self.vacuum, 0.0, 1)
114
        pack(vbox, [gtk.Label("Size: \tx: "), buttons[0],
115
                    gtk.Label(" unit cells")])
116
        pack(vbox, [gtk.Label("\t\ty: "), buttons[1],
117
                    gtk.Label(" unit cells")])
118
        pack(vbox, [gtk.Label("      \t\tz: "), buttons[2],
119
                    gtk.Label(" layers,  "),
120
                    vacuum_box, gtk.Label(" Å vacuum")])
121
        self.nosize = "\t\tNo size information yet."
122
        self.sizelabel = gtk.Label(self.nosize)
123
        pack(vbox, [self.sizelabel])
124
        for s in self.size:
125
            s.connect('value-changed', self.update)
126
        self.vacuum.connect('value-changed', self.update)
127
        pack(vbox, gtk.Label(""))
128

    
129
        # Buttons
130
        self.pybut = PyButton("Creating a surface slab.")
131
        self.pybut.connect('clicked', self.update)
132
        buts = cancel_apply_ok(cancel=lambda widget: self.destroy(),
133
                               apply=self.apply,
134
                               ok=self.ok)
135
        pack(vbox, [self.pybut, buts], end=True, bottom=True)
136
        
137
        self.add(vbox)
138
        vbox.show()
139
        self.show()
140
        self.gui = gui
141

    
142
        # Hide the HCP stuff to begin with.
143
        self.vbox_hcp.hide_all()
144

    
145
    # update_element inherited from SetupWindow
146

    
147
    def update(self, *args):
148
        "Called when something has changed."
149
        struct = self.structchoice.get_active_text()
150
        if struct:
151
            structinfo = self.surfinfo[struct]
152
            if structinfo[1] == 'hcp':
153
                self.vbox_hcp.show_all()
154
                ca = self.lattice_const_c.value / self.lattice_const.value
155
                self.hcp_c_over_a_label.set_text(self.hcp_c_over_a_format %
156
                                                 (ca, 100 * ca / self.hcp_ideal))
157
            else:
158
                self.vbox_hcp.hide_all()
159
        # Abort if element or structure is invalid
160
        if not (self.update_element() and struct):
161
            self.sizelabel.set_text(self.nosize)
162
            self.atoms = None
163
            self.pybut.python = None
164
            return False
165
        # Make the atoms
166
        assert self.legal_element
167
        kw = {}
168
        kw2 = {}
169
        if structinfo[3]:  # Support othogonal keyword?
170
            kw['orthogonal'] = structinfo[2]
171
            kw2['orthoarg'] = ', orthogonal='+str(kw['orthogonal'])
172
        else:
173
            kw2['orthoarg'] = ''
174
        kw2['func'] = structinfo[4].__name__
175
        kw['symbol'] = self.legal_element
176
        kw['size'] = [int(s.value) for s in self.size]
177
        kw['a'] = self.lattice_const.value
178
        kw['vacuum'] = self.vacuum.value
179
        # Now create the atoms
180
        try:
181
            self.atoms = structinfo[4](**kw)
182
        except ValueError, e:
183
            # The values were illegal - for example some size
184
            # constants must be even for some structures.
185
            self.pybut.python = None
186
            self.atoms = None
187
            self.sizelabel.set_text(str(e).replace(".  ", ".\n"))
188
            return False
189
        kw2.update(kw)
190
        self.pybut.python = py_template % kw2
191
        # Find the heights of the unit cell
192
        h = np.zeros(3)
193
        uc = self.atoms.get_cell()
194
        for i in range(3):
195
            norm = np.cross(uc[i-1], uc[i-2])
196
            norm /= np.sqrt(np.dot(norm, norm))
197
            h[i] = np.abs(np.dot(norm, uc[i]))
198
        natoms = len(self.atoms)
199
        txt = ("\t\t%.2f Å x %.2f Å x %.2f Å,  %i atoms."
200
               % (h[0], h[1], h[2], natoms))
201
        self.sizelabel.set_text(txt)
202
        return True
203
    
204
    def get_lattice_const(self, *args):
205
        if not self.update_element():
206
            oops("Invalid element.")
207
            return
208
        z = ase.atomic_numbers[self.legal_element]
209
        ref = ase.data.reference_states[z]
210
        surface = self.structchoice.get_active_text()
211
        if not surface:
212
            oops("No structure specified!")
213
            return
214
        struct = self.surfinfo[surface][1]
215
        if ref is None or ref['symmetry'].lower() != struct:
216
            oops(struct.upper() + " lattice constant unknown for "
217
                      + self.legal_element + ".")
218
            return
219
        a = ref['a']
220
        self.lattice_const.set_value(a)
221
        if struct == 'hcp':
222
            c = ref['c/a'] * a
223
            self.lattice_const_c.set_value(c)
224

    
225
    def apply(self, *args):
226
        self.update()
227
        if self.atoms is not None:
228
            self.gui.new_atoms(self.atoms)
229
            return True
230
        else:
231
            oops("No valid atoms.",
232
                 "You have not (yet) specified a consistent set of parameters.")
233
            return False
234

    
235
    def ok(self, *args):
236
        if self.apply():
237
            self.destroy()
238
            
239

    
240