import numpy as np
import os
import warnings
from storq.tools import getstatusoutput
[docs]
class Runner:
def _get_runcmd(self):
"""Determine the appropriate run command for vasp.
Builds up a list of commands to run the appropriate vasp version
(std, ncl, gamma) with or without mpi. If mpi is used the number of
procs is determined automatically if the standard mpirun is used.
Returns
-------
list
A list of commands that can be passed to subprocess in order
to run vasp.
"""
conf = self.conf
site = self.siteconf
mpi_command = conf.get("mpi_command", None)
# determine the appropriate vasp version
kpts = self.parameters.get("kpts", None)
# kspacing = self.parameters.get("kspacing", None)
ncl = self.parameters.get("lnoncollinear", None)
if ncl:
if self.conf.get("vasp_executable_ncl", None):
executable = conf["vasp_executable_ncl"]
else:
raise RuntimeError(
(
"vasp_executable_ncl must be set in order"
"to run non-collinear calculations"
)
)
elif "size" in kpts and np.all(np.equal(kpts["size"], np.array([1, 1, 1]))):
if conf.get("vasp_executable_gam", None):
executable = conf["vasp_executable_gam"]
else:
executable = conf["vasp_executable_std"]
else:
executable = conf["vasp_executable_std"]
if mpi_command:
vasp_runcmd = [mpi_command]
mpi_options = conf.get("mpi_options", None)
# if mpi options are specified we check if they contain an accepted
# proc count flag else determine the count automatically
if mpi_options is None:
mpi_options = ""
mpi_options_split = mpi_options.split()
vasp_runcmd += [option for option in mpi_options_split]
mpi_proc_flags = ["-n", "-np"]
# add automatic core counting only if needed
if (
conf.get("mpi_count_cores", False)
and site["env"]["nodelist"] in os.environ
):
if set(mpi_proc_flags).isdisjoint(set(mpi_options_split)):
vasp_runcmd += ["-n", str(self.get_ntasks())]
vasp_runcmd += [executable]
else: # no MPI and running at cl
vasp_runcmd = [executable]
return vasp_runcmd
def _run(self):
"""
If this is called, then the calculator thinks a job should be run.
If we are in the queue, we should run it, otherwise, a job should
be submitted.
"""
conf = self.conf
site = self.siteconf
cwd = os.getcwd()
self.write_input()
self.write_persistence_db(self.atoms)
if conf["vasp_mode"] == "run" or (
site and site["env"]["submitdir"] in os.environ
):
# we get the run command and run vasp here
os.chdir(self.directory)
vasp_runcmd = self._get_runcmd()
if conf.get("vasp_stdout", "vasp.out"):
with open(conf["vasp_stdout"], "wb") as fout:
retcode = getstatusoutput(vasp_runcmd, stdout=fout, stderr=fout)
# state will be changed after running so we must update it
self.state = self.get_state()
if self.state == self.UNCONVERGED:
warnings.warn(
"{0}: Calculation is not converged".format(self.directory),
UserWarning,
)
elif self.state == self.UNFINISHED:
warnings.warn(
"{0}: Vasp did not finish".format(self.directory), UserWarning
)
self.read_results()
os.chdir(cwd)
return retcode
# if we are in queue vasp_mode we should submit a job
elif conf["vasp_mode"] == "queue":
file_args = "{} {}".format(cwd, self.directory)
self.submit("runvasp.py", file_args)