From ea58ff89ca2299c762eecd870dc96178e0ce1931 Mon Sep 17 00:00:00 2001 From: hongyi-zhao Date: Thu, 22 Aug 2024 02:55:37 +0800 Subject: [PATCH] Add HSE-specific vdW parameters for dftd3 and dftd3-bj to MPHSERelaxSet. (#3955) * Add HSE-specific vdW parameters for dftd3 and dftd3-bj to MPHSERelaxSet. * pre-commit auto-fixes --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- src/pymatgen/io/vasp/sets.py | 22 +++++++++++- tests/io/vasp/test_sets.py | 68 ++++++++++++++++++++++++++++++++++++ 2 files changed, 89 insertions(+), 1 deletion(-) diff --git a/src/pymatgen/io/vasp/sets.py b/src/pymatgen/io/vasp/sets.py index dbd1e42d0bb..d238e4881ef 100644 --- a/src/pymatgen/io/vasp/sets.py +++ b/src/pymatgen/io/vasp/sets.py @@ -1357,9 +1357,29 @@ def kpoints_updates(self) -> dict: @dataclass class MPHSERelaxSet(VaspInputSet): - """Same as the MPRelaxSet, but with HSE parameters.""" + """Same as the MPRelaxSet, but with HSE parameters and vdW corrections.""" CONFIG = _load_yaml_config("MPHSERelaxSet") + vdw: Literal["dftd3", "dftd3-bj"] | None = None + + def __post_init__(self) -> None: + super().__post_init__() + self._config_dict["INCAR"]["LASPH"] = True + + @property + def incar_updates(self) -> dict[str, Any]: + """Updates to the INCAR config for this calculation type.""" + updates: dict[str, Any] = {} + + if self.vdw: + hse_vdw_par = { + "dftd3": {"VDW_SR": 1.129, "VDW_S8": 0.109}, + "dftd3-bj": {"VDW_A1": 0.383, "VDW_S8": 2.310, "VDW_A2": 5.685}, + } + if vdw_param := hse_vdw_par.get(self.vdw): + updates.update(vdw_param) + + return updates @dataclass diff --git a/tests/io/vasp/test_sets.py b/tests/io/vasp/test_sets.py index a912d1a489c..051d1ba59fd 100644 --- a/tests/io/vasp/test_sets.py +++ b/tests/io/vasp/test_sets.py @@ -2,6 +2,7 @@ import hashlib import os +import unittest from glob import glob from zipfile import ZipFile @@ -1524,6 +1525,73 @@ def test_bse(self): assert mvlgwgbse1.incar["ALGO"] == "Bse" +class TestMPHSERelaxSet(PymatgenTest): + def setUp(self): + self.structure = dummy_structure + self.set = MPHSERelaxSet + + def test_vdw_and_lasph_none(self): + vis = self.set(self.structure, vdw=None) + assert vis.incar["LASPH"], "LASPH is not set to True" + vdw_keys = {"VDW_SR", "VDW_S8", "VDW_A1", "VDW_A2"} + assert all(key not in vis.incar for key in vdw_keys), "Unexpected vdW parameters are set" + + def test_vdw_and_lasph_dftd3(self): + vis = self.set(self.structure, vdw="dftd3") + assert vis.incar["LASPH"], "LASPH is not set to True" + assert vis.incar["VDW_SR"] == pytest.approx(1.129), "VDW_SR is not set correctly" + assert vis.incar["VDW_S8"] == pytest.approx(0.109), "VDW_S8 is not set correctly" + + def test_vdw_and_lasph_dftd3_bj(self): + vis = self.set(self.structure, vdw="dftd3-bj") + assert vis.incar["LASPH"], "LASPH is not set to True" + assert vis.incar["VDW_A1"] == pytest.approx(0.383), "VDW_A1 is not set correctly" + assert vis.incar["VDW_S8"] == pytest.approx(2.310), "VDW_S8 is not set correctly" + assert vis.incar["VDW_A2"] == pytest.approx(5.685), "VDW_A2 is not set correctly" + + def test_user_incar_settings(self): + user_incar_settings = {"LASPH": False, "VDW_SR": 1.5} + vis = self.set(self.structure, vdw="dftd3", user_incar_settings=user_incar_settings) + assert not vis.incar["LASPH"], "LASPH user setting not applied" + assert vis.incar["VDW_SR"] == 1.5, "VDW_SR user setting not applied" + + @unittest.skipIf(not os.path.exists(TEST_DIR), "Test files are not present.") + def test_from_prev_calc(self): + prev_run = os.path.join(TEST_DIR, "fixtures", "relaxation") + + # Test for dftd3 + vis_d3 = self.set.from_prev_calc(prev_calc_dir=prev_run, vdw="dftd3") + assert vis_d3.incar["LASPH"] + assert "VDW_SR" in vis_d3.incar + assert "VDW_S8" in vis_d3.incar + + # Test for dftd3-bj + vis_bj = self.set.from_prev_calc(prev_calc_dir=prev_run, vdw="dftd3-bj") + assert vis_bj.incar["LASPH"] + assert "VDW_A1" in vis_bj.incar + assert "VDW_A2" in vis_bj.incar + assert "VDW_S8" in vis_bj.incar + + @unittest.skipIf(not os.path.exists(TEST_DIR), "Test files are not present.") + def test_override_from_prev_calc(self): + prev_run = os.path.join(TEST_DIR, "fixtures", "relaxation") + + # Test for dftd3 + vis_d3 = self.set(self.structure, vdw="dftd3") + vis_d3 = vis_d3.override_from_prev_calc(prev_calc_dir=prev_run) + assert vis_d3.incar["LASPH"] + assert "VDW_SR" in vis_d3.incar + assert "VDW_S8" in vis_d3.incar + + # Test for dftd3-bj + vis_bj = self.set(self.structure, vdw="dftd3-bj") + vis_bj = vis_bj.override_from_prev_calc(prev_calc_dir=prev_run) + assert vis_bj.incar["LASPH"] + assert "VDW_A1" in vis_bj.incar + assert "VDW_A2" in vis_bj.incar + assert "VDW_S8" in vis_bj.incar + + class TestMPHSEBS(PymatgenTest): def setUp(self): self.set = MPHSEBSSet