Skip to content
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
2 changes: 1 addition & 1 deletion paths_cli/tests/wizard/test_load_from_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ def test_get_ops_object(ops_file_fixture, with_failure):
assert obj.name == 'bar'
log = wizard.console.log_text
assert 'name of the FOOMAGIC' in log
fail_msg = 'Something went wrong'
fail_msg = 'not a valid option'
if with_failure:
assert fail_msg in log
else:
Expand Down
27 changes: 11 additions & 16 deletions paths_cli/wizard/load_from_ops.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
from paths_cli.parameters import INPUT_FILE
from paths_cli.wizard.core import get_object
from paths_cli.wizard.standard_categories import CATEGORIES
from paths_cli.wizard.helper import Helper
from functools import partial

from paths_cli.wizard.errors import FILE_LOADING_ERROR_MSG
LABEL = "Load existing from OPS file"


def named_objs_helper(storage, store_name):
def list_items(user_input, context=None):
store = getattr(storage, store_name)
Expand All @@ -25,24 +23,21 @@ def _get_ops_storage(wizard):
storage = INPUT_FILE.get(filename)
except Exception as e:
wizard.exception(FILE_LOADING_ERROR_MSG, e)
return
return None

return storage


@get_object
def _get_ops_object(wizard, storage, store_name, obj_name):
name = wizard.ask(f"What's the name of the {obj_name} you want to "
"load? (Type '?' to get a list of them)",
helper=named_objs_helper(storage, store_name))
if name:
try:
obj = getattr(storage, store_name)[name]
except Exception as e:
wizard.exception("Something went wrong when loading "
f"{name}. Maybe check the spelling?", e)
return
else:
return obj
store = getattr(storage, store_name)
options = {obj.name: obj for obj in store if obj.is_named}
result = wizard.ask_enumerate_dict(
f"What's the name of the {obj_name} you want to load?",
options
)
return result


def load_from_ops(wizard, store_name, obj_name):
wizard.say("Okay, we'll load it from an OPS file.")
Expand Down
7 changes: 6 additions & 1 deletion paths_cli/wizard/openmm.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,12 @@
ProxyParameter(
name='n_frames_max',
ask="How many frames before aborting a trajectory?",
helper=None,
helper=("Sometimes trajectories can get stuck in "
"unexpected basins. To prevent your trajectory "
"from running forever, you need to add a cutoff "
"trajectory length. This should be significantly "
"longer than you would expect a transition to "
"take."),
),
],
compiler_plugin=OPENMM_COMPILING,
Expand Down
27 changes: 25 additions & 2 deletions paths_cli/wizard/volumes.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import operator
from functools import partial
from paths_cli.wizard.parameters import ProxyParameter
from paths_cli.wizard.plugin_classes import (
LoadFromOPS, WizardParameterObjectPlugin, WizardObjectPlugin,
Expand All @@ -7,7 +8,7 @@
from paths_cli.wizard.helper import EvalHelperFunc, Helper
from paths_cli.wizard.core import interpret_req
import paths_cli.compiling.volumes
from functools import partial


def _binary_func_volume(wizard, context, op):
wizard.say("Let's make the first constituent volume:")
Expand All @@ -28,6 +29,7 @@ def _binary_func_volume(wizard, context, op):
_LAMBDA_STR = ("What is the {minmax} allowed value for "
"'{{obj_dict[cv].name}}' in this volume?")


CV_DEFINED_VOLUME_PLUGIN = WizardParameterObjectPlugin.from_proxies(
name="CV-defined volume (allowed values of CV)",
category="volume",
Expand Down Expand Up @@ -57,24 +59,33 @@ def _binary_func_volume(wizard, context, op):
compiler_plugin=paths_cli.compiling.volumes.CV_VOLUME_PLUGIN,
)


INTERSECTION_VOLUME_PLUGIN = WizardObjectPlugin(
name='Intersection of two volumes (must be in both)',
category="volume",
intro=("This volume will be the intersection of two other volumes. "
"This means that it only allows phase space points that are "
"in both of the constituent volumes."),
builder=partial(_binary_func_volume, op=operator.__and__),
description=("Create a volume that is the intersection of two existing "
"volumes -- that is, all points in this volume are in "
"both of the volumes that define it."),
)


UNION_VOLUME_PLUGIN = WizardObjectPlugin(
name='Union of two volumes (must be in at least one)',
category="volume",
intro=("This volume will be the union of two other volumes. "
"This means that it allows phase space points that are in "
"either of the constituent volumes."),
builder=partial(_binary_func_volume, op=operator.__or__),
description=("Create a volume that is the union of two existing "
"volumes -- that is, any point in either of the volumes "
"that define this are also in this volume"),
)


NEGATED_VOLUME_PLUGIN = WizardObjectPlugin(
name='Complement of a volume (not in given volume)',
category='volume',
Expand All @@ -83,15 +94,19 @@ def _binary_func_volume(wizard, context, op):
builder=lambda wizard, context: ~VOLUMES_PLUGIN(
wizard, volume_set_context(wizard, context, None)
),
description=("Create a volume that includes every that is NOT "
"in the existing volume."),
)


_FIRST_STATE = ("Now let's define state states for your system. "
"You'll need to define {n_states_string} of them.")
_ADDITIONAL_STATES = "Okay, let's define another stable state."
_VOL_DESC = ("You can describe this as either a range of values for some "
"CV, or as some combination of other such volumes "
"(i.e., intersection or union).")


def volume_intro(wizard, context):
as_state = context.get('depth', 0) == 0
n_states = len(wizard.states)
Expand All @@ -106,24 +121,32 @@ def volume_intro(wizard, context):
intro += [_VOL_DESC]
return intro


def volume_set_context(wizard, context, selected):
depth = context.get('depth', 0) + 1
new_context = {
'depth': depth,
}
return new_context


def volume_ask(wizard, context):
as_state = context.get('depth', 0) == 0
obj = {True: 'state', False: 'volume'}[as_state]
return f"What describes this {obj}?"


VOLUME_FROM_FILE = LoadFromOPS('volume')

VOLUMES_PLUGIN = WrapCategory(
name='volume',
intro=volume_intro,
ask=volume_ask,
set_context=volume_set_context,
helper="No volume help yet"
helper=("This will define a (hyper)volume in phase space. States and "
"interfaces in OPS are described by volumes. You can combine "
"ranges along different CVs in any way you want to defined the "
"volume.")
)

if __name__ == "__main__": # no-cov
Expand Down