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
@@ -1,12 +1,7 @@
|
|
1
|
-
imdclient/
|
2
|
-
imdclient/IMDClient.py,sha256=9AMKniQaCNDgWO2esF_SXEgdf3fp_4pcZ5fUNpzewcY,34349
|
1
|
+
imdclient/IMDClient.py,sha256=X4bTbEY9CjV7riRyWxZnsXsWvUPItb3ZC0VyoSRG6b0,34402
|
3
2
|
imdclient/IMDProtocol.py,sha256=wePIuFlKGIULWXHJPCmzRVWBGlBiyDOJXgjxyQb7ssY,4063
|
4
|
-
imdclient/__init__.py,sha256=
|
5
|
-
imdclient/
|
6
|
-
imdclient/results.py,sha256=2MyjFdQMW7BfiHhG5X6wQwMVrF_0mKYFnv907lgLMas,9920
|
7
|
-
imdclient/streamanalysis.py,sha256=Qq0h_WPO-wb0_lP8jTRHe0HX7UDZNgJFA6C4PZdUmK8,38385
|
8
|
-
imdclient/streambase.py,sha256=rwhdyC2V3_9pSz_6rNwjSc4MNToI9S318OH7AH0arHA,6176
|
9
|
-
imdclient/utils.py,sha256=VWxk4vQ6hzxoYRu-8Ge8fJG-EitJwgJR93wOWCvzY-0,3308
|
3
|
+
imdclient/__init__.py,sha256=lSbwmZHgCd74dGAEKVb3RaBr4oTTuRLil8sbtKuOwE4,207
|
4
|
+
imdclient/utils.py,sha256=itf_Z24KnJxe-db6dHi7A2umCp_ZjjlpAMpETYYMxUs,4224
|
10
5
|
imdclient/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
11
6
|
imdclient/data/gromacs/md/gromacs_struct.gro,sha256=kt4vE10iF_1RbeyTogmYmIY9yKJacofrzNT-hPHGyL8,1459301
|
12
7
|
imdclient/data/gromacs/md/gromacs_v3.top,sha256=AXFEDjvz5Qqq-VECffimdeEvhD6L-H0SFPILW-6Sums,348329
|
@@ -18,40 +13,41 @@ imdclient/data/lammps/md/lammps_v3_nst_8.in,sha256=gpdAp1dDhJbG06wZVDtBGUs6biJNz
|
|
18
13
|
imdclient/data/namd/md/alanin.params,sha256=zWw-UfqYD3-xpdA_8R8T-0OYBbUM6py7jKAq_uyu8HE,17389
|
19
14
|
imdclient/data/namd/md/alanin.pdb,sha256=eccDD-ledUXjbB2s1fxY40lmAKWWDpxkxANbsOkqjHc,5615
|
20
15
|
imdclient/data/namd/md/alanin.psf,sha256=VhCZeGFhpUa8yN5iEL19zlVjqIJg2JIdPzhazpRForY,12953
|
21
|
-
imdclient/data/namd/md/
|
16
|
+
imdclient/data/namd/md/namd3,sha256=NuLCXQFTWUFo6lQgTs5QQqsuX2HG0eHeLRmjAJnr8Bs,18234624
|
17
|
+
imdclient/data/namd/md/namd_v3_nst_1.namd,sha256=lx-cRWISTiqdKo9TMjifOGS7gQm6Mif3ykKm0T82jos,984
|
22
18
|
imdclient/data/namd/md/namd_v3_nst_8.namd,sha256=WJmwj0E4nJVhYRr_ALBlTax6kyNkdRE1krPsmY-QFLM,984
|
23
19
|
imdclient/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
24
|
-
imdclient/tests/base.py,sha256=
|
20
|
+
imdclient/tests/base.py,sha256=AjxIls31BYf9E8bkSiyKBz9dDbTA06UHuD4hsb7M6yc,7009
|
25
21
|
imdclient/tests/conftest.py,sha256=Xqz9ZjBXpnViSryR4CXjJdOyqZ1MOCAjuA0sRVwAVfk,31
|
26
|
-
imdclient/tests/datafiles.py,sha256=
|
27
|
-
imdclient/tests/
|
28
|
-
imdclient/tests/
|
29
|
-
imdclient/tests/
|
30
|
-
imdclient/tests/
|
31
|
-
imdclient/tests/test_lammps.py,sha256=
|
32
|
-
imdclient/tests/test_manual.py,sha256=
|
33
|
-
imdclient/tests/test_namd.py,sha256=
|
34
|
-
imdclient/tests/
|
22
|
+
imdclient/tests/datafiles.py,sha256=G3Zsyuv3R6H0cpBoOuJQl0G_EAuuOLXzt9WvohHm33I,1497
|
23
|
+
imdclient/tests/minimalreader.py,sha256=84gvbule_6oRALO1bQAnrfECWcEkOz5NHHI0g18IXKk,2589
|
24
|
+
imdclient/tests/server.py,sha256=qmEJS53QNuz0SJAtKwPqTo7A59FZGt1IFHPBd4O_uC8,6619
|
25
|
+
imdclient/tests/test_gromacs.py,sha256=SMs3HkU2dScRsMae770TVbFJQzO_m6eoe6cvXxG5Rj0,1775
|
26
|
+
imdclient/tests/test_imdclient.py,sha256=JdEEG7qB-e1ro1BshPT6HJiW_aqyzCWRAF23N3lc1fs,7637
|
27
|
+
imdclient/tests/test_lammps.py,sha256=de5G8EHSh8AmTeEniPVnETYbBd1229K7UMtZ4oSp8wU,2341
|
28
|
+
imdclient/tests/test_manual.py,sha256=is4pnIUV_VuoywbQKjm8PICvEBGfMYcp8GqlsKX8JsU,8088
|
29
|
+
imdclient/tests/test_namd.py,sha256=GsViDL6xcNF4xruWbjNW-dU5F_ANIEZwGeMkiU88rcc,4417
|
30
|
+
imdclient/tests/test_utils.py,sha256=4T6pnOQshl8hkMkS_oT-o9v66Sx5ZiQi6OqWSGNQ7YY,880
|
35
31
|
imdclient/tests/utils.py,sha256=_x1gVQ3AmhaMurpcEPLKBG5BTGu4ZMy5EGUpr0P6D6g,854
|
36
|
-
imdclient/tests/docker_testing/docker.md,sha256=
|
32
|
+
imdclient/tests/docker_testing/docker.md,sha256=wW42KFaGiO82RngNJg0yWPDwIQmgNcmhaUOdstvDgxE,840
|
37
33
|
imdclient/tests/hpc_testing/gromacs/README.md,sha256=2SHVtIu5EyS8bwCMeWTZFgQoh1mmOwcBFjijzYDkj6k,2847
|
38
34
|
imdclient/tests/hpc_testing/gromacs/gmx_gpu_test.mdp,sha256=BZl554WoHVi0bQq-Eb8UeYrdfum2TBHhtWFj4DxReCY,3050
|
39
35
|
imdclient/tests/hpc_testing/gromacs/gmx_gpu_test.top,sha256=AXFEDjvz5Qqq-VECffimdeEvhD6L-H0SFPILW-6Sums,348329
|
40
36
|
imdclient/tests/hpc_testing/gromacs/struct.gro,sha256=uT_Je8Jc37-o8gfkhFRH0PWcg3LOGkQj4ErSCkLMk00,1459301
|
41
37
|
imdclient/tests/hpc_testing/gromacs/validate_gmx.sh,sha256=dszRgiWu-_9b4DxQP4u5x4Hi1liedjMG2YXQNURZQsQ,1938
|
42
|
-
imdclient/tests/hpc_testing/lammps/README.md,sha256=
|
38
|
+
imdclient/tests/hpc_testing/lammps/README.md,sha256=Zatm6Wby2_tysDMrGPSLsfI7d79y1RfNDEBpk5mUXRo,1634
|
43
39
|
imdclient/tests/hpc_testing/lammps/lammps_v3_nst_1.in,sha256=AcvkgNNDtTkB7RlFZwpUEKKp6W_7o_UFgrX_LwC3HXI,2586
|
44
40
|
imdclient/tests/hpc_testing/lammps/topology_after_min.data,sha256=6CXJTFiVnnK6rKGK541sFYZ_6xjlkjebeWu0KPQl8Gc,172948
|
45
41
|
imdclient/tests/hpc_testing/lammps/validate_lmp.sh,sha256=gqNFUvxLojBM1yrUHloL4FJm8pl4CNjTvgSYwh11pTc,1402
|
46
|
-
imdclient/tests/hpc_testing/namd/README.md,sha256=
|
42
|
+
imdclient/tests/hpc_testing/namd/README.md,sha256=9bL5jtgWifbhxqze3Y59aA6BJEdD7TkbacWm-Kh-6-I,3633
|
47
43
|
imdclient/tests/hpc_testing/namd/alanin.params,sha256=zWw-UfqYD3-xpdA_8R8T-0OYBbUM6py7jKAq_uyu8HE,17389
|
48
44
|
imdclient/tests/hpc_testing/namd/alanin.pdb,sha256=eccDD-ledUXjbB2s1fxY40lmAKWWDpxkxANbsOkqjHc,5615
|
49
45
|
imdclient/tests/hpc_testing/namd/alanin.psf,sha256=VhCZeGFhpUa8yN5iEL19zlVjqIJg2JIdPzhazpRForY,12953
|
50
46
|
imdclient/tests/hpc_testing/namd/namd_v3_nst_1.namd,sha256=EZU7PGyytZdGixrBnmpAcwonN0n_JTk9U-Q82FoqO7k,983
|
51
47
|
imdclient/tests/hpc_testing/namd/validate_namd.sh,sha256=oMZNkY2p13q_4TJwepS5WjlT4xwxCoaZbDiWfLIWIvs,1543
|
52
|
-
imdclient-0.
|
53
|
-
imdclient-0.
|
54
|
-
imdclient-0.
|
55
|
-
imdclient-0.
|
56
|
-
imdclient-0.
|
57
|
-
imdclient-0.
|
48
|
+
imdclient-0.2.0b0.dist-info/licenses/AUTHORS.md,sha256=7GNvwDxWmGCYAB2BtazCCsBlHYWXMnpnWEiRL-XU53g,704
|
49
|
+
imdclient-0.2.0b0.dist-info/licenses/LICENSE,sha256=cTaJq_fhRiCQLCob0QRha2-437_8352CM36u14GQbZE,1060
|
50
|
+
imdclient-0.2.0b0.dist-info/METADATA,sha256=xEXouQ_n3pJ51CZUObT_n77nH6h3WzPeHfCNuL_Oeic,6095
|
51
|
+
imdclient-0.2.0b0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
52
|
+
imdclient-0.2.0b0.dist-info/top_level.txt,sha256=40W62GWiXUT2CbDm-No7GTeJG160wyIMpk1hBNrdkkE,10
|
53
|
+
imdclient-0.2.0b0.dist-info/RECORD,,
|
@@ -4,7 +4,7 @@ IMDClient was created by Lawson in 2024.
|
|
4
4
|
|
5
5
|
|
6
6
|
<!-- All contributing authors are listed in this file below.
|
7
|
-
The repository history at https://github.com/becksteinlab/
|
7
|
+
The repository history at https://github.com/becksteinlab/imdclient
|
8
8
|
and the CHANGELOG show individual code contributions. -->
|
9
9
|
|
10
10
|
## Chronological list of authors
|
@@ -19,5 +19,8 @@ The rules for this file:
|
|
19
19
|
* Don't ever delete anything
|
20
20
|
-->
|
21
21
|
|
22
|
+
**2025**
|
23
|
+
- Amruthesh Thirumalaiswamy <@amruthesht>
|
24
|
+
|
22
25
|
**2024**
|
23
26
|
- Lawson <@ljwoods2>
|
@@ -2,4 +2,6 @@ Copyright 2024 Lawson Woods
|
|
2
2
|
|
3
3
|
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:
|
4
4
|
|
5
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
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.
|
imdclient/IMD.py
DELETED
@@ -1,132 +0,0 @@
|
|
1
|
-
"""
|
2
|
-
MDAnalysis IMDReader
|
3
|
-
^^^^^^^^^^^^^^^^^^^^
|
4
|
-
|
5
|
-
.. autoclass:: IMDReader
|
6
|
-
:members:
|
7
|
-
:inherited-members:
|
8
|
-
|
9
|
-
"""
|
10
|
-
|
11
|
-
from MDAnalysis.coordinates import core
|
12
|
-
from MDAnalysis.lib.util import store_init_arguments
|
13
|
-
|
14
|
-
# NOTE: changeme
|
15
|
-
from .IMDClient import IMDClient
|
16
|
-
from .utils import *
|
17
|
-
import logging
|
18
|
-
|
19
|
-
from .streambase import StreamReaderBase
|
20
|
-
|
21
|
-
logger = logging.getLogger("imdclient.IMDClient")
|
22
|
-
|
23
|
-
|
24
|
-
class IMDReader(StreamReaderBase):
|
25
|
-
"""
|
26
|
-
Reader for IMD protocol packets.
|
27
|
-
|
28
|
-
Parameters
|
29
|
-
----------
|
30
|
-
filename : a string of the form "host:port" where host is the hostname
|
31
|
-
or IP address of the listening GROMACS server and port
|
32
|
-
is the port number.
|
33
|
-
n_atoms : int (optional)
|
34
|
-
number of atoms in the system. defaults to number of atoms
|
35
|
-
in the topology. don't set this unless you know what you're doing.
|
36
|
-
kwargs : dict (optional)
|
37
|
-
keyword arguments passed to the constructed :class:`IMDClient`
|
38
|
-
"""
|
39
|
-
|
40
|
-
format = "IMD"
|
41
|
-
one_pass = True
|
42
|
-
|
43
|
-
@store_init_arguments
|
44
|
-
def __init__(
|
45
|
-
self,
|
46
|
-
filename,
|
47
|
-
convert_units=True,
|
48
|
-
n_atoms=None,
|
49
|
-
**kwargs,
|
50
|
-
):
|
51
|
-
super(IMDReader, self).__init__(filename, **kwargs)
|
52
|
-
|
53
|
-
self._imdclient = None
|
54
|
-
logger.debug("IMDReader initializing")
|
55
|
-
|
56
|
-
if n_atoms is None:
|
57
|
-
raise ValueError("IMDReader: n_atoms must be specified")
|
58
|
-
self.n_atoms = n_atoms
|
59
|
-
|
60
|
-
host, port = parse_host_port(filename)
|
61
|
-
|
62
|
-
# This starts the simulation
|
63
|
-
self._imdclient = IMDClient(host, port, n_atoms, **kwargs)
|
64
|
-
|
65
|
-
imdsinfo = self._imdclient.get_imdsessioninfo()
|
66
|
-
# NOTE: after testing phase, fail out on IMDv2
|
67
|
-
|
68
|
-
self.ts = self._Timestep(
|
69
|
-
self.n_atoms,
|
70
|
-
positions=imdsinfo.positions,
|
71
|
-
velocities=imdsinfo.velocities,
|
72
|
-
forces=imdsinfo.forces,
|
73
|
-
**self._ts_kwargs,
|
74
|
-
)
|
75
|
-
|
76
|
-
self._frame = -1
|
77
|
-
|
78
|
-
try:
|
79
|
-
self._read_next_timestep()
|
80
|
-
except StopIteration:
|
81
|
-
raise RuntimeError("IMDReader: No data found in stream")
|
82
|
-
|
83
|
-
def _read_frame(self, frame):
|
84
|
-
|
85
|
-
try:
|
86
|
-
imdf = self._imdclient.get_imdframe()
|
87
|
-
except EOFError as e:
|
88
|
-
raise e
|
89
|
-
|
90
|
-
self._frame = frame
|
91
|
-
self._load_imdframe_into_ts(imdf)
|
92
|
-
|
93
|
-
logger.debug(f"IMDReader: Loaded frame {self._frame}")
|
94
|
-
return self.ts
|
95
|
-
|
96
|
-
def _load_imdframe_into_ts(self, imdf):
|
97
|
-
self.ts.frame = self._frame
|
98
|
-
if imdf.time is not None:
|
99
|
-
self.ts.time = imdf.time
|
100
|
-
# NOTE: timestep.pyx "dt" method is suspicious bc it uses "new" keyword for a float
|
101
|
-
self.ts.data["dt"] = imdf.dt
|
102
|
-
self.ts.data["step"] = imdf.step
|
103
|
-
if imdf.energies is not None:
|
104
|
-
self.ts.data.update(
|
105
|
-
{k: v for k, v in imdf.energies.items() if k != "step"}
|
106
|
-
)
|
107
|
-
if imdf.box is not None:
|
108
|
-
self.ts.dimensions = core.triclinic_box(*imdf.box)
|
109
|
-
if imdf.positions is not None:
|
110
|
-
# must call copy because reference is expected to reset
|
111
|
-
# see 'test_frame_collect_all_same' in MDAnalysisTests.coordinates.base
|
112
|
-
self.ts.positions = imdf.positions
|
113
|
-
if imdf.velocities is not None:
|
114
|
-
self.ts.velocities = imdf.velocities
|
115
|
-
if imdf.forces is not None:
|
116
|
-
self.ts.forces = imdf.forces
|
117
|
-
|
118
|
-
@staticmethod
|
119
|
-
def _format_hint(thing):
|
120
|
-
try:
|
121
|
-
parse_host_port(thing)
|
122
|
-
except:
|
123
|
-
return False
|
124
|
-
return True
|
125
|
-
|
126
|
-
def close(self):
|
127
|
-
"""Gracefully shut down the reader. Stops the producer thread."""
|
128
|
-
logger.debug("IMDReader close() called")
|
129
|
-
if self._imdclient is not None:
|
130
|
-
self._imdclient.stop()
|
131
|
-
# NOTE: removeme after testing
|
132
|
-
logger.debug("IMDReader shut down gracefully.")
|
imdclient/backends.py
DELETED
@@ -1,352 +0,0 @@
|
|
1
|
-
# Copy of backends from MDA 2.8.0
|
2
|
-
"""Analysis backends --- :mod:`MDAnalysis.analysis.backends`
|
3
|
-
============================================================
|
4
|
-
|
5
|
-
.. versionadded:: 2.8.0
|
6
|
-
|
7
|
-
|
8
|
-
The :mod:`backends` module provides :class:`BackendBase` base class to
|
9
|
-
implement custom execution backends for
|
10
|
-
:meth:`MDAnalysis.analysis.base.AnalysisBase.run` and its
|
11
|
-
subclasses.
|
12
|
-
|
13
|
-
.. SeeAlso:: :ref:`parallel-analysis`
|
14
|
-
|
15
|
-
.. _backends:
|
16
|
-
|
17
|
-
Backends
|
18
|
-
--------
|
19
|
-
|
20
|
-
Three built-in backend classes are provided:
|
21
|
-
|
22
|
-
* *serial*: :class:`BackendSerial`, that is equivalent to using no
|
23
|
-
parallelization and is the default
|
24
|
-
|
25
|
-
* *multiprocessing*: :class:`BackendMultiprocessing` that supports
|
26
|
-
parallelization via standard Python :mod:`multiprocessing` module
|
27
|
-
and uses default :mod:`pickle` serialization
|
28
|
-
|
29
|
-
* *dask*: :class:`BackendDask`, that uses the same process-based
|
30
|
-
parallelization as :class:`BackendMultiprocessing`, but different
|
31
|
-
serialization algorithm via `dask <https://dask.org/>`_ (see `dask
|
32
|
-
serialization algorithms
|
33
|
-
<https://distributed.dask.org/en/latest/serialization.html>`_ for details)
|
34
|
-
|
35
|
-
Classes
|
36
|
-
-------
|
37
|
-
|
38
|
-
"""
|
39
|
-
import warnings
|
40
|
-
from typing import Callable
|
41
|
-
import importlib.util
|
42
|
-
|
43
|
-
|
44
|
-
def is_installed(modulename: str):
|
45
|
-
"""Checks if module is installed
|
46
|
-
|
47
|
-
Parameters
|
48
|
-
----------
|
49
|
-
modulename : str
|
50
|
-
name of the module to be tested
|
51
|
-
|
52
|
-
|
53
|
-
.. versionadded:: 2.8.0
|
54
|
-
"""
|
55
|
-
return importlib.util.find_spec(modulename) is not None
|
56
|
-
|
57
|
-
|
58
|
-
class BackendBase:
|
59
|
-
"""Base class for backend implementation.
|
60
|
-
|
61
|
-
Initializes an instance and performs checks for its validity, such as
|
62
|
-
``n_workers`` and possibly other ones.
|
63
|
-
|
64
|
-
Parameters
|
65
|
-
----------
|
66
|
-
n_workers : int
|
67
|
-
number of workers (usually, processes) over which the work is split
|
68
|
-
|
69
|
-
Examples
|
70
|
-
--------
|
71
|
-
.. code-block:: python
|
72
|
-
|
73
|
-
from MDAnalysis.analysis.backends import BackendBase
|
74
|
-
|
75
|
-
class ThreadsBackend(BackendBase):
|
76
|
-
def apply(self, func, computations):
|
77
|
-
from multiprocessing.dummy import Pool
|
78
|
-
|
79
|
-
with Pool(processes=self.n_workers) as pool:
|
80
|
-
results = pool.map(func, computations)
|
81
|
-
return results
|
82
|
-
|
83
|
-
import MDAnalysis as mda
|
84
|
-
from MDAnalysis.tests.datafiles import PSF, DCD
|
85
|
-
from MDAnalysis.analysis.rms import RMSD
|
86
|
-
|
87
|
-
u = mda.Universe(PSF, DCD)
|
88
|
-
ref = mda.Universe(PSF, DCD)
|
89
|
-
|
90
|
-
R = RMSD(u, ref)
|
91
|
-
|
92
|
-
n_workers = 2
|
93
|
-
backend = ThreadsBackend(n_workers=n_workers)
|
94
|
-
R.run(backend=backend, unsupported_backend=True)
|
95
|
-
|
96
|
-
.. warning::
|
97
|
-
Using `ThreadsBackend` above will lead to erroneous results, since it
|
98
|
-
is an educational example. Do not use it for real analysis.
|
99
|
-
|
100
|
-
|
101
|
-
.. versionadded:: 2.8.0
|
102
|
-
|
103
|
-
"""
|
104
|
-
|
105
|
-
def __init__(self, n_workers: int):
|
106
|
-
self.n_workers = n_workers
|
107
|
-
self._validate()
|
108
|
-
|
109
|
-
def _get_checks(self):
|
110
|
-
"""Get dictionary with ``condition: error_message`` pairs that ensure the
|
111
|
-
validity of the backend instance
|
112
|
-
|
113
|
-
Returns
|
114
|
-
-------
|
115
|
-
dict
|
116
|
-
dictionary with ``condition: error_message`` pairs that will get
|
117
|
-
checked during ``_validate()`` run
|
118
|
-
"""
|
119
|
-
return {
|
120
|
-
isinstance(self.n_workers, int)
|
121
|
-
and self.n_workers
|
122
|
-
> 0: f"n_workers should be positive integer, got {self.n_workers=}",
|
123
|
-
}
|
124
|
-
|
125
|
-
def _get_warnings(self):
|
126
|
-
"""Get dictionary with ``condition: warning_message`` pairs that ensure
|
127
|
-
the good usage of the backend instance
|
128
|
-
|
129
|
-
Returns
|
130
|
-
-------
|
131
|
-
dict
|
132
|
-
dictionary with ``condition: warning_message`` pairs that will get
|
133
|
-
checked during ``_validate()`` run
|
134
|
-
"""
|
135
|
-
return dict()
|
136
|
-
|
137
|
-
def _validate(self):
|
138
|
-
"""Check correctness (e.g. ``dask`` is installed if using ``backend='dask'``)
|
139
|
-
and good usage (e.g. ``n_workers=1`` if backend is serial) of the backend
|
140
|
-
|
141
|
-
Raises
|
142
|
-
------
|
143
|
-
ValueError
|
144
|
-
if one of the conditions in :meth:`_get_checks` is ``True``
|
145
|
-
"""
|
146
|
-
for check, msg in self._get_checks().items():
|
147
|
-
if not check:
|
148
|
-
raise ValueError(msg)
|
149
|
-
for check, msg in self._get_warnings().items():
|
150
|
-
if not check:
|
151
|
-
warnings.warn(msg)
|
152
|
-
|
153
|
-
def apply(self, func: Callable, computations: list) -> list:
|
154
|
-
"""map function `func` to all tasks in the `computations` list
|
155
|
-
|
156
|
-
Main method that will get called when using an instance of
|
157
|
-
``BackendBase``. It is equivalent to running ``[func(item) for item in
|
158
|
-
computations]`` while using the parallel backend capabilities.
|
159
|
-
|
160
|
-
Parameters
|
161
|
-
----------
|
162
|
-
func : Callable
|
163
|
-
function to be called on each of the tasks in computations list
|
164
|
-
computations : list
|
165
|
-
computation tasks to apply function to
|
166
|
-
|
167
|
-
Returns
|
168
|
-
-------
|
169
|
-
list
|
170
|
-
list of results of the function
|
171
|
-
|
172
|
-
"""
|
173
|
-
raise NotImplementedError
|
174
|
-
|
175
|
-
|
176
|
-
class BackendSerial(BackendBase):
|
177
|
-
"""A built-in backend that does serial execution of the function, without any
|
178
|
-
parallelization.
|
179
|
-
|
180
|
-
Parameters
|
181
|
-
----------
|
182
|
-
n_workers : int
|
183
|
-
Is ignored in this class, and if ``n_workers`` > 1, a warning will be
|
184
|
-
given.
|
185
|
-
|
186
|
-
|
187
|
-
.. versionadded:: 2.8.0
|
188
|
-
"""
|
189
|
-
|
190
|
-
def _get_warnings(self):
|
191
|
-
"""Get dictionary with ``condition: warning_message`` pairs that ensure
|
192
|
-
the good usage of the backend instance. Here, it checks if the number
|
193
|
-
of workers is not 1, otherwise gives warning.
|
194
|
-
|
195
|
-
Returns
|
196
|
-
-------
|
197
|
-
dict
|
198
|
-
dictionary with ``condition: warning_message`` pairs that will get
|
199
|
-
checked during ``_validate()`` run
|
200
|
-
"""
|
201
|
-
return {
|
202
|
-
self.n_workers
|
203
|
-
== 1: "n_workers is ignored when executing with backend='serial'"
|
204
|
-
}
|
205
|
-
|
206
|
-
def apply(self, func: Callable, computations: list) -> list:
|
207
|
-
"""
|
208
|
-
Serially applies `func` to each task object in ``computations``.
|
209
|
-
|
210
|
-
Parameters
|
211
|
-
----------
|
212
|
-
func : Callable
|
213
|
-
function to be called on each of the tasks in computations list
|
214
|
-
computations : list
|
215
|
-
computation tasks to apply function to
|
216
|
-
|
217
|
-
Returns
|
218
|
-
-------
|
219
|
-
list
|
220
|
-
list of results of the function
|
221
|
-
"""
|
222
|
-
return [func(task) for task in computations]
|
223
|
-
|
224
|
-
|
225
|
-
class BackendMultiprocessing(BackendBase):
|
226
|
-
"""A built-in backend that executes a given function using the
|
227
|
-
:meth:`multiprocessing.Pool.map <multiprocessing.pool.Pool.map>` method.
|
228
|
-
|
229
|
-
Parameters
|
230
|
-
----------
|
231
|
-
n_workers : int
|
232
|
-
number of processes in :class:`multiprocessing.Pool
|
233
|
-
<multiprocessing.pool.Pool>` to distribute the workload
|
234
|
-
between. Must be a positive integer.
|
235
|
-
|
236
|
-
Examples
|
237
|
-
--------
|
238
|
-
|
239
|
-
.. code-block:: python
|
240
|
-
|
241
|
-
from MDAnalysis.analysis.backends import BackendMultiprocessing
|
242
|
-
import multiprocessing as mp
|
243
|
-
|
244
|
-
backend_obj = BackendMultiprocessing(n_workers=mp.cpu_count())
|
245
|
-
|
246
|
-
|
247
|
-
.. versionadded:: 2.8.0
|
248
|
-
|
249
|
-
"""
|
250
|
-
|
251
|
-
def apply(self, func: Callable, computations: list) -> list:
|
252
|
-
"""Applies `func` to each object in ``computations`` using `multiprocessing`'s `Pool.map`.
|
253
|
-
|
254
|
-
Parameters
|
255
|
-
----------
|
256
|
-
func : Callable
|
257
|
-
function to be called on each of the tasks in computations list
|
258
|
-
computations : list
|
259
|
-
computation tasks to apply function to
|
260
|
-
|
261
|
-
Returns
|
262
|
-
-------
|
263
|
-
list
|
264
|
-
list of results of the function
|
265
|
-
"""
|
266
|
-
from multiprocessing import Pool
|
267
|
-
|
268
|
-
with Pool(processes=self.n_workers) as pool:
|
269
|
-
results = pool.map(func, computations)
|
270
|
-
return results
|
271
|
-
|
272
|
-
|
273
|
-
class BackendDask(BackendBase):
|
274
|
-
"""A built-in backend that executes a given function with *dask*.
|
275
|
-
|
276
|
-
Execution is performed with the :func:`dask.compute` function of
|
277
|
-
:class:`dask.delayed.Delayed` object (created with
|
278
|
-
:func:`dask.delayed.delayed`) with ``scheduler='processes'`` and
|
279
|
-
``chunksize=1`` (this ensures uniform distribution of tasks among
|
280
|
-
processes). Requires the `dask package <https://docs.dask.org/en/stable/>`_
|
281
|
-
to be `installed <https://docs.dask.org/en/stable/install.html>`_.
|
282
|
-
|
283
|
-
Parameters
|
284
|
-
----------
|
285
|
-
n_workers : int
|
286
|
-
number of processes in to distribute the workload
|
287
|
-
between. Must be a positive integer. Workers are actually
|
288
|
-
:class:`multiprocessing.pool.Pool` processes, but they use a different and
|
289
|
-
more flexible `serialization protocol
|
290
|
-
<https://docs.dask.org/en/stable/phases-of-computation.html#graph-serialization>`_.
|
291
|
-
|
292
|
-
Examples
|
293
|
-
--------
|
294
|
-
|
295
|
-
.. code-block:: python
|
296
|
-
|
297
|
-
from MDAnalysis.analysis.backends import BackendDask
|
298
|
-
import multiprocessing as mp
|
299
|
-
|
300
|
-
backend_obj = BackendDask(n_workers=mp.cpu_count())
|
301
|
-
|
302
|
-
|
303
|
-
.. versionadded:: 2.8.0
|
304
|
-
|
305
|
-
"""
|
306
|
-
|
307
|
-
def apply(self, func: Callable, computations: list) -> list:
|
308
|
-
"""Applies `func` to each object in ``computations``.
|
309
|
-
|
310
|
-
Parameters
|
311
|
-
----------
|
312
|
-
func : Callable
|
313
|
-
function to be called on each of the tasks in computations list
|
314
|
-
computations : list
|
315
|
-
computation tasks to apply function to
|
316
|
-
|
317
|
-
Returns
|
318
|
-
-------
|
319
|
-
list
|
320
|
-
list of results of the function
|
321
|
-
"""
|
322
|
-
from dask.delayed import delayed
|
323
|
-
import dask
|
324
|
-
|
325
|
-
computations = [delayed(func)(task) for task in computations]
|
326
|
-
results = dask.compute(
|
327
|
-
computations,
|
328
|
-
scheduler="processes",
|
329
|
-
chunksize=1,
|
330
|
-
num_workers=self.n_workers,
|
331
|
-
)[0]
|
332
|
-
return results
|
333
|
-
|
334
|
-
def _get_checks(self):
|
335
|
-
"""Get dictionary with ``condition: error_message`` pairs that ensure the
|
336
|
-
validity of the backend instance. Here checks if ``dask`` module is
|
337
|
-
installed in the environment.
|
338
|
-
|
339
|
-
Returns
|
340
|
-
-------
|
341
|
-
dict
|
342
|
-
dictionary with ``condition: error_message`` pairs that will get
|
343
|
-
checked during ``_validate()`` run
|
344
|
-
"""
|
345
|
-
base_checks = super()._get_checks()
|
346
|
-
checks = {
|
347
|
-
is_installed("dask"): (
|
348
|
-
"module 'dask' is missing. Please install 'dask': "
|
349
|
-
"https://docs.dask.org/en/stable/install.html"
|
350
|
-
)
|
351
|
-
}
|
352
|
-
return base_checks | checks
|