Skip to content

Commit

Permalink
CV Mode from CLI
Browse files Browse the repository at this point in the history
OPS (SimStore) CVs have several ways the can get the value for a given
input object: (1) the can evaluate the function; (2) they can find the
result in a memory cache; (3) they can find the result in an on-disk
cache.

The order in which they attempt these define the "mode" of the CV:

* `analysis`: first memory cache, then disk cache, then evaluate
* `production`: first memory cache, the evaluate
* `no-caching`: always evaluate

This PR allows a CLI interface to specify these behaviors. In
particular, this might be useful for users who don't want to save CVs to
disk for cheap CVs, like in toy models.
  • Loading branch information
dwhswenson committed Aug 30, 2024
1 parent 02b3374 commit 63034a1
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 2 deletions.
8 changes: 6 additions & 2 deletions paths_cli/commands/pathsampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

from paths_cli import OPSCommandPlugin
from paths_cli.parameters import (
INPUT_FILE, OUTPUT_FILE, INIT_CONDS, SCHEME, N_STEPS_MC
INPUT_FILE, OUTPUT_FILE, INIT_CONDS, SCHEME, N_STEPS_MC,
SIMULATION_CV_MODE,
)


Expand All @@ -16,9 +17,12 @@
@SCHEME.clicked(required=False)
@INIT_CONDS.clicked(required=False)
@N_STEPS_MC
def pathsampling(input_file, output_file, scheme, init_conds, nsteps):
@SIMULATION_CV_MODE.clicked()
def pathsampling(input_file, output_file, scheme, init_conds, nsteps,
cv_mode):
"""General path sampling, using setup in INPUT_FILE"""
storage = INPUT_FILE.get(input_file)
SIMULATION_CV_MODE(storage, cv_mode)
pathsampling_main(output_storage=OUTPUT_FILE.get(output_file),
scheme=SCHEME.get(storage, scheme),
init_conds=INIT_CONDS.get(storage, init_conds),
Expand Down
39 changes: 39 additions & 0 deletions paths_cli/parameters.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import click
import warnings
from paths_cli.param_core import (
Option, Argument, OPSStorageLoadSingle, OPSStorageLoadMultiple,
OPSStorageLoadNames, StorageLoader, GetByName, GetByNumber, GetOnly,
Expand Down Expand Up @@ -133,3 +134,41 @@ def get(self, storage, names):
help="number of Monte Carlo trials to run")

MULTI_CV = CVS


class CVMode:
"""Class for generating CVMode parameters.
"""
def __init__(self, options, default):
allowed = {"production", "analysis", "no-caching"}
if extras := set(options) - allowed:
raise ValueError(f"Invalid options: {extras}")
if default not in options:
raise ValueError(f"Default '{default}' not in options {options}")

self.default = default
self.param = Option(
"--cv-mode",
type=click.Choice(options),
help=(
"Mode for CVs (only used for SimStore DB files). Default "
f"'{default}'."
),
default=default,
)

def clicked(self):
return self.param.clicked()

def __call__(self, storage, cv_mode):
from openpathsampling.experimental.storage import Storage
if cv_mode != self.default and not isinstance(storage, Storage):
warnings.warn("Not a SimStore file: cv-mode argument unused")
return

for cv in storage.cvs:
# TODO: add logger
# _logger.info(f"Setting '{cv.name}' to mode '{cv_mode}'.")
cv.mode = cv_mode

SIMULATION_CV_MODE = CVMode(["production", "no-caching"], "production")
46 changes: 46 additions & 0 deletions paths_cli/tests/test_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,3 +511,49 @@ def test_APPEND_FILE(ext):
os.remove(filename)
os.rmdir(tempdir)
undo_monkey_patch(stored_functions)


class TestCVMode:
def test_bad_option(self):
with pytest.raises(ValueError, match="Invalid options"):
CVMode(["production", "foo"], "production")

def test_bad_default(self):
with pytest.raises(ValueError, match="not in options"):
CVMode(["production", "no-caching"], "analysis")

def test_call(self, tmp_path):
cv_mode = CVMode(["production", "no-caching"], "no-caching")
from openpathsampling.experimental.storage.collective_variables \
import CollectiveVariable
from openpathsampling.experimental.storage import (
Storage, monkey_patch_all
)
cv = CollectiveVariable(lambda s: s.xyz[0][0]).named('x')
filename = str(tmp_path / "foo.db")
stored_functions = pre_monkey_patch()
monkey_patch_all(paths)
st = Storage(filename, mode='w')
assert cv.mode == "analysis"
st.save(cv)
st.close()
del cv

storage = Storage(filename, mode='r')
cv = storage.cvs['x']
assert cv.mode == "analysis"
cv_mode(storage, "no-caching")
assert cv.mode == "no-caching"
undo_monkey_patch(stored_functions)

def test_call_non_simstore(self, tmp_path):
cv_mode = CVMode(["production", "no-caching"], "no-caching")
filename = str(tmp_path / "foo.nc")
cv = paths.FunctionCV("x", lambda x: x.xyz[0][0])
st = paths.Storage(filename, mode='w')
st.save(cv)
st.close()

storage = paths.Storage(filename, mode='r')
with pytest.warns(UserWarning, match="Not a SimStore"):
cv_mode(storage, "production")

0 comments on commit 63034a1

Please sign in to comment.