From c29ab43cdb77c9c3c3b9b11e93ecd7ff24f66cbe Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Thu, 4 Jul 2024 12:41:33 -0400 Subject: [PATCH 1/7] New command: Load trajectory --- paths_cli/commands/load_trajectory.py | 51 +++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 paths_cli/commands/load_trajectory.py diff --git a/paths_cli/commands/load_trajectory.py b/paths_cli/commands/load_trajectory.py new file mode 100644 index 0000000..c9087ef --- /dev/null +++ b/paths_cli/commands/load_trajectory.py @@ -0,0 +1,51 @@ +import click + +import paths_cli.utils +from paths_cli.parameters import APPEND_FILE, ENGINE, MULTI_TAG +from paths_cli import OPSCommandPlugin + + +@click.command( + "load-trajectory", + short_help="Load an external trajectory file", +) +@click.argument('traj_file') +@click.option( + '--top', + help=( + "Topology information (typically PDB). Only for required " + "formats." + ), + default=None, +) +@APPEND_FILE.clicked(required=True) +@MULTI_TAG.clicked() +def load_trajectory(traj_file, top, append, tag): + """Load a trajectory from a file. + + This uses MDTraj under the hood, and can load any file format that + MDTraj can. NB: This stores in a format based on OpenMM snapshots. + Trajectories loaded this way will work with engines compatible with + that input (e.g., GROMACS). + """ + import mdtraj as md + from openpathsampling.engines.openmm.tools import ops_load_trajectory + traj = ops_load_trajectory(traj_file, top=top) + storage = append.get() + storage.save(traj) + for tag_name in tag: + storage.tags[tag_name] = traj + + + # tests: + # * check that we load PDB + # * check that if we load PDB with top as well works + # * check that we can load trr / xtc files (only with top) + # * maybe check for error if top doesn't match traj file? (atom numbers) + +PLUGIN = OPSCommandPlugin( + command=load_trajectory, + section="Miscellaneous", + requires_ops=(1, 6), + requires_cli=(0, 4), +) From 2df9112a49d6578d5954a348e6a88fd74ce38898 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Sat, 6 Jul 2024 17:57:44 -0500 Subject: [PATCH 2/7] fix up load trajectory so it works --- paths_cli/commands/load_trajectory.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/paths_cli/commands/load_trajectory.py b/paths_cli/commands/load_trajectory.py index c9087ef..ca9b127 100644 --- a/paths_cli/commands/load_trajectory.py +++ b/paths_cli/commands/load_trajectory.py @@ -13,14 +13,14 @@ @click.option( '--top', help=( - "Topology information (typically PDB). Only for required " + "Topology file (typically PDB). Only for required " "formats." ), default=None, ) @APPEND_FILE.clicked(required=True) @MULTI_TAG.clicked() -def load_trajectory(traj_file, top, append, tag): +def load_trajectory(traj_file, top, append_file, tag): """Load a trajectory from a file. This uses MDTraj under the hood, and can load any file format that @@ -31,7 +31,7 @@ def load_trajectory(traj_file, top, append, tag): import mdtraj as md from openpathsampling.engines.openmm.tools import ops_load_trajectory traj = ops_load_trajectory(traj_file, top=top) - storage = append.get() + storage = APPEND_FILE.get(append_file) storage.save(traj) for tag_name in tag: storage.tags[tag_name] = traj From 41b79f45680fe68f8107af9f32c571b3228cc2c1 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Wed, 21 Aug 2024 17:45:41 -0500 Subject: [PATCH 3/7] some cleanup for load_trajectory --- paths_cli/commands/load_trajectory.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/paths_cli/commands/load_trajectory.py b/paths_cli/commands/load_trajectory.py index ca9b127..9b4567a 100644 --- a/paths_cli/commands/load_trajectory.py +++ b/paths_cli/commands/load_trajectory.py @@ -28,9 +28,12 @@ def load_trajectory(traj_file, top, append_file, tag): Trajectories loaded this way will work with engines compatible with that input (e.g., GROMACS). """ - import mdtraj as md from openpathsampling.engines.openmm.tools import ops_load_trajectory - traj = ops_load_trajectory(traj_file, top=top) + if top: + traj = ops_load_trajectory(traj_file, top=top) + else: + traj = ops_load_trajectory(traj_file) + storage = APPEND_FILE.get(append_file) storage.save(traj) for tag_name in tag: From b61f83123f5483bf15484c9421acd6e71c1bf622 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Wed, 21 Aug 2024 22:45:03 -0500 Subject: [PATCH 4/7] run load_trajectory from module --- paths_cli/commands/load_trajectory.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/paths_cli/commands/load_trajectory.py b/paths_cli/commands/load_trajectory.py index 9b4567a..6901a8a 100644 --- a/paths_cli/commands/load_trajectory.py +++ b/paths_cli/commands/load_trajectory.py @@ -52,3 +52,6 @@ def load_trajectory(traj_file, top, append_file, tag): requires_ops=(1, 6), requires_cli=(0, 4), ) + +if __name__ == "__main__": # -no-cov- + load_trajectory() From 128301dd714cad82b808a2bd0b2d201e4ebea822 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Sun, 25 Aug 2024 06:15:43 +0200 Subject: [PATCH 5/7] Add tests for load_trajectory --- .../tests/commands/test_load_trajectory.py | 83 +++++++++++++++++++ 1 file changed, 83 insertions(+) create mode 100644 paths_cli/tests/commands/test_load_trajectory.py diff --git a/paths_cli/tests/commands/test_load_trajectory.py b/paths_cli/tests/commands/test_load_trajectory.py new file mode 100644 index 0000000..db6dc29 --- /dev/null +++ b/paths_cli/tests/commands/test_load_trajectory.py @@ -0,0 +1,83 @@ +from click.testing import CliRunner +from contextlib import contextmanager +import pytest +from importlib import resources +from openpathsampling.tests.test_helpers import data_filename +import openpathsampling as paths + +from paths_cli.commands.load_trajectory import * + + +@contextmanager +def run_load_trajectory(args): + runner = CliRunner() + with runner.isolated_filesystem(): + storage = paths.Storage("setup.nc", 'w') + storage.close() + results = runner.invoke( + load_trajectory, + args + ) + assert results.exit_code == 0 + st = paths.Storage("setup.nc", mode='r') + assert len(st.trajectories) == 1 + yield st + + +@pytest.mark.parametrize("with_top", [True, False]) +@pytest.mark.parametrize("with_tag", [True, False]) +def test_load_trajectory_pdb(with_top, with_tag): + # test that we can load a PDB file with or without topology; also tests + # that the taging works correctly + pdb_path = data_filename("ala_small_traj.pdb") + out_file = "setup.nc" + args = [ + pdb_path, + '--append-file', out_file, + ] + if with_top: + args.extend(['--top', pdb_path]) + + if with_tag: + args.extend(['--tag', 'init_snap']) + + with run_load_trajectory(args) as st: + traj = st.trajectories[0] + assert len(traj) == 10 + if with_tag: + tagged = st.tags['init_snap'] + assert tagged == traj + +def test_load_trajectory_trr(): + trr = data_filename("gromacs_engine/project_trr/0000000.trr") + gro = data_filename("gromacs_engine/conf.gro") + out_file = "setup.nc" + args = [ + trr, + '--append-file', out_file, + '--top', gro, + ] + with run_load_trajectory(args) as st: + traj = st.trajectories[0] + assert len(traj) == 4 + +def test_load_trajectory_bad_topology(): + trr = data_filename("gromacs_engine/project_trr/0000000.trr") + pdb = data_filename("tip4p_water.pdb") + out_file = "setup.nc" + args = [ + trr, + '--append-file', out_file, + '--top', pdb, + ] + runner = CliRunner() + with runner.isolated_filesystem(): + storage = paths.Storage("setup.nc", 'w') + storage.close() + result = runner.invoke( + load_trajectory, + args + ) + assert result.exit_code == 1 + assert "topology" in str(result.exception) + assert "same atoms" in str(result.exception) From b5cb4a4f4a515e518516d837d8171da8c0a11043 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Sun, 25 Aug 2024 06:16:05 +0200 Subject: [PATCH 6/7] remove test planning comment --- paths_cli/commands/load_trajectory.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/paths_cli/commands/load_trajectory.py b/paths_cli/commands/load_trajectory.py index 6901a8a..6025b47 100644 --- a/paths_cli/commands/load_trajectory.py +++ b/paths_cli/commands/load_trajectory.py @@ -40,12 +40,6 @@ def load_trajectory(traj_file, top, append_file, tag): storage.tags[tag_name] = traj - # tests: - # * check that we load PDB - # * check that if we load PDB with top as well works - # * check that we can load trr / xtc files (only with top) - # * maybe check for error if top doesn't match traj file? (atom numbers) - PLUGIN = OPSCommandPlugin( command=load_trajectory, section="Miscellaneous", From 9772eef01352d54539fadf2466456d333b571b26 Mon Sep 17 00:00:00 2001 From: "David W.H. Swenson" Date: Sun, 25 Aug 2024 06:21:26 +0200 Subject: [PATCH 7/7] skip tests if OpenMM/MDTraj not installed --- paths_cli/tests/commands/test_load_trajectory.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/paths_cli/tests/commands/test_load_trajectory.py b/paths_cli/tests/commands/test_load_trajectory.py index db6dc29..083b93f 100644 --- a/paths_cli/tests/commands/test_load_trajectory.py +++ b/paths_cli/tests/commands/test_load_trajectory.py @@ -29,6 +29,8 @@ def run_load_trajectory(args): def test_load_trajectory_pdb(with_top, with_tag): # test that we can load a PDB file with or without topology; also tests # that the taging works correctly + pytest.importorskip("openmm") + pytest.importorskip("mdtraj") pdb_path = data_filename("ala_small_traj.pdb") out_file = "setup.nc" args = [ @@ -49,6 +51,8 @@ def test_load_trajectory_pdb(with_top, with_tag): assert tagged == traj def test_load_trajectory_trr(): + pytest.importorskip("openmm") + pytest.importorskip("mdtraj") trr = data_filename("gromacs_engine/project_trr/0000000.trr") gro = data_filename("gromacs_engine/conf.gro") out_file = "setup.nc" @@ -62,6 +66,8 @@ def test_load_trajectory_trr(): assert len(traj) == 4 def test_load_trajectory_bad_topology(): + pytest.importorskip("openmm") + pytest.importorskip("mdtraj") trr = data_filename("gromacs_engine/project_trr/0000000.trr") pdb = data_filename("tip4p_water.pdb") out_file = "setup.nc"