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/results.py
DELETED
@@ -1,332 +0,0 @@
|
|
1
|
-
# Copy of MDAnalysis.analysis.results from 2.8.0
|
2
|
-
|
3
|
-
"""Analysis results and their aggregation --- :mod:`MDAnalysis.analysis.results`
|
4
|
-
================================================================================
|
5
|
-
|
6
|
-
Module introduces two classes, :class:`Results` and :class:`ResultsGroup`,
|
7
|
-
used for storing and aggregating data in
|
8
|
-
:meth:`MDAnalysis.analysis.base.AnalysisBase.run()`, respectively.
|
9
|
-
|
10
|
-
|
11
|
-
Classes
|
12
|
-
-------
|
13
|
-
|
14
|
-
The :class:`Results` class is an extension of a built-in dictionary
|
15
|
-
type, that holds all assigned attributes in :attr:`self.data` and
|
16
|
-
allows for access either via dict-like syntax, or via class-like syntax:
|
17
|
-
|
18
|
-
.. code-block:: python
|
19
|
-
|
20
|
-
from MDAnalysis.analysis.results import Results
|
21
|
-
r = Results()
|
22
|
-
r.array = [1, 2, 3, 4]
|
23
|
-
assert r['array'] == r.array == [1, 2, 3, 4]
|
24
|
-
|
25
|
-
|
26
|
-
The :class:`ResultsGroup` can merge multiple :class:`Results` objects.
|
27
|
-
It is mainly used by :class:`MDAnalysis.analysis.base.AnalysisBase` class,
|
28
|
-
that uses :meth:`ResultsGroup.merge()` method to aggregate results from
|
29
|
-
multiple workers, initialized during a parallel run:
|
30
|
-
|
31
|
-
.. code-block:: python
|
32
|
-
|
33
|
-
from MDAnalysis.analysis.results import Results, ResultsGroup
|
34
|
-
import numpy as np
|
35
|
-
|
36
|
-
r1, r2 = Results(), Results()
|
37
|
-
r1.masses = [1, 2, 3, 4, 5]
|
38
|
-
r2.masses = [0, 0, 0, 0]
|
39
|
-
r1.vectors = np.arange(10).reshape(5, 2)
|
40
|
-
r2.vectors = np.arange(8).reshape(4, 2)
|
41
|
-
|
42
|
-
group = ResultsGroup(
|
43
|
-
lookup = {
|
44
|
-
'masses': ResultsGroup.flatten_sequence,
|
45
|
-
'vectors': ResultsGroup.ndarray_vstack
|
46
|
-
}
|
47
|
-
)
|
48
|
-
|
49
|
-
r = group.merge([r1, r2])
|
50
|
-
assert r.masses == list((*r1.masses, *r2.masses))
|
51
|
-
assert (r.vectors == np.vstack([r1.vectors, r2.vectors])).all()
|
52
|
-
"""
|
53
|
-
|
54
|
-
from collections import UserDict
|
55
|
-
import numpy as np
|
56
|
-
from typing import Callable, Sequence
|
57
|
-
|
58
|
-
|
59
|
-
class Results(UserDict):
|
60
|
-
r"""Container object for storing results.
|
61
|
-
|
62
|
-
:class:`Results` are dictionaries that provide two ways by which values
|
63
|
-
can be accessed: by dictionary key ``results["value_key"]`` or by object
|
64
|
-
attribute, ``results.value_key``. :class:`Results` stores all results
|
65
|
-
obtained from an analysis after calling :meth:`~AnalysisBase.run()`.
|
66
|
-
|
67
|
-
The implementation is similar to the :class:`sklearn.utils.Bunch`
|
68
|
-
class in `scikit-learn`_.
|
69
|
-
|
70
|
-
.. _`scikit-learn`: https://scikit-learn.org/
|
71
|
-
.. _`sklearn.utils.Bunch`: https://scikit-learn.org/stable/modules/generated/sklearn.utils.Bunch.html
|
72
|
-
|
73
|
-
Raises
|
74
|
-
------
|
75
|
-
AttributeError
|
76
|
-
If an assigned attribute has the same name as a default attribute.
|
77
|
-
|
78
|
-
ValueError
|
79
|
-
If a key is not of type ``str`` and therefore is not able to be
|
80
|
-
accessed by attribute.
|
81
|
-
|
82
|
-
Examples
|
83
|
-
--------
|
84
|
-
>>> from MDAnalysis.analysis.base import Results
|
85
|
-
>>> results = Results(a=1, b=2)
|
86
|
-
>>> results['b']
|
87
|
-
2
|
88
|
-
>>> results.b
|
89
|
-
2
|
90
|
-
>>> results.a = 3
|
91
|
-
>>> results['a']
|
92
|
-
3
|
93
|
-
>>> results.c = [1, 2, 3, 4]
|
94
|
-
>>> results['c']
|
95
|
-
[1, 2, 3, 4]
|
96
|
-
|
97
|
-
|
98
|
-
.. versionadded:: 2.0.0
|
99
|
-
|
100
|
-
.. versionchanged:: 2.8.0
|
101
|
-
Moved :class:`Results` to :mod:`MDAnalysis.analysis.results`
|
102
|
-
"""
|
103
|
-
|
104
|
-
def _validate_key(self, key):
|
105
|
-
if key in dir(self):
|
106
|
-
raise AttributeError(
|
107
|
-
f"'{key}' is a protected dictionary attribute"
|
108
|
-
)
|
109
|
-
elif isinstance(key, str) and not key.isidentifier():
|
110
|
-
raise ValueError(f"'{key}' is not a valid attribute")
|
111
|
-
|
112
|
-
def __init__(self, *args, **kwargs):
|
113
|
-
kwargs = dict(*args, **kwargs)
|
114
|
-
if "data" in kwargs.keys():
|
115
|
-
raise AttributeError(f"'data' is a protected dictionary attribute")
|
116
|
-
self.__dict__["data"] = {}
|
117
|
-
self.update(kwargs)
|
118
|
-
|
119
|
-
def __setitem__(self, key, item):
|
120
|
-
self._validate_key(key)
|
121
|
-
super().__setitem__(key, item)
|
122
|
-
|
123
|
-
def __setattr__(self, attr, val):
|
124
|
-
if attr == "data":
|
125
|
-
super().__setattr__(attr, val)
|
126
|
-
else:
|
127
|
-
self.__setitem__(attr, val)
|
128
|
-
|
129
|
-
def __getattr__(self, attr):
|
130
|
-
try:
|
131
|
-
return self[attr]
|
132
|
-
except KeyError as err:
|
133
|
-
raise AttributeError(
|
134
|
-
f"'Results' object has no attribute '{attr}'"
|
135
|
-
) from err
|
136
|
-
|
137
|
-
def __delattr__(self, attr):
|
138
|
-
try:
|
139
|
-
del self[attr]
|
140
|
-
except KeyError as err:
|
141
|
-
raise AttributeError(
|
142
|
-
f"'Results' object has no attribute '{attr}'"
|
143
|
-
) from err
|
144
|
-
|
145
|
-
def __getstate__(self):
|
146
|
-
return self.data
|
147
|
-
|
148
|
-
def __setstate__(self, state):
|
149
|
-
self.data = state
|
150
|
-
|
151
|
-
|
152
|
-
class ResultsGroup:
|
153
|
-
"""
|
154
|
-
Management and aggregation of results stored in :class:`Results` instances.
|
155
|
-
|
156
|
-
A :class:`ResultsGroup` is an optional description for :class:`Result` "dictionaries"
|
157
|
-
that are used in analysis classes based on :class:`AnalysisBase`. For each *key* in a
|
158
|
-
:class:`Result` it describes how multiple pieces of the data held under the key are
|
159
|
-
to be aggregated. This approach is necessary when parts of a trajectory are analyzed
|
160
|
-
independently (e.g., in parallel) and then need to me merged (with :meth:`merge`) to
|
161
|
-
obtain a complete data set.
|
162
|
-
|
163
|
-
Parameters
|
164
|
-
----------
|
165
|
-
lookup : dict[str, Callable], optional
|
166
|
-
aggregation functions lookup dict, by default None
|
167
|
-
|
168
|
-
Examples
|
169
|
-
--------
|
170
|
-
|
171
|
-
.. code-block:: python
|
172
|
-
|
173
|
-
from MDAnalysis.analysis.results import ResultsGroup, Results
|
174
|
-
group = ResultsGroup(lookup={'mass': ResultsGroup.float_mean})
|
175
|
-
obj1 = Results(mass=1)
|
176
|
-
obj2 = Results(mass=3)
|
177
|
-
assert {'mass': 2.0} == group.merge([obj1, obj2])
|
178
|
-
|
179
|
-
|
180
|
-
.. code-block:: python
|
181
|
-
|
182
|
-
# you can also set `None` for those attributes that you want to skip
|
183
|
-
lookup = {'mass': ResultsGroup.float_mean, 'trajectory': None}
|
184
|
-
group = ResultsGroup(lookup)
|
185
|
-
objects = [Results(mass=1, skip=None), Results(mass=3, skip=object)]
|
186
|
-
assert group.merge(objects, require_all_aggregators=False) == {'mass': 2.0}
|
187
|
-
|
188
|
-
.. versionadded:: 2.8.0
|
189
|
-
"""
|
190
|
-
|
191
|
-
def __init__(self, lookup: dict[str, Callable] = None):
|
192
|
-
self._lookup = lookup
|
193
|
-
|
194
|
-
def merge(
|
195
|
-
self, objects: Sequence[Results], require_all_aggregators: bool = True
|
196
|
-
) -> Results:
|
197
|
-
"""Merge multiple Results into a single Results instance.
|
198
|
-
|
199
|
-
Merge multiple :class:`Results` instances into a single one, using the
|
200
|
-
`lookup` dictionary to determine the appropriate aggregator functions for
|
201
|
-
each named results attribute. If the resulting object only contains a single
|
202
|
-
element, it just returns it without using any aggregators.
|
203
|
-
|
204
|
-
Parameters
|
205
|
-
----------
|
206
|
-
objects : Sequence[Results]
|
207
|
-
Multiple :class:`Results` instances with the same data attributes.
|
208
|
-
require_all_aggregators : bool, optional
|
209
|
-
if True, raise an exception when no aggregation function for a
|
210
|
-
particular argument is found. Allows to skip aggregation for the
|
211
|
-
parameters that aren't needed in the final object --
|
212
|
-
see :class:`ResultsGroup`.
|
213
|
-
|
214
|
-
Returns
|
215
|
-
-------
|
216
|
-
Results
|
217
|
-
merged :class:`Results`
|
218
|
-
|
219
|
-
Raises
|
220
|
-
------
|
221
|
-
ValueError
|
222
|
-
if no aggregation function for a key is found and ``require_all_aggregators=True``
|
223
|
-
"""
|
224
|
-
if len(objects) == 1:
|
225
|
-
merged_results = objects[0]
|
226
|
-
return merged_results
|
227
|
-
|
228
|
-
merged_results = Results()
|
229
|
-
for key in objects[0].keys():
|
230
|
-
agg_function = self._lookup.get(key, None)
|
231
|
-
if agg_function is not None:
|
232
|
-
results_of_t = [obj[key] for obj in objects]
|
233
|
-
merged_results[key] = agg_function(results_of_t)
|
234
|
-
elif require_all_aggregators:
|
235
|
-
raise ValueError(f"No aggregation function for {key=}")
|
236
|
-
return merged_results
|
237
|
-
|
238
|
-
@staticmethod
|
239
|
-
def flatten_sequence(arrs: list[list]):
|
240
|
-
"""Flatten a list of lists into a list
|
241
|
-
|
242
|
-
Parameters
|
243
|
-
----------
|
244
|
-
arrs : list[list]
|
245
|
-
list of lists
|
246
|
-
|
247
|
-
Returns
|
248
|
-
-------
|
249
|
-
list
|
250
|
-
flattened list
|
251
|
-
"""
|
252
|
-
return [item for sublist in arrs for item in sublist]
|
253
|
-
|
254
|
-
@staticmethod
|
255
|
-
def ndarray_sum(arrs: list[np.ndarray]):
|
256
|
-
"""sums an ndarray along ``axis=0``
|
257
|
-
|
258
|
-
Parameters
|
259
|
-
----------
|
260
|
-
arrs : list[np.ndarray]
|
261
|
-
list of input arrays. Must have the same shape.
|
262
|
-
|
263
|
-
Returns
|
264
|
-
-------
|
265
|
-
np.ndarray
|
266
|
-
sum of input arrays
|
267
|
-
"""
|
268
|
-
return np.array(arrs).sum(axis=0)
|
269
|
-
|
270
|
-
@staticmethod
|
271
|
-
def ndarray_mean(arrs: list[np.ndarray]):
|
272
|
-
"""calculates mean of input ndarrays along ``axis=0``
|
273
|
-
|
274
|
-
Parameters
|
275
|
-
----------
|
276
|
-
arrs : list[np.ndarray]
|
277
|
-
list of input arrays. Must have the same shape.
|
278
|
-
|
279
|
-
Returns
|
280
|
-
-------
|
281
|
-
np.ndarray
|
282
|
-
mean of input arrays
|
283
|
-
"""
|
284
|
-
return np.array(arrs).mean(axis=0)
|
285
|
-
|
286
|
-
@staticmethod
|
287
|
-
def float_mean(floats: list[float]):
|
288
|
-
"""calculates mean of input float values
|
289
|
-
|
290
|
-
Parameters
|
291
|
-
----------
|
292
|
-
floats : list[float]
|
293
|
-
list of float values
|
294
|
-
|
295
|
-
Returns
|
296
|
-
-------
|
297
|
-
float
|
298
|
-
mean value
|
299
|
-
"""
|
300
|
-
return np.array(floats).mean()
|
301
|
-
|
302
|
-
@staticmethod
|
303
|
-
def ndarray_hstack(arrs: list[np.ndarray]):
|
304
|
-
"""Performs horizontal stack of input arrays
|
305
|
-
|
306
|
-
Parameters
|
307
|
-
----------
|
308
|
-
arrs : list[np.ndarray]
|
309
|
-
input numpy arrays
|
310
|
-
|
311
|
-
Returns
|
312
|
-
-------
|
313
|
-
np.ndarray
|
314
|
-
result of stacking
|
315
|
-
"""
|
316
|
-
return np.hstack(arrs)
|
317
|
-
|
318
|
-
@staticmethod
|
319
|
-
def ndarray_vstack(arrs: list[np.ndarray]):
|
320
|
-
"""Performs vertical stack of input arrays
|
321
|
-
|
322
|
-
Parameters
|
323
|
-
----------
|
324
|
-
arrs : list[np.ndarray]
|
325
|
-
input numpy arrays
|
326
|
-
|
327
|
-
Returns
|
328
|
-
-------
|
329
|
-
np.ndarray
|
330
|
-
result of stacking
|
331
|
-
"""
|
332
|
-
return np.vstack(arrs)
|