Source code for sisl.io.vasp.car

"""
Sile object for reading/writing CONTCAR/POSCAR files
"""

from __future__ import print_function

import numpy as np
import warnings as warn

# Import sile objects
from .sile import SileVASP
from ..sile import *

# Import the geometry object
from sisl import Geometry, PeriodicTable, Atom, SuperCell

__all__ = ['CARSileVASP', 'POSCARSileVASP', 'CONTCARSileVASP']


[docs]class CARSileVASP(SileVASP): """ CAR file object This file-object handles both POSCAR and CONTCAR files """ def _setup(self): """ Setup the `POSCARSile` after initialization """ self._comment = [] self._scale = 1. @Sile_fh_open def write_geometry(self, geom): """ Writes the geometry to the contained file """ # Check that we can write to the file sile_raise_write(self) # LABEL self._write('sisl output\n') # Scale self._write(' 1.\n') # Write unit-cell fmt = (' ' + '{:18.9f}' * 3) * 2 + '\n' tmp = np.zeros([6], np.float64) for i in range(3): tmp[:3] = geom.cell[i, :] self._write(fmt.format(*tmp)) # Figure out how many species pt = PeriodicTable() s, d = [], [] for ia, a, idx_specie in geom.iter_species(): if idx_specie >= len(d): s.append(pt.Z_label(a.Z)) d.append(0) d[idx_specie] += + 1 fmt = ' ' + '{:s}' * len(d) + '\n' self._write(fmt.format(*s)) fmt = ' ' + '{:d}' * len(d) + '\n' self._write(fmt.format(*d)) self._write('Cartesian\n') fmt = '{:18.9f}' * 3 + '\n' for ia in geom: self._write(fmt.format(*geom.xyz[ia, :])) @Sile_fh_open def read_supercell(self): """ Returns `SuperCell` object from the CONTCAR/POSCAR file """ # read first line self.readline() # LABEL # Update scale-factor self._scale = float(self.readline()) # Read cell vectors cell = np.empty([3, 3], np.float64) for i in range(3): cell[i, :] = list(map(float, self.readline().split()[:3])) cell *= self._scale return SuperCell(cell) @Sile_fh_open def read_geometry(self): """ Returns Geometry object from the CONTCAR/POSCAR file """ sc = self.read_supercell() # The species labels are not always included in *CAR line1 = self.readline().split() opt = self.readline() try: species = line1 species_count = np.array(opt.split(), np.int32) except: species_count = np.array(line1, np.int32) # We have no species... # We default to consecutive elements in the # periodic table. species = [i+1 for i in range(len(species_count))] err = '\n'.join([ "POSCAR best format:", " <Specie-1> <Specie-2>", " <#Specie-1> <#Specie-2>", "Format not found, the species are defaulted to the first elements of the periodic table."]) warn.warn(err) # Create list of atoms to be used subsequently atom = [Atom[spec] for spec, nsp in zip(species, species_count) for i in range(nsp)] # Read whether this is selective or direct opt = self.readline() direct = True if opt[0] in 'Ss': direct = False opt = self.readline() # Check whether this is in fractional or direct # coordinates cart = False if opt[0] in 'CcKk': cart = True # Number of atoms na = len(atom) xyz = np.empty([na, 3], np.float64) aoff = 0 for ia in range(na): xyz[ia, :] = list(map(float, self.readline().split())) if cart: # The unit of the coordinates are cartesian xyz *= self._scale else: xyz = np.dot(xyz, sc.cell.T) # The POT/CONT-CAR does not contain information on the atomic species return Geometry(xyz=xyz, atom=atom, sc=sc)
[docs] def ArgumentParser(self, *args, **kwargs): """ Returns the arguments that is available for this Sile """ newkw = Geometry._ArgumentParser_args_single() newkw.update(kwargs) return self.read_geometry().ArgumentParser(*args, **newkw)
# Equivalent classes
[docs]class POSCARSileVASP(CARSileVASP): pass
[docs]class CONTCARSileVASP(CARSileVASP): pass
add_sile('CAR', CARSileVASP, gzip=True) add_sile('POSCAR', POSCARSileVASP, gzip=True) add_sile('CONTCAR', CONTCARSileVASP, gzip=True)