Skip to content
Draft
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
14 changes: 10 additions & 4 deletions examol/simulate/ase/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,11 @@
METHOD $METHOD$
&END QS
&SCF
&MIXING
NBUFFER 8
&END MIXING
&OUTER_SCF
MAX_SCF 5
MAX_SCF 3
&END OUTER_SCF
&OT T
PRECONDITIONER FULL_ALL
Expand Down Expand Up @@ -174,7 +177,7 @@ def create_configuration(self, name: str, xyz: str, charge: int, solvent: str |
}
elif name.startswith('cp2k_'):
# Get the name the basis set
xc_name, basis_set_id = name.rsplit('_', 2)[-2:]
xc_name, basis_set_id = name[5:].rsplit('_', 1)
xc_name = xc_name.upper()

# Determine the proper basis set, pseudopotential, and method
Expand Down Expand Up @@ -237,7 +240,7 @@ def create_configuration(self, name: str, xyz: str, charge: int, solvent: str |
uks=charge != 0,
inp=inp,
cutoff=cutoff * units.Ry,
max_scf=32,
max_scf=64,
basis_set_file=str(basis_set_file),
basis_set=basis_set_name,
pseudo_potential=potential,
Expand Down Expand Up @@ -401,14 +404,17 @@ def compute_energy(self, mol_key: str, xyz: str, config_name: str, charge: int =
# Make any changes to cell needed by the calculator
self._prepare_atoms(atoms, charge, calc_cfg)

# Remove the previous output file, if any
cp2k_output = Path('cp2k.out')
cp2k_output.unlink(True)

# Run a single point
atoms.calc = calc
forces = atoms.get_forces() if forces else None
energy = atoms.get_potential_energy()

# If CP2K, make sure it converged
if config_name.startswith('cp2k'):
cp2k_output = (run_path / 'cp2k.out')
assert cp2k_output.is_file(), f'Cannot find output at: {cp2k_output.absolute()}'
if ':: SCF run NOT converged ***' in cp2k_output.read_text(): # pragma: no-coverage
raise ValueError('CP2K computation did not converge')
Expand Down
15 changes: 2 additions & 13 deletions examol/simulate/ase/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,19 +38,8 @@ def make_ephemeral_calculator(calc: Calculator | dict) -> Iterator[Calculator]:
name = calc['name'].lower()
if name == 'cp2k':
from ase.calculators.cp2k import CP2K
calc = CP2K(*calc.get('args', []), **calc.get('kwargs', {}))
yield calc

# Kill the calculator by deleting the object to stop the underlying
# shell and then set the `_shell` parameter of the object so that the
# calculator object's destructor will skip the shell shutdown process
# when the object is finally garbage collected
try:
calc.__del__()
except AssertionError as e: # pragma: no-coverage
logger.info(f'CP2K was noisy on failure: {e}')
pass
calc._shell = None
with CP2K(*args, **kwargs) as calc:
yield calc
elif name == 'gaussian':
from ase.calculators.gaussian import Gaussian
yield Gaussian(*args, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion examol/store/recipes.py
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ def suggest_computations(self, record: MoleculeRecord) -> list[SimulationRequest
# Determine if the geometry has been computed
matching_conformers = [
(x.get_energy(geometry.config_name, geometry.charge, solvent=None), x) for x in record.conformers
if x.source == 'relaxation' and x.config_name == geometry.config_name and x.charge == geometry.charge
if x.config_name == geometry.config_name and x.charge == geometry.charge
]
if len(matching_conformers) > 0:
_, conformer = min(matching_conformers)
Expand Down
4 changes: 2 additions & 2 deletions examples/redoxmers/run/report.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# Run Report
Report time: 2023-10-18 17:38:06.910593
Report time: 2023-11-30 14:02:53.333870

## Task Summary
Measures how many tasks have run as part of the application

| Task Type | Count | Node Hours | Failures |
|-------------|---------|--------------|------------|
| simulation | 2 | 0.00041 | 0 (0.0%) |
| simulation | 2 | 0.0017 | 0 (0.0%) |

## Outcomes over Time
The property of the molecules over time.
Expand Down
21 changes: 20 additions & 1 deletion tests/simulation/test_ase.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

try:
import xtb # noqa: F401

has_xtb = True
except ImportError:
has_xtb = False
Expand All @@ -31,12 +32,22 @@
cp2k_configs_to_test = ['cp2k_b3lyp_svp', 'cp2k_blyp_szv', 'cp2k_wb97x_d3_tzvpd']


class FakeShell:

def __del__(self):
return


class FakeCP2K(LennardJones):
_shell = FakeShell()

def __init__(self, *args, **kwargs):
super().__init__()

def __del__(self):
def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
return


Expand Down Expand Up @@ -67,6 +78,14 @@ def test_cp2k_configs(tmpdir, strc):
assert 'GAPW' in config['kwargs']['inp']
assert Path(config['kwargs']['basis_set_file']).is_file()

# With wb97x-d3
config = sim.create_configuration('cp2k_wb97x_d3_tzvpd', strc, charge=1, solvent=None)
assert config['kwargs']['cutoff'] == 600 * units.Ry
assert config['kwargs']['charge'] == 1
assert config['kwargs']['uks']
assert 'GAPW' in config['kwargs']['inp']
assert Path(config['kwargs']['basis_set_file']).is_file()

# With an undefined basis set
with raises(AssertionError):
sim.create_configuration('cp2k_blyp_notreal', strc, charge=1, solvent=None)
Expand Down
4 changes: 2 additions & 2 deletions tests/steer/conftest.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from concurrent.futures import ProcessPoolExecutor
from concurrent.futures import ThreadPoolExecutor
from pathlib import Path
import sys

Expand Down Expand Up @@ -57,7 +57,7 @@ def simulator(tmp_path) -> ASESimulator:

@fixture()
def pool():
yield ProcessPoolExecutor()
yield ThreadPoolExecutor(max_workers=1)


@fixture()
Expand Down
28 changes: 14 additions & 14 deletions tests/steer/test_multi.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,26 +86,26 @@ def test_detect_level(thinker, recipe):
def test_iterator(thinker, recipe, mocker):
# Make sure we return xTB regardless of what the system asks for
for choice in [0, 1]:
with mocker.patch('numpy.random.choice', return_value=choice):
thinker.task_queue = [('C', 0)]
record, recipes, request = next(thinker.task_iterator)
assert record.identifier.smiles == 'C'
assert request.config_name == 'xtb'
assert recipes[0].level == 'xtb-vertical'
assert len(thinker.task_queue) == 0
mocker.patch('numpy.random.choice', return_value=choice)
thinker.task_queue = [('C', 0)]
record, recipes, request = next(thinker.task_iterator)
assert record.identifier.smiles == 'C'
assert request.config_name == 'xtb'
assert recipes[0].level == 'xtb-vertical'
assert len(thinker.task_queue) == 0

# Test after we add data for C
# We should default to C if it's the only item in the task queue
thinker.database.get_or_make_record('C').properties[recipe.name] = {'xtb-vertical': 1}
assert thinker.get_level('C') == 1
for choice in [0, 1]:
with mocker.patch('numpy.random.choice', return_value=choice):
thinker.task_queue = [('C', 0)]
record, recipes, request = next(thinker.task_iterator)
assert record.identifier.smiles == 'C'
assert recipes[0].level == 'mopac_pm7-vertical'
assert request.config_name == 'mopac_pm7', f'choice={choice}'
assert len(thinker.task_queue) == 0
mocker.patch('numpy.random.choice', return_value=choice)
thinker.task_queue = [('C', 0)]
record, recipes, request = next(thinker.task_iterator)
assert record.identifier.smiles == 'C'
assert recipes[0].level == 'mopac_pm7-vertical'
assert request.config_name == 'mopac_pm7', f'choice={choice}'
assert len(thinker.task_queue) == 0


@mark.timeout(120)
Expand Down