Skip to content

Commit 5a1a9d2

Browse files
SophiaRuanpre-commit-ci[bot]janoshshyuep
authored
Add VASP input set MatPESStaticSet (#3254)
* add MatPESStaticSet to sets.py * pre-commit auto-fixes * add MatPESStaticSet type hints * simplify to Incar(self.prev_incar or parent_incar) prev: incar = Incar(self.prev_incar) if self.prev_incar is not None else Incar(parent_incar) * handle functional="PBE" with no U correctly * fix MatPESStaticSet.incar() not returning anything * add return type hint def incar(self) -> Incar: same for def kpoint() * change formats * add pymatgen/io/vasp/PBE54Base.yaml * add pymatgen/io/vasp/PBE54Base.yaml * pre-commit auto-fixes * change Normal=All for R2SCAN * add PARENT to MatPESStaticSet PBE54Base * add test for MatPESStaticSet, fix typo in sets.py * remove setup() in TestMatPESStaticSet, remove unnecessary incar key checks --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> Co-authored-by: Janosh Riebesell <[email protected]> Co-authored-by: Shyue Ping Ong <[email protected]>
1 parent d027466 commit 5a1a9d2

File tree

4 files changed

+247
-14
lines changed

4 files changed

+247
-14
lines changed
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# Default VASP settings for static calculations in the MatPES Project
2+
# using the Regularized-Restored Strongly Constrained and Appropriately
3+
# Normed functional (default PBE, PBE+U or R2SCAN or R2SCAN+U).
4+
PARENT: PBE54Base
5+
INCAR:
6+
ALGO: Normal # Normal for PBE, ALL for R2SCAN, included to have some reasonable default
7+
EDIFF: 1.e-05
8+
ENAUG: 1360
9+
ENCUT: 680
10+
ISMEAR: 0 # change from 2 to 0, included to have some reasonable default
11+
ISPIN: 2
12+
KSPACING: 0.22 # included to have some reasonable default
13+
LAECHG: True
14+
LASPH: True
15+
LCHARG: True
16+
LELF: False # LELF = True restricts calculation to KPAR = 1
17+
LMIXTAU: True
18+
LORBIT: 11
19+
LREAL: Auto
20+
LVTOT: True
21+
LWAVE: False
22+
GGA: PE # change R2SCAN to PBE as default
23+
NELM: 200
24+
NSW: 0 # static calculation
25+
PREC: Accurate
26+
SIGMA: 0.05 # change from 0.02 to 0.05, included to have some reasonable default

pymatgen/io/vasp/PBE54Base.yaml

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
# POTCARs for PBE_54
2+
PARENT: VASPIncarBase
3+
POTCAR_FUNCTIONAL: PBE_54
4+
POTCAR:
5+
Ac: Ac
6+
Ag: Ag
7+
Al: Al
8+
Am: Am
9+
Ar: Ar
10+
As: As
11+
At: At
12+
Au: Au
13+
B: B
14+
Ba: Ba_sv
15+
Be: Be_sv
16+
Bi: Bi
17+
Br: Br
18+
C: C
19+
Ca: Ca_sv
20+
Cd: Cd
21+
Ce: Ce
22+
Cf: Cf
23+
Cl: Cl
24+
Cm: Cm
25+
Co: Co
26+
Cr: Cr_pv
27+
Cs: Cs_sv
28+
Cu: Cu_pv
29+
Dy: Dy_3
30+
Er: Er_3
31+
Eu: Eu
32+
F: F
33+
Fe: Fe_pv
34+
Fr: Fr_sv
35+
Ga: Ga_d
36+
Gd: Gd
37+
Ge: Ge_d
38+
H: H
39+
He: He
40+
Hf: Hf_pv
41+
Hg: Hg
42+
Ho: Ho_3
43+
I: I
44+
In: In_d
45+
Ir: Ir
46+
K: K_sv
47+
Kr: Kr
48+
La: La
49+
Li: Li_sv
50+
Lu: Lu_3
51+
Mg: Mg_pv
52+
Mn: Mn_pv
53+
Mo: Mo_pv
54+
N: N
55+
Na: Na_pv
56+
Nb: Nb_pv
57+
Nd: Nd_3
58+
Ne: Ne
59+
Ni: Ni_pv
60+
Np: Np
61+
O: O
62+
Os: Os_pv
63+
P: P
64+
Pa: Pa
65+
Pb: Pb_d
66+
Pd: Pd
67+
Pm: Pm_3
68+
Po: Po_d
69+
Pr: Pr_3
70+
Pt: Pt
71+
Pu: Pu
72+
Ra: Ra_sv
73+
Rb: Rb_sv
74+
Re: Re_pv
75+
Rh: Rh_pv
76+
Rn: Rn
77+
Ru: Ru_pv
78+
S: S
79+
Sb: Sb
80+
Sc: Sc_sv
81+
Se: Se
82+
Si: Si
83+
Sm: Sm_3
84+
Sn: Sn_d
85+
Sr: Sr_sv
86+
Ta: Ta_pv
87+
Tb: Tb_3
88+
Tc: Tc_pv
89+
Te: Te
90+
Th: Th
91+
Ti: Ti_pv
92+
Tl: Tl_d
93+
Tm: Tm_3
94+
U: U
95+
V: V_pv
96+
W: W_sv
97+
Xe: Xe
98+
Y: Y_sv
99+
# 2023-05-02: change Yb_2 to Yb_3 as Yb_2 gives incorrect thermodynamics for most systems with Yb3+
100+
# https://github.com/materialsproject/pymatgen/issues/2968
101+
Yb: Yb_3
102+
Zn: Zn
103+
Zr: Zr_sv

pymatgen/io/vasp/sets.py

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,10 +1084,10 @@ def __init__(
10841084
self.small_gap_multiply = small_gap_multiply
10851085

10861086
@property
1087-
def incar(self):
1087+
def incar(self) -> Incar:
10881088
"""Incar"""
10891089
parent_incar = super().incar
1090-
incar = Incar(self.prev_incar) if self.prev_incar is not None else Incar(parent_incar)
1090+
incar = Incar(self.prev_incar or parent_incar)
10911091

10921092
incar.update(
10931093
{
@@ -1215,6 +1215,43 @@ def from_prev_calc(cls, prev_calc_dir, **kwargs):
12151215
return input_set.override_from_prev_calc(prev_calc_dir=prev_calc_dir)
12161216

12171217

1218+
class MatPESStaticSet(MPStaticSet):
1219+
"""Creates input files for a MatPES static calculation."""
1220+
1221+
CONFIG = _load_yaml_config("MatPESStaticSet")
1222+
1223+
def __init__(
1224+
self,
1225+
structure: str,
1226+
functional: Literal["R2SCAN", "R2SCAN+U", "PBE", "PBE+U"] = "PBE",
1227+
**kwargs: Any,
1228+
) -> None:
1229+
"""
1230+
Args:
1231+
structure (Structure): Structure from previous run.
1232+
functional ('R2SCAN' | 'R2SCAN+U' | 'PBE' | 'PBE+U'): Which functional to use and whether to include
1233+
Hubbard U corrections. Defaults to 'PBE'.
1234+
**kwargs: Passed to MPStaticSet.
1235+
"""
1236+
super().__init__(structure, MatPESStaticSet.CONFIG, **kwargs)
1237+
if functional.startswith("R2SCAN"):
1238+
self.user_incar_settings.setdefault("METAGGA", "R2SCAN")
1239+
self.user_incar_settings.setdefault("ALGO", "ALL")
1240+
if functional.startswith("PBE"):
1241+
self.user_incar_settings.setdefault("GGA", "PE")
1242+
if functional.endswith("+U"):
1243+
self.user_incar_settings.setdefault("LDAU", True)
1244+
1245+
self.kwargs = kwargs
1246+
self.functional = functional
1247+
1248+
@property
1249+
def incar(self) -> Incar:
1250+
"""Incar"""
1251+
parent_incar = super().incar
1252+
return Incar(self.prev_incar or parent_incar)
1253+
1254+
12181255
class MPScanStaticSet(MPScanRelaxSet):
12191256
"""
12201257
Creates input files for a static calculation using the accurate and numerically
@@ -1245,10 +1282,10 @@ def __init__(self, structure: Structure, bandgap=0, prev_incar=None, lepsilon=Fa
12451282
self.lcalcpol = lcalcpol
12461283

12471284
@property
1248-
def incar(self):
1285+
def incar(self) -> Incar:
12491286
"""Incar"""
12501287
parent_incar = super().incar
1251-
incar = Incar(self.prev_incar) if self.prev_incar is not None else Incar(parent_incar)
1288+
incar = Incar(self.prev_incar or parent_incar)
12521289

12531290
incar.update({"LREAL": False, "NSW": 0, "LORBIT": 11, "LVHAR": True, "ISMEAR": -5})
12541291

@@ -1892,7 +1929,7 @@ def __init__(
18921929
super().__init__(structure, prev_incar=prev_incar, reciprocal_density=reciprocal_density, **kwargs)
18931930

18941931
@property
1895-
def incar(self):
1932+
def incar(self) -> Incar:
18961933
"""Incar"""
18971934
incar = super().incar
18981935

@@ -2037,18 +2074,18 @@ def __init__(
20372074
self.ncores = ncores
20382075

20392076
@property
2040-
def kpoints(self):
2077+
def kpoints(self) -> Kpoints:
20412078
"""
20422079
Generate gamma center k-points mesh grid for GW calc,
20432080
which is requested by GW calculation.
20442081
"""
20452082
return Kpoints.automatic_density_by_vol(self.structure, self.reciprocal_density, force_gamma=True)
20462083

20472084
@property
2048-
def incar(self):
2085+
def incar(self) -> Incar:
20492086
"""Incar"""
20502087
parent_incar = super().incar
2051-
incar = Incar(self.prev_incar) if self.prev_incar is not None else Incar(parent_incar)
2088+
incar = Incar(self.prev_incar or parent_incar)
20522089

20532090
if self.mode == "DIAG":
20542091
# Default parameters for diagonalization calculation.
@@ -2303,7 +2340,7 @@ def kpoints(self):
23032340
return kpt
23042341

23052342
@property
2306-
def incar(self):
2343+
def incar(self) -> Incar:
23072344
"""Incar"""
23082345
incar = super().incar
23092346

@@ -2531,7 +2568,7 @@ def __init__(self, structure: Structure, start_temp, end_temp, nsteps, time_step
25312568
self._config_dict["INCAR"].update(defaults)
25322569

25332570
@property
2534-
def kpoints(self):
2571+
def kpoints(self) -> Kpoints:
25352572
"""Kpoints"""
25362573
return Kpoints.gamma_automatic()
25372574

@@ -2613,7 +2650,7 @@ def __init__(self, structure: Structure, start_temp, end_temp, nsteps, spin_pola
26132650
self._config_dict["INCAR"].update(defaults)
26142651

26152652
@property
2616-
def kpoints(self):
2653+
def kpoints(self) -> Kpoints:
26172654
"""Kpoints"""
26182655
return Kpoints.gamma_automatic()
26192656

@@ -3106,15 +3143,15 @@ def __init__(
31063143
self.kwargs = kwargs
31073144

31083145
@property
3109-
def kpoints(self):
3146+
def kpoints(self) -> Kpoints:
31103147
"""
31113148
Generate gamma center k-points mesh grid for optical calculation. It is not mandatory for 'ALGO = Exact',
31123149
but is requested by 'ALGO = CHI' calculation.
31133150
"""
31143151
return Kpoints.automatic_density_by_vol(self.structure, self.reciprocal_density, force_gamma=True)
31153152

31163153
@property
3117-
def incar(self):
3154+
def incar(self) -> Incar:
31183155
"""Incar"""
31193156
parent_incar = super().incar
31203157
absorption_incar = {
@@ -3147,7 +3184,7 @@ def incar(self):
31473184
elif self.mode == "RPA":
31483185
# Default parameters for the response function calculation. NELM has to be set to 1.
31493186
# NOMEGA is set to 1000 in order to get smooth spectrum
3150-
incar = Incar(self.prev_incar) if self.prev_incar is not None else Incar(parent_incar)
3187+
incar = Incar(self.prev_incar or parent_incar)
31513188
incar.update({"ALGO": "CHI", "NELM": 1, "NOMEGA": 1000})
31523189

31533190
if self.nkred is not None:

tests/io/vasp/test_sets.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
BadInputSetWarning,
2626
DictSet,
2727
LobsterSet,
28+
MatPESStaticSet,
2829
MITMDSet,
2930
MITNEBSet,
3031
MITRelaxSet,
@@ -47,6 +48,7 @@
4748
MVLScanRelaxSet,
4849
MVLSlabSet,
4950
VaspInputSet,
51+
_load_yaml_config,
5052
batch_write_input,
5153
get_structure_from_prev_run,
5254
get_valid_magmom_struct,
@@ -743,6 +745,71 @@ def test_grid_size_from_struct(self):
743745
assert matched
744746

745747

748+
class TestMatPESStaticSet(PymatgenTest):
749+
def test_init(self):
750+
prev_run = f"{TEST_FILES_DIR}/relaxation"
751+
752+
vis = MatPESStaticSet.from_prev_calc(prev_calc_dir=prev_run)
753+
# Check that INCAR settings were load from yaml, check the default functional is PBE.
754+
CONFIG = _load_yaml_config("MatPESStaticSet")
755+
assert vis.incar == CONFIG["INCAR"]
756+
assert vis.kpoints.style == Kpoints.supported_modes.Monkhorst
757+
758+
# Check as from dict.
759+
vis = MatPESStaticSet.from_dict(vis.as_dict())
760+
# Check that INCAR settings were load from yaml.
761+
assert vis.incar == CONFIG["INCAR"]
762+
763+
prev_run_scan = f"{TEST_FILES_DIR}/scan_relaxation"
764+
765+
vis_scan = MatPESStaticSet.from_prev_calc(prev_calc_dir=prev_run_scan, functional="R2SCAN")
766+
# Check that INCAR settings were load from yaml, check the functional "R2SCAN".
767+
assert vis_scan.incar["METAGGA"] == "R2SCAN"
768+
assert vis_scan.incar["ALGO"] == "ALL"
769+
770+
# Check as from dict.
771+
vis_scan = MatPESStaticSet.from_dict(vis_scan.as_dict())
772+
# Check that INCAR settings were load from yaml.
773+
assert vis_scan.incar["METAGGA"] == "R2SCAN"
774+
assert vis_scan.incar["ALGO"] == "ALL"
775+
776+
# test with changed user_incar_settings
777+
non_prev_vis = MatPESStaticSet(vis.structure, user_incar_settings={"ENCUT": 800, "LORBIT": 12, "LWAVE": True})
778+
# Check that the ENCUT and Kpoints style has NOT been inherited.
779+
assert non_prev_vis.incar["ENCUT"] == 800
780+
# Check that user incar settings are applied.
781+
assert non_prev_vis.incar["LORBIT"] == 12
782+
assert non_prev_vis.incar["LWAVE"]
783+
784+
non_prev_vis = MatPESStaticSet.from_dict(non_prev_vis.as_dict())
785+
assert non_prev_vis.incar["ENCUT"] == 800
786+
# Check that user incar settings are applied.
787+
assert non_prev_vis.incar["LORBIT"] == 12
788+
assert non_prev_vis.incar["LWAVE"]
789+
790+
# test R2SCAN with changed user_incar_settings
791+
non_prev_vis_scan = MatPESStaticSet(
792+
vis_scan.structure, functional="R2SCAN", user_incar_settings={"ENCUT": 800, "LORBIT": 12, "LWAVE": True}
793+
)
794+
# Check functional has been changed to R2SCAN
795+
assert vis_scan.incar["METAGGA"] == "R2SCAN"
796+
assert vis_scan.incar["ALGO"] == "ALL"
797+
# Check that the ENCUT and Kpoints style has NOT been inherited.
798+
assert non_prev_vis_scan.incar["ENCUT"] == 800
799+
# Check that user incar settings are applied.
800+
assert non_prev_vis_scan.incar["LORBIT"] == 12
801+
assert non_prev_vis_scan.incar["LWAVE"]
802+
803+
non_prev_vis_scan = MatPESStaticSet.from_dict(non_prev_vis_scan.as_dict())
804+
# Check functional has been changed to R2SCAN
805+
assert vis_scan.incar["METAGGA"] == "R2SCAN"
806+
assert vis_scan.incar["ALGO"] == "ALL"
807+
assert non_prev_vis_scan.incar["ENCUT"] == 800
808+
# Check that user incar settings are applied.
809+
assert non_prev_vis_scan.incar["LORBIT"] == 12
810+
assert non_prev_vis_scan.incar["LWAVE"]
811+
812+
746813
class TestMPNonSCFSet(PymatgenTest):
747814
def setUp(self):
748815
self.set = MPNonSCFSet

0 commit comments

Comments
 (0)