Skip to content

Commit

Permalink
Merge pull request #317 from libAtoms/vasp_simplify
Browse files Browse the repository at this point in the history
simplify Vasp wrapper to minimize mangling to ASE Vasp calculator keywords
  • Loading branch information
bernstei authored Jun 14, 2024
2 parents 31204c5 + 45c77c4 commit 4c78d28
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 42 deletions.
2 changes: 1 addition & 1 deletion docs/source/overview.queued.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ cat<<EOF > 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}'}'" ]
}
Expand Down
95 changes: 74 additions & 21 deletions tests/calculators/test_vasp.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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):
Expand Down
2 changes: 1 addition & 1 deletion tests/local_scripts/complete_pytest.tin
Original file line number Diff line number Diff line change
Expand Up @@ -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/,//')
Expand Down
40 changes: 21 additions & 19 deletions wfl/calculators/vasp.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ class Vasp(WFLFileIOCalculator, ASE_Vasp):
Notes
-----
"directory" argument cannot be present. Use rundir_prefix and workdir instead.
"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 "<elem name>/POTCAR" files
Parameters
Expand All @@ -48,11 +52,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
"""
Expand All @@ -70,8 +71,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
Expand All @@ -91,16 +91,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)

Expand Down Expand Up @@ -132,11 +123,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:
Expand All @@ -145,7 +147,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

Expand Down

0 comments on commit 4c78d28

Please sign in to comment.