Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add new MP input sets #3916

Open
wants to merge 13 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ titel,alls,ans,nd,mater,nwo,te,hart,ontop,ist,ot,fo,nax,coo,
coul,ser,leary,thre,fase,rute,reson,titels,ges,scalr,strat,
struc,hda,nin,ons,pres,kno,loos,lamda,lew,atomate,nempty
"""
skip = "pymatgen/analysis/aflow_prototypes.json"
skip = "src/pymatgen/analysis/aflow_prototypes.json"
check-filenames = true

[tool.pyright]
Expand Down
30 changes: 30 additions & 0 deletions src/pymatgen/io/vasp/MP24RelaxSet.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Default VASP settings for calculations in the Materials Project
# using the Regularized-Restored Strongly Constrained and Appropriately
# Normed functional (r2SCAN).
PARENT: PBE64Base
INCAR:
ALGO: Normal
EDIFF: 1.e-05
EDIFFG: -0.02
ENAUG: 1360
ENCUT: 680
IBRION: 2
ISIF: 3
ISMEAR: 0 # included to have some reasonable default
ISPIN: 2
KSPACING: 0.22 # included to have some reasonable default
LAECHG: True
LASPH: True
LCHARG: True
LELF: False # LELF = True restricts calculation to KPAR = 1
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it restricts to NPAR = 1 not KPAR = 1. I am not sure where this restriction originates.

There is some logic that expensive-to-compute quantities should be saved by default? (e.g., to my knowledge the only way to recover the KE density from a VASP calculation is to store the ELF)

I see the sense in leaving this as False but I wonder what should be stored by default? I imagine there is a trade-off with I/O and post-processing time too, especially for simple calculations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The manual says NPAR = 1, but the actual error message I get when I run VASP 6.4.2 (just checked) is: ELF: KPAR>1 not implemented, sorry. Either way, restricts the parallelization

You can reconstruct the KED from the orbitals in WAVECAR, since those should just be the plane wave coefficients + wave vectors (think we have tools in PMG to parse this but haven't looked thoroughly)

I'm good with LELF = True for the final static in the MP workflow, since this is usually very cheap (it starts from the WAVECAR of the r2SCAN relaxation)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So we hard-code KPAR: 1 for the final static?

Makes sense with the WAVECAR, I am genuinely wondering whether one day we should encourage storage of this by default if storage costs continue to reduce. I am encountering more and more post-processing tools that would really benefit if a large dataset of wave functions were available. I wonder how compressible they are with modern methods too, something I will not have time to investigate unfortunately!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A little hesitant to do that, especially if we want to treat larger systems, but it'll require some testing for me to see if KPAR = 1 is a real practical issue

Saving the vaspwave.h5 file might be better in the long run. There's currently an open PR for this, I also need to finish the vaspout.h5 PR

LMAXMIX: 6 # per benchmark
LMIXTAU: True
LORBIT: 11
LREAL: False # per benchmark
LVTOT: True
LWAVE: False
METAGGA: R2SCAN
NELM: 200
NSW: 99
PREC: Accurate
SIGMA: 0.05 # included to have some reasonable default
24 changes: 12 additions & 12 deletions src/pymatgen/io/vasp/PBE64Base.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ POTCAR:
At: At
Au: Au
B: B
Ba: Ba_sv
Ba: Ba_sv_GW
Be: Be_sv
Bi: Bi
Br: Br
Expand All @@ -26,8 +26,8 @@ POTCAR:
Cr: Cr_pv
Cs: Cs_sv
Cu: Cu_pv
Dy: Dy_3
Er: Er_3
Dy: Dy_h
Er: Er_h
Eu: Eu
F: F
Fe: Fe_pv
Expand All @@ -39,7 +39,7 @@ POTCAR:
He: He
Hf: Hf_pv
Hg: Hg
Ho: Ho_3
Ho: Ho_h
I: I
In: In_d
Ir: Ir
Expand All @@ -54,7 +54,7 @@ POTCAR:
N: N
Na: Na_pv
Nb: Nb_pv
Nd: Nd_3
Nd: Nd_h
Ne: Ne
Ni: Ni_pv
Np: Np
Expand All @@ -64,9 +64,9 @@ POTCAR:
Pa: Pa
Pb: Pb_d
Pd: Pd
Pm: Pm_3
Pm: Pm_h
Po: Po_d
Pr: Pr_3
Pr: Pr_h
Pt: Pt
Pu: Pu
Ra: Ra_sv
Expand All @@ -80,22 +80,22 @@ POTCAR:
Sc: Sc_sv
Se: Se
Si: Si
Sm: Sm_3
Sm: Sm_h
Sn: Sn_d
Sr: Sr_sv
Ta: Ta_pv
Tb: Tb_3
Tb: Tb_h
Tc: Tc_pv
Te: Te
Th: Th
Ti: Ti_pv
Tl: Tl_d
Tm: Tm_3
Tm: Tm_h
U: U
V: V_pv
W: W_sv
Xe: Xe
Xe: Xe_GW
Y: Y_sv
Yb: Yb_3
Yb: Yb_h
Zn: Zn
Zr: Zr_sv
155 changes: 151 additions & 4 deletions src/pymatgen/io/vasp/sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@


def _load_yaml_config(fname):
config = loadfn(f"{MODULE_DIR}/{fname}.yaml")
fname = f"{MODULE_DIR}/{fname}"
if not fname.endswith(".yaml"):
fname += ".yaml"
config = loadfn(fname)
if "PARENT" in config:
parent_config = _load_yaml_config(config["PARENT"])
for k, v in parent_config.items():
Expand Down Expand Up @@ -602,7 +605,11 @@ def incar(self) -> Incar:
elif key == "KSPACING" and self.auto_kspacing:
# Default to metal if no prev calc available
bandgap = 0 if self.bandgap is None else self.bandgap
incar[key] = auto_kspacing(bandgap, self.bandgap_tol)
if new_kspacing := getattr(self, "kspacing_update", None):
# allow custom KSPACING update
incar[key] = new_kspacing
else:
incar[key] = auto_kspacing(bandgap, self.bandgap_tol)

else:
incar[key] = setting
Expand Down Expand Up @@ -1260,7 +1267,7 @@ class MPRelaxSet(VaspInputSet):

@due.dcite(
Doi("10.1021/acs.jpclett.0c02405"),
description="AccurAccurate and Numerically Efficient r2SCAN Meta-Generalized Gradient Approximation",
description="Accurate and Numerically Efficient r2SCAN Meta-Generalized Gradient Approximation",
)
@due.dcite(
Doi("10.1103/PhysRevLett.115.036402"),
Expand Down Expand Up @@ -1338,6 +1345,104 @@ def __post_init__(self) -> None:
self._config_dict["INCAR"].pop(k, None)


@dataclass
class MP24RelaxSet(VaspInputSet):
"""
Materials Project relax set after a 2023-2024 benchmarking effort.

By default, this uses r2SCAN as the xc functional.
"""

xc_functional: Literal["R2SCAN", "PBE", "PBESOL"] = "R2SCAN"
dispersion: Literal["rVV10", "D4"] | None = None
CONFIG = _load_yaml_config("MP24RelaxSet")
auto_ismear: bool = True

def __post_init__(self) -> None:
super().__post_init__()

to_func = {
"R2SCAN": "R2SCAN",
"PBE": "PE",
"PBESOL": "PS",
}

xc_func = self.xc_functional.upper()
config_updates: dict[str, Any] = {}
if xc_func == "R2SCAN":
config_updates = {"METAGGA": to_func[xc_func], "GGA": None}
elif xc_func in ["PBE", "PBESOL"]:
config_updates = {"METAGGA": None, "GGA": to_func[xc_func]}
else:
raise ValueError(f"Unknown XC functional {self.xc_functional}!")

if self.dispersion == "rVV10":
if xc_func == "R2SCAN":
config_updates = {"BPARAM": 11.95, "CPARAM": 0.0093}
else:
raise ValueError("Use of rVV10 with functionals other than r2 / SCAN is not currently supported.")

elif self.dispersion == "D4":
d4_pars = {
"R2SCAN": {
"S6": 1.0,
"S8": 0.60187490,
"A1": 0.51559235,
"A2": 5.77342911,
},
"PBE": {
"S6": 1.0,
"S8": 0.95948085,
"A1": 0.38574991,
"A2": 4.80688534,
},
"PBESOL": {
"S6": 1.0,
"S8": 1.71885698,
"A1": 0.47901421,
"A2": 5.96771589,
},
}
config_updates = {f"VDW_{k}": v for k, v in d4_pars[xc_func].items()}

if len(config_updates) > 0:
self._config_dict["INCAR"].update(config_updates)

@staticmethod
def _sigmoid_interp(
bg, min_dk: float = 0.22, max_dk: float = 0.5, shape: float = 0.43, center: float = 4.15, fac: float = 12.0
):
delta = shape * (bg - center)
sigmoid = delta / (1.0 + delta**fac) ** (1.0 / fac)
return 0.5 * (min_dk + max_dk + (max_dk - min_dk) * sigmoid)

def _multi_sigmoid_interp(
self,
bandgap: float,
dks: tuple[float, ...] = (0.22, 0.44, 0.5),
shape: tuple[float, ...] = (1.1, 2.5),
center: tuple[float, ...] = (2.35, 6.1),
fac: tuple[float, ...] = (8, 8),
bg_cut: tuple[float, ...] = (4.5,),
):
for icut, cutpt in enumerate(bg_cut):
min_bd = self.bandgap_tol if (icut == 0) else cutpt
if min_bd <= bandgap < cutpt:
return self._sigmoid_interp(
bandgap,
min_dk=dks[icut],
max_dk=dks[icut + 1],
shape=shape[icut],
center=center[icut],
fac=fac[icut],
)
return None

@property
def kspacing_update(self):
return self._multi_sigmoid_interp(self.bandgap)


@dataclass
class MPMetalRelaxSet(VaspInputSet):
"""
Expand Down Expand Up @@ -1521,7 +1626,8 @@ def __post_init__(self) -> None:
)

if self.xc_functional.upper() == "R2SCAN":
self._config_dict["INCAR"].update({"METAGGA": "R2SCAN", "ALGO": "ALL", "GGA": None})
self._config_dict["INCAR"].update({"METAGGA": "R2SCAN", "ALGO": "ALL"})
self._config_dict["INCAR"].pop("GGA", None)
if self.xc_functional.upper().endswith("+U"):
self._config_dict["INCAR"]["LDAU"] = True

Expand Down Expand Up @@ -1551,6 +1657,7 @@ class MPScanStaticSet(MPScanRelaxSet):
def incar_updates(self) -> dict[str, Any]:
"""Updates to the INCAR config for this calculation type."""
updates: dict[str, Any] = {
"ALGO": "Fast",
"LREAL": False,
"NSW": 0,
"LORBIT": 11,
Expand All @@ -1570,6 +1677,46 @@ def incar_updates(self) -> dict[str, Any]:
return updates


@dataclass
class MP24StaticSet(MP24RelaxSet):
"""Create input files for a static calculation using MP24 parameters

Args:
structure (Structure): Structure from previous run.
bandgap (float): Bandgap of the structure in eV. The bandgap is used to
compute the appropriate k-point density and determine the smearing settings.
lepsilon (bool): Whether to add static dielectric calculation
lcalcpol (bool): Whether to turn on evaluation of the Berry phase approximations
for electronic polarization.
**kwargs: Keywords supported by MP24RelaxSet.
"""

lepsilon: bool = False
lcalcpol: bool = False
inherit_incar: bool = True
auto_kspacing: bool = True

@property
def incar_updates(self) -> dict[str, Any]:
"""Updates to the INCAR config for this calculation type."""
updates: dict[str, Any] = {
"NSW": 0,
"LORBIT": 11,
"ISMEAR": -5,
}

if self.lepsilon:
# LPEAD=T: numerical evaluation of overlap integral prevents
# LRF_COMMUTATOR errors and can lead to better expt. agreement
# but produces slightly different results
updates |= {"IBRION": 8, "LEPSILON": True, "LPEAD": True, "NSW": 1, "NPAR": None}

if self.lcalcpol:
updates["LCALCPOL"] = True

return updates


@dataclass
class MPHSEBSSet(VaspInputSet):
"""Implementation of a VaspInputSet for HSE band structure computations.
Expand Down
3 changes: 2 additions & 1 deletion tests/io/vasp/test_sets.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,14 @@ def test_sets_changed(self):
"MPHSERelaxSet.yaml": "1779cb6a6af43ad54a12aec22882b9b8aa3469b764e29ac4ab486960d067b811",
"VASPIncarBase.yaml": "8c1ce90d6697e45b650e1881e2b3d82a733dba17fb1bd73747a38261ec65a4c4",
"MPSCANRelaxSet.yaml": "ad652ea740d06f9edd979494f31e25074b82b9fffdaaf7eff2ae5541fb0e6288",
"PBE64Base.yaml": "3434c918c17706feae397d0852f2224e771db94d7e4c988039e8658e66d87494",
"PBE64Base.yaml": "40e7e42159f59543b17f512666916001045f7644f422ccc45b8466d6a1cf0c48",
"MPRelaxSet.yaml": "c9b0a519588fb3709509a9f9964632692584905e2961a0fe2e5f657561913083",
"MITRelaxSet.yaml": "0b4bec619fa860dac648584853c3b3d5407e4148a85d0e95024fbd1dc315669d",
"vdW_parameters.yaml": "7d2599a855533865335a313c043b6f89e03fc2633c88b6bc721723d94cc862bd",
"MatPESStaticSet.yaml": "4ec60ad4bbbb9a756f1b3fea8ca4eab8fc767d8f6a67332e7af3908c910fd7c5",
"MPAbsorptionSet.yaml": "e49cd0ab87864f1c244e9b5ceb4703243116ec1fbb8958a374ddff07f7a5625c",
"PBE54Base.yaml": "cdffe123eca8b19354554b60a7f8de9b8776caac9e1da2bd2a0516b7bfac8634",
"MP24RelaxSet.yaml": "62035d9a270504f852f59c886165da5f5fa35a59f4c309695aac7120ad7a18ac",
}

for input_set, hash_str in hashes.items():
Expand Down