Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BUG: Fix the frequency analysis component of the BDE being incompatible with custom CP2K settings #114

Merged
merged 6 commits into from
Jan 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 33 additions & 7 deletions .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,21 @@ on:

jobs:
build:
name: Python ${{ matrix.version }} on ${{ matrix.os }}
name: ${{ matrix.os }} (py ${{ matrix.version }}${{ matrix.special }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
version: ["3.7", "3.8", "3.9", "3.10"]
special: [""]
include:
- os: ubuntu-latest
special: '; pre-release'
version: '3.10'
- os: ubuntu-latest
special: '; slow'
version: '3.10'
env:
CP2K_DATA_DIR: "/usr/share/cp2k"

Expand All @@ -31,7 +39,7 @@ jobs:
- uses: actions/checkout@v2

- name: Install CP2K
if: matrix.os == 'ubuntu-latest'
if: matrix.special == '; slow'
run: |
sudo apt-get update
sudo apt install cp2k
Expand All @@ -42,7 +50,19 @@ jobs:
python-version: ${{ matrix.version }}

- name: Install dependencies
run: pip install -e .[test]
run: |
case "${{ matrix.special }}" in
"; pre-release")
pip install --pre -e .[test] --upgrade --force-reinstall
pip install git+https://github.com/nlesc-nano/CAT@master --upgrade
pip install git+https://github.com/nlesc-nano/auto-FOX@master --upgrade
pip install git+https://github.com/SCM-NV/qmflows@master --upgrade
pip install git+https://github.com/SCM-NV/PLAMS@master --upgrade
;;
*)
pip install -e .[test]
;;
esac

- name: Info Python
run: |
Expand All @@ -53,11 +73,17 @@ jobs:
run: pip list

- name: Info CP2K
if: matrix.os == 'ubuntu-latest'
if: matrix.special == '; slow'
run: cp2k.popt --version

- name: Run tests
run: pytest -m "not slow"
run: |
case "${{ matrix.special }}" in
"; slow")
pytest -m "slow" ;;
*)
pytest -m "not slow" ;;
esac

- name: Run codecov
uses: codecov/codecov-action@v2
Expand All @@ -70,10 +96,10 @@ jobs:
steps:
- uses: actions/checkout@v2

- name: Set up Python 3.9 on ubuntu-latest
- name: Set up Python 3.10 on ubuntu-latest
uses: actions/setup-python@v2
with:
python-version: 3.9
python-version: "3.10"

- name: Install linters
run: pip install "flake8>=3.8.0"
Expand Down
9 changes: 6 additions & 3 deletions nanoCAT/bde/bde_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ def get_bde_ddG(tot: Molecule, lig: Molecule, core: Iterable[Molecule],
return np.full(len_core, np.nan)

# Optimize XYn
s.input.ams.Constraints.Atom = lig.properties.indices
if job is AMSJob:
s.input.ams.Constraints.Atom = lig.properties.indices
lig.job_freq(job, s, name='G_XYn_freq')

# Extract energies
Expand All @@ -282,7 +283,8 @@ def get_bde_ddG(tot: Molecule, lig: Molecule, core: Iterable[Molecule],
return np.full(len_core, np.nan)

# Optimize the full quantum dot
s.input.ams.Constraints.Atom = tot.properties.indices
if job is AMSJob:
s.input.ams.Constraints.Atom = tot.properties.indices
tot.job_freq(job, s, name='G_QD_freq')

# Extract energies
Expand All @@ -295,7 +297,8 @@ def get_bde_ddG(tot: Molecule, lig: Molecule, core: Iterable[Molecule],

# Optimize the quantum dot(s) - XYn
for mol in core:
s.input.ams.Constraints.Atom = mol.properties.indices
if job is AMSJob:
s.input.ams.Constraints.Atom = mol.properties.indices
mol.job_freq(job, s, name='G_QD-XYn_freq')

# Extract energies
Expand Down
4 changes: 2 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@
'noodles>=0.3.3',
'more-itertools>=1.0',
'plams>=1.5.1',
'qmflows>=0.11.0',
'nlesc-CAT>=0.10.4',
'qmflows>=0.11.1',
'nlesc-CAT>=0.10.5',
'Auto-FOX>=0.10.0',
'rdkit-pypi>=2018.03.1',
],
Expand Down
111 changes: 65 additions & 46 deletions tests/test_bde_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,68 @@
import pandas as pd
from assertionlib import assertion
from nanoutils import UniqueLoader
from scm.plams import readpdb, Settings
from scm.plams import readpdb, Settings, Cp2kJob

from CAT.base import validate_input
from CAT.settings_dataframe import SettingsDataFrame
from CAT.workflows import MOL
from nanoCAT.bde import init_bde

PATH = Path("tests") / "test_files"
BASE_SETTINGS = Settings(yaml.load(textwrap.dedent("""
path: tests/test_files
input_cores:
- Br5ClCs8Pb.xyz
input_ligands:
- CO
optional:
database:
read: False
write: False
qd:
dissociate:
core_atom: null
core_index: null
lig_count: 1

keep_files: True
xyn_pre_opt: False
job1: Cp2kJob
s1:
input:
motion:
geo_opt:
type: minimization
optimizer: bfgs
max_iter: 10
max_force: 1e-03
force_eval:
dft:
basis_set_file_name: BASIS_MOLOPT
potential_file_name: GTH_POTENTIALS
xc:
xc_functional pbe: {}
scf:
eps_scf: 1e-05
max_scf: 20
subsys:
cell:
abc: 8.00 8.00 8.00
periodic: None
kind H:
basis_set: DZVP-MOLOPT-SR-GTH
potential: GTH-PBE
kind Cl:
basis_set: DZVP-MOLOPT-SR-GTH
potential: GTH-PBE
job2: null
s2: null
""").strip(), Loader=UniqueLoader))


def construct_df() -> SettingsDataFrame:
# Construct the settings
settings = Settings(yaml.load(textwrap.dedent("""
path: tests/test_files
input_cores:
- Br5ClCs8Pb.xyz
input_ligands:
- CO
optional:
database:
read: False
write: False
qd:
dissociate:
core_atom: null
core_index: null
core_core_dist: 2.0
lig_count: 1

keep_files: True
xyn_pre_opt: False
job1: Cp2kJob
s1:
input:
FORCE_EVAL:
DFT:
BASIS_SET_FILE_NAME: BASIS_MOLOPT
POTENTIAL_FILE_NAME: GTH_POTENTIALS
XC:
XC_FUNCTIONAL pbe: {}
SUBSYS:
CELL:
ABC: 7.00 7.00 7.00
PERIODIC: None
KIND H:
BASIS_SET: DZVP-MOLOPT-SR-GTH-q1
POTENTIAL: GTH-PBE-q1
KIND Cl:
BASIS_SET: DZVP-MOLOPT-SR-GTH-q7
POTENTIAL: GTH-PBE-q7
job2: null
s2: null
""").strip(), Loader=UniqueLoader))
settings = BASE_SETTINGS.copy()
validate_input(settings)
settings.optional.database.db = None
settings.optional.qd.dissociate.xyn_opt = False
Expand All @@ -89,9 +98,14 @@ def construct_df() -> SettingsDataFrame:


@pytest.mark.skipif(find_executable("cp2k.popt") is None, reason="requires CP2K")
@pytest.mark.slow
class TestBDEWorkflow:
PARAMS = dict(
core_index=("core_index", [3]),
core_index={"core_index": [3]},
core_atom={"core_atom": "H", "lig_core_dist": 2.0},
freq={"core_index": [3], "job2": Cp2kJob,
"s2": BASE_SETTINGS.optional.qd.dissociate.s1.copy()},
qd_opt={"core_index": [3], "qd_opt": True},
)

@pytest.fixture(scope="function", autouse=True)
Expand All @@ -101,12 +115,17 @@ def clear_db(self) -> Generator[None, None, None]:
shutil.rmtree(PATH / "database", ignore_errors=True)
shutil.rmtree(PATH / "qd" / "bde", ignore_errors=True)

@pytest.mark.parametrize("key,value", PARAMS.values(), ids=PARAMS.keys())
def test_core_index(self, key: str, value: Any, clear_db: None) -> None:
@pytest.mark.parametrize("kwargs", PARAMS.values(), ids=PARAMS)
def test_pass(self, kwargs: dict[str, Any], clear_db: None) -> None:
qd_df = construct_df()
qd_df.settings.optional.qd.dissociate[key] = value
qd_df.settings.optional.qd.dissociate.update(kwargs)
init_bde(qd_df)

bde = qd_df["BDE dE", "0"].iloc[0]
assertion.len_eq(qd_df["BDE dE"].columns, 1)
assertion.assert_(np.isfinite, bde)

if "job2" in kwargs:
bde_gibbs = qd_df["BDE dG", "0"].iloc[0]
assertion.len_eq(qd_df["BDE dG"].columns, 1)
assertion.assert_(np.isfinite, bde_gibbs)
9 changes: 7 additions & 2 deletions tests/test_fast_sigma_recipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@
SANITIZE4_DF.index = pd.Index([None] * len(SANITIZE_DF.index), name=SANITIZE_DF.index.name)


def has_env_vars(*env_vars: str) -> bool:
"""Check if the passed environment variables are available."""
return set(env_vars).issubset(os.environ)


def compare_df(df1: pd.DataFrame, df2: pd.DataFrame) -> None:
"""Compare the content of two dataframes."""
__tracebackhide__ = True
Expand All @@ -64,10 +69,11 @@ def compare_df(df1: pd.DataFrame, df2: pd.DataFrame) -> None:
np.testing.assert_array_equal(v1, v2, err_msg=k)


@pytest.mark.slow
@pytest.mark.skipif(not has_env_vars("AMSBIN", "AMSHOME", "AMSRESOURCES"), reason="Requires AMS")
class TestFastSigma:
"""Tests for :func:`nanoCAT.recipes.run_fast_sigma`."""

@pytest.mark.slow
@pytest.mark.parametrize(
"kwargs",
[{}, {"return_df": True}, {"chunk_size": 1, "return_df": True}, {"processes": 1}],
Expand Down Expand Up @@ -114,7 +120,6 @@ def test_raises(
with pytest.raises(exc):
run_fast_sigma(SMILES, solvents, **kwargs)

@pytest.mark.slow
def test_warns(self, tmp_path: Path) -> None:
"""Test that whether appropiate warning is issued."""
with pytest.warns(RuntimeWarning) as record:
Expand Down