-
Notifications
You must be signed in to change notification settings - Fork 3
Simulation Setup Wizard #41
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
Merged
Merged
Changes from all commits
Commits
Show all changes
49 commits
Select commit
Hold shift + click to select a range
7af7eae
Add start to wizard
dwhswenson 7fec891
TPS wizard works through state defs
dwhswenson 250f4e2
a little more work on the wizard
dwhswenson 666f9a9
major steps toward TPS wizard
dwhswenson 8910ba2
A little more cleanup on wizard stuff
dwhswenson 0b60338
Start to add tests for wizard
dwhswenson 68066b1
tests for most of the Wizard object
dwhswenson 4da1b9a
move MockConsole, start to get_object decorator
dwhswenson c17f3d1
more work toward using get_object
dwhswenson 77fa5ce
tests for OpenMM wizard
dwhswenson 76ea517
Prep tests for CVs
dwhswenson 5d2e3f8
Some CV cleanup; more periodicity to CVs
dwhswenson b5ec9ce
Wizard ready for 2-state TPS demo
dwhswenson b32d03a
Add tests for CV wizards
dwhswenson a52bac0
tests for volume wizards
dwhswenson a9c4d96
simplify code to reflect current usage
dwhswenson a85118f
more cleanup of unused
dwhswenson 42aa3c9
More tests; work toward handling Spring Shooting
dwhswenson 13f7108
fix up tests
dwhswenson 9d6c3dd
Add tests for shooting, load_from_ops
dwhswenson 6467b59
Remove name from core (used as wizard.name)
dwhswenson d2050e4
Add tests for TPS wizard
dwhswenson 94cd34e
Tests for two_state_tps.py
dwhswenson 3f183de
tests for engines and errors
dwhswenson 35c9ca1
Update for parsing.tools.custom_eval
dwhswenson 97189a6
split off _do_one in wizard
dwhswenson f932fce
Add remaining tests for wizard
dwhswenson a3c7b4b
from unittest import mock...
dwhswenson a7fefd2
missed one
dwhswenson 9259aca
fix for tests locally
dwhswenson 10b676d
try ignoring wizard (does that fix test errors?)
dwhswenson 8b7c8b8
re-include wizard tests
dwhswenson 6c37dce
don't actually monkeypatch when testing Wizard
dwhswenson d444895
fix deprecation warnings for OPS 1.5
dwhswenson 47106e6
Add Wizard (skeleton form) to docs
dwhswenson e9dd815
Add test job with openmm etc integrations
dwhswenson ea29ac4
fix whitespace in yaml
dwhswenson b52c1ef
fix include in yaml
dwhswenson 3b64ce7
fix typo in workflow
dwhswenson 8dcd07d
fix workflow
dwhswenson e774caa
increase fetch-depth to help codecov
dwhswenson d07699e
... helps is fetch-depth is in the right heading
dwhswenson 2ba6390
finish test coverage
dwhswenson 59b6fbe
Add test for bad MDTraj atom index input
dwhswenson 4f3e53a
Add tests/wizard/__init__.py
dwhswenson 0b33b79
no-cov on joke
dwhswenson 60eb119
Apply suggestions from code review
dwhswenson 3d92cd2
misc review cleanup
dwhswenson 07b7d7c
Merge branch 'main' of github.com:openpathsampling/openpathsampling-c…
dwhswenson File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,3 +7,4 @@ exclude_lines = | |
| no-cov | ||
| def __repr__ | ||
| raise NotImplementedError | ||
| __name__ == "__main__": | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -60,6 +60,7 @@ wrappers around well-tested OPS code. | |
| plugins | ||
| parameters | ||
| workflows | ||
| wizard | ||
| full_cli | ||
| api/index | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| .. _wizard: | ||
|
|
||
| Writing tools for the Wizard | ||
| ============================ | ||
|
|
||
| The Wizard API is still rapidly in flux, and we don't recommend developing | ||
| custom Wizard tools at this time. However, once its API is more stable, the | ||
| Wizard will be extendable by outside developers. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| import click | ||
| from paths_cli.wizard.two_state_tps import TWO_STATE_TPS_WIZARD | ||
|
|
||
| @click.command( | ||
| 'wizard', | ||
| short_help="run wizard for setting up simulations", | ||
| ) | ||
| def wizard(): # no-cov | ||
| TWO_STATE_TPS_WIZARD.run_wizard() | ||
|
|
||
| CLI = wizard | ||
| SECTION = "Simulation setup" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| import numpy as np | ||
|
|
||
| def custom_eval(obj, named_objs=None): | ||
| """Parse user input to allow simple math. | ||
|
|
||
| This allows certain user input to be treated as a simplified subset of | ||
| Python. In particular, this is intended to allow simple arithmetic. It | ||
| allows use of the modules numpy (as ``np``) and math, which provide | ||
| potentially useful functions (e.g., ``cos``) as well as constants (e.g., | ||
| ``pi``). | ||
| """ | ||
| string = str(obj) | ||
| # TODO: check that the only attribute access comes from a whitelist | ||
| # (parse the AST for that) | ||
| namespace = { | ||
| 'np': __import__('numpy'), | ||
| 'math': __import__('math'), | ||
| } | ||
| return eval(string, namespace) | ||
|
|
||
|
|
||
| class UnknownAtomsError(RuntimeError): | ||
| pass | ||
|
|
||
| def mdtraj_parse_atomlist(inp_str, n_atoms, topology=None): | ||
| """ | ||
| n_atoms: int | ||
| number of atoms expected | ||
| """ | ||
| # TODO: change n_atoms to the shape desired? | ||
| # TODO: enable the parsing of either string-like atom labels or numeric | ||
| indices = custom_eval(inp_str) | ||
|
|
||
| arr = np.array(indices) | ||
| if arr.dtype != int: | ||
| raise TypeError("Input is not integers") | ||
| if arr.shape != (1, n_atoms): | ||
| # try to clean it up | ||
| if len(arr.shape) == 1 and arr.shape[0] == n_atoms: | ||
| arr.shape = (1, n_atoms) | ||
| else: | ||
| raise TypeError(f"Invalid input. Requires {n_atoms} " | ||
| "atoms.") | ||
|
|
||
| return arr | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import pytest | ||
| import numpy.testing as npt | ||
| import numpy as np | ||
| import math | ||
|
|
||
| from paths_cli.parsing.tools import * | ||
|
|
||
| @pytest.mark.parametrize('expr,expected', [ | ||
| ('1+1', 2), | ||
| ('np.pi / 2', np.pi / 2), | ||
| ('math.cos(1.5)', math.cos(1.5)), | ||
| ]) | ||
| def test_custom_eval(expr, expected): | ||
| npt.assert_allclose(custom_eval(expr), expected) | ||
|
|
||
| def test_mdtraj_parse_atomlist_bad_input(): | ||
| with pytest.raises(TypeError, match="not integers"): | ||
| mdtraj_parse_atomlist("['a', 'b']", n_atoms=2) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,18 @@ | ||
| import urllib.request | ||
|
|
||
| try: | ||
| urllib.request.urlopen('https://www.google.com') | ||
| except: | ||
| HAS_INTERNET = False | ||
| else: | ||
| HAS_INTERNET = True | ||
|
|
||
| def assert_url(url): | ||
| if not HAS_INTERNET: | ||
| pytest.skip("Internet connection seems faulty") | ||
|
|
||
| # TODO: On a 404 this will raise a urllib.error.HTTPError. It would be | ||
| # nice to give some better output to the user here. | ||
| resp = urllib.request.urlopen(url) | ||
| assert resp.status == 200 | ||
|
|
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,79 @@ | ||
| import pytest | ||
|
|
||
| import openpathsampling as paths | ||
| import mdtraj as md | ||
|
|
||
| @pytest.fixture | ||
| def ad_openmm(tmpdir): | ||
| """ | ||
| Provide directory with files to start alanine depeptide sim in OpenMM | ||
| """ | ||
| mm = pytest.importorskip('simtk.openmm') | ||
dwhswenson marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| u = pytest.importorskip('simtk.unit') | ||
| openmmtools = pytest.importorskip('openmmtools') | ||
| md = pytest.importorskip('mdtraj') | ||
| testsystem = openmmtools.testsystems.AlanineDipeptideVacuum() | ||
| integrator = openmmtools.integrators.VVVRIntegrator( | ||
| 300 * u.kelvin, | ||
| 1.0 / u.picosecond, | ||
| 2.0 * u.femtosecond | ||
| ) | ||
| traj = md.Trajectory([testsystem.positions.value_in_unit(u.nanometer)], | ||
| topology=testsystem.mdtraj_topology) | ||
| files = {'integrator.xml': integrator, | ||
| 'system.xml': testsystem.system} | ||
| with tmpdir.as_cwd(): | ||
| for fname, obj in files.items(): | ||
| with open(fname, mode='w') as f: | ||
| f.write(mm.XmlSerializer.serialize(obj)) | ||
|
|
||
| traj.save('ad.pdb') | ||
|
|
||
| return tmpdir | ||
|
|
||
| @pytest.fixture | ||
| def ad_engine(ad_openmm): | ||
| with ad_openmm.as_cwd(): | ||
| pdb = md.load('ad.pdb') | ||
| topology = paths.engines.MDTrajTopology( | ||
| pdb.topology | ||
| ) | ||
| engine = paths.engines.openmm.Engine( | ||
| system='system.xml', | ||
| integrator='integrator.xml', | ||
| topology=topology, | ||
| options={'n_steps_per_frame': 10, | ||
| 'n_frames_max': 10000} | ||
| ).named('ad_engine') | ||
| return engine | ||
|
|
||
| @pytest.fixture | ||
| def toy_engine(): | ||
| pes = (paths.engines.toy.OuterWalls([1.0, 1.0], [1.0, 1.0]) | ||
| + paths.engines.toy.Gaussian(-1.0, [12.0, 12.0], [-0.5, 0.0]) | ||
| + paths.engines.toy.Gaussian(-1.0, [12.0, 12.0], [0.5, 0.0])) | ||
| topology = paths.engines.toy.Topology(n_spatial=2, | ||
| masses=[1.0], | ||
| pes=pes) | ||
| integ = paths.engines.toy.LangevinBAOABIntegrator( | ||
| dt=0.02, | ||
| temperature=0.1, | ||
| gamma=2.5 | ||
| ) | ||
| options = {'integ': integ, | ||
| 'n_frames_max': 5000, | ||
| 'n_steps_per_frame': 1} | ||
| engine = paths.engines.toy.Engine( | ||
| options=options, | ||
| topology=topology | ||
| ).named('toy-engine') | ||
| return engine | ||
|
|
||
|
|
||
| @pytest.fixture | ||
| def tps_network(): | ||
| cv = paths.CoordinateFunctionCV('x', lambda s: s.xyz[0][0]) | ||
| state_A = paths.CVDefinedVolume(cv, float("-inf"), 0).named("A") | ||
| state_B = paths.CVDefinedVolume(cv, 0, float("inf")).named("B") | ||
| network = paths.TPSNetwork(state_A, state_B).named('tps-network') | ||
| return network | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| from paths_cli.wizard.wizard import Wizard | ||
| from unittest import mock | ||
|
|
||
| def make_mock_wizard(inputs): | ||
| wizard = Wizard([]) | ||
| wizard.console.input = mock.Mock(return_value=inputs) | ||
| return wizard | ||
|
|
||
| def make_mock_retry_wizard(inputs): | ||
| wizard = Wizard([]) | ||
| wizard.console.input = mock.Mock(side_effect=inputs) | ||
| return wizard | ||
|
|
||
| class MockConsole: | ||
| def __init__(self, inputs=None): | ||
| if isinstance(inputs, str): | ||
| inputs = [inputs] | ||
| elif inputs is None: | ||
| inputs = [] | ||
| self.inputs = inputs | ||
| self._input_iter = iter(inputs) | ||
| self.log = [] | ||
| self.width = 80 | ||
| self.input_call_count = 0 | ||
|
|
||
| def print(self, content=""): | ||
| self.log.append(content) | ||
|
|
||
| def input(self, content): | ||
| self.input_call_count += 1 | ||
| try: | ||
| user_input = next(self._input_iter) | ||
| except StopIteration as e: | ||
| print(self.log_text) | ||
| raise e | ||
|
|
||
| self.log.append(content + " " + user_input) | ||
| return user_input | ||
|
|
||
| @property | ||
| def log_text(self): | ||
| return "\n".join(self.log) | ||
|
|
||
| def mock_wizard(inputs): | ||
| wizard = Wizard([]) | ||
| console = MockConsole(inputs) | ||
| wizard.console = console | ||
| return wizard | ||
|
|
||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| import pytest | ||
| from unittest import mock | ||
|
|
||
| from openpathsampling.experimental.storage.collective_variables import \ | ||
| CoordinateFunctionCV | ||
|
|
||
| from paths_cli.wizard.core import * | ||
|
|
||
| from paths_cli.tests.wizard.mock_wizard import ( | ||
| make_mock_wizard, make_mock_retry_wizard | ||
| ) | ||
|
|
||
| @pytest.mark.parametrize('req,expected', [ | ||
| (('foo', 2, 2), '2'), (('foo', 2, float('inf')), 'at least 2'), | ||
| (('foo', 0, 2), 'at most 2'), | ||
| (('foo', 1, 3), 'at least 1 and at most 3') | ||
| ]) | ||
| def test_interpret_req(req, expected): | ||
| assert interpret_req(req) == expected | ||
|
|
||
| @pytest.mark.parametrize('length,expected', [ | ||
| (0, 'foo'), (1, 'baz'), (2, 'quux'), | ||
| ]) | ||
| def test_get_missing_object(length, expected): | ||
| dct = dict([('bar', 'baz'), ('qux', 'quux')][:length]) | ||
| fallback = lambda x: 'foo' | ||
| wizard = make_mock_wizard('2') | ||
| result = get_missing_object(wizard, dct, display_name='string', | ||
| fallback_func=fallback) | ||
| assert result == expected |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.