From a0021a9945328a931f907e7a5cf3e9708c3895d2 Mon Sep 17 00:00:00 2001 From: Noam Bernstein Date: Tue, 11 Jun 2024 09:50:47 -0400 Subject: [PATCH 1/3] simplify Vasp wrapper to minimize mangling to ASE Vasp calculator keywords --- complete_pytest.tin | 2 +- tests/calculators/test_vasp.py | 95 ++++++++++++++++++++++++++-------- wfl/calculators/vasp.py | 37 +++++++------ 3 files changed, 93 insertions(+), 41 deletions(-) diff --git a/complete_pytest.tin b/complete_pytest.tin index 2d9274e3..7bd2b0da 100755 --- a/complete_pytest.tin +++ b/complete_pytest.tin @@ -65,7 +65,7 @@ l=`egrep '^=.*(passed|failed|skipped|xfailed)' complete_pytest.tin.out` echo "summary line $l" lp=$( echo $l | sed -E -e 's/ in .*//' -e 's/\s*,\s*/\n/g' ) -declare -A expected_n=( ["passed"]="175" ["skipped"]="21" ["warnings"]=823 ["xfailed"]=2 ["xpassed"]=1 ) +declare -A expected_n=( ["passed"]="176" ["skipped"]="21" ["warnings"]=823 ["xfailed"]=2 ["xpassed"]=1 ) IFS=$'\n' for out in $lp; do out_n=$(echo $out | sed -e 's/^=* //' -e 's/ .*//' -e 's/,//') diff --git a/tests/calculators/test_vasp.py b/tests/calculators/test_vasp.py index bfe45424..3be3485e 100644 --- a/tests/calculators/test_vasp.py +++ b/tests/calculators/test_vasp.py @@ -31,21 +31,20 @@ def test_vasp_gamma(tmp_path, monkeypatch): output_prefix='TEST_', ) - run_dir = list(tmp_path.glob('run_VASP_*')) - nfiles = len(list(os.scandir(run_dir[0]))) + for run_dir in tmp_path.glob('run_VASP_*'): + nfiles = len(list(os.scandir(run_dir))) - assert nfiles == 18 + assert nfiles == 18 - ats = list(configs_eval) - assert 'TEST_energy' in ats[0].info - assert 'TEST_forces' in ats[0].arrays - # ase.io.write(sys.stdout, list(configs_eval), format='extxyz') - with open(Path(run_dir[0]) / "OUTCAR") as fin: - l = fin.readline() - assert "gamma-only" in l + ats = list(configs_eval) + assert 'TEST_energy' in ats[0].info + assert 'TEST_forces' in ats[0].arrays + # ase.io.write(sys.stdout, list(configs_eval), format='extxyz') + with open(Path(run_dir) / "OUTCAR") as fin: + l = fin.readline() + assert "gamma-only" in l # try with command_gamma - command_gamma = os.environ["ASE_VASP_COMMAND_GAMMA"] for cmd in Vasp.env_commands: monkeypatch.delenv(cmd + "_GAMMA", raising=False) @@ -57,18 +56,72 @@ def test_vasp_gamma(tmp_path, monkeypatch): output_prefix='TEST_', ) - run_dir = list(tmp_path.glob('run_VASP_*')) - nfiles = len(list(os.scandir(run_dir[0]))) + for run_dir in tmp_path.glob('run_VASP_*'): + nfiles = len(list(os.scandir(run_dir))) - assert nfiles == 18 + assert nfiles == 18 - ats = list(configs_eval) - assert 'TEST_energy' in ats[0].info - assert 'TEST_forces' in ats[0].arrays - # ase.io.write(sys.stdout, list(configs_eval), format='extxyz') - with open(Path(run_dir[0]) / "OUTCAR") as fin: - l = fin.readline() - assert "gamma-only" in l + ats = list(configs_eval) + assert 'TEST_energy' in ats[0].info + assert 'TEST_forces' in ats[0].arrays + # ase.io.write(sys.stdout, list(configs_eval), format='extxyz') + with open(Path(run_dir) / "OUTCAR") as fin: + l = fin.readline() + assert "gamma-only" in l + + +def test_vasp_gamma_auto(tmp_path): + ase.io.write(tmp_path / 'vasp_in.xyz', Atoms('Si', cell=(6, 2, 2), pbc=[True] * 3), format='extxyz') + + # try with not large enough kspacing + configs_eval = generic.calculate( + inputs=ConfigSet(tmp_path / 'vasp_in.xyz'), + outputs=OutputSpec('vasp_out.auto_gamma_no.xyz', file_root=tmp_path), + calculator=Vasp(workdir=tmp_path, encut=200, pp=os.environ['PYTEST_VASP_POTCAR_DIR'], + keep_files=True, kspacing=2), + output_prefix='TEST_', + ) + + for run_dir in tmp_path.glob('run_VASP_*'): + nfiles = len(list(os.scandir(run_dir))) + + assert nfiles == 18 + + for at in configs_eval: + assert 'TEST_energy' in at.info + assert 'TEST_forces' in at.arrays + # ase.io.write(sys.stdout, list(configs_eval), format='extxyz') + with open(Path(run_dir) / "OUTCAR") as fin: + l = fin.readline() + assert "gamma-only" not in l + + print("BOB clean non-gamma", run_dir) + shutil.rmtree(run_dir) + + # try with large enough kspacing + configs_eval = generic.calculate( + inputs=ConfigSet(tmp_path / 'vasp_in.xyz'), + outputs=OutputSpec('vasp_out.auto_gamma_yes.xyz', file_root=tmp_path), + calculator=Vasp(workdir=tmp_path, encut=200, pp=os.environ['PYTEST_VASP_POTCAR_DIR'], + keep_files=True, kspacing=4), + output_prefix='TEST_', + ) + + for run_dir in tmp_path.glob('run_VASP_*'): + nfiles = len(list(os.scandir(run_dir))) + + assert nfiles == 18 + + for at in configs_eval: + assert 'TEST_energy' in at.info + assert 'TEST_forces' in at.arrays + # ase.io.write(sys.stdout, list(configs_eval), format='extxyz') + with open(Path(run_dir) / "OUTCAR") as fin: + l = fin.readline() + assert "gamma-only" in l + + print("BOB clean gamma", run_dir) + shutil.rmtree(run_dir) def test_vasp(tmp_path): diff --git a/wfl/calculators/vasp.py b/wfl/calculators/vasp.py index 20c896f3..a9c4dbd5 100644 --- a/wfl/calculators/vasp.py +++ b/wfl/calculators/vasp.py @@ -31,6 +31,7 @@ class Vasp(WFLFileIOCalculator, ASE_Vasp): Notes ----- "directory" argument cannot be present. Use rundir_prefix and workdir instead. + "command_gamma" is used when non-periodic cells or large enough kspacing are detected "pp" defaults to ".", so VASP_PP_PATH env var is absolute path to "/POTCAR" files Parameters @@ -48,11 +49,8 @@ class Vasp(WFLFileIOCalculator, ASE_Vasp): scratchdir: str / Path, default None temporary directory to execute calculations in and delete or copy back results (set by "keep_files") if needed. For example, directory on a local disk with fast file I/O. - calculator_exec: str - executable to run (without ASE-specific command line arguments). Mutually exclusive with ASE-built-in "command" - calculator_exec_gamma: str - executable to run for nonperiodic systems (overrides ASE_VASP_COMMAND_GAMMA, VASP_COMMAND_GAMMA, VASP_SCRIPT_GAMMA). - Mutually exclusive with ASE-built-in "command" and "command_gamma" + command_gamma: str, default None + command to use when gamma-only calculations are detected (e.g. large kspacing, or pbc=False) **kwargs: arguments for ase.calculators.vasp.vasp.Vasp remaining arguments to ASE's Vasp calculator constructor """ @@ -70,8 +68,7 @@ class Vasp(WFLFileIOCalculator, ASE_Vasp): }) def __init__(self, keep_files="default", rundir_prefix="run_VASP_", - workdir=None, scratchdir=None, - calculator_exec=None, calculator_exec_gamma=None, + workdir=None, scratchdir=None, command_gamma=None, **kwargs): # get initialparams from env var @@ -91,16 +88,7 @@ def __init__(self, keep_files="default", rundir_prefix="run_VASP_", if "pp" not in kwargs_use: kwargs_use["pp"] = "." - if calculator_exec is not None: - if "command" in kwargs_use or "command_gamma" in kwargs_use: - raise ValueError("Cannot specify both calculator_exec and command or command_gamma") - self.command = calculator_exec - if calculator_exec_gamma is not None: - if "command" in kwargs_use or "command_gamma" in kwargs_use: - raise ValueError("Cannot specify both calculator_exec_gamma and command or command_gamma") - self._command_gamma = calculator_exec_gamma - else: - self._command_gamma = kwargs_use.pop("command_gamma", None) + self._command_gamma = command_gamma self.universal_kspacing = kwargs_use.pop("universal_kspacing", None) @@ -132,11 +120,22 @@ def per_config_setup(self, atoms): self._orig_command = self.command self._orig_kspacing = self.float_params["kspacing"] self._orig_kgamma = self.bool_params["kgamma"] - if np.all(~self._orig_pbc): + use_gamma_exec = np.all(~self._orig_pbc) + # gamma centered if kgamma is undefined (default) or True + if self._orig_kgamma is None or self._orig_kgamma: + try: + n_k = np.maximum(1, np.ceil(np.linalg.norm(atoms.cell.reciprocal(), axis=1) * 2.0 * np.pi / self._orig_kspacing)) + use_gamma_exec |= np.all(n_k == 1) + except TypeError: + pass + + if use_gamma_exec: # set command if self._command_gamma is not None: + # from constructor argument that was saved command_gamma = self._command_gamma else: + # from env var command_gamma = None for env_var in self.env_commands: if env_var + "_GAMMA" in os.environ: @@ -145,7 +144,7 @@ def per_config_setup(self, atoms): if command_gamma is not None: self.command = command_gamma - # set k-points for nonperiodic systems + # explicitly set k-points for nonperiodic systems self.float_params["kspacing"] = 1.0e8 self.bool_params["kgamma"] = True From a78e5a6161d585f5480ecc710d5c5e91285ceb8f Mon Sep 17 00:00:00 2001 From: Noam Bernstein Date: Fri, 14 Jun 2024 10:04:25 -0400 Subject: [PATCH 2/3] Mentioned ASE_VASP_COMMAND_GAMMA in Vasp calculator docstring --- wfl/calculators/vasp.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/wfl/calculators/vasp.py b/wfl/calculators/vasp.py index a9c4dbd5..88c21018 100644 --- a/wfl/calculators/vasp.py +++ b/wfl/calculators/vasp.py @@ -31,7 +31,10 @@ class Vasp(WFLFileIOCalculator, ASE_Vasp): Notes ----- "directory" argument cannot be present. Use rundir_prefix and workdir instead. - "command_gamma" is used when non-periodic cells or large enough kspacing are detected + + "command_gamma" (or ASE_VASP_COMMAND_GAMMA) is used when non-periodic cells or large + enough kspacing are detected + "pp" defaults to ".", so VASP_PP_PATH env var is absolute path to "/POTCAR" files Parameters From 45c77c4955ba1fb6e331d83b71c48a8fdd7dea14 Mon Sep 17 00:00:00 2001 From: Noam Bernstein Date: Fri, 14 Jun 2024 12:04:35 -0400 Subject: [PATCH 3/3] Replace VASP_COMMAND with ASE_VASP_COMMAND in docs overview of queued jobs --- docs/source/overview.queued.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/overview.queued.md b/docs/source/overview.queued.md index 6c16b354..6b01f2e3 100644 --- a/docs/source/overview.queued.md +++ b/docs/source/overview.queued.md @@ -70,7 +70,7 @@ cat< remoteinfo.json "resources": { "num_nodes" : 1, "max_time": "24h" }, "num_inputs_per_queued_job" : 1, "input_files": ["POTCARs"], - "env_vars": ["VASP_COMMAND=${vasp_path}", "VASP_PP_PATH=POTCARs", + "env_vars": ["ASE_VASP_COMMAND=${vasp_path}", "VASP_PP_PATH=POTCARs", "WFL_NUM_PYTHON_SUBPROCESSES=\${EXPYRE_NCORES_PER_NODE}", "WFL_VASP_KWARGS='{ \"ncore\": '\${EXPYRE_NCORES_PER_NODE}'}'" ] }