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
3import numpy as np
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
16class CLICommand:
17 """Build an atom, molecule or bulk structure.
19 Atom:
21 ase build <chemical symbol> ...
23 Molecule:
25 ase build <formula> ...
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).
30 Bulk:
32 ase build -x <crystal structure> <formula> ...
34 Examples:
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 """
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')
84 @staticmethod
85 def run(args, parser):
86 if args.vacuum0:
87 parser.error('Please use -V or --vacuum instead!')
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)
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)))
103 if args.modify:
104 exec(args.modify, {'atoms': atoms})
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])
112 if args.gui:
113 view(atoms)
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)
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)
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()
176 atoms.pbc = args.periodic
178 return atoms
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)
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))
194 return atoms