Hide keyboard shortcuts

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 

4 

5import ase.gui.ui as ui 

6import ase.build as build 

7from ase.data import reference_states 

8from ase.gui.widgets import Element, pybutton 

9 

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. 

16 

17 If the structure matches the experimental crystal structure, you can 

18look up the lattice constant, otherwise you have to specify it 

19yourself.""") 

20 

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)] 

33 

34structures, crystal, orthogonal, functions = zip(*surfaces) 

35 

36py_template = """ 

37from ase.build import {func} 

38 

39atoms = {func}(symbol='{symbol}', size={size}, 

40 a={a}, {c}vacuum={vacuum}, orthogonal={ortho}) 

41""" 

42 

43 

44class SetupSurfaceSlab: 

45 '''Window for setting up a surface.''' 

46 

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('') 

65 

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)]) 

84 

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() 

91 

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() 

98 

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() 

120 

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'] 

132 

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() 

141 

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 

151 

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() 

162 

163 ortho_warn_even = _('Please enter an even value for orthogonal cell') 

164 

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 

185 

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) 

194 

195 if vacuum is not None: 

196 vacuumtext = _(' Vacuum: {} Å.').format(vacuum) 

197 else: 

198 vacuumtext = '' 

199 

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) 

210 

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) 

215 

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 

226 

227 def ok(self, *args): 

228 if self.apply(): 

229 self.win.close()