Skip to content

Commit

Permalink
Merge pull request #290 from SCM-NV/cp2k_version
Browse files Browse the repository at this point in the history
MAINT: Do not extract the CP2K version via `cp2k.popt --version`
  • Loading branch information
BvB93 committed Feb 17, 2022
2 parents a7391c2 + d3e9bc8 commit 47f3df0
Show file tree
Hide file tree
Showing 3 changed files with 17 additions and 96 deletions.
58 changes: 16 additions & 42 deletions src/qmflows/parsers/cp2KParser.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

__all__ = ['readCp2KBasis', 'read_cp2k_coefficients', 'get_cp2k_freq',
'read_cp2k_number_of_orbitals', 'read_cp2k_xyz', 'read_cp2k_table',
'read_cp2k_table_slc', 'get_cp2k_version', 'get_cp2k_version_run']
'read_cp2k_table_slc', 'get_cp2k_version']


# Starting logger
Expand Down Expand Up @@ -97,11 +97,10 @@ def read_cp2k_coefficients(

file_in = fnmatch.filter(os.listdir(plams_dir), '*in')[0]
file_out = fnmatch.filter(os.listdir(plams_dir), '*out')[0]
file_run = fnmatch.filter(os.listdir(plams_dir), '*run')[0]

path_in = plams_dir / file_in
path_out = plams_dir / file_out
cp2k_version = get_cp2k_version_run(plams_dir / file_run)
cp2k_version = get_cp2k_version(plams_dir / file_out)

orbitals_info = read_cp2k_number_of_orbitals(path_out)
_, range_mos = read_mos_data_input(path_in)
Expand Down Expand Up @@ -677,50 +676,25 @@ def read_cp2k_pressure(
return np.fromiter(islice(iterator, start, stop, step), dtype=dtype)


PATTERN = re.compile(r"CP2K version ([0-9]+)\.([0-9]+)")


def get_cp2k_version(out_file: PathLike) -> CP2KVersion:
"""Read the CP2K major and minor version from the passed .out file.
Returns :code:`(0, 0)` if the versions cannot be identified.
"""
with open(out_file, 'r') as f:
for i in f:
if i.startswith(" CP2K| version string:"):
version_str = i.split()[-1]

# if an error is encoutered here then we must be dealing with
# a very old CP2K version; fall back to `major = 0` in such case
try:
return CP2KVersion._make(int(i) for i in version_str.split("."))
except ValueError:
pass
warnings.warn("Failed to identify the CP2K version", QMFlows_Warning, stacklevel=2)
i = i.strip()
if i.startswith("CP2K| version string:"):
match = PATTERN.search(i)
if match is None:
continue
return CP2KVersion(int(match[1]), int(match[2]))

warnings.warn(
f"Failed extract the CP2K version from {os.fsdecode(out_file)!r}",
QMFlows_Warning, stacklevel=2,
)
return CP2KVersion(0, 0)


EXECUTABLE_PATTERN = re.compile(r"""(".+"|'.+'|\S+)\s+-i""")
VERSION_PATTERN = re.compile(r"CP2K version (\d+).(\d+)")


def get_cp2k_version_run(run_file: PathLike) -> CP2KVersion:
"""Get the CP2K version using the PLAMS .run."""
# Extract the executable
with open(run_file, 'r') as f:
match = EXECUTABLE_PATTERN.search(f.read())
if match is None:
raise ValueError(f"Failed to extract the CP2K executable from {f.name!r}")
executable = match.groups()[0]

# Get the `--version` of the executable
try:
out = subprocess.run(
f"{executable} --version",
check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, encoding="utf8", shell=True
)
except subprocess.CalledProcessError as ex:
raise ValueError(f"Failed to execute `{executable} --version`:\n\n{ex.stderr}") from ex

# Parse the `--version` output
match = VERSION_PATTERN.search(out.stdout)
if match is None:
raise ValueError(f"Failed to parse the `{executable} --version` output:\n\n{out.stdout}")
return CP2KVersion._make(int(i) for i in match.groups())
7 changes: 0 additions & 7 deletions test/test_cp2k_mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from qmflows.packages.cp2k_package import CP2K_Result
from qmflows.utils import init_restart
from qmflows.common import CP2KVersion
from qmflows.parsers.cp2KParser import get_cp2k_version_run
from qmflows.test_utils import (
PATH,
PATH_MOLECULES,
Expand All @@ -21,11 +20,6 @@
validate_status,
)

try:
CP2K_VERSION = get_cp2k_version_run("cp2k.popt")
except Exception:
CP2K_VERSION = CP2KVersion(0, 0)


def mock_runner(mocker_instance, jobname: str) -> Callable[..., CP2K_Result]:
"""Create a Result instance using a mocked runner."""
Expand Down Expand Up @@ -63,7 +57,6 @@ def test_deepcopy():

# See https://github.com/SCM-NV/qmflows/issues/225
@pytest.mark.xfail(raises=AssertionError)
@pytest.mark.skipif(CP2K_VERSION >= (8, 2), reason="Requires CP2K < 8.2")
@requires_cp2k
def test_cp2k_singlepoint_mock(mocker: MockFixture):
"""Mock a call to CP2K."""
Expand Down
48 changes: 1 addition & 47 deletions test/test_cp2k_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import pytest
from assertionlib import assertion

from qmflows.parsers.cp2KParser import parse_cp2k_warnings, readCp2KBasis, get_cp2k_version_run
from qmflows.parsers.cp2KParser import parse_cp2k_warnings, readCp2KBasis
from qmflows.test_utils import PATH, requires_cp2k
from qmflows.warnings_qmflows import QMFlows_Warning, cp2k_warnings
from qmflows.common import AtomBasisKey
Expand Down Expand Up @@ -57,49 +57,3 @@ def test_raise(self, filename: str, lineno: int) -> None:
pattern = r"Failed to parse the '.+' basis set on line {}".format(lineno)
with pytest.raises(ValueError, match=pattern):
readCp2KBasis(PATH / filename)


@requires_cp2k
class TestGetCP2KVersion:
@classmethod
def setup_class(cls) -> None:
"""Add ``cp2k.popt`` to a space-containing directory and add it to ``$PATH``."""
cp2k_popt = shutil.which("cp2k.popt")
assert cp2k_popt is not None

os.mkdir(PATH / "test dir")
shutil.copy2(cp2k_popt, PATH / "test dir" / "cp2k.popt")

@classmethod
def teardown_class(cls) -> None:
"""Restore the old ``$PATH`` environment variable."""
shutil.rmtree(PATH / "test dir")

PASS_DICT = {
"mpirun": "bin/mpirun cp2k.popt -i file.in -o file.out",
"srun": "srun cp2k.popt -i file.in -o file.out",
"none": "cp2k.popt -i file.in -o file.out",
"space": " cp2k.popt -i file.in -o file.out",
"single_quote": f"'{PATH}/test dir/cp2k.popt' -i file.in -o file.out",
"double_quote": f'"{PATH}/test dir/cp2k.popt" -i file.in -o file.out',
}

@pytest.mark.parametrize("name,txt", PASS_DICT.items(), ids=PASS_DICT)
def test_pass(self, name: str, txt: str, tmp_path: Path) -> None:
with open(tmp_path / f"{name}.run", "w") as f:
f.write(txt)
out = get_cp2k_version_run(tmp_path / f"{name}.run")
assertion.truth(out)

RAISE_DICT = {
"invalid_run": "cp2k.popt -j file.in -o file.out",
"invalid_exec": "cp2k.bob -i file.in -o file.out",
"invalid_exec_version": "python -i file.in -o file.out",
}

@pytest.mark.parametrize("name,txt", RAISE_DICT.items(), ids=RAISE_DICT)
def test_raise(self, name: str, txt: str, tmp_path: Path) -> None:
with open(tmp_path / f"{name}.run", "w") as f:
f.write(txt)
with pytest.raises(ValueError):
get_cp2k_version_run(tmp_path / f"{name}.run")

0 comments on commit 47f3df0

Please sign in to comment.