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
"""
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):
from pymatgen.io.vasp import Potcar, PotcarSingle
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 = f"Functional: {self.functional}\n"
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):
from pymatgen.io.vasp import Potcar
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]
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.
"""
from pymatgen.io.vasp import Incar, Kpoints, Poscar
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)