root / ase / io / aims.py @ 13
Historique | Voir | Annoter | Télécharger (10,59 ko)
1 |
|
---|---|
2 |
def read_aims(filename): |
3 |
"""Import FHI-aims geometry type files.
|
4 |
|
5 |
Reads unitcell, atom positions and constraints from
|
6 |
a geometry.in file.
|
7 |
"""
|
8 |
|
9 |
from ase import Atoms |
10 |
from ase.constraints import FixAtoms, FixCartesian |
11 |
import numpy as np |
12 |
|
13 |
atoms = Atoms() |
14 |
fd = open(filename, 'r') |
15 |
lines = fd.readlines() |
16 |
fd.close() |
17 |
positions = [] |
18 |
cell = [] |
19 |
symbols = [] |
20 |
fix = [] |
21 |
fix_cart = [] |
22 |
xyz = np.array([0, 0, 0]) |
23 |
i = -1
|
24 |
n_periodic = -1
|
25 |
periodic = np.array([False, False, False]) |
26 |
for n, line in enumerate(lines): |
27 |
inp = line.split() |
28 |
if inp == []:
|
29 |
continue
|
30 |
if inp[0] == 'atom': |
31 |
if xyz.all():
|
32 |
fix.append(i) |
33 |
elif xyz.any():
|
34 |
print 1 |
35 |
fix_cart.append(FixCartesian(i, xyz)) |
36 |
floatvect = float(inp[1]), float(inp[2]), float(inp[3]) |
37 |
positions.append(floatvect) |
38 |
symbols.append(inp[-1])
|
39 |
i += 1
|
40 |
xyz = np.array([0, 0, 0]) |
41 |
elif inp[0] == 'lattice_vector': |
42 |
floatvect = float(inp[1]), float(inp[2]), float(inp[3]) |
43 |
cell.append(floatvect) |
44 |
n_periodic = n_periodic + 1
|
45 |
periodic[n_periodic] = True
|
46 |
if inp[0] == 'constrain_relaxation': |
47 |
if inp[1] == '.true.': |
48 |
fix.append(i) |
49 |
elif inp[1] == 'x': |
50 |
xyz[0] = 1 |
51 |
elif inp[1] == 'y': |
52 |
xyz[1] = 1 |
53 |
elif inp[1] == 'z': |
54 |
xyz[2] = 1 |
55 |
if xyz.all():
|
56 |
fix.append(i) |
57 |
elif xyz.any():
|
58 |
fix_cart.append(FixCartesian(i, xyz)) |
59 |
atoms = Atoms(symbols, positions) |
60 |
if periodic.all():
|
61 |
atoms.set_cell(cell) |
62 |
atoms.set_pbc(periodic) |
63 |
if len(fix): |
64 |
atoms.set_constraint([FixAtoms(indices=fix)]+fix_cart) |
65 |
else:
|
66 |
atoms.set_constraint(fix_cart) |
67 |
return atoms
|
68 |
|
69 |
def write_aims(filename, atoms): |
70 |
"""Method to write FHI-aims geometry files.
|
71 |
|
72 |
Writes the atoms positions and constraints (only FixAtoms is
|
73 |
supported at the moment).
|
74 |
"""
|
75 |
|
76 |
from ase.constraints import FixAtoms, FixCartesian |
77 |
import numpy as np |
78 |
|
79 |
if isinstance(atoms, (list, tuple)): |
80 |
if len(atoms) > 1: |
81 |
raise RuntimeError("Don't know how to save more than "+ |
82 |
"one image to FHI-aims input")
|
83 |
else:
|
84 |
atoms = atoms[0]
|
85 |
|
86 |
fd = open(filename, 'w') |
87 |
fd.write('#=======================================================\n')
|
88 |
fd.write('#FHI-aims file: '+filename+'\n') |
89 |
fd.write('#Created using the Atomic Simulation Environment (ASE)\n')
|
90 |
fd.write('#=======================================================\n')
|
91 |
i = 0
|
92 |
if atoms.get_pbc().any():
|
93 |
for n, vector in enumerate(atoms.get_cell()): |
94 |
fd.write('lattice_vector ')
|
95 |
for i in range(3): |
96 |
fd.write('%16.16f ' % vector[i])
|
97 |
fd.write('\n')
|
98 |
fix_cart = np.zeros([len(atoms),3]) |
99 |
|
100 |
if atoms.constraints:
|
101 |
for constr in atoms.constraints: |
102 |
if isinstance(constr, FixAtoms): |
103 |
fix_cart[constr.index] = [1,1,1] |
104 |
elif isinstance(constr, FixCartesian): |
105 |
fix_cart[constr.a] = -constr.mask+1
|
106 |
|
107 |
for i, atom in enumerate(atoms): |
108 |
fd.write('atom ')
|
109 |
for pos in atom.get_position(): |
110 |
fd.write('%16.16f ' % pos)
|
111 |
fd.write(atom.symbol) |
112 |
fd.write('\n')
|
113 |
# (1) all coords are constrained:
|
114 |
if fix_cart[i].all():
|
115 |
fd.write('constrain_relaxation .true.\n')
|
116 |
# (2) some coords are constrained:
|
117 |
elif fix_cart[i].any():
|
118 |
xyz = fix_cart[i] |
119 |
for n in range(3): |
120 |
if xyz[n]:
|
121 |
fd.write('constrain_relaxation %s\n' % 'xyz'[n]) |
122 |
if atom.charge:
|
123 |
fd.write('initial_charge %16.6f\n' % atom.charge)
|
124 |
if atom.magmom:
|
125 |
fd.write('initial_moment %16.6f\n' % atom.magmom)
|
126 |
# except KeyError:
|
127 |
# continue
|
128 |
|
129 |
def read_energy(filename): |
130 |
for line in open(filename, 'r'): |
131 |
if line.startswith(' | Total energy corrected'): |
132 |
E = float(line.split()[-2]) |
133 |
return E
|
134 |
|
135 |
def read_aims_output(filename, index = -1): |
136 |
""" Import FHI-aims output files with all data available, i.e. relaxations,
|
137 |
MD information, force information etc etc etc. """
|
138 |
from ase import Atoms, Atom |
139 |
from ase.calculators.singlepoint import SinglePointCalculator |
140 |
from ase.units import Ang, fs |
141 |
molecular_dynamics = False
|
142 |
fd = open(filename, 'r') |
143 |
cell = [] |
144 |
images = [] |
145 |
n_periodic = -1
|
146 |
f = None
|
147 |
pbc = False
|
148 |
found_aims_calculator = False
|
149 |
v_unit = Ang/(1000.0*fs)
|
150 |
while True: |
151 |
line = fd.readline() |
152 |
if not line: |
153 |
break
|
154 |
if "List of parameters used to initialize the calculator:" in line: |
155 |
fd.readline() |
156 |
calc = read_aims_calculator(fd) |
157 |
calc.out = filename |
158 |
found_aims_calculator = True
|
159 |
if "Number of atoms" in line: |
160 |
inp = line.split() |
161 |
n_atoms = int(inp[5]) |
162 |
if "| Unit cell:" in line: |
163 |
if not pbc: |
164 |
pbc = True
|
165 |
for i in range(3): |
166 |
inp = fd.readline().split() |
167 |
cell.append([inp[1],inp[2],inp[3]]) |
168 |
if "Atomic structure:" in line and not molecular_dynamics: |
169 |
fd.readline() |
170 |
atoms = Atoms() |
171 |
for i in range(n_atoms): |
172 |
inp = fd.readline().split() |
173 |
atoms.append(Atom(inp[3],(inp[4],inp[5],inp[6]))) |
174 |
if "Complete information for previous time-step:" in line: |
175 |
molecular_dynamics = True
|
176 |
if "Updated atomic structure:" in line and not molecular_dynamics: |
177 |
fd.readline() |
178 |
atoms = Atoms() |
179 |
velocities = [] |
180 |
for i in range(n_atoms): |
181 |
inp = fd.readline().split() |
182 |
atoms.append(Atom(inp[4],(inp[1],inp[2],inp[3]))) |
183 |
if molecular_dynamics:
|
184 |
inp = fd.readline().split() |
185 |
if "Atomic structure (and velocities)" in line: |
186 |
fd.readline() |
187 |
atoms = Atoms() |
188 |
velocities = [] |
189 |
for i in range(n_atoms): |
190 |
inp = fd.readline().split() |
191 |
atoms.append(Atom(inp[4],(inp[1],inp[2],inp[3]))) |
192 |
inp = fd.readline().split() |
193 |
velocities += [[float(inp[1])*v_unit,float(inp[2])*v_unit,float(inp[3])*v_unit]] |
194 |
atoms.set_velocities(velocities) |
195 |
images.append(atoms) |
196 |
if "Total atomic forces" in line: |
197 |
f = [] |
198 |
for i in range(n_atoms): |
199 |
inp = fd.readline().split() |
200 |
f.append([float(inp[2]),float(inp[3]),float(inp[4])]) |
201 |
if not found_aims_calculator: |
202 |
e = images[-1].get_potential_energy()
|
203 |
images[-1].set_calculator(SinglePointCalculator(e,f,None,None,atoms)) |
204 |
e = None
|
205 |
f = None
|
206 |
if "Total energy corrected" in line: |
207 |
e = float(line.split()[5]) |
208 |
if pbc:
|
209 |
atoms.set_cell(cell) |
210 |
atoms.pbc = True
|
211 |
if not found_aims_calculator: |
212 |
atoms.set_calculator(SinglePointCalculator(e,None,None,None,atoms)) |
213 |
if not molecular_dynamics: |
214 |
images.append(atoms) |
215 |
e = None
|
216 |
if found_aims_calculator:
|
217 |
calc.set_results(images[-1])
|
218 |
images[-1].set_calculator(calc)
|
219 |
fd.close() |
220 |
if molecular_dynamics:
|
221 |
images = images[1:]
|
222 |
|
223 |
# return requested images, code borrowed from ase/io/trajectory.py
|
224 |
if isinstance(index, int): |
225 |
return images[index]
|
226 |
else:
|
227 |
step = index.step or 1 |
228 |
if step > 0: |
229 |
start = index.start or 0 |
230 |
if start < 0: |
231 |
start += len(images)
|
232 |
stop = index.stop or len(images) |
233 |
if stop < 0: |
234 |
stop += len(images)
|
235 |
else:
|
236 |
if index.start is None: |
237 |
start = len(images) - 1 |
238 |
else:
|
239 |
start = index.start |
240 |
if start < 0: |
241 |
start += len(images)
|
242 |
if index.stop is None: |
243 |
stop = -1
|
244 |
else:
|
245 |
stop = index.stop |
246 |
if stop < 0: |
247 |
stop += len(images)
|
248 |
return [images[i] for i in range(start, stop, step)] |
249 |
|
250 |
def read_aims_calculator(file): |
251 |
""" found instructions for building an FHI-aims calculator in the output file,
|
252 |
read its specifications and return it. """
|
253 |
from ase.calculators.aims import Aims |
254 |
calc = Aims() |
255 |
while True: |
256 |
line = file.readline()
|
257 |
if "=======================================================" in line: |
258 |
break
|
259 |
else:
|
260 |
args = line.split() |
261 |
key = args[0]
|
262 |
if key == '#': |
263 |
comment = True
|
264 |
elif calc.float_params.has_key(key):
|
265 |
calc.float_params[key] = float(args[1]) |
266 |
elif calc.exp_params.has_key(key):
|
267 |
calc.exp_params[key] = float(args[1]) |
268 |
elif calc.string_params.has_key(key):
|
269 |
calc.string_params[key] = args[1]
|
270 |
if len(args) > 2: |
271 |
for s in args[2:]: |
272 |
calc.string_params[key] += " "+s
|
273 |
elif calc.int_params.has_key(key):
|
274 |
calc.int_params[key] = int(args[1]) |
275 |
elif calc.bool_params.has_key(key):
|
276 |
try:
|
277 |
calc.bool_params[key] = bool(args[1]) |
278 |
except:
|
279 |
if key == 'vdw_correction_hirshfeld': |
280 |
calc.bool_params[key] = True
|
281 |
elif calc.list_params.has_key(key):
|
282 |
if key == 'output': |
283 |
# build output string from args:
|
284 |
out_option = ''
|
285 |
for arg in args[1:]: |
286 |
out_option +=str(arg)+' ' |
287 |
if calc.list_params['output'] is not None: |
288 |
calc.list_params['output'] += [out_option]
|
289 |
else:
|
290 |
calc.list_params['output'] = [out_option]
|
291 |
else:
|
292 |
calc.list_params[key] = list(args[1:]) |
293 |
elif '#' in key: |
294 |
key = key[1:]
|
295 |
if calc.input_parameters.has_key(key):
|
296 |
calc.input_parameters[key] = args[1]
|
297 |
if len(args) > 2: |
298 |
for s in args[2:]: |
299 |
calc.input_parameters[key] += " "+s
|
300 |
else:
|
301 |
raise TypeError('FHI-aims keyword not defined in ASE: ' + key + '. Please check.') |
302 |
return calc
|