imdclient 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. imdclient/{IMDREADER.py → IMD.py} +16 -15
  2. imdclient/IMDClient.py +146 -71
  3. imdclient/data/gromacs/md/gromacs_v3_nst8.mdp +58 -0
  4. imdclient/data/lammps/md/{lammps_v3.in → lammps_v3_nst_1.in} +3 -3
  5. imdclient/data/lammps/md/lammps_v3_nst_8.in +71 -0
  6. imdclient/data/namd/md/{namd_v3.namd → namd_v3_nst_1.namd} +17 -5
  7. imdclient/data/namd/md/namd_v3_nst_8.namd +59 -0
  8. imdclient/tests/base.py +133 -45
  9. imdclient/tests/conftest.py +14 -10
  10. imdclient/tests/datafiles.py +17 -9
  11. imdclient/tests/docker_testing/docker.md +25 -0
  12. imdclient/tests/test_gromacs.py +32 -10
  13. imdclient/tests/test_imdclient.py +51 -0
  14. imdclient/tests/test_imdreader.py +20 -6
  15. imdclient/tests/test_lammps.py +57 -12
  16. imdclient/tests/test_manual.py +52 -29
  17. imdclient/tests/test_namd.py +101 -14
  18. imdclient/tests/test_stream_analysis.py +2 -2
  19. imdclient/tests/utils.py +0 -1
  20. imdclient/utils.py +8 -8
  21. imdclient-0.1.3.dist-info/LICENSE +5 -0
  22. {imdclient-0.1.1.dist-info → imdclient-0.1.3.dist-info}/METADATA +21 -32
  23. imdclient-0.1.3.dist-info/RECORD +42 -0
  24. {imdclient-0.1.1.dist-info → imdclient-0.1.3.dist-info}/WHEEL +1 -1
  25. imdclient/data/gromacs/md/gromacs_v3_nst1.tpr +0 -0
  26. imdclient/data/gromacs/md/gromacs_v3_nst1.trr +0 -0
  27. imdclient/data/lammps/md/lammps_trj.h5md +0 -0
  28. imdclient/data/namd/md/alanin.dcd +0 -0
  29. imdclient-0.1.1.dist-info/LICENSE +0 -21
  30. imdclient-0.1.1.dist-info/RECORD +0 -42
  31. {imdclient-0.1.1.dist-info → imdclient-0.1.3.dist-info}/AUTHORS.md +0 -0
  32. {imdclient-0.1.1.dist-info → imdclient-0.1.3.dist-info}/top_level.txt +0 -0
imdclient/tests/base.py CHANGED
@@ -1,4 +1,5 @@
1
1
  from imdclient.IMDClient import IMDClient
2
+ from imdclient.IMD import IMDReader
2
3
  import pytest
3
4
  from pathlib import Path
4
5
  import os
@@ -9,8 +10,11 @@ from numpy.testing import (
9
10
  assert_allclose,
10
11
  )
11
12
  import numpy as np
12
-
13
+ import docker
13
14
  import logging
15
+ import shutil
16
+ import MDAnalysis as mda
17
+ from .utils import get_free_port
14
18
 
15
19
  logger = logging.getLogger("imdclient.IMDClient")
16
20
 
@@ -61,62 +65,146 @@ def assert_allclose_with_logging(a, b, rtol=1e-07, atol=0, equal_nan=False):
61
65
  class IMDv3IntegrationTest:
62
66
 
63
67
  @pytest.fixture()
64
- def run_sim_and_wait(self, tmp_path, command, match_string):
65
- old_cwd = Path.cwd()
66
- os.chdir(tmp_path)
67
- p = subprocess.Popen(
68
- command,
69
- stdout=subprocess.PIPE,
70
- stderr=subprocess.STDOUT,
71
- shell=True,
72
- text=True,
73
- bufsize=0,
74
- preexec_fn=os.setsid,
68
+ def setup_command(self):
69
+ return None
70
+
71
+ @pytest.fixture()
72
+ def port(self):
73
+ yield get_free_port()
74
+
75
+ @pytest.fixture()
76
+ def docker_client(
77
+ self,
78
+ tmp_path,
79
+ input_files,
80
+ setup_command,
81
+ simulation_command,
82
+ port,
83
+ ):
84
+ # In CI, container process needs access to tmp_path
85
+ tmp_path.chmod(0o777)
86
+ docker_client = docker.from_env()
87
+ img = docker_client.images.pull(
88
+ "ghcr.io/becksteinlab/streaming-md-docker:main-Common-CPU"
89
+ )
90
+ # Copy input files into tmp_path
91
+ for inp in input_files:
92
+ shutil.copy(inp, tmp_path)
93
+
94
+ cmdstring = "cd '/tmp'"
95
+ # Run the setup command, if any
96
+ if setup_command is not None:
97
+ # This should be blocking
98
+ cmdstring += " && " + setup_command
99
+
100
+ cmdstring += " && " + simulation_command
101
+
102
+ # Start the container, mount tmp_path, run simulation
103
+ container = docker_client.containers.run(
104
+ img,
105
+ f"/bin/sh -c '{cmdstring}'",
106
+ detach=True,
107
+ volumes={tmp_path.as_posix(): {"bind": "/tmp", "mode": "rw"}},
108
+ ports={"8888/tcp": port},
109
+ name="sim",
110
+ remove=True,
75
111
  )
76
- t = time.time()
77
112
 
78
- for stdout_line in iter(p.stdout.readline, ""):
79
- logger.debug(f"stdout: {stdout_line}")
80
- if match_string in stdout_line:
113
+ # For now, just wait 30 seconds
114
+ # life is too short to figure out how to redirect all stdout from inside
115
+ # a container
116
+ time.sleep(30)
117
+
118
+ yield
119
+ try:
120
+ container.stop()
121
+ except docker.errors.NotFound:
122
+ pass
123
+
124
+ @pytest.fixture()
125
+ def imd_u(self, docker_client, topol, tmp_path, port):
126
+ u = mda.Universe((tmp_path / topol), f"imd://localhost:{port}")
127
+ with mda.Writer(
128
+ (tmp_path / "imd.trr").as_posix(), u.trajectory.n_atoms
129
+ ) as w:
130
+ for ts in u.trajectory:
131
+ w.write(u.atoms)
132
+ yield mda.Universe((tmp_path / topol), (tmp_path / "imd.trr"))
133
+
134
+ @pytest.fixture()
135
+ def true_u(self, topol, traj, imd_u, tmp_path):
136
+ u = mda.Universe(
137
+ (tmp_path / topol),
138
+ (tmp_path / traj),
139
+ )
140
+ yield u
81
141
 
82
- break
83
- if time.time() - t > 10:
84
- raise TimeoutError("Timeout waiting for match string")
142
+ @pytest.fixture()
143
+ def comp_time(self):
144
+ return True
85
145
 
86
- logger.debug("Match string found")
87
- yield p
88
- os.chdir(old_cwd)
89
- os.killpg(os.getpgid(p.pid), signal.SIGTERM)
146
+ @pytest.fixture()
147
+ def comp_dt(self):
148
+ return True
90
149
 
91
150
  @pytest.fixture()
92
- def client(self, run_sim_and_wait, universe):
93
- client = IMDClient("localhost", 8888, universe.trajectory.n_atoms)
94
- yield client
95
- client.stop()
96
-
97
- def test_compare_imd_to_true_traj(self, universe, client, first_frame):
98
- imdsinfo = client.get_imdsessioninfo()
99
-
100
- for ts in universe.trajectory[first_frame:]:
101
- imdf = client.get_imdframe()
102
- if imdsinfo.time:
103
- assert_allclose(imdf.time, ts.time, atol=1e-03)
104
- assert_allclose(imdf.step, ts.data["step"])
105
- if imdsinfo.box:
151
+ def comp_step(self):
152
+ return True
153
+
154
+ def test_compare_imd_to_true_traj(
155
+ self, imd_u, true_u, first_frame, comp_time, comp_dt, comp_step
156
+ ):
157
+ for i in range(first_frame, len(true_u.trajectory)):
158
+ if comp_time:
159
+ assert_allclose(
160
+ true_u.trajectory[i].time,
161
+ imd_u.trajectory[i - first_frame].time,
162
+ atol=1e-03,
163
+ )
164
+ if comp_dt:
165
+ assert_allclose(
166
+ true_u.trajectory[i].dt,
167
+ imd_u.trajectory[i - first_frame].dt,
168
+ atol=1e-03,
169
+ )
170
+ if comp_step:
171
+ assert_allclose(
172
+ true_u.trajectory[i].data["step"],
173
+ imd_u.trajectory[i - first_frame].data["step"],
174
+ )
175
+ if (
176
+ true_u.trajectory[i].dimensions is not None
177
+ and imd_u.trajectory[i - first_frame].dimensions is not None
178
+ ):
106
179
  assert_allclose_with_logging(
107
- imdf.box,
108
- ts.triclinic_dimensions,
180
+ true_u.trajectory[i].dimensions,
181
+ imd_u.trajectory[i - first_frame].dimensions,
109
182
  atol=1e-03,
110
183
  )
111
- if imdsinfo.positions:
184
+ if (
185
+ true_u.trajectory[i].has_positions
186
+ and imd_u.trajectory[i - first_frame].has_positions
187
+ ):
112
188
  assert_allclose_with_logging(
113
- imdf.positions, ts.positions, atol=1e-03
189
+ true_u.trajectory[i].positions,
190
+ imd_u.trajectory[i - first_frame].positions,
191
+ atol=1e-03,
114
192
  )
115
- if imdsinfo.velocities:
193
+ if (
194
+ true_u.trajectory[i].has_velocities
195
+ and imd_u.trajectory[i - first_frame].has_velocities
196
+ ):
116
197
  assert_allclose_with_logging(
117
- imdf.velocities, ts.velocities, atol=1e-03
198
+ true_u.trajectory[i].velocities,
199
+ imd_u.trajectory[i - first_frame].velocities,
200
+ atol=1e-03,
118
201
  )
119
- if imdsinfo.forces:
202
+ if (
203
+ true_u.trajectory[i].has_forces
204
+ and imd_u.trajectory[i - first_frame].has_forces
205
+ ):
120
206
  assert_allclose_with_logging(
121
- imdf.forces, ts.forces, atol=1e-03
207
+ true_u.trajectory[i].forces,
208
+ imd_u.trajectory[i - first_frame].forces,
209
+ atol=1e-03,
122
210
  )
@@ -6,33 +6,37 @@ Global pytest fixtures
6
6
  # Command line arguments for 'test_manual.py'
7
7
  def pytest_addoption(parser):
8
8
  parser.addoption(
9
- "--topol_arg",
9
+ "--topol_path_arg",
10
10
  action="store",
11
+ default=None,
11
12
  )
12
13
  parser.addoption(
13
- "--traj_arg",
14
+ "--traj_path_arg",
14
15
  action="store",
16
+ default=None,
17
+ )
18
+ parser.addoption(
19
+ "--first_frame_arg", action="store", type=int, default=None
15
20
  )
16
- parser.addoption("--first_frame_arg", action="store", type=int)
17
21
 
18
22
 
19
23
  def pytest_generate_tests(metafunc):
20
24
  # This is called for every test. Only get/set command line arguments
21
25
  # if the argument is specified in the list of test "fixturenames".
22
- topol = metafunc.config.option.topol_arg
23
- traj = metafunc.config.option.traj_arg
26
+ topol = metafunc.config.option.topol_path_arg
27
+ traj = metafunc.config.option.traj_path_arg
24
28
  first_frame = metafunc.config.option.first_frame_arg
25
29
 
26
30
  if all(
27
31
  arg in metafunc.fixturenames
28
- for arg in ["topol_arg", "traj_arg", "first_frame_arg"]
32
+ for arg in ["topol_path_arg", "traj_path_arg", "first_frame_arg"]
29
33
  ):
30
34
  if topol is None or traj is None or first_frame is None:
31
35
  raise ValueError(
32
- "Must pass all three of '--topol_arg <path/to/topology>', "
33
- + "'--traj_arg <path/to/trajectory>', "
36
+ "Must pass all three of '--topol_path_arg <path/to/topology>', "
37
+ + "'--traj_path_arg <path/to/trajectory>', "
34
38
  + "'--first_frame_arg <first traj frame to compare to IMD>"
35
39
  )
36
- metafunc.parametrize("topol_arg", [topol])
37
- metafunc.parametrize("traj_arg", [traj])
40
+ metafunc.parametrize("topol_path_arg", [topol])
41
+ metafunc.parametrize("traj_path_arg", [traj])
38
42
  metafunc.parametrize("first_frame_arg", [first_frame])
@@ -16,18 +16,26 @@ from pathlib import Path
16
16
  _data_ref = resources.files("imdclient.data")
17
17
 
18
18
  LAMMPS_TOPOL = (_data_ref / "lammps" / "md" / "lammps_topol.data").as_posix()
19
- LAMMPS_IN = (_data_ref / "lammps" / "md" / "lammps_v3.in").as_posix()
20
- LAMMPS_TRAJ = (_data_ref / "lammps" / "md" / "lammps_trj.h5md").as_posix()
21
- GROMACS_TRAJ = (
22
- _data_ref / "gromacs" / "md" / "gromacs_v3_nst1.trr"
19
+ LAMMPS_IN_NST_1 = (
20
+ _data_ref / "lammps" / "md" / "lammps_v3_nst_1.in"
23
21
  ).as_posix()
24
- GROMACS_TOPOL = (
25
- _data_ref / "gromacs" / "md" / "gromacs_struct.gro"
22
+ LAMMPS_IN_NST_8 = (
23
+ _data_ref / "lammps" / "md" / "lammps_v3_nst_8.in"
26
24
  ).as_posix()
27
- GROMACS_TPR = (_data_ref / "gromacs" / "md" / "gromacs_v3_nst1.tpr").as_posix()
25
+
26
+
27
+ GROMACS_GRO = (_data_ref / "gromacs" / "md" / "gromacs_struct.gro").as_posix()
28
+ GROMACS_MDP_NST_1 = (
29
+ _data_ref / "gromacs" / "md" / "gromacs_v3_nst1.mdp"
30
+ ).as_posix()
31
+ GROMACS_MDP_NST_8 = (
32
+ _data_ref / "gromacs" / "md" / "gromacs_v3_nst8.mdp"
33
+ ).as_posix()
34
+ GROMACS_TOP = (_data_ref / "gromacs" / "md" / "gromacs_v3.top").as_posix()
35
+
28
36
  NAMD_TOPOL = (_data_ref / "namd" / "md" / "alanin.pdb").as_posix()
29
- NAMD_CONF = (_data_ref / "namd" / "md" / "namd_v3.namd").as_posix()
30
- NAMD_TRAJ = (_data_ref / "namd" / "md" / "alanin.dcd").as_posix()
37
+ NAMD_CONF_NST_1 = (_data_ref / "namd" / "md" / "namd_v3_nst_1.namd").as_posix()
38
+ NAMD_CONF_NST_8 = (_data_ref / "namd" / "md" / "namd_v3_nst_8.namd").as_posix()
31
39
  NAMD_PARAMS = (_data_ref / "namd" / "md" / "alanin.params").as_posix()
32
40
  NAMD_PSF = (_data_ref / "namd" / "md" / "alanin.psf").as_posix()
33
41
 
@@ -0,0 +1,25 @@
1
+ # Running simulation engines compiled for GPU acceleration from a container
2
+
3
+ Ensure [docker](https://www.docker.com/) and the [NVIDIA container toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html) are installed.
4
+
5
+
6
+ To run the container:
7
+ ```bash
8
+ docker pull ghcr.io/becksteinlab/streaming-md-docker:main-Common-GPU
9
+
10
+ docker run -v $PWD/imdclient/data:/home/conda:rw -it --runtime=nvidia --gpus=all \
11
+ ghcr.io/becksteinlab/streaming-md-docker:main-Common-GPU
12
+ ```
13
+
14
+ To run each simulation engine with repository simulation configurations:
15
+ ```bash
16
+ cd /home/conda/namd/md
17
+ namd3 +devices 0 namd_v3.namd
18
+
19
+ cd /home/conda/gromacs/md
20
+ gmx grompp -f gromacs_v3_nst1.mdp -c gromacs_struct.gro -p gromacs_v3.top
21
+ gmx mdrun -s topol.tpr -nb gpu
22
+
23
+ cd /home/conda/lammps/md
24
+ lmp -sf gpu < lammps_v3_nst_1.in
25
+ ```
@@ -2,10 +2,16 @@ import MDAnalysis as mda
2
2
  import pytest
3
3
  import logging
4
4
  from .base import IMDv3IntegrationTest
5
- from .datafiles import GROMACS_TOPOL, GROMACS_TRAJ, GROMACS_TPR
5
+ from .datafiles import (
6
+ GROMACS_GRO,
7
+ GROMACS_TOP,
8
+ GROMACS_MDP_NST_1,
9
+ GROMACS_MDP_NST_8,
10
+ )
11
+ from pathlib import Path
6
12
 
7
13
  logger = logging.getLogger("imdclient.IMDClient")
8
- file_handler = logging.FileHandler("test.log")
14
+ file_handler = logging.FileHandler("gromacs_test.log")
9
15
  formatter = logging.Formatter(
10
16
  "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
11
17
  )
@@ -16,18 +22,34 @@ logger.setLevel(logging.DEBUG)
16
22
 
17
23
  class TestIMDv3Gromacs(IMDv3IntegrationTest):
18
24
 
25
+ @pytest.fixture(params=[GROMACS_MDP_NST_1, GROMACS_MDP_NST_8])
26
+ def mdp(self, request):
27
+ return request.param
28
+
19
29
  @pytest.fixture()
20
- def command(self):
21
- return f". /usr/local/gromacs/bin/GMXRC && gmx mdrun -s {GROMACS_TPR} -imdport 8888 -imdwait"
30
+ def setup_command(self, mdp):
31
+ return f"gmx grompp -f {Path(mdp).name} -c {Path(GROMACS_GRO).name} -p {Path(GROMACS_TOP).name} -o topol.tpr"
22
32
 
23
33
  @pytest.fixture()
24
- def match_string(self):
25
- return "IMD: Will wait until I have a connection and IMD_GO orders."
34
+ def simulation_command(self):
35
+ return f"gmx mdrun -s topol.tpr -o ci.trr -imdport 8888 -imdwait"
26
36
 
27
37
  @pytest.fixture()
28
- def first_frame(self):
29
- return 0
38
+ def input_files(self, mdp):
39
+ return [GROMACS_TOP, mdp, GROMACS_GRO]
40
+
41
+ @pytest.fixture()
42
+ def traj(self):
43
+ return "ci.trr"
30
44
 
31
45
  @pytest.fixture()
32
- def universe(self):
33
- return mda.Universe(GROMACS_TOPOL, GROMACS_TRAJ)
46
+ def topol(self):
47
+ return Path(GROMACS_GRO).name
48
+
49
+ # @pytest.fixture()
50
+ # def match_string(self):
51
+ # return "IMD: Will wait until I have a connection and IMD_GO orders."
52
+
53
+ @pytest.fixture()
54
+ def first_frame(self):
55
+ return 0
@@ -148,3 +148,54 @@ class TestIMDClientV3:
148
148
  client.get_imdframe()
149
149
  # server should receive disconnect from client (though it doesn't have to do anything)
150
150
  server.expect_packet(IMDHeaderType.IMD_DISCONNECT)
151
+
152
+
153
+ class TestIMDClientV3ContextManager:
154
+ @pytest.fixture
155
+ def port(self):
156
+ return get_free_port()
157
+
158
+ @pytest.fixture
159
+ def universe(self):
160
+ return mda.Universe(COORDINATES_TOPOLOGY, COORDINATES_H5MD)
161
+
162
+ @pytest.fixture
163
+ def imdsinfo(self):
164
+ return create_default_imdsinfo_v3()
165
+
166
+ @pytest.fixture
167
+ def server(self, universe, imdsinfo, port):
168
+ server = InThreadIMDServer(universe.trajectory)
169
+ server.set_imdsessioninfo(imdsinfo)
170
+ yield server
171
+ server.cleanup()
172
+
173
+ def test_context_manager_traj_unchanged(self, server, port, universe):
174
+ server.handshake_sequence("localhost", port, first_frame=False)
175
+
176
+ i = 0
177
+ with IMDClient(
178
+ "localhost",
179
+ port,
180
+ universe.trajectory.n_atoms,
181
+ ) as client:
182
+ server.send_frames(0, 5)
183
+ while i < 5:
184
+
185
+ imdf = client.get_imdframe()
186
+ assert_allclose(universe.trajectory[i].time, imdf.time)
187
+ assert_allclose(universe.trajectory[i].dt, imdf.dt)
188
+ assert_allclose(universe.trajectory[i].data["step"], imdf.step)
189
+ assert_allclose(
190
+ universe.trajectory[i].positions, imdf.positions
191
+ )
192
+ assert_allclose(
193
+ universe.trajectory[i].velocities, imdf.velocities
194
+ )
195
+ assert_allclose(universe.trajectory[i].forces, imdf.forces)
196
+ assert_allclose(
197
+ universe.trajectory[i].triclinic_dimensions, imdf.box
198
+ )
199
+ i += 1
200
+ server.expect_packet(IMDHeaderType.IMD_DISCONNECT)
201
+ assert i == 5
@@ -31,7 +31,7 @@ import pytest
31
31
  from MDAnalysis.transformations import translate
32
32
  import pickle
33
33
 
34
- from imdclient.IMDREADER import IMDReader
34
+ from imdclient.IMD import IMDReader
35
35
 
36
36
  logger = logging.getLogger("imdclient.IMDClient")
37
37
  file_handler = logging.FileHandler("test.log")
@@ -55,7 +55,7 @@ class IMDReference(BaseReference):
55
55
  self.n_atoms = traj.n_atoms
56
56
  self.prec = 3
57
57
 
58
- self.trajectory = f"localhost:{self.port}"
58
+ self.trajectory = f"imd://localhost:{self.port}"
59
59
  self.topology = COORDINATES_TOPOLOGY
60
60
  self.changing_dimensions = True
61
61
  self.reader = IMDReader
@@ -171,9 +171,7 @@ class TestIMDReaderBaseAPI(MultiframeReaderTest):
171
171
  decimal=ref.prec,
172
172
  )
173
173
 
174
- @pytest.mark.skip(
175
- reason="Stream-based reader can only be read iteratively"
176
- )
174
+ @pytest.mark.skip(reason="Stream-based reader can only be read iteratively")
177
175
  def test_changing_dimensions(self, ref, reader):
178
176
  if ref.changing_dimensions:
179
177
  reader.rewind()
@@ -585,7 +583,7 @@ class TestStreamIteration:
585
583
  server.set_imdsessioninfo(imdsinfo)
586
584
  server.handshake_sequence("localhost", port, first_frame=True)
587
585
  reader = IMDReader(
588
- f"localhost:{port}",
586
+ f"imd://localhost:{port}",
589
587
  n_atoms=universe.trajectory.n_atoms,
590
588
  )
591
589
  server.send_frames(1, 5)
@@ -642,3 +640,19 @@ class TestStreamIteration:
642
640
  with pytest.raises(RuntimeError):
643
641
  for ts in sub_sliced_reader:
644
642
  pass
643
+
644
+
645
+ def test_n_atoms_mismatch():
646
+ universe = mda.Universe(COORDINATES_TOPOLOGY, COORDINATES_H5MD)
647
+ port = get_free_port()
648
+ server = InThreadIMDServer(universe.trajectory)
649
+ server.set_imdsessioninfo(create_default_imdsinfo_v3())
650
+ server.handshake_sequence("localhost", port, first_frame=True)
651
+ with pytest.raises(
652
+ EOFError,
653
+ match="IMDProducer: Expected n_atoms value 6, got 5. Ensure you are using the correct topology file.",
654
+ ):
655
+ IMDReader(
656
+ f"imd://localhost:{port}",
657
+ n_atoms=universe.trajectory.n_atoms + 1,
658
+ )
@@ -1,11 +1,12 @@
1
1
  import MDAnalysis as mda
2
2
  import pytest
3
+ from pathlib import Path
3
4
  import logging
4
5
  from .base import IMDv3IntegrationTest
5
- from .datafiles import LAMMPS_IN, LAMMPS_TOPOL, LAMMPS_TRAJ
6
+ from .datafiles import LAMMPS_TOPOL, LAMMPS_IN_NST_1, LAMMPS_IN_NST_8
6
7
 
7
8
  logger = logging.getLogger("imdclient.IMDClient")
8
- file_handler = logging.FileHandler("test.log")
9
+ file_handler = logging.FileHandler("lammps_test.log")
9
10
  formatter = logging.Formatter(
10
11
  "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
11
12
  )
@@ -16,23 +17,67 @@ logger.setLevel(logging.DEBUG)
16
17
 
17
18
  class TestIMDv3Lammps(IMDv3IntegrationTest):
18
19
 
20
+ @pytest.fixture(params=[LAMMPS_IN_NST_1, LAMMPS_IN_NST_8])
21
+ def inp(self, request):
22
+ return request.param
23
+
24
+ @pytest.fixture()
25
+ def simulation_command(self, inp):
26
+ return f"lmp < {Path(inp).name}"
27
+
28
+ @pytest.fixture()
29
+ def topol(self):
30
+ return Path(LAMMPS_TOPOL).name
31
+
32
+ @pytest.fixture()
33
+ def traj(self):
34
+ return "lammps_trj.h5md"
35
+
19
36
  @pytest.fixture()
20
- def command(self):
21
- return f"lmp < {LAMMPS_IN}"
37
+ def input_files(self, inp):
38
+ return [inp, LAMMPS_TOPOL]
39
+
40
+ # @pytest.fixture()
41
+ # def match_string(self):
42
+ # return "Waiting for IMD connection on port 8888"
22
43
 
23
44
  @pytest.fixture()
24
- def match_string(self):
25
- return "Waiting for IMD connection on port 8888"
45
+ def first_frame(self, inp):
46
+ if inp == LAMMPS_IN_NST_1:
47
+ return 1
48
+ else:
49
+ return 0
26
50
 
51
+ # Not present in lammps-produced H5MD
27
52
  @pytest.fixture()
28
- def first_frame(self):
29
- return 1
53
+ def comp_dt(self):
54
+ return False
30
55
 
56
+ # This must wait until after imd stream has ended
31
57
  @pytest.fixture()
32
- def universe(self):
33
- return mda.Universe(
34
- LAMMPS_TOPOL,
35
- LAMMPS_TRAJ,
58
+ def true_u(self, topol, traj, imd_u, tmp_path):
59
+ u = mda.Universe(
60
+ (tmp_path / topol),
61
+ (tmp_path / traj),
36
62
  atom_style="id type x y z",
37
63
  convert_units=False,
38
64
  )
65
+ yield u
66
+
67
+ @pytest.fixture()
68
+ def imd_u(self, docker_client, topol, tmp_path, port):
69
+ u = mda.Universe(
70
+ (tmp_path / topol),
71
+ f"imd://localhost:{port}",
72
+ atom_style="id type x y z",
73
+ )
74
+ with mda.Writer(
75
+ (tmp_path / "imd.trr").as_posix(), u.trajectory.n_atoms
76
+ ) as w:
77
+ for ts in u.trajectory:
78
+ w.write(u.atoms)
79
+ yield mda.Universe(
80
+ (tmp_path / topol),
81
+ (tmp_path / "imd.trr"),
82
+ atom_style="id type x y z",
83
+ )