Statistiques
| Révision :

root / ase / io / vasp.py

Historique | Voir | Annoter | Télécharger (11,62 ko)

1 1 tkerber
"""
2 1 tkerber
This module contains functionality for reading and writing an ASE
3 1 tkerber
Atoms object in VASP POSCAR format.
4 1 tkerber

5 1 tkerber
"""
6 1 tkerber
7 1 tkerber
import os
8 1 tkerber
9 1 tkerber
def get_atomtypes(fname):
10 1 tkerber
    """Given a file name, get the atomic symbols.
11 1 tkerber

12 1 tkerber
    The function can get this information from OUTCAR and POTCAR
13 1 tkerber
    format files.  The files can also be compressed with gzip or
14 1 tkerber
    bzip2.
15 1 tkerber

16 1 tkerber
    """
17 1 tkerber
    atomtypes=[]
18 1 tkerber
    if fname.find('.gz') != -1:
19 1 tkerber
        import gzip
20 1 tkerber
        f = gzip.open(fname)
21 1 tkerber
    elif fname.find('.bz2') != -1:
22 1 tkerber
        import bz2
23 1 tkerber
        f = bz2.BZ2File(fname)
24 1 tkerber
    else:
25 1 tkerber
        f = open(fname)
26 1 tkerber
    for line in f:
27 1 tkerber
        if line.find('TITEL') != -1:
28 1 tkerber
            atomtypes.append(line.split()[3].split('_')[0].split('.')[0])
29 1 tkerber
    return atomtypes
30 1 tkerber
31 1 tkerber
def atomtypes_outpot(posfname, numsyms):
32 1 tkerber
    """Try to retreive chemical symbols from OUTCAR or POTCAR
33 1 tkerber

34 1 tkerber
    If getting atomtypes from the first line in POSCAR/CONTCAR fails, it might
35 1 tkerber
    be possible to find the data in OUTCAR or POTCAR, if these files exist.
36 1 tkerber

37 1 tkerber
    posfname -- The filename of the POSCAR/CONTCAR file we're trying to read
38 1 tkerber

39 1 tkerber
    numsyms -- The number of symbols we must find
40 1 tkerber

41 1 tkerber
    """
42 1 tkerber
    import os.path as op
43 1 tkerber
    import glob
44 1 tkerber
45 1 tkerber
    # First check files with exactly same name except POTCAR/OUTCAR instead
46 1 tkerber
    # of POSCAR/CONTCAR.
47 1 tkerber
    fnames = [posfname.replace('POSCAR', 'POTCAR').replace('CONTCAR',
48 1 tkerber
                                                           'POTCAR')]
49 1 tkerber
    fnames.append(posfname.replace('POSCAR', 'OUTCAR').replace('CONTCAR',
50 1 tkerber
                                                               'OUTCAR'))
51 1 tkerber
    # Try the same but with compressed files
52 1 tkerber
    fsc = []
53 1 tkerber
    for fn in fnames:
54 1 tkerber
        fsc.append(fn + '.gz')
55 1 tkerber
        fsc.append(fn + '.bz2')
56 1 tkerber
    for f in fsc:
57 1 tkerber
        fnames.append(f)
58 1 tkerber
    # Finally try anything with POTCAR or OUTCAR in the name
59 1 tkerber
    vaspdir = op.dirname(posfname)
60 1 tkerber
    fs = glob.glob(vaspdir + '*POTCAR*')
61 1 tkerber
    for f in fs:
62 1 tkerber
        fnames.append(f)
63 1 tkerber
    fs = glob.glob(vaspdir + '*OUTCAR*')
64 1 tkerber
    for f in fs:
65 1 tkerber
        fnames.append(f)
66 1 tkerber
67 1 tkerber
    tried = []
68 1 tkerber
    files_in_dir = os.listdir('.')
69 1 tkerber
    for fn in fnames:
70 1 tkerber
        tried.append(fn)
71 1 tkerber
        if fn in files_in_dir:
72 1 tkerber
            at = get_atomtypes(fn)
73 1 tkerber
            if len(at) == numsyms:
74 1 tkerber
                return at
75 1 tkerber
76 1 tkerber
    raise IOError('Could not determine chemical symbols. Tried files '
77 1 tkerber
                  + str(tried))
78 1 tkerber
79 1 tkerber
80 1 tkerber
def read_vasp(filename='CONTCAR'):
81 1 tkerber
    """Import POSCAR/CONTCAR type file.
82 1 tkerber

83 1 tkerber
    Reads unitcell, atom positions and constraints from the POSCAR/CONTCAR
84 1 tkerber
    file and tries to read atom types from POSCAR/CONTCAR header, if this fails
85 1 tkerber
    the atom types are read from OUTCAR or POTCAR file.
86 1 tkerber
    """
87 1 tkerber
88 1 tkerber
    from ase import Atoms, Atom
89 1 tkerber
    from ase.constraints import FixAtoms, FixScaled
90 1 tkerber
    from ase.data import chemical_symbols
91 1 tkerber
    import numpy as np
92 1 tkerber
93 1 tkerber
    if isinstance(filename, str):
94 1 tkerber
        f = open(filename)
95 1 tkerber
    else: # Assume it's a file-like object
96 1 tkerber
        f = filename
97 1 tkerber
98 1 tkerber
    # First line should contain the atom symbols , eg. "Ag Ge" in
99 1 tkerber
    # the same order
100 1 tkerber
    # as later in the file (and POTCAR for the full vasp run)
101 1 tkerber
    atomtypes = f.readline().split()
102 1 tkerber
103 1 tkerber
    lattice_constant = float(f.readline())
104 1 tkerber
105 1 tkerber
    # Now the lattice vectors
106 1 tkerber
    a = []
107 1 tkerber
    for ii in range(3):
108 1 tkerber
        s = f.readline().split()
109 1 tkerber
        floatvect = float(s[0]), float(s[1]), float(s[2])
110 1 tkerber
        a.append(floatvect)
111 1 tkerber
112 1 tkerber
    basis_vectors = np.array(a) * lattice_constant
113 1 tkerber
114 1 tkerber
    # Number of atoms. Again this must be in the same order as
115 1 tkerber
    # in the first line
116 1 tkerber
    # or in the POTCAR or OUTCAR file
117 1 tkerber
    atom_symbols = []
118 1 tkerber
    numofatoms = f.readline().split()
119 1 tkerber
    #vasp5.1 has an additional line which gives the atom types
120 1 tkerber
    #the following try statement skips this line
121 1 tkerber
    try:
122 1 tkerber
        int(numofatoms[0])
123 1 tkerber
    except ValueError:
124 1 tkerber
        numofatoms = f.readline().split()
125 1 tkerber
126 1 tkerber
    numsyms = len(numofatoms)
127 1 tkerber
    if len(atomtypes) < numsyms:
128 1 tkerber
        # First line in POSCAR/CONTCAR didn't contain enough symbols.
129 1 tkerber
        atomtypes = atomtypes_outpot(f.name, numsyms)
130 1 tkerber
    else:
131 1 tkerber
        try:
132 1 tkerber
            for atype in atomtypes[:numsyms]:
133 1 tkerber
                if not atype in chemical_symbols:
134 1 tkerber
                    raise KeyError
135 1 tkerber
        except KeyError:
136 1 tkerber
            atomtypes = atomtypes_outpot(f.name, numsyms)
137 1 tkerber
138 1 tkerber
    for i, num in enumerate(numofatoms):
139 1 tkerber
        numofatoms[i] = int(num)
140 1 tkerber
        [atom_symbols.append(atomtypes[i]) for na in xrange(numofatoms[i])]
141 1 tkerber
142 1 tkerber
    # Check if Selective dynamics is switched on
143 1 tkerber
    sdyn = f.readline()
144 1 tkerber
    selective_dynamics = sdyn[0].lower() == "s"
145 1 tkerber
146 1 tkerber
    # Check if atom coordinates are cartesian or direct
147 1 tkerber
    if selective_dynamics:
148 1 tkerber
        ac_type = f.readline()
149 1 tkerber
    else:
150 1 tkerber
        ac_type = sdyn
151 1 tkerber
    cartesian = ac_type[0].lower() == "c" or ac_type[0].lower() == "k"
152 1 tkerber
    tot_natoms = sum(numofatoms)
153 1 tkerber
    atoms_pos = np.empty((tot_natoms, 3))
154 1 tkerber
    if selective_dynamics:
155 1 tkerber
        selective_flags = np.empty((tot_natoms, 3), dtype=bool)
156 1 tkerber
    for atom in xrange(tot_natoms):
157 1 tkerber
        ac = f.readline().split()
158 1 tkerber
        atoms_pos[atom] = (float(ac[0]), float(ac[1]), float(ac[2]))
159 1 tkerber
        if selective_dynamics:
160 1 tkerber
            curflag = []
161 1 tkerber
            for flag in ac[3:6]:
162 1 tkerber
                curflag.append(flag == 'F')
163 1 tkerber
            selective_flags[atom] = curflag
164 1 tkerber
    # Done with all reading
165 1 tkerber
    if type(filename) == str:
166 1 tkerber
        f.close()
167 1 tkerber
    if cartesian:
168 1 tkerber
        atoms_pos *= lattice_constant
169 1 tkerber
    atoms = Atoms(symbols = atom_symbols, cell = basis_vectors, pbc = True)
170 1 tkerber
    if cartesian:
171 1 tkerber
        atoms.set_positions(atoms_pos)
172 1 tkerber
    else:
173 1 tkerber
        atoms.set_scaled_positions(atoms_pos)
174 1 tkerber
    if selective_dynamics:
175 1 tkerber
        constraints = []
176 1 tkerber
        indices = []
177 1 tkerber
        for ind, sflags in enumerate(selective_flags):
178 1 tkerber
            if sflags.any() and not sflags.all():
179 1 tkerber
                constraints.append(FixScaled(atoms.get_cell(), ind, sflags))
180 1 tkerber
            elif sflags.all():
181 1 tkerber
                indices.append(ind)
182 1 tkerber
        if indices:
183 1 tkerber
            constraints.append(FixAtoms(indices))
184 1 tkerber
        if constraints:
185 1 tkerber
            atoms.set_constraint(constraints)
186 1 tkerber
    return atoms
187 1 tkerber
188 1 tkerber
def read_vasp_out(filename='OUTCAR',index = -1):
189 1 tkerber
    """Import OUTCAR type file.
190 1 tkerber

191 1 tkerber
    Reads unitcell, atom positions, energies, and forces from the OUTCAR file.
192 1 tkerber

193 1 tkerber
    - does not (yet) read any constraints
194 1 tkerber
    """
195 1 tkerber
    import os
196 1 tkerber
    import numpy as np
197 1 tkerber
    from ase.calculators.singlepoint import SinglePointCalculator
198 1 tkerber
    from ase import Atoms, Atom
199 1 tkerber
200 1 tkerber
    if isinstance(filename, str):
201 1 tkerber
        f = open(filename)
202 1 tkerber
    else: # Assume it's a file-like object
203 1 tkerber
        f = filename
204 1 tkerber
    data    = f.readlines()
205 1 tkerber
    natoms  = 0
206 1 tkerber
    images  = []
207 1 tkerber
    atoms   = Atoms(pbc = True)
208 1 tkerber
    energy  = 0
209 1 tkerber
    species = []
210 1 tkerber
    species_num = []
211 1 tkerber
    symbols = []
212 1 tkerber
    for n,line in enumerate(data):
213 1 tkerber
        if 'POSCAR:' in line:
214 1 tkerber
            temp = line.split()
215 1 tkerber
            species = temp[1:]
216 1 tkerber
        if 'ions per type' in line:
217 1 tkerber
            temp = line.split()
218 1 tkerber
            for ispecies in range(len(species)):
219 1 tkerber
                species_num += [int(temp[ispecies+4])]
220 1 tkerber
                natoms += species_num[-1]
221 1 tkerber
                for iatom in range(species_num[-1]): symbols += [species[ispecies]]
222 1 tkerber
        if 'direct lattice vectors' in line:
223 1 tkerber
            cell = []
224 1 tkerber
            for i in range(3):
225 1 tkerber
                temp = data[n+1+i].split()
226 1 tkerber
                cell += [[float(temp[0]), float(temp[1]), float(temp[2])]]
227 1 tkerber
            atoms.set_cell(cell)
228 1 tkerber
        if 'FREE ENERGIE OF THE ION-ELECTRON SYSTEM' in line:
229 1 tkerber
            energy = float(data[n+2].split()[4])
230 1 tkerber
        if 'POSITION          ' in line:
231 1 tkerber
            forces = []
232 1 tkerber
            for iatom in range(natoms):
233 1 tkerber
                temp    = data[n+2+iatom].split()
234 1 tkerber
                atoms  += Atom(symbols[iatom],[float(temp[0]),float(temp[1]),float(temp[2])])
235 1 tkerber
                forces += [[float(temp[3]),float(temp[4]),float(temp[5])]]
236 1 tkerber
                atoms.set_calculator(SinglePointCalculator(energy,forces,None,None,atoms))
237 1 tkerber
            images += [atoms]
238 1 tkerber
            atoms = Atoms(pbc = True)
239 1 tkerber
240 1 tkerber
    # return requested images, code borrowed from ase/io/trajectory.py
241 1 tkerber
    if isinstance(index, int):
242 1 tkerber
        return images[index]
243 1 tkerber
    else:
244 1 tkerber
        step = index.step or 1
245 1 tkerber
        if step > 0:
246 1 tkerber
            start = index.start or 0
247 1 tkerber
            if start < 0:
248 1 tkerber
                start += len(images)
249 1 tkerber
            stop = index.stop or len(images)
250 1 tkerber
            if stop < 0:
251 1 tkerber
                stop += len(images)
252 1 tkerber
        else:
253 1 tkerber
            if index.start is None:
254 1 tkerber
                start = len(images) - 1
255 1 tkerber
            else:
256 1 tkerber
                start = index.start
257 1 tkerber
                if start < 0:
258 1 tkerber
                    start += len(images)
259 1 tkerber
            if index.stop is None:
260 1 tkerber
                stop = -1
261 1 tkerber
            else:
262 1 tkerber
                stop = index.stop
263 1 tkerber
                if stop < 0:
264 1 tkerber
                    stop += len(images)
265 1 tkerber
        return [images[i] for i in range(start, stop, step)]
266 1 tkerber
267 1 tkerber
def write_vasp(filename, atoms, label='', direct=False, sort=None, symbol_count = None ):
268 1 tkerber
    """Method to write VASP position (POSCAR/CONTCAR) files.
269 1 tkerber

270 1 tkerber
    Writes label, scalefactor, unitcell, # of various kinds of atoms,
271 1 tkerber
    positions in cartesian or scaled coordinates (Direct), and constraints
272 1 tkerber
    to file. Cartesian coordiantes is default and default label is the
273 1 tkerber
    atomic species, e.g. 'C N H Cu'.
274 1 tkerber
    """
275 1 tkerber
276 1 tkerber
    import numpy as np
277 1 tkerber
    from ase.constraints import FixAtoms, FixScaled
278 1 tkerber
279 1 tkerber
    if isinstance(filename, str):
280 1 tkerber
        f = open(filename, 'w')
281 1 tkerber
    else: # Assume it's a 'file-like object'
282 1 tkerber
        f = filename
283 1 tkerber
284 1 tkerber
    if isinstance(atoms, (list, tuple)):
285 1 tkerber
        if len(atoms) > 1:
286 1 tkerber
            raise RuntimeError("Don't know how to save more than "+
287 1 tkerber
                               "one image to VASP input")
288 1 tkerber
        else:
289 1 tkerber
            atoms = atoms[0]
290 1 tkerber
291 1 tkerber
    # Write atom positions in scaled or cartesian coordinates
292 1 tkerber
    if direct:
293 1 tkerber
        coord = atoms.get_scaled_positions()
294 1 tkerber
    else:
295 1 tkerber
        coord = atoms.get_positions()
296 1 tkerber
297 1 tkerber
    if atoms.constraints:
298 1 tkerber
        sflags = np.zeros((len(atoms), 3), dtype=bool)
299 1 tkerber
        for constr in atoms.constraints:
300 1 tkerber
            if isinstance(constr, FixScaled):
301 1 tkerber
                sflags[constr.a] = constr.mask
302 1 tkerber
            elif isinstance(constr, FixAtoms):
303 1 tkerber
                sflags[constr.index] = [True, True, True]
304 1 tkerber
305 1 tkerber
    if sort:
306 1 tkerber
        ind = np.argsort(atoms.get_chemical_symbols())
307 1 tkerber
        symbols = np.array(atoms.get_chemical_symbols())[ind]
308 1 tkerber
        coord = coord[ind]
309 1 tkerber
        if atoms.constraints:
310 1 tkerber
            sflags = sflags[ind]
311 1 tkerber
    else:
312 1 tkerber
        symbols = atoms.get_chemical_symbols()
313 1 tkerber
314 1 tkerber
    # Create a list sc of (symbol, count) pairs
315 1 tkerber
    if symbol_count:
316 1 tkerber
        sc = symbol_count
317 1 tkerber
    else:
318 1 tkerber
        sc = []
319 1 tkerber
        psym = symbols[0]
320 1 tkerber
        count = 0
321 1 tkerber
        for sym in symbols:
322 1 tkerber
            if sym != psym:
323 1 tkerber
                sc.append((psym, count))
324 1 tkerber
                psym = sym
325 1 tkerber
                count = 1
326 1 tkerber
            else:
327 1 tkerber
                count += 1
328 1 tkerber
        sc.append((psym, count))
329 1 tkerber
330 1 tkerber
    # Create the label
331 1 tkerber
    if label == '':
332 1 tkerber
        for sym, c in sc:
333 1 tkerber
            label += '%2s ' % sym
334 1 tkerber
    f.write(label + '\n')
335 1 tkerber
336 1 tkerber
    # Write unitcell in real coordinates and adapt to VASP convention
337 1 tkerber
    # for unit cell
338 1 tkerber
    # ase Atoms doesn't store the lattice constant separately, so always
339 1 tkerber
    # write 1.0.
340 1 tkerber
    f.write('%19.16f\n' % 1.0)
341 1 tkerber
    for vec in atoms.get_cell():
342 1 tkerber
        f.write(' ')
343 1 tkerber
        for el in vec:
344 1 tkerber
            f.write(' %21.16f' % el)
345 1 tkerber
        f.write('\n')
346 1 tkerber
347 1 tkerber
    # Numbers of each atom
348 1 tkerber
    for sym, count in sc:
349 1 tkerber
        f.write(' %3i' % count)
350 1 tkerber
    f.write('\n')
351 1 tkerber
352 1 tkerber
    if atoms.constraints:
353 1 tkerber
        f.write('Selective dynamics\n')
354 1 tkerber
355 1 tkerber
    if direct:
356 1 tkerber
        f.write('Direct\n')
357 1 tkerber
    else:
358 1 tkerber
        f.write('Cartesian\n')
359 1 tkerber
360 1 tkerber
    for iatom, atom in enumerate(coord):
361 1 tkerber
        for dcoord in atom:
362 1 tkerber
            f.write(' %19.16f' % dcoord)
363 1 tkerber
        if atoms.constraints:
364 1 tkerber
            for flag in sflags[iatom]:
365 1 tkerber
                if flag:
366 1 tkerber
                    s = 'F'
367 1 tkerber
                else:
368 1 tkerber
                    s = 'T'
369 1 tkerber
                f.write('%4s' % s)
370 1 tkerber
        f.write('\n')
371 1 tkerber
372 1 tkerber
    if type(filename) == str:
373 1 tkerber
        f.close()