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/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)