Coverage for /builds/ase/ase/ase/cli/build.py : 59.22%

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# Note:
2# Try to avoid module level import statements here to reduce
3# import time during CLI execution
4import sys
5import numpy as np
8class CLICommand:
9 """Build an atom, molecule or bulk structure.
11 Atom:
13 ase build <chemical symbol> ...
15 Molecule:
17 ase build <formula> ...
19 where <formula> must be one of the formulas known to ASE
20 (see here: https://wiki.fysik.dtu.dk/ase/ase/build/build.html#molecules).
22 Bulk:
24 ase build -x <crystal structure> <formula> ...
26 Examples:
28 ase build Li # lithium atom
29 ase build Li -M 1 # ... with a magnetic moment of 1
30 ase build Li -M 1 -V 3.5 # ... in a 7x7x7 Ang cell
31 ase build H2O # water molecule
32 ase build -x fcc Cu -a 3.6 # FCC copper
33 """
35 @staticmethod
36 def add_arguments(parser):
37 add = parser.add_argument
38 add('name', metavar='formula/input-file',
39 help='Chemical formula or input filename.')
40 add('output', nargs='?', help='Output file.')
41 add('-M', '--magnetic-moment',
42 metavar='M1,M2,...',
43 help='Magnetic moments. '
44 'Use "-M 1" or "-M 2.3,-2.3"')
45 add('--modify', metavar='...',
46 help='Modify atoms with Python statement. '
47 'Example: --modify="atoms.positions[-1,2]+=0.1"')
48 add('-V', '--vacuum', type=float,
49 help='Amount of vacuum to add around isolated atoms '
50 '(in Angstrom)')
51 add('-v', '--vacuum0', type=float,
52 help='Deprecated. Use -V or --vacuum instead')
53 add('--unit-cell', metavar='CELL',
54 help='Unit cell in Angstrom. Examples: "10.0" or "9,10,11"')
55 add('--bond-length', type=float, metavar='LENGTH',
56 help='Bond length of dimer in Angstrom')
57 add('-x', '--crystal-structure',
58 help='Crystal structure',
59 choices=['sc', 'fcc', 'bcc', 'hcp', 'diamond',
60 'zincblende', 'rocksalt', 'cesiumchloride',
61 'fluorite', 'wurtzite'])
62 add('-a', '--lattice-constant', default='', metavar='LENGTH',
63 help='Lattice constant or comma-separated lattice constantes in '
64 'Angstrom')
65 add('--orthorhombic', action='store_true',
66 help='Use orthorhombic unit cell')
67 add('--cubic', action='store_true',
68 help='Use cubic unit cell')
69 add('-r', '--repeat',
70 help='Repeat unit cell. Use "-r 2" or "-r 2,3,1"')
71 add('-g', '--gui', action='store_true',
72 help='open ase gui')
73 add('--periodic', action='store_true',
74 help='make structure fully periodic')
76 @staticmethod
77 def run(args, parser):
78 from ase.db import connect
79 from ase.io import read, write
80 from ase.visualize import view
82 if args.vacuum0:
83 parser.error('Please use -V or --vacuum instead!')
85 if '.' in args.name:
86 # Read from file:
87 atoms = read(args.name)
88 elif args.crystal_structure:
89 atoms = build_bulk(args)
90 else:
91 atoms = build_molecule(args)
93 if args.magnetic_moment:
94 magmoms = np.array(
95 [float(m) for m in args.magnetic_moment.split(',')])
96 atoms.set_initial_magnetic_moments(
97 np.tile(magmoms, len(atoms) // len(magmoms)))
99 if args.modify:
100 exec(args.modify, {'atoms': atoms})
102 if args.repeat is not None:
103 r = args.repeat.split(',')
104 if len(r) == 1:
105 r = 3 * r
106 atoms = atoms.repeat([int(c) for c in r])
108 if args.gui:
109 view(atoms)
111 if args.output:
112 write(args.output, atoms)
113 elif sys.stdout.isatty():
114 write(args.name + '.json', atoms)
115 else:
116 con = connect(sys.stdout, type='json')
117 con.write(atoms, name=args.name)
120def build_molecule(args):
121 from ase.atoms import Atoms
122 from ase.build import molecule
123 from ase.data import ground_state_magnetic_moments
124 from ase.data import atomic_numbers, covalent_radii
125 from ase.symbols import string2symbols
127 try:
128 # Known molecule or atom?
129 atoms = molecule(args.name)
130 except (NotImplementedError, KeyError):
131 symbols = string2symbols(args.name)
132 if len(symbols) == 1:
133 Z = atomic_numbers[symbols[0]]
134 magmom = ground_state_magnetic_moments[Z]
135 atoms = Atoms(args.name, magmoms=[magmom])
136 elif len(symbols) == 2:
137 # Dimer
138 if args.bond_length is None:
139 b = (covalent_radii[atomic_numbers[symbols[0]]] +
140 covalent_radii[atomic_numbers[symbols[1]]])
141 else:
142 b = args.bond_length
143 atoms = Atoms(args.name, positions=[(0, 0, 0),
144 (b, 0, 0)])
145 else:
146 raise ValueError('Unknown molecule: ' + args.name)
147 else:
148 if len(atoms) == 2 and args.bond_length is not None:
149 atoms.set_distance(0, 1, args.bond_length)
151 if args.unit_cell is None:
152 if args.vacuum:
153 atoms.center(vacuum=args.vacuum)
154 else:
155 atoms.center(about=[0, 0, 0])
156 else:
157 a = [float(x) for x in args.unit_cell.split(',')]
158 if len(a) == 1:
159 cell = [a[0], a[0], a[0]]
160 elif len(a) == 3:
161 cell = a
162 else:
163 a, b, c, alpha, beta, gamma = a
164 degree = np.pi / 180.0
165 cosa = np.cos(alpha * degree)
166 cosb = np.cos(beta * degree)
167 sinb = np.sin(beta * degree)
168 cosg = np.cos(gamma * degree)
169 sing = np.sin(gamma * degree)
170 cell = [[a, 0, 0],
171 [b * cosg, b * sing, 0],
172 [c * cosb, c * (cosa - cosb * cosg) / sing,
173 c * np.sqrt(
174 sinb**2 - ((cosa - cosb * cosg) / sing)**2)]]
175 atoms.cell = cell
176 atoms.center()
178 atoms.pbc = args.periodic
180 return atoms
183def build_bulk(args):
184 from ase.build import bulk
186 L = args.lattice_constant.replace(',', ' ').split()
187 d = dict([(key, float(x)) for key, x in zip('ac', L)])
188 atoms = bulk(args.name, crystalstructure=args.crystal_structure,
189 a=d.get('a'), c=d.get('c'),
190 orthorhombic=args.orthorhombic, cubic=args.cubic)
192 M, X = {'Fe': (2.3, 'bcc'),
193 'Co': (1.2, 'hcp'),
194 'Ni': (0.6, 'fcc')}.get(args.name, (None, None))
195 if M is not None and args.crystal_structure == X:
196 atoms.set_initial_magnetic_moments([M] * len(atoms))
198 return atoms