imas-python 0.1.dev1618__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.
Potentially problematic release.
This version of imas-python might be problematic. Click here for more details.
- imas/__init__.py +34 -0
- imas/__main__.py +17 -0
- imas/_util.py +260 -0
- imas/_version.py +16 -0
- imas/assets/IDSDef2MDSpreTree.xsl +161 -0
- imas/assets/IDS_fake_toplevel.xml +318 -0
- imas/assets/IDS_minimal.xml +37 -0
- imas/assets/IDS_minimal_2.xml +37 -0
- imas/assets/IDS_minimal_struct_array.xml +43 -0
- imas/assets/IDS_minimal_types.xml +169 -0
- imas/assets/ITER_134173_106_core_profiles.ids +2438 -0
- imas/assets/ITER_134173_106_equilibrium.ids +3172 -0
- imas/assets/README.md +5 -0
- imas/assets/core_profiles.ids +2438 -0
- imas/assets/equilibrium.ids +3172 -0
- imas/backends/__init__.py +12 -0
- imas/backends/db_entry_impl.py +122 -0
- imas/backends/imas_core/__init__.py +4 -0
- imas/backends/imas_core/al_context.py +391 -0
- imas/backends/imas_core/db_entry_al.py +405 -0
- imas/backends/imas_core/db_entry_helpers.py +200 -0
- imas/backends/imas_core/imas_interface.py +216 -0
- imas/backends/imas_core/mdsplus_model.py +367 -0
- imas/backends/imas_core/uda_support.py +56 -0
- imas/backends/netcdf/__init__.py +4 -0
- imas/backends/netcdf/db_entry_nc.py +176 -0
- imas/backends/netcdf/ids2nc.py +306 -0
- imas/backends/netcdf/nc2ids.py +302 -0
- imas/backends/netcdf/nc_metadata.py +357 -0
- imas/backends/netcdf/nc_validate.py +53 -0
- imas/command/cli.py +239 -0
- imas/command/db_analysis.py +290 -0
- imas/command/helpers.py +45 -0
- imas/command/timer.py +77 -0
- imas/db_entry.py +802 -0
- imas/dd_helpers.py +300 -0
- imas/dd_zip.py +297 -0
- imas/exception.py +107 -0
- imas/ids_base.py +149 -0
- imas/ids_convert.py +920 -0
- imas/ids_coordinates.py +400 -0
- imas/ids_data_type.py +115 -0
- imas/ids_defs.py +171 -0
- imas/ids_factory.py +108 -0
- imas/ids_identifiers.py +125 -0
- imas/ids_metadata.py +307 -0
- imas/ids_path.py +254 -0
- imas/ids_primitive.py +510 -0
- imas/ids_struct_array.py +233 -0
- imas/ids_structure.py +331 -0
- imas/ids_toplevel.py +381 -0
- imas/setup_logging.py +64 -0
- imas/test/test_all_dd_versions.py +28 -0
- imas/test/test_cli.py +44 -0
- imas/test/test_dbentry.py +104 -0
- imas/test/test_dd_helpers.py +134 -0
- imas/test/test_dd_zip.py +29 -0
- imas/test/test_deepcopy.py +25 -0
- imas/test/test_exception.py +12 -0
- imas/test/test_get_sample.py +388 -0
- imas/test/test_hash.py +188 -0
- imas/test/test_helpers.py +354 -0
- imas/test/test_identifiers.py +105 -0
- imas/test/test_ids2nc.py +166 -0
- imas/test/test_ids_ascii_data.py +39 -0
- imas/test/test_ids_convert.py +415 -0
- imas/test/test_ids_coordinates.py +165 -0
- imas/test/test_ids_data_type.py +40 -0
- imas/test/test_ids_factory.py +35 -0
- imas/test/test_ids_metadata.py +66 -0
- imas/test/test_ids_mixin.py +20 -0
- imas/test/test_ids_path.py +192 -0
- imas/test/test_ids_primitive.py +109 -0
- imas/test/test_ids_struct_array.py +89 -0
- imas/test/test_ids_structure.py +70 -0
- imas/test/test_ids_toplevel.py +55 -0
- imas/test/test_ids_validate.py +343 -0
- imas/test/test_latest_dd_autofill.py +74 -0
- imas/test/test_latest_dd_manual.py +38 -0
- imas/test/test_latest_dd_resample.py +102 -0
- imas/test/test_lazy_loading.py +201 -0
- imas/test/test_list_occurrences.py +82 -0
- imas/test/test_minimal.py +37 -0
- imas/test/test_minimal_conversion.py +44 -0
- imas/test/test_minimal_io.py +21 -0
- imas/test/test_minimal_struct_array_io.py +60 -0
- imas/test/test_minimal_types.py +436 -0
- imas/test/test_minimal_types_io.py +70 -0
- imas/test/test_minimal_types_io_automatic.py +66 -0
- imas/test/test_nbc_change.py +408 -0
- imas/test/test_nc_autofill.py +13 -0
- imas/test/test_nc_entry.py +28 -0
- imas/test/test_nc_metadata.py +153 -0
- imas/test/test_nc_validation.py +197 -0
- imas/test/test_snippets.py +25 -0
- imas/test/test_static_ids.py +39 -0
- imas/test/test_str_1d.py +99 -0
- imas/test/test_time_slicing.py +182 -0
- imas/test/test_uda_support.py +12 -0
- imas/test/test_util.py +209 -0
- imas/training.py +45 -0
- imas/util.py +526 -0
- imas_python-0.1.dev1618.dist-info/LICENSE.txt +165 -0
- imas_python-0.1.dev1618.dist-info/METADATA +288 -0
- imas_python-0.1.dev1618.dist-info/RECORD +108 -0
- imas_python-0.1.dev1618.dist-info/WHEEL +5 -0
- imas_python-0.1.dev1618.dist-info/entry_points.txt +3 -0
- imas_python-0.1.dev1618.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# A minimal testcase loading an IDS file and checking that the structure built is ok
|
|
2
|
+
from numbers import Complex, Integral, Number, Real
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
import pytest
|
|
6
|
+
|
|
7
|
+
from imas.ids_data_type import IDSDataType
|
|
8
|
+
from imas.ids_factory import IDSFactory
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@pytest.fixture
|
|
12
|
+
def minimal(ids_minimal_types):
|
|
13
|
+
return IDSFactory(xml_path=ids_minimal_types).new("minimal")
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# The test_assign_* tests are testing IDSPrimitive.cast_value
|
|
17
|
+
sample_values = {
|
|
18
|
+
"str": ["0D string", ["list", "of", "strings"]],
|
|
19
|
+
"int": [1, *(np.ones((2,) * i, dtype=np.int32) for i in range(1, 4))],
|
|
20
|
+
"flt": [1.1, *(np.ones((2,) * i, dtype=np.float64) for i in range(1, 7))],
|
|
21
|
+
"cpx": [
|
|
22
|
+
1.1 + 1.1j,
|
|
23
|
+
*(np.ones((2,) * i, dtype=np.complex128) * (1 + 1j) for i in range(1, 7)),
|
|
24
|
+
],
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_assign_str_0d(minimal, caplog):
|
|
29
|
+
caplog.set_level("INFO", "imas")
|
|
30
|
+
|
|
31
|
+
# Test auto-encoding
|
|
32
|
+
minimal.str_0d = b"123"
|
|
33
|
+
assert minimal.str_0d.value == "123"
|
|
34
|
+
assert len(caplog.records) == 1 # Should trigger a warning about auto-conversion
|
|
35
|
+
|
|
36
|
+
for name, values in sample_values.items():
|
|
37
|
+
for ndim, value in enumerate(values):
|
|
38
|
+
caplog.clear()
|
|
39
|
+
minimal.str_0d = value
|
|
40
|
+
# All values except sample_values["str"][0] should log a warning
|
|
41
|
+
assert len(caplog.records) == 0 if name == "str" and ndim == 0 else 1
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def test_assign_str_1d(minimal, caplog):
|
|
45
|
+
caplog.set_level("INFO", "imas")
|
|
46
|
+
|
|
47
|
+
# Test auto-encoding
|
|
48
|
+
minimal.str_1d = [b"123", "456"]
|
|
49
|
+
assert minimal.str_1d.value == ["123", "456"]
|
|
50
|
+
assert len(caplog.records) > 0 # Should trigger a warning about auto-conversion
|
|
51
|
+
|
|
52
|
+
for name, values in sample_values.items():
|
|
53
|
+
for ndim, value in enumerate(values):
|
|
54
|
+
caplog.clear()
|
|
55
|
+
minimal.str_1d = value
|
|
56
|
+
# All values except sample_values["str"][1] should log a warning
|
|
57
|
+
if name == "str" and ndim == 1:
|
|
58
|
+
assert len(caplog.records) == 0
|
|
59
|
+
else:
|
|
60
|
+
assert len(caplog.records) > 0
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
# Prevent the expected numpy ComplexWarnings from cluttering pytest output
|
|
64
|
+
@pytest.mark.filterwarnings("ignore::numpy.ComplexWarning")
|
|
65
|
+
@pytest.mark.parametrize("typ, max_dim", [("flt", 6), ("cpx", 6), ("int", 3)])
|
|
66
|
+
def test_assign_numeric_types(minimal, caplog, typ, max_dim):
|
|
67
|
+
caplog.set_level("INFO", "imas")
|
|
68
|
+
for dim in range(max_dim + 1):
|
|
69
|
+
name = f"{typ}_{dim}d"
|
|
70
|
+
|
|
71
|
+
for other_typ, values in sample_values.items():
|
|
72
|
+
can_assign = (
|
|
73
|
+
other_typ == typ
|
|
74
|
+
or (other_typ != "str" and typ == "cpx") # Store float/int in complex
|
|
75
|
+
or (other_typ == "flt" and typ == "int") # Store float in int
|
|
76
|
+
or (other_typ == "int" and typ == "flt") # Store int in float
|
|
77
|
+
)
|
|
78
|
+
for other_ndim, value in enumerate(values):
|
|
79
|
+
# We attempt to store other_typ (uppercase) with dimension other_ndim in
|
|
80
|
+
# a variable of type typ (lowercase) and dimension dim
|
|
81
|
+
if dim == other_ndim and can_assign:
|
|
82
|
+
caplog.clear()
|
|
83
|
+
minimal[name].value = value
|
|
84
|
+
if typ == other_typ or (dim == 0 and other_typ == "int"):
|
|
85
|
+
assert len(caplog.records) == 0
|
|
86
|
+
else:
|
|
87
|
+
len(caplog.records) == 1
|
|
88
|
+
elif dim == other_ndim >= 1 and other_typ == "cpx":
|
|
89
|
+
# np allows casting of complex to float or int, but warns:
|
|
90
|
+
with pytest.warns(np.ComplexWarning):
|
|
91
|
+
caplog.clear()
|
|
92
|
+
minimal[name].value = value
|
|
93
|
+
assert len(caplog.records) == 1
|
|
94
|
+
else:
|
|
95
|
+
with pytest.raises(Exception) as excinfo:
|
|
96
|
+
minimal[name].value = value
|
|
97
|
+
assert excinfo.type in (ValueError, TypeError)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def test_load_minimal_types(minimal):
|
|
101
|
+
"""Check if the standard datatypes are loaded correctly"""
|
|
102
|
+
assert minimal.flt_0d.data_type == "FLT_0D"
|
|
103
|
+
assert minimal.flt_1d.data_type == "FLT_1D"
|
|
104
|
+
assert minimal.flt_2d.data_type == "FLT_2D"
|
|
105
|
+
assert minimal.flt_3d.data_type == "FLT_3D"
|
|
106
|
+
assert minimal.flt_4d.data_type == "FLT_4D"
|
|
107
|
+
assert minimal.flt_5d.data_type == "FLT_5D"
|
|
108
|
+
assert minimal.flt_6d.data_type == "FLT_6D"
|
|
109
|
+
|
|
110
|
+
assert minimal.str_0d.data_type == "STR_0D"
|
|
111
|
+
assert minimal.str_1d.data_type == "STR_1D"
|
|
112
|
+
|
|
113
|
+
assert minimal.int_0d.data_type == "INT_0D"
|
|
114
|
+
assert minimal.int_1d.data_type == "INT_1D"
|
|
115
|
+
assert minimal.int_2d.data_type == "INT_2D"
|
|
116
|
+
assert minimal.int_3d.data_type == "INT_3D"
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def test_load_minimal_types_legacy(minimal):
|
|
120
|
+
"""Check if the legacy datatypes are loaded correctly"""
|
|
121
|
+
assert minimal.flt_type.data_type == "FLT_0D"
|
|
122
|
+
assert minimal.flt_1d_type.data_type == "FLT_1D"
|
|
123
|
+
assert minimal.int_type.data_type == "INT_0D"
|
|
124
|
+
assert minimal.str_type.data_type == "STR_0D"
|
|
125
|
+
assert minimal.str_1d_type.data_type == "STR_1D"
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
def test_numeric_array_value(minimal):
|
|
129
|
+
assert not minimal.flt_0d.has_value
|
|
130
|
+
assert not minimal.flt_1d.has_value
|
|
131
|
+
|
|
132
|
+
minimal.flt_0d.value = 7.4
|
|
133
|
+
assert minimal.flt_0d.has_value
|
|
134
|
+
|
|
135
|
+
minimal.flt_1d.value = [1.3, 3.4]
|
|
136
|
+
assert minimal.flt_1d.has_value
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
@pytest.mark.parametrize("tp", ["flt_0d", "cpx_0d", "int_0d", "str_0d"])
|
|
140
|
+
def test_ids_primitive_properties_0d(minimal, tp):
|
|
141
|
+
assert not minimal[tp].has_value
|
|
142
|
+
assert minimal[tp].shape == tuple()
|
|
143
|
+
assert minimal[tp].size == 1
|
|
144
|
+
|
|
145
|
+
minimal[tp] = 1
|
|
146
|
+
assert minimal[tp].has_value
|
|
147
|
+
assert minimal[tp].shape == tuple()
|
|
148
|
+
assert minimal[tp].size == 1
|
|
149
|
+
|
|
150
|
+
minimal[tp] = minimal[tp].metadata.data_type.default
|
|
151
|
+
assert not minimal[tp].has_value
|
|
152
|
+
assert minimal[tp].shape == tuple()
|
|
153
|
+
assert minimal[tp].size == 1
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_ids_primitive_properties_str_1d(minimal):
|
|
157
|
+
assert minimal.str_1d.shape == (0,)
|
|
158
|
+
assert minimal.str_1d.size == 0
|
|
159
|
+
assert not minimal.str_1d.has_value
|
|
160
|
+
|
|
161
|
+
minimal.str_1d.value.append("1")
|
|
162
|
+
assert minimal.str_1d.has_value
|
|
163
|
+
assert minimal.str_1d.shape == (1,)
|
|
164
|
+
assert minimal.str_1d.size == 1
|
|
165
|
+
|
|
166
|
+
minimal.str_1d.value.pop()
|
|
167
|
+
assert not minimal.str_1d.has_value
|
|
168
|
+
assert minimal.str_1d.shape == (0,)
|
|
169
|
+
assert minimal.str_1d.size == 0
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
@pytest.mark.parametrize("typ, max_dim", [("flt", 6), ("cpx", 6), ("int", 3)])
|
|
173
|
+
def test_ids_primitive_properties_numeric_arrays(minimal, typ, max_dim):
|
|
174
|
+
for dim in range(1, max_dim + 1):
|
|
175
|
+
tp = f"{typ}_{dim}d"
|
|
176
|
+
|
|
177
|
+
assert not minimal[tp].has_value
|
|
178
|
+
assert minimal[tp].shape == (0,) * dim
|
|
179
|
+
assert minimal[tp].size == 0
|
|
180
|
+
|
|
181
|
+
new_size = (2,) * dim
|
|
182
|
+
minimal[tp].value = np.ones(new_size)
|
|
183
|
+
assert minimal[tp].has_value
|
|
184
|
+
assert minimal[tp].shape == new_size
|
|
185
|
+
assert minimal[tp].size == 2**dim
|
|
186
|
+
|
|
187
|
+
minimal[tp] = np.empty((0,) * dim)
|
|
188
|
+
assert not minimal[tp].has_value
|
|
189
|
+
assert minimal[tp].shape == (0,) * dim
|
|
190
|
+
assert minimal[tp].size == 0
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
def test_ducktype_str0d(minimal):
|
|
194
|
+
node = minimal.str_0d
|
|
195
|
+
node.value = "Test"
|
|
196
|
+
assert str(node) == "Test"
|
|
197
|
+
assert len(node) == 4
|
|
198
|
+
# Iteration
|
|
199
|
+
assert list(node) == ["T", "e", "s", "t"]
|
|
200
|
+
# A small selection of string manipulation functions
|
|
201
|
+
assert node.upper() == "TEST"
|
|
202
|
+
assert node.lower() == "test"
|
|
203
|
+
assert node.split("e") == ["T", "st"]
|
|
204
|
+
assert node.isprintable()
|
|
205
|
+
assert node.replace("es", "eapo") == "Teapot"
|
|
206
|
+
# Indexing and slicing
|
|
207
|
+
assert node[:3] == "Tes"
|
|
208
|
+
assert node[1:2] == node[1] == "e"
|
|
209
|
+
# Arithmetic
|
|
210
|
+
assert node + "!" == "Test!"
|
|
211
|
+
assert node * 2 == 2 * node == "TestTest"
|
|
212
|
+
# In place operation and __eq__
|
|
213
|
+
minimal.str_0d += "X"
|
|
214
|
+
assert node == node.value == "TestX"
|
|
215
|
+
# Contains
|
|
216
|
+
assert "estX" in node
|
|
217
|
+
# Check we haven't accidentally replaced `node` with an actual string
|
|
218
|
+
assert node is minimal.str_0d
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def test_ducktype_str1d(minimal):
|
|
222
|
+
node = minimal.str_1d
|
|
223
|
+
assert len(node) == 0
|
|
224
|
+
# List operations and functions
|
|
225
|
+
node.append(1)
|
|
226
|
+
assert node == ["1"]
|
|
227
|
+
assert node.pop() == "1"
|
|
228
|
+
assert bool(node) is False
|
|
229
|
+
node[0:] = ["a", "b"]
|
|
230
|
+
assert node == ["a", "b"]
|
|
231
|
+
node.extend("cdefgh")
|
|
232
|
+
assert node == list("abcdefgh")
|
|
233
|
+
assert "d" in node
|
|
234
|
+
# Indexing and slicing
|
|
235
|
+
assert node[:3] == ["a", "b", "c"]
|
|
236
|
+
assert node[4] == "e"
|
|
237
|
+
node[5] = "X"
|
|
238
|
+
assert node == list("abcdeXgh")
|
|
239
|
+
# More functions
|
|
240
|
+
assert node.count("X") == node.count("a") == 1
|
|
241
|
+
assert len(node) == 8
|
|
242
|
+
node.clear()
|
|
243
|
+
assert node == []
|
|
244
|
+
node.value = [1, 2]
|
|
245
|
+
node.reverse()
|
|
246
|
+
assert node == ["2", "1"]
|
|
247
|
+
node.sort()
|
|
248
|
+
assert node == ["1", "2"]
|
|
249
|
+
# Iteration
|
|
250
|
+
assert tuple(node) == ("1", "2")
|
|
251
|
+
# Arithmetic
|
|
252
|
+
assert node + ["3"] == list("123")
|
|
253
|
+
assert node * 2 == 2 * node == list("1212")
|
|
254
|
+
# Check we haven't accidentally replaced `node` with an actual list
|
|
255
|
+
assert node is minimal.str_1d
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def test_ducktype_int0d(minimal):
|
|
259
|
+
node = minimal.int_0d
|
|
260
|
+
node.value = 1
|
|
261
|
+
assert node == 1
|
|
262
|
+
assert int(node) == 1
|
|
263
|
+
assert float(node) == 1.0
|
|
264
|
+
assert complex(node) == 1.0 + 0.0j
|
|
265
|
+
assert str(node) == "1"
|
|
266
|
+
assert isinstance(node, Number)
|
|
267
|
+
assert isinstance(node, Integral)
|
|
268
|
+
# int functions/properties
|
|
269
|
+
assert node.real == 1.0
|
|
270
|
+
assert node.imag == 0.0
|
|
271
|
+
assert node.bit_length() == 1
|
|
272
|
+
assert node.to_bytes(1, "little") == b"\x01"
|
|
273
|
+
# Arithmetic
|
|
274
|
+
minimal.int_0d += 3
|
|
275
|
+
assert node == 4
|
|
276
|
+
assert +node == 4
|
|
277
|
+
assert -node == -4
|
|
278
|
+
assert bool(node) is True
|
|
279
|
+
assert 2 * node == node * 2 == node + node == node + 4 == 4 + node == 8
|
|
280
|
+
assert node - node == 0
|
|
281
|
+
minimal.int_0d -= node
|
|
282
|
+
assert node == 0
|
|
283
|
+
assert bool(node) is False
|
|
284
|
+
node.value = 2
|
|
285
|
+
assert 3**node == 9
|
|
286
|
+
assert node**3 == 8
|
|
287
|
+
assert node / 3 == 2 / 3
|
|
288
|
+
assert node // 3 == 0
|
|
289
|
+
assert node % 3 == 2
|
|
290
|
+
assert node << 1 == 4
|
|
291
|
+
assert node >> 1 == 1
|
|
292
|
+
assert 1 < node <= 2
|
|
293
|
+
assert 2 <= node < 2.01
|
|
294
|
+
node.value = 7
|
|
295
|
+
assert divmod(node, 2) == (3, 1)
|
|
296
|
+
assert divmod(10, node) == (1, 3)
|
|
297
|
+
# Check we haven't accidentally replaced `node` with an actual int
|
|
298
|
+
assert node is minimal.int_0d
|
|
299
|
+
|
|
300
|
+
# Numpy operations
|
|
301
|
+
assert np.array_equal(node, 7)
|
|
302
|
+
assert np.isclose(node, 7)
|
|
303
|
+
assert np.array(node).dtype.kind == "i" # Don't care if int32 or int64
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
def test_ducktype_flt0d(minimal):
|
|
307
|
+
node = minimal.flt_0d
|
|
308
|
+
node.value = np.pi
|
|
309
|
+
assert node == np.pi
|
|
310
|
+
assert int(node) == 3
|
|
311
|
+
assert float(node) == np.pi
|
|
312
|
+
assert complex(node) == np.pi + 0.0j
|
|
313
|
+
assert str(node) == str(np.pi)
|
|
314
|
+
assert isinstance(node, Number)
|
|
315
|
+
assert isinstance(node, Real)
|
|
316
|
+
# float functions/properties
|
|
317
|
+
assert node.real == np.pi
|
|
318
|
+
assert node.imag == 0.0
|
|
319
|
+
assert node.conjugate() == np.pi
|
|
320
|
+
assert not node.is_integer()
|
|
321
|
+
# Arithmetic
|
|
322
|
+
assert +node == np.pi
|
|
323
|
+
assert -node == -np.pi
|
|
324
|
+
assert bool(node) is True
|
|
325
|
+
twopi = 2 * np.pi
|
|
326
|
+
assert 2 * node == node * 2 == node + node == node + np.pi == np.pi + node == twopi
|
|
327
|
+
assert node - node == 0.0
|
|
328
|
+
minimal.flt_0d -= node
|
|
329
|
+
assert node == 0
|
|
330
|
+
assert bool(node) is False
|
|
331
|
+
node.value = 2
|
|
332
|
+
assert isinstance(node.value, float)
|
|
333
|
+
assert 3**node == 9
|
|
334
|
+
assert node**3 == 8
|
|
335
|
+
assert node / 3 == 2 / 3
|
|
336
|
+
assert node // 3 == 0
|
|
337
|
+
assert node % 3 == 2
|
|
338
|
+
assert 1 < node <= 2
|
|
339
|
+
assert 2 <= node < 2.01
|
|
340
|
+
node.value = 7
|
|
341
|
+
assert divmod(node, 2) == (3, 1)
|
|
342
|
+
assert divmod(10, node) == (1, 3)
|
|
343
|
+
# Check we haven't accidentally replaced `node` with an actual float
|
|
344
|
+
assert node is minimal.flt_0d
|
|
345
|
+
|
|
346
|
+
# Numpy operations
|
|
347
|
+
assert np.array_equal(node, 7)
|
|
348
|
+
assert np.isclose(node, 7)
|
|
349
|
+
assert np.array(node).dtype == np.float64
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def test_ducktype_cpx0d(minimal):
|
|
353
|
+
node = minimal.cpx_0d
|
|
354
|
+
node.value = 1.0 - 1.5j
|
|
355
|
+
assert node == 1.0 - 1.5j
|
|
356
|
+
assert complex(node) == 1.0 - 1.5j
|
|
357
|
+
assert str(node) == str(1.0 - 1.5j)
|
|
358
|
+
assert isinstance(node, Number)
|
|
359
|
+
assert isinstance(node, Complex)
|
|
360
|
+
# complex functions/properties
|
|
361
|
+
assert node.real == 1.0
|
|
362
|
+
assert node.imag == -1.5
|
|
363
|
+
assert node.conjugate() == 1.0 + 1.5j
|
|
364
|
+
# Arithmetic
|
|
365
|
+
assert +node == 1.0 - 1.5j
|
|
366
|
+
assert -node == -1.0 + 1.5j
|
|
367
|
+
assert bool(node) is True
|
|
368
|
+
assert 2 * node == node * 2 == node + node == 2.0 - 3.0j
|
|
369
|
+
assert node + 1.0 == 1.0 + node == 2.0 - 1.5j
|
|
370
|
+
assert node - node == 0
|
|
371
|
+
minimal.cpx_0d -= node
|
|
372
|
+
assert node == 0
|
|
373
|
+
assert bool(node) is False
|
|
374
|
+
node.value = 2.0 + 1j
|
|
375
|
+
assert 3**node == 3 ** (2.0 + 1j)
|
|
376
|
+
assert node**3 == (2.0 + 1j) ** 3
|
|
377
|
+
assert node / 3 == 2 / 3 + 1j / 3
|
|
378
|
+
# Check we haven't accidentally replaced `node` with an actual complex
|
|
379
|
+
assert node is minimal.cpx_0d
|
|
380
|
+
|
|
381
|
+
# Numpy operations
|
|
382
|
+
assert np.array_equal(node, 2 + 1j)
|
|
383
|
+
assert np.isclose(node, 2 + 1j)
|
|
384
|
+
assert np.array(node).dtype == np.complex128
|
|
385
|
+
|
|
386
|
+
|
|
387
|
+
ducktype_params = []
|
|
388
|
+
for dtype in (IDSDataType.INT, IDSDataType.FLT, IDSDataType.CPX):
|
|
389
|
+
for ndim in range(1, 4 if dtype is IDSDataType.INT else 7):
|
|
390
|
+
value = np.ones((2,) * ndim, dtype=dtype.numpy_dtype)
|
|
391
|
+
ducktype_params.append((f"{dtype.value}_{ndim}D", value))
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
@pytest.mark.parametrize("tp, val", ducktype_params)
|
|
395
|
+
def test_ducktype_ndarray(minimal, tp, val):
|
|
396
|
+
node = minimal[tp.lower()]
|
|
397
|
+
node.value = val
|
|
398
|
+
# Numpy array properties
|
|
399
|
+
assert node.shape == val.shape
|
|
400
|
+
assert len(node) == len(val)
|
|
401
|
+
assert node.ndim == val.ndim == node.metadata.ndim
|
|
402
|
+
# Comparisons
|
|
403
|
+
assert np.all(node == 1)
|
|
404
|
+
assert not np.any(node != 1)
|
|
405
|
+
assert np.all(0 < node)
|
|
406
|
+
assert np.all(node <= 1)
|
|
407
|
+
assert np.all(1 <= node)
|
|
408
|
+
assert np.all(node < 2)
|
|
409
|
+
# Some array functions
|
|
410
|
+
assert node.all()
|
|
411
|
+
assert node.min() == node.max() == node.mean() == 1.0
|
|
412
|
+
assert node.std() == 0.0
|
|
413
|
+
# Indexing
|
|
414
|
+
assert np.array_equal(node[1], val[1])
|
|
415
|
+
assert np.array_equal(node[:1], val[:1])
|
|
416
|
+
# Arithmetic
|
|
417
|
+
assert np.array_equal([1, 1] @ node, node @ [1, 1])
|
|
418
|
+
assert np.array_equal([1, 1] @ node, [1, 1] @ val)
|
|
419
|
+
assert np.array_equal(1 + node, node + 1)
|
|
420
|
+
assert np.array_equal(node + 1, val + 1)
|
|
421
|
+
assert np.array_equal(2 * node, node * 2)
|
|
422
|
+
assert np.array_equal(2 * node, node + node)
|
|
423
|
+
assert np.array_equal(2 * node, 2 * val)
|
|
424
|
+
assert np.array_equal(node / 2, val / 2)
|
|
425
|
+
assert np.array_equal(node * node, node**2)
|
|
426
|
+
assert np.array_equal(node**2, val**2)
|
|
427
|
+
if not tp.startswith("CPX"):
|
|
428
|
+
assert np.array_equal(node // 2, val // 2)
|
|
429
|
+
# Assignment
|
|
430
|
+
node[(1,) * node.ndim] = 0
|
|
431
|
+
assert node[(1,) * node.ndim] == 0
|
|
432
|
+
# In place operation
|
|
433
|
+
minimal[tp.lower()] += 2
|
|
434
|
+
assert node[(0,) * node.ndim] == 3
|
|
435
|
+
# Check we haven't accidentally replaced `node` with an actual numpy array
|
|
436
|
+
assert node is minimal[tp.lower()]
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""A minimal testcase loading an IDS file and checking that the structure built is ok"""
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from imas.ids_defs import IDS_TIME_MODE_INDEPENDENT, MEMORY_BACKEND
|
|
6
|
+
from imas.test.test_helpers import open_dbentry, randdims
|
|
7
|
+
|
|
8
|
+
TEST_DATA = {
|
|
9
|
+
"str_0d": "test",
|
|
10
|
+
"str_1d": ["test0", "test1"],
|
|
11
|
+
"str_type": "test_legacy",
|
|
12
|
+
"str_1d_type": ["test0_legacy", "test1_legacy"],
|
|
13
|
+
"flt_type": 2.0,
|
|
14
|
+
"flt_1d_type": np.asarray([3.0, 4.0]),
|
|
15
|
+
"int_type": 5,
|
|
16
|
+
}
|
|
17
|
+
for i in range(0, 7):
|
|
18
|
+
# dimensions are random
|
|
19
|
+
TEST_DATA["flt_%dd" % i] = np.random.random_sample(size=randdims(i))
|
|
20
|
+
if i < 4:
|
|
21
|
+
TEST_DATA["int_%dd" % i] = np.random.randint(0, 1000, size=randdims(i))
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_minimal_types_io(backend, ids_minimal_types, worker_id, tmp_path):
|
|
25
|
+
"""Write and then read again a number on our minimal IDS."""
|
|
26
|
+
dbentry = open_dbentry(
|
|
27
|
+
backend, "w", worker_id, tmp_path, xml_path=ids_minimal_types
|
|
28
|
+
)
|
|
29
|
+
minimal = dbentry.factory.new("minimal")
|
|
30
|
+
for k, v in TEST_DATA.items():
|
|
31
|
+
minimal[k] = v
|
|
32
|
+
|
|
33
|
+
minimal.ids_properties.homogeneous_time = IDS_TIME_MODE_INDEPENDENT
|
|
34
|
+
dbentry.put(minimal)
|
|
35
|
+
|
|
36
|
+
dbentry2 = open_dbentry(
|
|
37
|
+
backend, "a", worker_id, tmp_path, xml_path=ids_minimal_types
|
|
38
|
+
)
|
|
39
|
+
minimal2 = dbentry2.get("minimal")
|
|
40
|
+
for k, v in TEST_DATA.items():
|
|
41
|
+
if isinstance(v, np.ndarray):
|
|
42
|
+
assert np.array_equal(minimal2[k].value, v)
|
|
43
|
+
else:
|
|
44
|
+
assert minimal2[k].value == v
|
|
45
|
+
|
|
46
|
+
dbentry.close()
|
|
47
|
+
if backend != MEMORY_BACKEND: # MEM backend already cleaned up, prevent SEGFAULT
|
|
48
|
+
dbentry2.close()
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def test_large_numbers(backend, ids_minimal_types, worker_id, tmp_path):
|
|
52
|
+
"""Write and then read again a large number"""
|
|
53
|
+
dbentry = open_dbentry(
|
|
54
|
+
backend, "w", worker_id, tmp_path, xml_path=ids_minimal_types
|
|
55
|
+
)
|
|
56
|
+
minimal = dbentry.factory.new("minimal")
|
|
57
|
+
minimal["int_0d"] = 955683416
|
|
58
|
+
|
|
59
|
+
minimal.ids_properties.homogeneous_time = IDS_TIME_MODE_INDEPENDENT
|
|
60
|
+
dbentry.put(minimal)
|
|
61
|
+
|
|
62
|
+
dbentry2 = open_dbentry(
|
|
63
|
+
backend, "a", worker_id, tmp_path, xml_path=ids_minimal_types
|
|
64
|
+
)
|
|
65
|
+
minimal2 = dbentry2.get("minimal")
|
|
66
|
+
assert minimal2["int_0d"] == 955683416
|
|
67
|
+
|
|
68
|
+
dbentry.close()
|
|
69
|
+
if backend != MEMORY_BACKEND: # MEM backend already cleaned up, prevent SEGFAULT
|
|
70
|
+
dbentry2.close()
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"""A minimal testcase loading an IDS file and checking that the structure built is ok
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from imas.ids_defs import IDS_TIME_MODE_INDEPENDENT, MEMORY_BACKEND
|
|
7
|
+
from imas.ids_factory import IDSFactory
|
|
8
|
+
from imas.test.test_helpers import fill_with_random_data, open_dbentry
|
|
9
|
+
from imas.test.test_minimal_types_io import TEST_DATA
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_minimal_types_str_1d_decode(ids_minimal_types):
|
|
13
|
+
minimal = IDSFactory(xml_path=ids_minimal_types).new("minimal")
|
|
14
|
+
minimal.str_1d = [b"test", b"test2"]
|
|
15
|
+
assert minimal.str_1d.value == ["test", "test2"]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_minimal_types_str_1d_decode_and_put(
|
|
19
|
+
backend, ids_minimal_types, worker_id, tmp_path
|
|
20
|
+
):
|
|
21
|
+
"""The access layer changed 1d string types to bytes.
|
|
22
|
+
This is unexpected, especially since on read it is converted from bytes to string
|
|
23
|
+
again (which implies that the proper form for in python is as strings)"""
|
|
24
|
+
dbentry = open_dbentry(
|
|
25
|
+
backend, "w", worker_id, tmp_path, xml_path=ids_minimal_types
|
|
26
|
+
)
|
|
27
|
+
minimal = dbentry.factory.new("minimal")
|
|
28
|
+
minimal.str_1d = [b"test", b"test2"]
|
|
29
|
+
minimal.ids_properties.homogeneous_time = IDS_TIME_MODE_INDEPENDENT
|
|
30
|
+
|
|
31
|
+
assert minimal.str_1d.value == ["test", "test2"]
|
|
32
|
+
dbentry.put(minimal)
|
|
33
|
+
assert minimal.str_1d.value == ["test", "test2"]
|
|
34
|
+
dbentry.close()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def test_minimal_types_io_automatic(backend, ids_minimal_types, worker_id, tmp_path):
|
|
38
|
+
"""Write and then read again our minimal IDS."""
|
|
39
|
+
dbentry = open_dbentry(
|
|
40
|
+
backend, "w", worker_id, tmp_path, xml_path=ids_minimal_types
|
|
41
|
+
)
|
|
42
|
+
minimal = dbentry.factory.new("minimal")
|
|
43
|
+
fill_with_random_data(minimal)
|
|
44
|
+
|
|
45
|
+
minimal.ids_properties.homogeneous_time = IDS_TIME_MODE_INDEPENDENT
|
|
46
|
+
dbentry.put(minimal)
|
|
47
|
+
|
|
48
|
+
dbentry2 = open_dbentry(
|
|
49
|
+
backend, "a", worker_id, tmp_path, xml_path=ids_minimal_types
|
|
50
|
+
)
|
|
51
|
+
minimal2 = dbentry2.get("minimal")
|
|
52
|
+
for k, v in TEST_DATA.items():
|
|
53
|
+
if isinstance(v, np.ndarray):
|
|
54
|
+
assert np.array_equal(minimal2[k].value, minimal[k].value)
|
|
55
|
+
else:
|
|
56
|
+
if isinstance(minimal2[k].value, np.ndarray):
|
|
57
|
+
assert np.array_equal(
|
|
58
|
+
minimal2[k].value,
|
|
59
|
+
np.asarray(minimal[k].value, dtype=minimal2[k].value.dtype),
|
|
60
|
+
)
|
|
61
|
+
else:
|
|
62
|
+
assert minimal2[k].value == minimal[k].value
|
|
63
|
+
|
|
64
|
+
dbentry.close()
|
|
65
|
+
if backend != MEMORY_BACKEND: # MEM backend already cleaned up, prevent SEGFAULT
|
|
66
|
+
dbentry2.close()
|