imdclient 0.1.4__py3-none-any.whl → 0.2.0b0__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.
- imdclient/IMDClient.py +24 -22
- imdclient/__init__.py +0 -5
- imdclient/data/namd/md/namd3 +0 -0
- imdclient/data/namd/md/namd_v3_nst_1.namd +1 -1
- imdclient/tests/base.py +82 -103
- imdclient/tests/datafiles.py +1 -1
- imdclient/tests/docker_testing/docker.md +1 -1
- imdclient/tests/hpc_testing/lammps/README.md +2 -2
- imdclient/tests/hpc_testing/namd/README.md +93 -19
- imdclient/tests/minimalreader.py +86 -0
- imdclient/tests/server.py +4 -3
- imdclient/tests/test_gromacs.py +15 -3
- imdclient/tests/test_imdclient.py +8 -7
- imdclient/tests/test_lammps.py +22 -19
- imdclient/tests/test_manual.py +24 -22
- imdclient/tests/test_namd.py +39 -16
- imdclient/tests/test_utils.py +31 -0
- imdclient/utils.py +50 -17
- {imdclient-0.1.4.dist-info → imdclient-0.2.0b0.dist-info}/METADATA +60 -39
- {imdclient-0.1.4.dist-info → imdclient-0.2.0b0.dist-info}/RECORD +24 -28
- {imdclient-0.1.4.dist-info → imdclient-0.2.0b0.dist-info}/WHEEL +1 -1
- {imdclient-0.1.4.dist-info → imdclient-0.2.0b0.dist-info/licenses}/AUTHORS.md +4 -1
- {imdclient-0.1.4.dist-info → imdclient-0.2.0b0.dist-info/licenses}/LICENSE +3 -1
- imdclient/IMD.py +0 -132
- imdclient/backends.py +0 -352
- imdclient/results.py +0 -332
- imdclient/streamanalysis.py +0 -1056
- imdclient/streambase.py +0 -199
- imdclient/tests/test_imdreader.py +0 -717
- imdclient/tests/test_stream_analysis.py +0 -61
- {imdclient-0.1.4.dist-info → imdclient-0.2.0b0.dist-info}/top_level.txt +0 -0
imdclient/tests/test_gromacs.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
-
import MDAnalysis as mda
|
2
|
-
import pytest
|
3
1
|
import logging
|
2
|
+
from pathlib import Path
|
3
|
+
import re
|
4
|
+
|
5
|
+
import pytest
|
6
|
+
|
4
7
|
from .base import IMDv3IntegrationTest
|
5
8
|
from .datafiles import (
|
6
9
|
GROMACS_GRO,
|
@@ -8,7 +11,6 @@ from .datafiles import (
|
|
8
11
|
GROMACS_MDP_NST_1,
|
9
12
|
GROMACS_MDP_NST_8,
|
10
13
|
)
|
11
|
-
from pathlib import Path
|
12
14
|
|
13
15
|
logger = logging.getLogger("imdclient.IMDClient")
|
14
16
|
file_handler = logging.FileHandler("gromacs_test.log")
|
@@ -46,6 +48,16 @@ class TestIMDv3Gromacs(IMDv3IntegrationTest):
|
|
46
48
|
def topol(self):
|
47
49
|
return Path(GROMACS_GRO).name
|
48
50
|
|
51
|
+
@pytest.fixture()
|
52
|
+
def dt(self, mdp):
|
53
|
+
pattern = re.compile(r"^\s*dt\s*=\s*(\S+)")
|
54
|
+
with open(mdp, "r") as file:
|
55
|
+
for line in file:
|
56
|
+
match = pattern.match(line)
|
57
|
+
if match:
|
58
|
+
return float(match.group(1))
|
59
|
+
raise ValueError(f"No dt found in {mdp}")
|
60
|
+
|
49
61
|
# @pytest.fixture()
|
50
62
|
# def match_string(self):
|
51
63
|
# return "IMD: Will wait until I have a connection and IMD_GO orders."
|
@@ -1,10 +1,17 @@
|
|
1
1
|
"""Test for IMDClient functionality"""
|
2
2
|
|
3
|
+
import logging
|
4
|
+
|
5
|
+
import pytest
|
6
|
+
from numpy.testing import (
|
7
|
+
assert_allclose,
|
8
|
+
)
|
9
|
+
import MDAnalysis as mda
|
3
10
|
from MDAnalysisTests.datafiles import (
|
4
11
|
COORDINATES_TOPOLOGY,
|
5
12
|
COORDINATES_H5MD,
|
6
13
|
)
|
7
|
-
|
14
|
+
|
8
15
|
from imdclient.IMDClient import imdframe_memsize, IMDClient
|
9
16
|
from imdclient.IMDProtocol import IMDHeaderType
|
10
17
|
from .utils import (
|
@@ -12,12 +19,6 @@ from .utils import (
|
|
12
19
|
create_default_imdsinfo_v3,
|
13
20
|
)
|
14
21
|
from .server import InThreadIMDServer
|
15
|
-
from MDAnalysisTests.coordinates.base import (
|
16
|
-
assert_allclose,
|
17
|
-
)
|
18
|
-
from MDAnalysisTests.coordinates.test_xdr import TRRReference
|
19
|
-
import logging
|
20
|
-
import pytest
|
21
22
|
|
22
23
|
|
23
24
|
logger = logging.getLogger("imdclient.IMDClient")
|
imdclient/tests/test_lammps.py
CHANGED
@@ -1,7 +1,11 @@
|
|
1
|
-
import MDAnalysis as mda
|
2
|
-
import pytest
|
3
|
-
from pathlib import Path
|
4
1
|
import logging
|
2
|
+
from pathlib import Path
|
3
|
+
import re
|
4
|
+
|
5
|
+
import pytest
|
6
|
+
import MDAnalysis as mda
|
7
|
+
|
8
|
+
from .minimalreader import MinimalReader
|
5
9
|
from .base import IMDv3IntegrationTest
|
6
10
|
from .datafiles import LAMMPS_TOPOL, LAMMPS_IN_NST_1, LAMMPS_IN_NST_8
|
7
11
|
|
@@ -48,10 +52,15 @@ class TestIMDv3Lammps(IMDv3IntegrationTest):
|
|
48
52
|
else:
|
49
53
|
return 0
|
50
54
|
|
51
|
-
# Not present in lammps-produced H5MD
|
52
55
|
@pytest.fixture()
|
53
|
-
def
|
54
|
-
|
56
|
+
def dt(self, inp):
|
57
|
+
pattern = re.compile(r"^\s*timestep\s*(\S+)")
|
58
|
+
with open(inp, "r") as file:
|
59
|
+
for line in file:
|
60
|
+
match = pattern.match(line)
|
61
|
+
if match:
|
62
|
+
return float(match.group(1))
|
63
|
+
raise ValueError(f"No dt found in {inp}")
|
55
64
|
|
56
65
|
# This must wait until after imd stream has ended
|
57
66
|
@pytest.fixture()
|
@@ -66,18 +75,12 @@ class TestIMDv3Lammps(IMDv3IntegrationTest):
|
|
66
75
|
|
67
76
|
@pytest.fixture()
|
68
77
|
def imd_u(self, docker_client, topol, tmp_path, port):
|
69
|
-
|
70
|
-
|
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"),
|
78
|
+
n_atoms = mda.Universe(
|
79
|
+
tmp_path / topol,
|
82
80
|
atom_style="id type x y z",
|
81
|
+
convert_units=False,
|
82
|
+
).atoms.n_atoms
|
83
|
+
u = MinimalReader(
|
84
|
+
f"imd://localhost:{port}", n_atoms=n_atoms, process_stream=True
|
83
85
|
)
|
86
|
+
yield u
|
imdclient/tests/test_manual.py
CHANGED
@@ -1,5 +1,4 @@
|
|
1
|
-
import
|
2
|
-
from imdclient.IMD import IMDReader
|
1
|
+
from .minimalreader import MinimalReader
|
3
2
|
import MDAnalysis as mda
|
4
3
|
from numpy.testing import assert_allclose
|
5
4
|
import numpy as np
|
@@ -91,17 +90,15 @@ def load_true_universe(topol_path, traj_path):
|
|
91
90
|
|
92
91
|
def load_imd_universe(topol_path, tmp_path):
|
93
92
|
# Pass atom_style (ignored if not using LAMMPS topol)
|
94
|
-
|
93
|
+
n_atoms = mda.Universe(
|
95
94
|
topol_path,
|
96
|
-
"imd://localhost:8888",
|
97
95
|
atom_style="id type x y z",
|
96
|
+
convert_units=False,
|
97
|
+
).atoms.n_atoms
|
98
|
+
tmp_u = MinimalReader(
|
99
|
+
f"imd://localhost:8888", n_atoms=n_atoms, process_stream=True
|
98
100
|
)
|
99
|
-
|
100
|
-
with mda.Writer(tmp_traj_file, tmp_u.atoms.n_atoms) as w:
|
101
|
-
for ts in tmp_u.trajectory:
|
102
|
-
w.write(tmp_u.atoms)
|
103
|
-
time.sleep(10) # Give MPI ranks a chance to release FD
|
104
|
-
return mda.Universe(topol_path, tmp_traj_file, atom_style="id type x y z")
|
101
|
+
return tmp_u
|
105
102
|
|
106
103
|
|
107
104
|
def test_compare_imd_to_true_traj_vel(imd_u, true_u_vel, first_frame):
|
@@ -123,23 +120,27 @@ def test_compare_imd_to_true_traj_forces(imd_u, true_u_force, first_frame):
|
|
123
120
|
)
|
124
121
|
|
125
122
|
|
126
|
-
def test_compare_imd_to_true_traj(
|
123
|
+
def test_compare_imd_to_true_traj(
|
124
|
+
imd_u, true_u, first_frame, vel, force, dt, step
|
125
|
+
):
|
127
126
|
for i in range(first_frame, len(true_u.trajectory)):
|
128
127
|
assert_allclose(
|
129
128
|
true_u.trajectory[i].time,
|
130
129
|
imd_u.trajectory[i - first_frame].time,
|
131
130
|
atol=1e-03,
|
132
131
|
)
|
133
|
-
|
132
|
+
# Issue #63
|
133
|
+
# if dt:
|
134
|
+
# assert_allclose(
|
135
|
+
# true_u.trajectory[i].dt,
|
136
|
+
# imd_u.trajectory[i - first_frame].dt,
|
137
|
+
# atol=1e-03,
|
138
|
+
# )
|
139
|
+
if step:
|
134
140
|
assert_allclose(
|
135
|
-
true_u.trajectory[i].
|
136
|
-
imd_u.trajectory[i - first_frame].
|
137
|
-
atol=1e-03,
|
141
|
+
true_u.trajectory[i].data["step"],
|
142
|
+
imd_u.trajectory[i - first_frame].data["step"],
|
138
143
|
)
|
139
|
-
assert_allclose(
|
140
|
-
true_u.trajectory[i].data["step"],
|
141
|
-
imd_u.trajectory[i - first_frame].data["step"],
|
142
|
-
)
|
143
144
|
assert_allclose_with_logging(
|
144
145
|
true_u.trajectory[i].dimensions,
|
145
146
|
imd_u.trajectory[i - first_frame].dimensions,
|
@@ -207,6 +208,8 @@ def main():
|
|
207
208
|
vel_in_trr = args.vel_path is None
|
208
209
|
force_in_trr = args.force_path is None
|
209
210
|
dt_in_trr = not args.topol_path.endswith(".data")
|
211
|
+
# True when not using DCDReader
|
212
|
+
step_in_trr = not args.traj_path.endswith(".coor")
|
210
213
|
|
211
214
|
test_compare_imd_to_true_traj(
|
212
215
|
imd_u,
|
@@ -215,6 +218,7 @@ def main():
|
|
215
218
|
vel_in_trr,
|
216
219
|
force_in_trr,
|
217
220
|
dt_in_trr,
|
221
|
+
step_in_trr,
|
218
222
|
)
|
219
223
|
|
220
224
|
if args.vel_path is not None:
|
@@ -223,9 +227,7 @@ def main():
|
|
223
227
|
)
|
224
228
|
true_vel = load_true_universe(args.topol_path, args.vel_path)
|
225
229
|
print("Comparing velocities...")
|
226
|
-
test_compare_imd_to_true_traj_vel(
|
227
|
-
imd_u, true_vel, args.first_frame
|
228
|
-
)
|
230
|
+
test_compare_imd_to_true_traj_vel(imd_u, true_vel, args.first_frame)
|
229
231
|
|
230
232
|
if args.force_path is not None:
|
231
233
|
print(
|
imdclient/tests/test_namd.py
CHANGED
@@ -1,6 +1,13 @@
|
|
1
|
-
import MDAnalysis as mda
|
2
|
-
import pytest
|
3
1
|
import logging
|
2
|
+
from pathlib import Path
|
3
|
+
import re
|
4
|
+
|
5
|
+
import pytest
|
6
|
+
from numpy.testing import (
|
7
|
+
assert_allclose,
|
8
|
+
)
|
9
|
+
import MDAnalysis as mda
|
10
|
+
|
4
11
|
from .base import IMDv3IntegrationTest, assert_allclose_with_logging
|
5
12
|
from .datafiles import (
|
6
13
|
NAMD_TOPOL,
|
@@ -9,10 +16,6 @@ from .datafiles import (
|
|
9
16
|
NAMD_PARAMS,
|
10
17
|
NAMD_PSF,
|
11
18
|
)
|
12
|
-
from pathlib import Path
|
13
|
-
from numpy.testing import (
|
14
|
-
assert_allclose,
|
15
|
-
)
|
16
19
|
|
17
20
|
logger = logging.getLogger("imdclient.IMDClient")
|
18
21
|
file_handler = logging.FileHandler("namd_test.log")
|
@@ -26,6 +29,10 @@ logger.setLevel(logging.DEBUG)
|
|
26
29
|
|
27
30
|
class TestIMDv3NAMD(IMDv3IntegrationTest):
|
28
31
|
|
32
|
+
@pytest.fixture()
|
33
|
+
def container_name(self):
|
34
|
+
return "ghcr.io/becksteinlab/streaming-namd-docker:main-common-cpu"
|
35
|
+
|
29
36
|
@pytest.fixture(params=[NAMD_CONF_NST_1, NAMD_CONF_NST_8])
|
30
37
|
def inp(self, request):
|
31
38
|
return request.param
|
@@ -42,6 +49,18 @@ class TestIMDv3NAMD(IMDv3IntegrationTest):
|
|
42
49
|
def topol(self):
|
43
50
|
return Path(NAMD_TOPOL).name
|
44
51
|
|
52
|
+
@pytest.fixture()
|
53
|
+
def dt(self, inp):
|
54
|
+
pattern = re.compile(r"^\s*timestep\s*(\S+)")
|
55
|
+
with open(inp, "r") as file:
|
56
|
+
for line in file:
|
57
|
+
match = pattern.match(line)
|
58
|
+
if match:
|
59
|
+
# NAMD timestep is in femtoseconds, convert to picoseconds
|
60
|
+
# as IMDv3 expects dt in ps, 1fs = 0.001ps
|
61
|
+
return float(match.group(1)) * 0.001
|
62
|
+
raise ValueError(f"No dt found in {inp}")
|
63
|
+
|
45
64
|
@pytest.fixture()
|
46
65
|
def true_u(self, topol, imd_u, tmp_path):
|
47
66
|
u = mda.Universe(
|
@@ -75,40 +94,43 @@ class TestIMDv3NAMD(IMDv3IntegrationTest):
|
|
75
94
|
return 0
|
76
95
|
|
77
96
|
# Compare coords, box, time, dt, step
|
78
|
-
def test_compare_imd_to_true_traj(self, imd_u, true_u, first_frame):
|
97
|
+
def test_compare_imd_to_true_traj(self, imd_u, true_u, first_frame, dt):
|
79
98
|
for i in range(first_frame, len(true_u.trajectory)):
|
99
|
+
|
80
100
|
assert_allclose(
|
81
101
|
true_u.trajectory[i].time,
|
82
102
|
imd_u.trajectory[i - first_frame].time,
|
83
103
|
atol=1e-03,
|
84
104
|
)
|
105
|
+
|
85
106
|
assert_allclose(
|
86
|
-
|
107
|
+
dt,
|
87
108
|
imd_u.trajectory[i - first_frame].dt,
|
88
109
|
atol=1e-03,
|
89
110
|
)
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
)
|
111
|
+
# step in DCDReader is frame index, not integration step
|
112
|
+
# don't compare step
|
113
|
+
|
94
114
|
assert_allclose_with_logging(
|
95
115
|
true_u.trajectory[i].dimensions,
|
96
116
|
imd_u.trajectory[i - first_frame].dimensions,
|
97
117
|
atol=1e-03,
|
98
118
|
)
|
119
|
+
|
99
120
|
assert_allclose_with_logging(
|
100
121
|
true_u.trajectory[i].positions,
|
101
122
|
imd_u.trajectory[i - first_frame].positions,
|
102
123
|
atol=1e-03,
|
103
124
|
)
|
104
125
|
|
126
|
+
# Since NAMD does not write velocities, forces to the DCD file, we need to do so seperately by extracting that info from their respective DCD files
|
105
127
|
# Compare velocities
|
106
|
-
def test_compare_imd_to_true_traj_vel(
|
107
|
-
self, imd_u, true_u_vel, first_frame
|
108
|
-
):
|
128
|
+
def test_compare_imd_to_true_traj_vel(self, imd_u, true_u_vel, first_frame):
|
109
129
|
for i in range(first_frame, len(true_u_vel.trajectory)):
|
130
|
+
|
110
131
|
assert_allclose_with_logging(
|
111
|
-
|
132
|
+
# Unit conversion
|
133
|
+
true_u_vel.trajectory[i].positions * 20.45482706,
|
112
134
|
imd_u.trajectory[i - first_frame].velocities,
|
113
135
|
atol=1e-03,
|
114
136
|
)
|
@@ -118,6 +140,7 @@ class TestIMDv3NAMD(IMDv3IntegrationTest):
|
|
118
140
|
self, imd_u, true_u_force, first_frame
|
119
141
|
):
|
120
142
|
for i in range(first_frame, len(true_u_force.trajectory)):
|
143
|
+
|
121
144
|
assert_allclose_with_logging(
|
122
145
|
true_u_force.trajectory[i].positions,
|
123
146
|
imd_u.trajectory[i - first_frame].forces,
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# tests/test_utils.py
|
2
|
+
import pytest
|
3
|
+
from imdclient.utils import parse_host_port
|
4
|
+
|
5
|
+
|
6
|
+
@pytest.mark.parametrize(
|
7
|
+
"server_address,host_port",
|
8
|
+
[
|
9
|
+
("imd://localhost:8888", ("localhost", 8888)),
|
10
|
+
("imd://example.com:12345", ("example.com", 12345)),
|
11
|
+
],
|
12
|
+
)
|
13
|
+
def test_parse_host_port_valid(server_address, host_port):
|
14
|
+
assert parse_host_port(server_address) == host_port
|
15
|
+
|
16
|
+
|
17
|
+
@pytest.mark.parametrize(
|
18
|
+
"server_address",
|
19
|
+
[
|
20
|
+
"", # empty
|
21
|
+
"http://localhost:80", # wrong protocol prefix
|
22
|
+
"imd://", # missing host and port
|
23
|
+
"imd://localhost:", # missing port
|
24
|
+
"imd://:8080", # missing host
|
25
|
+
"imd://host:notaport", # port not integer
|
26
|
+
"imd://host:80:90", # too many segments
|
27
|
+
],
|
28
|
+
)
|
29
|
+
def test_parse_host_port_invalid(server_address):
|
30
|
+
with pytest.raises(ValueError):
|
31
|
+
parse_host_port(server_address)
|
imdclient/utils.py
CHANGED
@@ -43,23 +43,6 @@ class timeit(object):
|
|
43
43
|
# always propagate exceptions forward
|
44
44
|
return False
|
45
45
|
|
46
|
-
# NOTE: think of other edge cases as well- should be robust
|
47
|
-
def parse_host_port(filename):
|
48
|
-
if not filename.startswith("imd://"):
|
49
|
-
raise ValueError("IMDReader: URL must be in the format 'imd://host:port'")
|
50
|
-
|
51
|
-
# Check if the format is correct
|
52
|
-
parts = filename.split("imd://")[1].split(":")
|
53
|
-
if len(parts) == 2:
|
54
|
-
host = parts[0]
|
55
|
-
try:
|
56
|
-
port = int(parts[1])
|
57
|
-
return (host, port)
|
58
|
-
except ValueError:
|
59
|
-
raise ValueError("IMDReader: Port must be an integer")
|
60
|
-
else:
|
61
|
-
raise ValueError("IMDReader: URL must be in the format 'imd://host:port'")
|
62
|
-
|
63
46
|
|
64
47
|
def approximate_timestep_memsize(
|
65
48
|
n_atoms, energies, dimensions, positions, velocities, forces
|
@@ -116,3 +99,53 @@ def sock_contains_data(sock, timeout) -> bool:
|
|
116
99
|
[sock], [], [], timeout
|
117
100
|
)
|
118
101
|
return sock in ready_to_read
|
102
|
+
|
103
|
+
|
104
|
+
def parse_host_port(filename):
|
105
|
+
"""
|
106
|
+
Parses a URL in the format 'imd://host:port' and returns the host and port.
|
107
|
+
Parameters
|
108
|
+
----------
|
109
|
+
filename : str
|
110
|
+
The URL to parse, must be in the format 'imd://host:port'.
|
111
|
+
|
112
|
+
Returns
|
113
|
+
-------
|
114
|
+
tuple[str, int]
|
115
|
+
A 2-tuple ``(host, port)`` where `host` is the host server name
|
116
|
+
and `port` is the TCP port number.
|
117
|
+
Raises
|
118
|
+
------
|
119
|
+
ValueError
|
120
|
+
If the URL is not in the correct format or if the host or port is invalid.
|
121
|
+
|
122
|
+
Examples
|
123
|
+
--------
|
124
|
+
>>> parse_host_port("imd://localhost:8888")
|
125
|
+
('localhost', 8888)
|
126
|
+
>>> parse_host_port("invalid://localhost:12345")
|
127
|
+
Traceback (most recent call last):
|
128
|
+
... ValueError: IMDClient: URL must be in the format 'imd://host:port'
|
129
|
+
"""
|
130
|
+
if not filename.startswith("imd://"):
|
131
|
+
raise ValueError(
|
132
|
+
"IMDClient: URL must be in the format 'imd://host:port'"
|
133
|
+
)
|
134
|
+
|
135
|
+
# Check if the format is correct
|
136
|
+
parts = filename.split("imd://")[1].split(":")
|
137
|
+
if len(parts) == 2:
|
138
|
+
host = parts[0]
|
139
|
+
if not host:
|
140
|
+
raise ValueError("IMDClient: Host cannot be empty")
|
141
|
+
if not parts[1]:
|
142
|
+
raise ValueError("IMDClient: Port cannot be empty")
|
143
|
+
try:
|
144
|
+
port = int(parts[1])
|
145
|
+
return (host, port)
|
146
|
+
except ValueError:
|
147
|
+
raise ValueError("IMDClient: Port must be an integer")
|
148
|
+
else:
|
149
|
+
raise ValueError(
|
150
|
+
"IMDClient: URL must be in the format 'imd://host:port'"
|
151
|
+
)
|
@@ -1,29 +1,36 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: imdclient
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.2.0b0
|
4
4
|
Summary: Receiver for IMD v2 and v3 data from simulation engines like Gromacs, LAMMPS, and NAMD
|
5
5
|
Author-email: Lawson <ljwoods2@asu.edu>
|
6
|
-
Maintainer-email: Lawson <ljwoods2@asu.edu>
|
6
|
+
Maintainer-email: Lawson <ljwoods2@asu.edu>, Amruthesh Thirumalaiswamy <athiru12@asu.edu>
|
7
7
|
License: Copyright 2024 Lawson Woods
|
8
8
|
|
9
9
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
10
10
|
|
11
11
|
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
14
|
+
|
15
|
+
Project-URL: source, https://github.com/becksteinlab/imdclient
|
16
|
+
Project-URL: documentation, https://imdclient.readthedocs.io
|
12
17
|
Keywords: molecular simulations
|
13
|
-
Requires-Python: >=3.
|
18
|
+
Requires-Python: >=3.10
|
14
19
|
Description-Content-Type: text/markdown
|
15
20
|
License-File: LICENSE
|
16
21
|
License-File: AUTHORS.md
|
17
|
-
Requires-Dist:
|
22
|
+
Requires-Dist: numpy
|
18
23
|
Provides-Extra: test
|
19
24
|
Requires-Dist: pytest>=6.0; extra == "test"
|
20
25
|
Requires-Dist: pytest-xdist>=2.5; extra == "test"
|
21
26
|
Requires-Dist: pytest-cov>=3.0; extra == "test"
|
22
|
-
Requires-Dist:
|
27
|
+
Requires-Dist: MDAnalysis; extra == "test"
|
28
|
+
Requires-Dist: MDAnalysisTests; extra == "test"
|
23
29
|
Requires-Dist: docker-py; extra == "test"
|
24
30
|
Provides-Extra: doc
|
25
31
|
Requires-Dist: sphinx; extra == "doc"
|
26
|
-
Requires-Dist:
|
32
|
+
Requires-Dist: mdanalysis-sphinx-theme>=1.0.1; extra == "doc"
|
33
|
+
Dynamic: license-file
|
27
34
|
|
28
35
|
IMDClient
|
29
36
|
==============================
|
@@ -32,86 +39,99 @@ IMDClient
|
|
32
39
|
| **Latest release** | [![Last release tag][badge_release]][url_latest_release] ![GitHub commits since latest release (by date) for a branch][badge_commits_since] [![Documentation Status][badge_docs]][url_docs]|
|
33
40
|
| :----------------- | :------- |
|
34
41
|
| **Status** | [![GH Actions Status][badge_actions]][url_actions] [![codecov][badge_codecov]][url_codecov] |
|
35
|
-
| **Community** | [![License: MIT][badge_license]][url_license]
|
42
|
+
| **Community** | [![License: MIT][badge_license]][url_license]
|
36
43
|
|
37
44
|
[badge_actions]: https://github.com/becksteinlab/imdclient/actions/workflows/gh-ci.yaml/badge.svg
|
38
45
|
[badge_codecov]: https://codecov.io/gh/becksteinlab/imdclient/branch/main/graph/badge.svg
|
39
46
|
[badge_commits_since]: https://img.shields.io/github/commits-since/becksteinlab/imdclient/latest
|
40
47
|
[badge_docs]: https://readthedocs.org/projects/imdclient/badge/?version=latest
|
41
48
|
[badge_license]: https://img.shields.io/badge/License-MIT-blue.svg
|
42
|
-
[badge_mda]: https://img.shields.io/badge/powered%20by-MDAnalysis-orange.svg?logoWidth=16&logo=data:image/x-icon;base64,AAABAAEAEBAAAAEAIAAoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJD+XwCY/fEAkf3uAJf97wGT/a+HfHaoiIWE7n9/f+6Hh4fvgICAjwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACT/yYAlP//AJ///wCg//8JjvOchXly1oaGhv+Ghob/j4+P/39/f3IAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJH8aQCY/8wAkv2kfY+elJ6al/yVlZX7iIiI8H9/f7h/f38UAAAAAAAAAAAAAAAAAAAAAAAAAAB/f38egYF/noqAebF8gYaagnx3oFpUUtZpaWr/WFhY8zo6OmT///8BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgICAn46Ojv+Hh4b/jouJ/4iGhfcAAADnAAAA/wAAAP8AAADIAAAAAwCj/zIAnf2VAJD/PAAAAAAAAAAAAAAAAICAgNGHh4f/gICA/4SEhP+Xl5f/AwMD/wAAAP8AAAD/AAAA/wAAAB8Aov9/ALr//wCS/Z0AAAAAAAAAAAAAAACBgYGOjo6O/4mJif+Pj4//iYmJ/wAAAOAAAAD+AAAA/wAAAP8AAABhAP7+FgCi/38Axf4fAAAAAAAAAAAAAAAAiIiID4GBgYKCgoKogoB+fYSEgZhgYGDZXl5e/m9vb/9ISEjpEBAQxw8AAFQAAAAAAAAANQAAADcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAjo6Mb5iYmP+cnJz/jY2N95CQkO4pKSn/AAAA7gAAAP0AAAD7AAAAhgAAAAEAAAAAAAAAAACL/gsAkv2uAJX/QQAAAAB9fX3egoKC/4CAgP+NjY3/c3Nz+wAAAP8AAAD/AAAA/wAAAPUAAAAcAAAAAAAAAAAAnP4NAJL9rgCR/0YAAAAAfX19w4ODg/98fHz/i4uL/4qKivwAAAD/AAAA/wAAAP8AAAD1AAAAGwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALGxsVyqqqr/mpqa/6mpqf9KSUn/AAAA5QAAAPkAAAD5AAAAhQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADkUFBSuZ2dn/3V1df8uLi7bAAAATgBGfyQAAAA2AAAAMwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0AAADoAAAA/wAAAP8AAAD/AAAAWgC3/2AAnv3eAJ/+dgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA9AAAA/wAAAP8AAAD/AAAA/wAKDzEAnP3WAKn//wCS/OgAf/8MAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIQAAANwAAADtAAAA7QAAAMAAABUMAJn9gwCe/e0Aj/2LAP//AQAAAAAAAAAA
|
43
49
|
[badge_release]: https://img.shields.io/github/release-pre/becksteinlab/imdclient.svg
|
44
50
|
[url_actions]: https://github.com/becksteinlab/imdclient/actions?query=branch%3Amain+workflow%3Agh-ci
|
45
51
|
[url_codecov]: https://codecov.io/gh/becksteinlab/imdclient/branch/main
|
46
52
|
[url_docs]: https://imdclient.readthedocs.io/en/latest/?badge=latest
|
47
53
|
[url_latest_release]: https://github.com/becksteinlab/imdclient/releases
|
48
54
|
[url_license]: https://opensource.org/license/mit
|
49
|
-
[url_mda]: https://www.mdanalysis.org
|
50
55
|
|
51
56
|
Receiver for [IMDv3 protocol](https://imdclient.readthedocs.io/en/latest/protocol_v3.html) from simulation engines like Gromacs, LAMMPS, and NAMD.
|
52
57
|
|
53
|
-
IMDClient is bound by a [Code of Conduct](https://github.com/becksteinlab/
|
58
|
+
IMDClient is bound by a [Code of Conduct](https://github.com/becksteinlab/imdclient/blob/main/CODE_OF_CONDUCT.md).
|
54
59
|
|
55
60
|
### Installation
|
56
61
|
|
57
|
-
|
58
|
-
|
62
|
+
#### Install via mamba (recommended)
|
63
|
+
To install the latest release of IMDClient from conda-forge:
|
64
|
+
|
65
|
+
```
|
66
|
+
mamba install -c conda-forge imdclient
|
67
|
+
```
|
68
|
+
|
69
|
+
#### Install via pip
|
70
|
+
To install the latest release of IMDClient from PyPI:
|
71
|
+
|
72
|
+
```
|
59
73
|
pip install imdclient
|
60
74
|
```
|
61
75
|
|
62
|
-
|
63
|
-
we highly recommend using virtual environments.
|
64
|
-
If possible, we strongly recommend that you use
|
65
|
-
[Anaconda](https://docs.conda.io/en/latest/) as your package manager.
|
66
|
-
Below we provide instructions both for `conda` and
|
67
|
-
for `pip`.
|
76
|
+
---
|
68
77
|
|
69
|
-
|
78
|
+
### Building from Source
|
79
|
+
To build IMDClient from source, we highly recommend using virtual environments.
|
80
|
+
If possible, we recommend that you use [mamba](https://mamba.readthedocs.io/en/latest/) as your package manager through [miniforge](https://github.com/conda-forge/miniforge). (You can substitute `conda` for `mamba` in the commands below if you prefer.)
|
70
81
|
|
71
|
-
|
82
|
+
Below we provide instructions both for `mamba` and for `pip`.
|
72
83
|
|
73
|
-
|
84
|
+
#### Source build with mamba
|
85
|
+
1. Ensure you have [mamba](https://mamba.readthedocs.io/en/latest/installation/mamba-installation.html) installed.
|
86
|
+
|
87
|
+
2. Create and activate a new environment:
|
74
88
|
|
75
89
|
```
|
76
|
-
|
77
|
-
|
90
|
+
mamba create --name imdclient
|
91
|
+
mamba activate imdclient
|
78
92
|
```
|
79
93
|
|
80
|
-
|
94
|
+
3. (Recommended) Install all dependencies using the provided environment YAML files for a clean and reproducible environment:
|
81
95
|
|
82
96
|
```
|
83
|
-
|
84
|
-
|
85
|
-
```
|
97
|
+
mamba env update --name imdclient --file devtools/conda-envs/test_env.yaml
|
98
|
+
mamba env update --name imdclient --file docs/requirements.yaml
|
99
|
+
```
|
86
100
|
|
87
|
-
Build
|
101
|
+
4. Build and install IMDClient in editable mode:
|
88
102
|
|
89
103
|
```
|
90
104
|
pip install -e .
|
91
105
|
```
|
92
106
|
|
93
|
-
|
107
|
+
5. (Optional) Update dependencies:
|
94
108
|
|
95
109
|
```
|
96
|
-
|
110
|
+
mamba update --all
|
97
111
|
```
|
98
112
|
|
99
|
-
|
113
|
+
6. Deactivate the environment when finished:
|
100
114
|
|
101
115
|
```
|
102
|
-
|
116
|
+
mamba deactivate
|
103
117
|
```
|
104
118
|
|
105
|
-
####
|
119
|
+
#### Source build with pip
|
106
120
|
|
107
|
-
|
121
|
+
1. (Optional) Create and activate a virtual environment:
|
122
|
+
|
123
|
+
```
|
124
|
+
python -m venv venv
|
125
|
+
source venv/bin/activate
|
126
|
+
```
|
127
|
+
|
128
|
+
2. Install IMDClient from source:
|
108
129
|
|
109
130
|
```
|
110
131
|
pip install .
|
111
132
|
```
|
112
133
|
|
113
|
-
|
114
|
-
the dependencies required for tests and docs with:
|
134
|
+
3. (Optional) For development (tests and docs):
|
115
135
|
|
116
136
|
```
|
117
137
|
pip install ".[test,doc]"
|
@@ -122,11 +142,12 @@ pip install ".[test,doc]"
|
|
122
142
|
The IMDClient source code is hosted at https://github.com/becksteinlab/imdclient
|
123
143
|
and is available under the MIT license (see the file [LICENSE](https://github.com/becksteinlab/imdclient/blob/main/LICENSE)).
|
124
144
|
|
125
|
-
Copyright (c) 2024,
|
145
|
+
Copyright (c) 2024-2025, imdclient [AUTHORS](https://github.com/Becksteinlab/imdclient/blob/main/AUTHORS.md)
|
126
146
|
|
127
147
|
|
128
148
|
#### Acknowledgements
|
129
149
|
|
130
150
|
Project based on the
|
131
151
|
[MDAnalysis Cookiecutter](https://github.com/MDAnalysis/cookiecutter-mda) version 0.1.
|
132
|
-
|
152
|
+
|
153
|
+
**If you use IMDClient in your research, please cite [IMDClient](https://github.com/Becksteinlab/imdclient) in your publications.**
|