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

1import sys 

2 

3import numpy as np 

4 

5from ase.db import connect 

6from ase.build import bulk 

7from ase.io import read, write 

8from ase.visualize import view 

9from ase.build import molecule 

10from ase.atoms import Atoms 

11from ase.symbols import string2symbols 

12from ase.data import ground_state_magnetic_moments 

13from ase.data import atomic_numbers, covalent_radii 

14 

15 

16class CLICommand: 

17 """Build an atom, molecule or bulk structure. 

18 

19 Atom: 

20 

21 ase build <chemical symbol> ... 

22 

23 Molecule: 

24 

25 ase build <formula> ... 

26 

27 where <formula> must be one of the formulas known to ASE 

28 (see here: https://wiki.fysik.dtu.dk/ase/ase/build/build.html#molecules). 

29 

30 Bulk: 

31 

32 ase build -x <crystal structure> <formula> ... 

33 

34 Examples: 

35 

36 ase build Li # lithium atom 

37 ase build Li -M 1 # ... with a magnetic moment of 1 

38 ase build Li -M 1 -V 3.5 # ... in a 7x7x7 Ang cell 

39 ase build H2O # water molecule 

40 ase build -x fcc Cu -a 3.6 # FCC copper 

41 """ 

42 

43 @staticmethod 

44 def add_arguments(parser): 

45 add = parser.add_argument 

46 add('name', metavar='formula/input-file', 

47 help='Chemical formula or input filename.') 

48 add('output', nargs='?', help='Output file.') 

49 add('-M', '--magnetic-moment', 

50 metavar='M1,M2,...', 

51 help='Magnetic moments. ' 

52 'Use "-M 1" or "-M 2.3,-2.3"') 

53 add('--modify', metavar='...', 

54 help='Modify atoms with Python statement. ' 

55 'Example: --modify="atoms.positions[-1,2]+=0.1"') 

56 add('-V', '--vacuum', type=float, 

57 help='Amount of vacuum to add around isolated atoms ' 

58 '(in Angstrom)') 

59 add('-v', '--vacuum0', type=float, 

60 help='Deprecated. Use -V or --vacuum instead') 

61 add('--unit-cell', metavar='CELL', 

62 help='Unit cell in Angstrom. Examples: "10.0" or "9,10,11"') 

63 add('--bond-length', type=float, metavar='LENGTH', 

64 help='Bond length of dimer in Angstrom') 

65 add('-x', '--crystal-structure', 

66 help='Crystal structure', 

67 choices=['sc', 'fcc', 'bcc', 'hcp', 'diamond', 

68 'zincblende', 'rocksalt', 'cesiumchloride', 

69 'fluorite', 'wurtzite']) 

70 add('-a', '--lattice-constant', default='', metavar='LENGTH', 

71 help='Lattice constant or comma-separated lattice constantes in ' 

72 'Angstrom') 

73 add('--orthorhombic', action='store_true', 

74 help='Use orthorhombic unit cell') 

75 add('--cubic', action='store_true', 

76 help='Use cubic unit cell') 

77 add('-r', '--repeat', 

78 help='Repeat unit cell. Use "-r 2" or "-r 2,3,1"') 

79 add('-g', '--gui', action='store_true', 

80 help='open ase gui') 

81 add('--periodic', action='store_true', 

82 help='make structure fully periodic') 

83 

84 @staticmethod 

85 def run(args, parser): 

86 if args.vacuum0: 

87 parser.error('Please use -V or --vacuum instead!') 

88 

89 if '.' in args.name: 

90 # Read from file: 

91 atoms = read(args.name) 

92 elif args.crystal_structure: 

93 atoms = build_bulk(args) 

94 else: 

95 atoms = build_molecule(args) 

96 

97 if args.magnetic_moment: 

98 magmoms = np.array( 

99 [float(m) for m in args.magnetic_moment.split(',')]) 

100 atoms.set_initial_magnetic_moments( 

101 np.tile(magmoms, len(atoms) // len(magmoms))) 

102 

103 if args.modify: 

104 exec(args.modify, {'atoms': atoms}) 

105 

106 if args.repeat is not None: 

107 r = args.repeat.split(',') 

108 if len(r) == 1: 

109 r = 3 * r 

110 atoms = atoms.repeat([int(c) for c in r]) 

111 

112 if args.gui: 

113 view(atoms) 

114 

115 if args.output: 

116 write(args.output, atoms) 

117 elif sys.stdout.isatty(): 

118 write(args.name + '.json', atoms) 

119 else: 

120 con = connect(sys.stdout, type='json') 

121 con.write(atoms, name=args.name) 

122 

123 

124def build_molecule(args): 

125 try: 

126 # Known molecule or atom? 

127 atoms = molecule(args.name) 

128 except (NotImplementedError, KeyError): 

129 symbols = string2symbols(args.name) 

130 if len(symbols) == 1: 

131 Z = atomic_numbers[symbols[0]] 

132 magmom = ground_state_magnetic_moments[Z] 

133 atoms = Atoms(args.name, magmoms=[magmom]) 

134 elif len(symbols) == 2: 

135 # Dimer 

136 if args.bond_length is None: 

137 b = (covalent_radii[atomic_numbers[symbols[0]]] + 

138 covalent_radii[atomic_numbers[symbols[1]]]) 

139 else: 

140 b = args.bond_length 

141 atoms = Atoms(args.name, positions=[(0, 0, 0), 

142 (b, 0, 0)]) 

143 else: 

144 raise ValueError('Unknown molecule: ' + args.name) 

145 else: 

146 if len(atoms) == 2 and args.bond_length is not None: 

147 atoms.set_distance(0, 1, args.bond_length) 

148 

149 if args.unit_cell is None: 

150 if args.vacuum: 

151 atoms.center(vacuum=args.vacuum) 

152 else: 

153 atoms.center(about=[0, 0, 0]) 

154 else: 

155 a = [float(x) for x in args.unit_cell.split(',')] 

156 if len(a) == 1: 

157 cell = [a[0], a[0], a[0]] 

158 elif len(a) == 3: 

159 cell = a 

160 else: 

161 a, b, c, alpha, beta, gamma = a 

162 degree = np.pi / 180.0 

163 cosa = np.cos(alpha * degree) 

164 cosb = np.cos(beta * degree) 

165 sinb = np.sin(beta * degree) 

166 cosg = np.cos(gamma * degree) 

167 sing = np.sin(gamma * degree) 

168 cell = [[a, 0, 0], 

169 [b * cosg, b * sing, 0], 

170 [c * cosb, c * (cosa - cosb * cosg) / sing, 

171 c * np.sqrt( 

172 sinb**2 - ((cosa - cosb * cosg) / sing)**2)]] 

173 atoms.cell = cell 

174 atoms.center() 

175 

176 atoms.pbc = args.periodic 

177 

178 return atoms 

179 

180 

181def build_bulk(args): 

182 L = args.lattice_constant.replace(',', ' ').split() 

183 d = dict([(key, float(x)) for key, x in zip('ac', L)]) 

184 atoms = bulk(args.name, crystalstructure=args.crystal_structure, 

185 a=d.get('a'), c=d.get('c'), 

186 orthorhombic=args.orthorhombic, cubic=args.cubic) 

187 

188 M, X = {'Fe': (2.3, 'bcc'), 

189 'Co': (1.2, 'hcp'), 

190 'Ni': (0.6, 'fcc')}.get(args.name, (None, None)) 

191 if M is not None and args.crystal_structure == X: 

192 atoms.set_initial_magnetic_moments([M] * len(atoms)) 

193 

194 return atoms