Source code for dpgen.database.vasp

# /usr/bin/env python
# Copyright (c) PThe Dpmodeling Team.


import os
import warnings

from monty.io import zopen
from monty.json import MontyDecoder, MSONable
from monty.os.path import zpath
from pymatgen.io.vasp import Incar, Kpoints, Poscar, Potcar, PotcarSingle

"""
Classes for reading/manipulating/writing VASP input files. All major VASP input
files.
"""


[docs] class DPPotcar(MSONable): def __init__(self, symbols=None, functional="PBE", pp_file=None, pp_lists=None): if pp_lists is not None and pp_file is None: for pp in pp_lists: assert isinstance(pp, PotcarSingle) self.potcars = pp_lists elif pp_file is not None and pp_lists is None: self.potcars = Potcar.from_file(pp_file) elif pp_file is not None and pp_lists is not None: self.potcars = Potcar.from_file(pp_file) else: try: self.potcars = Potcar(symbols=symbols, functional=functional) except Exception: warnings.warn("""Inproperly configure of POTCAR !""") self.potcars = None if self.potcars is not None: self.symbols = [pp.symbol for pp in self.potcars] self.functional = list(set([pp.functional for pp in self.potcars]))[0] self.hashs = [pp.get_potcar_hash() for pp in self.potcars] else: self.symbols = symbols self.functional = functional self.hashs = "" self.elements = self._get_elements() def __repr__(self): return str(self) def __str__(self): if self.potcars is not None: return str(self.potcars) else: ret = "Functional: %s\n" % self.functional ret += " ".join(self.symbols) + "\n" return ret def _get_elements(self): elements = [] for el in self.symbols: if "_" in el: elements.append(el.split("_")[0]) else: elements.append(el) return elements
[docs] @classmethod def from_dict(cls, d): return cls(symbols=d["symbols"], functional=d["functional"])
[docs] def as_dict(self): d = {} d["@module"] = self.__class__.__module__ d["@class"] = self.__class__.__name__ d["symbols"] = self.symbols d["elements"] = self.elements d["hashs"] = self.hashs d["functional"] = self.functional return d
[docs] @classmethod def from_file(cls, filename): try: potcars = Potcar.from_file(filename) return cls(pp_lists=potcars) except Exception: with open(filename) as f: content = f.readlines() functional = content[0].strip().split(":")[-1].strip() symbols = content[1].strip().split() return cls(symbols=symbols, functional=functional)
[docs] def write_file(self, filename): with open(filename, "w") as f: f.write(str(self))
[docs] class VaspInput(dict, MSONable): """Class to contain a set of vasp input objects corresponding to a run. Args: ---- incar: Incar object. kpoints: Kpoints object. poscar: Poscar object. potcar: Potcar object. optional_files: Other input files supplied as a dict of { filename: object}. The object should follow standard pymatgen conventions in implementing a as_dict() and from_dict method. """ def __init__( self, incar, poscar, potcar, kpoints=None, optional_files=None, **kwargs ): super().__init__(**kwargs) self.update({"INCAR": incar, "POSCAR": poscar, "POTCAR": potcar}) if kpoints: self.update({"KPOINTS": kpoints}) if optional_files is not None: self.update(optional_files) def __str__(self): output = [] for k, v in self.items(): output.append(k) output.append(str(v)) output.append("") return "\n".join(output)
[docs] def as_dict(self): d = {k: v.as_dict() for k, v in self.items()} d["@module"] = self.__class__.__module__ d["@class"] = self.__class__.__name__ return d
[docs] @classmethod def from_dict(cls, d): dec = MontyDecoder() sub_d = {"optional_files": {}} for k, v in d.items(): if k in ["INCAR", "POSCAR", "POTCAR", "KPOINTS"]: sub_d[k.lower()] = dec.process_decoded(v) elif k not in ["@module", "@class"]: sub_d["optional_files"][k] = dec.process_decoded(v) return cls(**sub_d)
[docs] def write_input(self, output_dir=".", make_dir_if_not_present=True): """Write VASP input to a directory. Parameters ---------- output_dir : str Directory to write to. Defaults to current directory ("."). make_dir_if_not_present : bool Create the directory if not present. Defaults to True. """ if make_dir_if_not_present and not os.path.exists(output_dir): os.makedirs(output_dir) for k, v in self.items(): with zopen(os.path.join(output_dir, k), "wt") as f: f.write(v.__str__())
[docs] @staticmethod def from_directory(input_dir, optional_files=None): """Read in a set of VASP input from a directory. Note that only the standard INCAR, POSCAR, POTCAR and KPOINTS files are read unless optional_filenames is specified. Parameters ---------- input_dir : str Directory to read VASP input from. optional_files : dict Optional files to read in as well as a dict of {filename: Object type}. Object type must have a static method from_file. """ sub_d = {} try: for fname, ftype in [ ("INCAR", Incar), ("KPOINTS", Kpoints), ("POSCAR", Poscar), ("POTCAR", DPPotcar), ]: fullzpath = zpath(os.path.join(input_dir, fname)) sub_d[fname.lower()] = ftype.from_file(fullzpath) except Exception: for fname, ftype in [ ("INCAR", Incar), ("POSCAR", Poscar), ("POTCAR", DPPotcar), ]: fullzpath = zpath(os.path.join(input_dir, fname)) sub_d[fname.lower()] = ftype.from_file(fullzpath) sub_d["optional_files"] = {} if optional_files is not None: for fname, ftype in optional_files.items(): sub_d["optional_files"][fname] = ftype.from_file( os.path.join(input_dir, fname) ) return VaspInput(**sub_d)