Coverage for /builds/ase/ase/ase/gui/surfaceslab.py : 70.75%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1'''surfaceslab.py - Window for setting up surfaces
2'''
3from ase.gui.i18n import _, ngettext
5import ase.gui.ui as ui
6import ase.build as build
7from ase.data import reference_states
8from ase.gui.widgets import Element, pybutton
10introtext = _("""\
11 Use this dialog to create surface slabs. Select the element by
12writing the chemical symbol or the atomic number in the box. Then
13select the desired surface structure. Note that some structures can
14be created with an othogonal or a non-orthogonal unit cell, in these
15cases the non-orthogonal unit cell will contain fewer atoms.
17 If the structure matches the experimental crystal structure, you can
18look up the lattice constant, otherwise you have to specify it
19yourself.""")
21# Name, structure, orthogonal, function
22surfaces = [(_('FCC(100)'), _('fcc'), 'ortho', build.fcc100),
23 (_('FCC(110)'), _('fcc'), 'ortho', build.fcc110),
24 (_('FCC(111)'), _('fcc'), 'both', build.fcc111),
25 (_('FCC(211)'), _('fcc'), 'ortho', build.fcc211),
26 (_('BCC(100)'), _('bcc'), 'ortho', build.bcc100),
27 (_('BCC(110)'), _('bcc'), 'both', build.bcc110),
28 (_('BCC(111)'), _('bcc'), 'both', build.bcc111),
29 (_('HCP(0001)'), _('hcp'), 'both', build.hcp0001),
30 (_('HCP(10-10)'), _('hcp'), 'ortho', build.hcp10m10),
31 (_('DIAMOND(100)'), _('diamond'), 'ortho', build.diamond100),
32 (_('DIAMOND(111)'), _('diamond'), 'non-ortho', build.diamond111)]
34structures, crystal, orthogonal, functions = zip(*surfaces)
36py_template = """
37from ase.build import {func}
39atoms = {func}(symbol='{symbol}', size={size},
40 a={a}, {c}vacuum={vacuum}, orthogonal={ortho})
41"""
44class SetupSurfaceSlab:
45 '''Window for setting up a surface.'''
47 def __init__(self, gui):
48 self.element = Element('', self.apply)
49 self.structure = ui.ComboBox(structures, structures,
50 self.structure_changed)
51 self.structure_warn = ui.Label('', 'red')
52 self.orthogonal = ui.CheckButton('', True, self.make)
53 self.lattice_a = ui.SpinBox(3.2, 0.0, 10.0, 0.001, self.make)
54 self.retrieve = ui.Button(_('Get from database'),
55 self.structure_changed)
56 self.lattice_c = ui.SpinBox(None, 0.0, 10.0, 0.001, self.make)
57 self.x = ui.SpinBox(1, 1, 30, 1, self.make)
58 self.x_warn = ui.Label('', 'red')
59 self.y = ui.SpinBox(1, 1, 30, 1, self.make)
60 self.y_warn = ui.Label('', 'red')
61 self.z = ui.SpinBox(1, 1, 30, 1, self.make)
62 self.vacuum_check = ui.CheckButton('', False, self.vacuum_checked)
63 self.vacuum = ui.SpinBox(5, 0, 40, 0.01, self.make)
64 self.description = ui.Label('')
66 win = self.win = ui.Window(_('Surface'), wmtype='utility')
67 win.add(ui.Text(introtext))
68 win.add(self.element)
69 win.add([_('Structure:'), self.structure, self.structure_warn])
70 win.add([_('Orthogonal cell:'), self.orthogonal])
71 win.add([_('Lattice constant:')])
72 win.add([_('\ta'), self.lattice_a, (u'Å'), self.retrieve])
73 win.add([_('\tc'), self.lattice_c, (u'Å')])
74 win.add([_('Size:')])
75 win.add([_('\tx: '), self.x, _(' unit cells'), self.x_warn])
76 win.add([_('\ty: '), self.y, _(' unit cells'), self.y_warn])
77 win.add([_('\tz: '), self.z, _(' unit cells')])
78 win.add([_('Vacuum: '), self.vacuum_check, self.vacuum, (u'Å')])
79 win.add(self.description)
80 # TRANSLATORS: This is a title of a window.
81 win.add([pybutton(_('Creating a surface.'), self.make),
82 ui.Button(_('Apply'), self.apply),
83 ui.Button(_('OK'), self.ok)])
85 self.element.grab_focus()
86 self.gui = gui
87 self.atoms = None
88 self.lattice_c.active = False
89 self.vacuum.active = False
90 self.structure_changed()
92 def vacuum_checked(self, *args):
93 if self.vacuum_check.var.get():
94 self.vacuum.active = True
95 else:
96 self.vacuum.active = False
97 self.make()
99 def get_lattice(self, *args):
100 if self.element.symbol is None:
101 return
102 ref = reference_states[self.element.Z]
103 symmetry = "unknown"
104 for struct in surfaces:
105 if struct[0] == self.structure.value:
106 symmetry = struct[1]
107 if ref['symmetry'] != symmetry:
108 # TRANSLATORS: E.g. "... assume fcc crystal structure for Au"
109 self.structure_warn.text = (_('Error: Reference values assume {} '
110 'crystal structure for {}!').
111 format(ref['symmetry'],
112 self.element.symbol))
113 else:
114 if symmetry == 'fcc' or symmetry == 'bcc' or symmetry == 'diamond':
115 self.lattice_a.value = ref['a']
116 elif symmetry == 'hcp':
117 self.lattice_a.value = ref['a']
118 self.lattice_c.value = ref['a'] * ref['c/a']
119 self.make()
121 def structure_changed(self, *args):
122 for surface in surfaces:
123 if surface[0] == self.structure.value:
124 if surface[2] == 'ortho':
125 self.orthogonal.var.set(True)
126 self.orthogonal.check['state'] = ['disabled']
127 elif surface[2] == 'non-ortho':
128 self.orthogonal.var.set(False)
129 self.orthogonal.check['state'] = ['disabled']
130 else:
131 self.orthogonal.check['state'] = ['normal']
133 if surface[1] == _('hcp'):
134 self.lattice_c.active = True
135 self.lattice_c.value = round(self.lattice_a.value *
136 ((8.0 / 3.0) ** (0.5)), 3)
137 else:
138 self.lattice_c.active = False
139 self.lattice_c.value = 'None'
140 self.get_lattice()
142 def make(self, *args):
143 symbol = self.element.symbol
144 self.atoms = None
145 self.description.text = ''
146 self.python = None
147 self.x_warn.text = ''
148 self.y_warn.text = ''
149 if symbol is None:
150 return
152 x = self.x.value
153 y = self.y.value
154 z = self.z.value
155 size = (x, y, z)
156 a = self.lattice_a.value
157 c = self.lattice_c.value
158 vacuum = self.vacuum.value
159 if not self.vacuum_check.var.get():
160 vacuum = None
161 ortho = self.orthogonal.var.get()
163 ortho_warn_even = _('Please enter an even value for orthogonal cell')
165 struct = self.structure.value
166 if struct == _('BCC(111)') and (not (y % 2 == 0) and ortho):
167 self.y_warn.text = ortho_warn_even
168 return
169 if struct == _('BCC(110)') and (not (y % 2 == 0) and ortho):
170 self.y_warn.text = ortho_warn_even
171 return
172 if struct == _('FCC(111)') and (not (y % 2 == 0) and ortho):
173 self.y_warn.text = ortho_warn_even
174 return
175 if struct == _('FCC(211)') and (not (x % 3 == 0) and ortho):
176 self.x_warn.text = _('Please enter a value divisible by 3'
177 ' for orthogonal cell')
178 return
179 if struct == _('HCP(0001)') and (not (y % 2 == 0) and ortho):
180 self.y_warn.text = ortho_warn_even
181 return
182 if struct == _('HCP(10-10)') and (not (y % 2 == 0) and ortho):
183 self.y_warn.text = ortho_warn_even
184 return
186 for surface in surfaces:
187 if surface[0] == struct:
188 c_py = ""
189 if surface[1] == _('hcp'):
190 self.atoms = surface[3](symbol, size, a, c, vacuum, ortho)
191 c_py = "{}, ".format(c)
192 else:
193 self.atoms = surface[3](symbol, size, a, vacuum, ortho)
195 if vacuum is not None:
196 vacuumtext = _(' Vacuum: {} Å.').format(vacuum)
197 else:
198 vacuumtext = ''
200 natoms = len(self.atoms)
201 label = ngettext(
202 # TRANSLATORS: e.g. "Au fcc100 surface with 2 atoms."
203 # or "Au fcc100 surface with 2 atoms. Vacuum: 5 Å."
204 '{symbol} {surf} surface with one atom.{vacuum}',
205 '{symbol} {surf} surface with {natoms} atoms.{vacuum}',
206 natoms).format(symbol=symbol,
207 surf=surface[3].__name__,
208 natoms=natoms,
209 vacuum=vacuumtext)
211 self.description.text = label
212 return py_template.format(func=surface[3].__name__, a=a,
213 c=c_py, symbol=symbol, size=size,
214 ortho=ortho, vacuum=vacuum)
216 def apply(self, *args):
217 self.make()
218 if self.atoms is not None:
219 self.gui.new_atoms(self.atoms)
220 return True
221 else:
222 ui.error(_('No valid atoms.'),
223 _('You have not (yet) specified a consistent '
224 'set of parameters.'))
225 return False
227 def ok(self, *args):
228 if self.apply():
229 self.win.close()