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 numpy as np
2from ase.atoms import Atoms
3from ase.utils import reader, writer
6@reader
7def read_dftb(fd):
8 """Method to read coordinates from the Geometry section
9 of a DFTB+ input file (typically called "dftb_in.hsd").
11 As described in the DFTB+ manual, this section can be
12 in a number of different formats. This reader supports
13 the GEN format and the so-called "explicit" format.
15 The "explicit" format is unique to DFTB+ input files.
16 The GEN format can also be used in a stand-alone fashion,
17 as coordinate files with a `.gen` extension. Reading and
18 writing such files is implemented in `ase.io.gen`.
19 """
20 lines = fd.readlines()
22 atoms_pos = []
23 atom_symbols = []
24 type_names = []
25 my_pbc = False
26 fractional = False
27 mycell = []
29 for iline, line in enumerate(lines):
30 if line.strip().startswith('#'):
31 pass
32 elif 'genformat' in line.lower():
33 natoms = int(lines[iline + 1].split()[0])
34 if lines[iline + 1].split()[1].lower() == 's':
35 my_pbc = True
36 elif lines[iline + 1].split()[1].lower() == 'f':
37 my_pbc = True
38 fractional = True
40 symbols = lines[iline + 2].split()
42 for i in range(natoms):
43 index = iline + 3 + i
44 aindex = int(lines[index].split()[1]) - 1
45 atom_symbols.append(symbols[aindex])
47 position = [float(p) for p in lines[index].split()[2:]]
48 atoms_pos.append(position)
50 if my_pbc:
51 for i in range(3):
52 index = iline + 4 + natoms + i
53 cell = [float(c) for c in lines[index].split()]
54 mycell.append(cell)
55 else:
56 if 'TypeNames' in line:
57 col = line.split()
58 for i in range(3, len(col) - 1):
59 type_names.append(col[i].strip("\""))
60 elif 'Periodic' in line:
61 if 'Yes' in line:
62 my_pbc = True
63 elif 'LatticeVectors' in line:
64 for imycell in range(3):
65 extraline = lines[iline + imycell + 1]
66 cols = extraline.split()
67 mycell.append(
68 [float(cols[0]), float(cols[1]), float(cols[2])])
69 else:
70 pass
72 if not my_pbc:
73 mycell = [0.] * 3
75 start_reading_coords = False
76 stop_reading_coords = False
77 for line in lines:
78 if line.strip().startswith('#'):
79 pass
80 else:
81 if 'TypesAndCoordinates' in line:
82 start_reading_coords = True
83 if start_reading_coords:
84 if '}' in line:
85 stop_reading_coords = True
86 if (start_reading_coords and not stop_reading_coords
87 and 'TypesAndCoordinates' not in line):
88 typeindexstr, xxx, yyy, zzz = line.split()[:4]
89 typeindex = int(typeindexstr)
90 symbol = type_names[typeindex - 1]
91 atom_symbols.append(symbol)
92 atoms_pos.append([float(xxx), float(yyy), float(zzz)])
94 if fractional:
95 atoms = Atoms(scaled_positions=atoms_pos, symbols=atom_symbols,
96 cell=mycell, pbc=my_pbc)
97 elif not fractional:
98 atoms = Atoms(positions=atoms_pos, symbols=atom_symbols,
99 cell=mycell, pbc=my_pbc)
101 return atoms
104def read_dftb_velocities(atoms, filename):
105 """Method to read velocities (AA/ps) from DFTB+ output file geo_end.xyz
106 """
107 from ase.units import second
108 # AA/ps -> ase units
109 AngdivPs2ASE = 1.0 / (1e-12 * second)
111 with open(filename) as fd:
112 lines = fd.readlines()
114 # remove empty lines
115 lines_ok = []
116 for line in lines:
117 if line.rstrip():
118 lines_ok.append(line)
120 velocities = []
121 natoms = len(atoms)
122 last_lines = lines_ok[-natoms:]
123 for iline, line in enumerate(last_lines):
124 inp = line.split()
125 velocities.append([float(inp[5]) * AngdivPs2ASE,
126 float(inp[6]) * AngdivPs2ASE,
127 float(inp[7]) * AngdivPs2ASE])
129 atoms.set_velocities(velocities)
130 return atoms
133@reader
134def read_dftb_lattice(fileobj, images=None):
135 """Read lattice vectors from MD and return them as a list.
137 If a molecules are parsed add them there."""
138 if images is not None:
139 append = True
140 if hasattr(images, 'get_positions'):
141 images = [images]
142 else:
143 append = False
145 fileobj.seek(0)
146 lattices = []
147 for line in fileobj:
148 if 'Lattice vectors' in line:
149 vec = []
150 for i in range(3): # DFTB+ only supports 3D PBC
151 line = fileobj.readline().split()
152 try:
153 line = [float(x) for x in line]
154 except ValueError:
155 raise ValueError('Lattice vector elements should be of '
156 'type float.')
157 vec.extend(line)
158 lattices.append(np.array(vec).reshape((3, 3)))
160 if append:
161 if len(images) != len(lattices):
162 raise ValueError('Length of images given does not match number of '
163 'cell vectors found')
165 for i, atoms in enumerate(images):
166 atoms.set_cell(lattices[i])
167 # DFTB+ only supports 3D PBC
168 atoms.set_pbc(True)
169 return
170 else:
171 return lattices
174@writer
175def write_dftb(fileobj, images):
176 """Write structure in GEN format (refer to DFTB+ manual).
177 Multiple snapshots are not allowed. """
178 from ase.io.gen import write_gen
179 write_gen(fileobj, images)
182def write_dftb_velocities(atoms, filename):
183 """Method to write velocities (in atomic units) from ASE
184 to a file to be read by dftb+
185 """
186 from ase.units import AUT, Bohr
187 # ase units -> atomic units
188 ASE2au = Bohr / AUT
190 with open(filename, 'w') as fd:
191 velocities = atoms.get_velocities()
192 for velocity in velocities:
193 fd.write(' %19.16f %19.16f %19.16f \n'
194 % (velocity[0] / ASE2au,
195 velocity[1] / ASE2au,
196 velocity[2] / ASE2au))