Merge commit d30f2cb6 from release-2020 into master
[alexxy/gromacs.git] / python_packaging / src / gmxapi / datamodel.py
1 #
2 # This file is part of the GROMACS molecular simulation package.
3 #
4 # Copyright (c) 2019,2020, by the GROMACS development team, led by
5 # Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 # and including many others, as listed in the AUTHORS file in the
7 # top-level source directory and at http://www.gromacs.org.
8 #
9 # GROMACS is free software; you can redistribute it and/or
10 # modify it under the terms of the GNU Lesser General Public License
11 # as published by the Free Software Foundation; either version 2.1
12 # of the License, or (at your option) any later version.
13 #
14 # GROMACS is distributed in the hope that it will be useful,
15 # but WITHOUT ANY WARRANTY; without even the implied warranty of
16 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 # Lesser General Public License for more details.
18 #
19 # You should have received a copy of the GNU Lesser General Public
20 # License along with GROMACS; if not, see
21 # http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23 #
24 # If you want to redistribute modifications to GROMACS, please
25 # consider that scientific software is very special. Version
26 # control is crucial - bugs must be traceable. We will be happy to
27 # consider code for inclusion in the official distribution, but
28 # derived work must not be called official GROMACS. Details are found
29 # in the README & COPYING files - if they are missing, get the
30 # official version at http://www.gromacs.org.
31 #
32 # To help us fund GROMACS development, we humbly ask that you cite
33 # the research papers on the package. Check out http://www.gromacs.org.
34
35 """gmxapi data types and interfaces.
36 """
37
38 __all__ = ['ndarray', 'NDArray']
39
40 import collections
41
42 import gmxapi.abc
43 from gmxapi import exceptions
44
45
46 class NDArray(gmxapi.abc.NDArray):
47     """N-Dimensional array type.
48     """
49
50     def __init__(self, data=None):
51         self._values = []
52         self.dtype = None
53         self.shape = ()
54         if data is not None:
55             if hasattr(data, 'result') or (
56                     isinstance(data, collections.abc.Iterable) and any([hasattr(item, 'result') for item in data])):
57                 raise exceptions.ValueError(
58                     'Make a Future of type NDArray instead of NDArray of type Future, or call result() first.')
59             if isinstance(data, (str, bytes)):
60                 data = [data]
61                 length = 1
62             else:
63                 try:
64                     length = len(data)
65                 except TypeError:
66                     # data is a scalar
67                     length = 1
68                     data = [data]
69             self._values = data
70             if length > 0:
71                 self.dtype = type(data[0])
72                 self.shape = (length,)
73
74     def to_list(self):
75         return self._values
76
77     def __getitem__(self, i: int):
78         return self._values[i]
79
80     def __len__(self) -> int:
81         return len(self._values)
82
83
84 def ndarray(data=None, shape=None, dtype=None):
85     """Create an NDArray object from the provided iterable.
86
87     Arguments:
88         data: object supporting sequence, buffer, or Array Interface protocol
89
90     ..  versionadded:: 0.1
91         *shape* and *dtype* parameters
92
93     If ``data`` is provided, ``shape`` and ``dtype`` are optional. If ``data`` is not
94     provided, both ``shape`` and ``dtype`` are required.
95
96     If ``data`` is provided and shape is provided, ``data`` must be compatible with
97     or convertible to ``shape``. See Broadcast Rules in `datamodel` documentation.
98
99     If ``data`` is provided and ``dtype`` is not provided, data type is inferred
100     as the narrowest scalar type necessary to hold any element in ``data``.
101     ``dtype``, whether inferred or explicit, must be compatible with all elements
102     of ``data``.
103
104     The returned object implements the gmxapi N-dimensional Array Interface.
105     """
106     if data is None:
107         array = NDArray()
108     else:
109         if isinstance(data, NDArray):
110             return data
111         # data is not None, but may still be an empty sequence.
112         length = 0
113         try:
114             length = len(data)
115         except TypeError:
116             # data is a scalar
117             length = 1
118             data = [data]
119         array = NDArray(data)
120     return array