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.

Files changed (108) hide show
  1. imas/__init__.py +34 -0
  2. imas/__main__.py +17 -0
  3. imas/_util.py +260 -0
  4. imas/_version.py +16 -0
  5. imas/assets/IDSDef2MDSpreTree.xsl +161 -0
  6. imas/assets/IDS_fake_toplevel.xml +318 -0
  7. imas/assets/IDS_minimal.xml +37 -0
  8. imas/assets/IDS_minimal_2.xml +37 -0
  9. imas/assets/IDS_minimal_struct_array.xml +43 -0
  10. imas/assets/IDS_minimal_types.xml +169 -0
  11. imas/assets/ITER_134173_106_core_profiles.ids +2438 -0
  12. imas/assets/ITER_134173_106_equilibrium.ids +3172 -0
  13. imas/assets/README.md +5 -0
  14. imas/assets/core_profiles.ids +2438 -0
  15. imas/assets/equilibrium.ids +3172 -0
  16. imas/backends/__init__.py +12 -0
  17. imas/backends/db_entry_impl.py +122 -0
  18. imas/backends/imas_core/__init__.py +4 -0
  19. imas/backends/imas_core/al_context.py +391 -0
  20. imas/backends/imas_core/db_entry_al.py +405 -0
  21. imas/backends/imas_core/db_entry_helpers.py +200 -0
  22. imas/backends/imas_core/imas_interface.py +216 -0
  23. imas/backends/imas_core/mdsplus_model.py +367 -0
  24. imas/backends/imas_core/uda_support.py +56 -0
  25. imas/backends/netcdf/__init__.py +4 -0
  26. imas/backends/netcdf/db_entry_nc.py +176 -0
  27. imas/backends/netcdf/ids2nc.py +306 -0
  28. imas/backends/netcdf/nc2ids.py +302 -0
  29. imas/backends/netcdf/nc_metadata.py +357 -0
  30. imas/backends/netcdf/nc_validate.py +53 -0
  31. imas/command/cli.py +239 -0
  32. imas/command/db_analysis.py +290 -0
  33. imas/command/helpers.py +45 -0
  34. imas/command/timer.py +77 -0
  35. imas/db_entry.py +802 -0
  36. imas/dd_helpers.py +300 -0
  37. imas/dd_zip.py +297 -0
  38. imas/exception.py +107 -0
  39. imas/ids_base.py +149 -0
  40. imas/ids_convert.py +920 -0
  41. imas/ids_coordinates.py +400 -0
  42. imas/ids_data_type.py +115 -0
  43. imas/ids_defs.py +171 -0
  44. imas/ids_factory.py +108 -0
  45. imas/ids_identifiers.py +125 -0
  46. imas/ids_metadata.py +307 -0
  47. imas/ids_path.py +254 -0
  48. imas/ids_primitive.py +510 -0
  49. imas/ids_struct_array.py +233 -0
  50. imas/ids_structure.py +331 -0
  51. imas/ids_toplevel.py +381 -0
  52. imas/setup_logging.py +64 -0
  53. imas/test/test_all_dd_versions.py +28 -0
  54. imas/test/test_cli.py +44 -0
  55. imas/test/test_dbentry.py +104 -0
  56. imas/test/test_dd_helpers.py +134 -0
  57. imas/test/test_dd_zip.py +29 -0
  58. imas/test/test_deepcopy.py +25 -0
  59. imas/test/test_exception.py +12 -0
  60. imas/test/test_get_sample.py +388 -0
  61. imas/test/test_hash.py +188 -0
  62. imas/test/test_helpers.py +354 -0
  63. imas/test/test_identifiers.py +105 -0
  64. imas/test/test_ids2nc.py +166 -0
  65. imas/test/test_ids_ascii_data.py +39 -0
  66. imas/test/test_ids_convert.py +415 -0
  67. imas/test/test_ids_coordinates.py +165 -0
  68. imas/test/test_ids_data_type.py +40 -0
  69. imas/test/test_ids_factory.py +35 -0
  70. imas/test/test_ids_metadata.py +66 -0
  71. imas/test/test_ids_mixin.py +20 -0
  72. imas/test/test_ids_path.py +192 -0
  73. imas/test/test_ids_primitive.py +109 -0
  74. imas/test/test_ids_struct_array.py +89 -0
  75. imas/test/test_ids_structure.py +70 -0
  76. imas/test/test_ids_toplevel.py +55 -0
  77. imas/test/test_ids_validate.py +343 -0
  78. imas/test/test_latest_dd_autofill.py +74 -0
  79. imas/test/test_latest_dd_manual.py +38 -0
  80. imas/test/test_latest_dd_resample.py +102 -0
  81. imas/test/test_lazy_loading.py +201 -0
  82. imas/test/test_list_occurrences.py +82 -0
  83. imas/test/test_minimal.py +37 -0
  84. imas/test/test_minimal_conversion.py +44 -0
  85. imas/test/test_minimal_io.py +21 -0
  86. imas/test/test_minimal_struct_array_io.py +60 -0
  87. imas/test/test_minimal_types.py +436 -0
  88. imas/test/test_minimal_types_io.py +70 -0
  89. imas/test/test_minimal_types_io_automatic.py +66 -0
  90. imas/test/test_nbc_change.py +408 -0
  91. imas/test/test_nc_autofill.py +13 -0
  92. imas/test/test_nc_entry.py +28 -0
  93. imas/test/test_nc_metadata.py +153 -0
  94. imas/test/test_nc_validation.py +197 -0
  95. imas/test/test_snippets.py +25 -0
  96. imas/test/test_static_ids.py +39 -0
  97. imas/test/test_str_1d.py +99 -0
  98. imas/test/test_time_slicing.py +182 -0
  99. imas/test/test_uda_support.py +12 -0
  100. imas/test/test_util.py +209 -0
  101. imas/training.py +45 -0
  102. imas/util.py +526 -0
  103. imas_python-0.1.dev1618.dist-info/LICENSE.txt +165 -0
  104. imas_python-0.1.dev1618.dist-info/METADATA +288 -0
  105. imas_python-0.1.dev1618.dist-info/RECORD +108 -0
  106. imas_python-0.1.dev1618.dist-info/WHEEL +5 -0
  107. imas_python-0.1.dev1618.dist-info/entry_points.txt +3 -0
  108. imas_python-0.1.dev1618.dist-info/top_level.txt +1 -0
@@ -0,0 +1,89 @@
1
+ import logging
2
+ import pprint
3
+ from copy import deepcopy
4
+
5
+ import pytest
6
+
7
+ from imas.ids_factory import IDSFactory
8
+ from imas.ids_struct_array import IDSStructArray
9
+
10
+
11
+ @pytest.fixture
12
+ def struct_array(fake_filled_toplevel) -> IDSStructArray:
13
+ struct_array = fake_filled_toplevel.wavevector
14
+ struct_array.resize(3)
15
+ assert len(struct_array.value) == 3
16
+ return struct_array
17
+
18
+
19
+ @pytest.mark.parametrize("keep", (True, False))
20
+ @pytest.mark.parametrize("target_len", (1, 3, 7))
21
+ def test_resize(keep, target_len, struct_array):
22
+ pre_struct_array_len = len(struct_array)
23
+ pre_struct_array = deepcopy(struct_array)
24
+ n_comp_values = min(target_len, pre_struct_array_len)
25
+ pre_values = [struct_array[ii] for ii in range(n_comp_values)]
26
+
27
+ # Test if resize works for 3->1, 3->3, and 3->7
28
+ struct_array.resize(target_len, keep=keep)
29
+
30
+ # Test if internal data is the right length
31
+ assert len(struct_array) == target_len
32
+
33
+ # Test if internal data is explicitly new (keep = False) or
34
+ # explicitly kept (keep = True)
35
+ for ii in range(n_comp_values):
36
+ if keep:
37
+ assert (
38
+ struct_array[ii] is pre_values[ii]
39
+ ), f"On element {ii} of {struct_array.value} vs {pre_struct_array.value}"
40
+ else:
41
+ assert (
42
+ struct_array[ii] is not pre_values[ii]
43
+ ), f"On element {ii} of {struct_array.value} vs {pre_struct_array.value}"
44
+
45
+
46
+ def test_pretty_print(struct_array):
47
+ assert (
48
+ pprint.pformat(struct_array)
49
+ == "<IDSStructArray (IDS:gyrokinetics, wavevector with 3 items)>"
50
+ )
51
+
52
+
53
+ def test_path_non_indexable_parent(caplog, fake_filled_toplevel):
54
+ top = fake_filled_toplevel
55
+ top.wavevector.resize(1)
56
+ wv = top.wavevector[0]
57
+ with caplog.at_level(logging.WARNING):
58
+ assert wv._path == "wavevector[0]"
59
+ for record in caplog.records:
60
+ assert record.levelname != "WARNING"
61
+
62
+ # Remove the referenced profiles_1d from its parent
63
+ top.wavevector.resize(0)
64
+
65
+ # Check if singular warning is raised
66
+ with caplog.at_level(logging.WARNING):
67
+ assert wv._path == "wavevector[?]"
68
+ assert len(caplog.records) == 1
69
+ assert caplog.records[0].levelname == "WARNING"
70
+
71
+
72
+ def test_struct_array_eq():
73
+ cp1 = IDSFactory("3.39.0").core_profiles()
74
+ cp2 = IDSFactory("3.39.0").core_profiles()
75
+
76
+ assert cp1.profiles_1d != 1
77
+ assert cp1.profiles_1d != "profiles_1d"
78
+
79
+ assert cp1.profiles_1d == cp2.profiles_1d
80
+ cp1.profiles_1d.resize(1)
81
+ assert cp1.profiles_1d != cp2.profiles_1d
82
+ cp2.profiles_1d.resize(2)
83
+ assert cp1.profiles_1d != cp2.profiles_1d
84
+ cp1.profiles_1d.resize(2)
85
+ assert cp1.profiles_1d == cp2.profiles_1d
86
+ cp1.profiles_1d[0].time = 1
87
+ assert cp1.profiles_1d != cp2.profiles_1d
88
+ cp2.profiles_1d[0].time = 1
89
+ assert cp1.profiles_1d == cp2.profiles_1d
@@ -0,0 +1,70 @@
1
+ # This file is part of imas-python.
2
+ # You should have received the imas-python LICENSE file with this project.
3
+ import copy
4
+ import pprint
5
+
6
+ import pytest
7
+
8
+ from imas.ids_factory import IDSFactory
9
+ from imas.ids_structure import IDSStructure
10
+
11
+
12
+ @pytest.fixture
13
+ def structure(fake_filled_toplevel) -> IDSStructure:
14
+ yield fake_filled_toplevel.ids_properties
15
+
16
+
17
+ def test_pretty_print(structure):
18
+ assert (
19
+ pprint.pformat(structure) == "<IDSStructure (IDS:gyrokinetics, ids_properties)>"
20
+ )
21
+
22
+
23
+ def test_dict_like_access(fake_filled_toplevel):
24
+ assert fake_filled_toplevel["ids_properties"] is fake_filled_toplevel.ids_properties
25
+ node = fake_filled_toplevel.ids_properties.provenance.node
26
+ assert fake_filled_toplevel["ids_properties/provenance/node"] is node
27
+ node.resize(1)
28
+ assert fake_filled_toplevel["ids_properties/provenance/node[0]"] is node[0]
29
+ assert fake_filled_toplevel["ids_properties/provenance/node[0]"] is node[0]
30
+ path = node[0].path
31
+ assert fake_filled_toplevel["ids_properties/provenance/node[0]/path"] is path
32
+
33
+
34
+ def test_dict_like_setitem():
35
+ cp = IDSFactory("3.39.0").core_profiles()
36
+
37
+ cp["time"] = [1, 2, 3]
38
+ assert cp.time[0] == 1, cp.time[2] == 3
39
+
40
+ cp["ids_properties/homogeneous_time"] = 1
41
+ assert cp.ids_properties.homogeneous_time == 1
42
+
43
+ provenance_copy = copy.deepcopy(cp.ids_properties.provenance)
44
+ provenance_copy.node.resize(1)
45
+ provenance_copy.node[0].path = "test"
46
+ cp["ids_properties/provenance/node"] = provenance_copy.node
47
+
48
+
49
+ def test_structure_eq():
50
+ cp1 = IDSFactory("3.39.0").core_profiles()
51
+ cp2 = IDSFactory("3.39.0").core_profiles()
52
+
53
+ assert cp1 != 1
54
+ assert cp1 != "1"
55
+ assert cp1 != cp1.time
56
+
57
+ assert cp1 == cp2
58
+ assert cp1.ids_properties == cp2.ids_properties
59
+ cp1.ids_properties.comment = "x"
60
+ assert cp1 != cp2
61
+ assert cp1.ids_properties != cp2.ids_properties
62
+ cp2.ids_properties.comment = "x"
63
+ assert cp1 == cp2
64
+ assert cp1.ids_properties == cp2.ids_properties
65
+ cp2.ids_properties.homogeneous_time = 1
66
+ assert cp1 != cp2
67
+ assert cp1.ids_properties != cp2.ids_properties
68
+ cp1.ids_properties.homogeneous_time = 1
69
+ assert cp1 == cp2
70
+ assert cp1.ids_properties == cp2.ids_properties
@@ -0,0 +1,55 @@
1
+ """A testcase checking higher-level IDSToplevel features with a fake
2
+ constant-in-time DD
3
+ """
4
+
5
+ import pprint
6
+ from pathlib import Path
7
+
8
+ import pytest
9
+
10
+ from imas.ids_factory import IDSFactory
11
+ from imas.ids_toplevel import IDSToplevel
12
+ from imas.test.test_helpers import compare_children, fill_with_random_data
13
+
14
+
15
+ @pytest.fixture
16
+ def ids(fake_toplevel_xml: Path):
17
+ return IDSFactory(xml_path=fake_toplevel_xml).new("gyrokinetics")
18
+
19
+
20
+ def test_toplevel_init(ids):
21
+ assert isinstance(ids, IDSToplevel)
22
+
23
+
24
+ def test_structure_xml_noncopy(ids):
25
+ assert id(list(ids.metadata._structure_xml)[0].attrib) == id(
26
+ ids.ids_properties.metadata._structure_xml.attrib
27
+ )
28
+
29
+
30
+ def test_metadata_lifecycle_status(ids):
31
+ assert ids.metadata.lifecycle_status == "alpha"
32
+ assert ids.wavevector.metadata.structure_reference == "gyrokinetics_wavevector"
33
+
34
+
35
+ def test_metadata_non_exist(ids):
36
+ with pytest.raises(AttributeError):
37
+ ids.wavevector.metadata.lifecycle_status
38
+
39
+
40
+ def test_metadata_attribute_not_exists(ids):
41
+ with pytest.raises(AttributeError):
42
+ ids.metadata.blergh
43
+
44
+
45
+ def test_pretty_print(ids):
46
+ assert pprint.pformat(ids) == "<IDSToplevel (IDS:gyrokinetics)>"
47
+
48
+
49
+ def test_serialize_nondefault_dd_version():
50
+ ids = IDSFactory("3.31.0").core_profiles()
51
+ fill_with_random_data(ids)
52
+ data = ids.serialize()
53
+ ids2 = IDSFactory("3.31.0").core_profiles()
54
+ ids2.deserialize(data)
55
+ compare_children(ids, ids2)
@@ -0,0 +1,343 @@
1
+ import logging
2
+ from unittest.mock import Mock
3
+
4
+ import numpy as np
5
+ import pytest
6
+
7
+ from imas import DBEntry, IDSFactory
8
+ from imas.exception import ValidationError
9
+ from imas.ids_defs import (
10
+ IDS_TIME_MODE_HETEROGENEOUS,
11
+ IDS_TIME_MODE_HOMOGENEOUS,
12
+ IDS_TIME_MODE_INDEPENDENT,
13
+ MEMORY_BACKEND,
14
+ )
15
+ from imas.test.test_helpers import fill_consistent
16
+
17
+
18
+ @pytest.fixture(autouse=True)
19
+ def raise_on_logged_warnings(caplog):
20
+ """Catch warnings logged by validate() and fail the testcase if there are any."""
21
+ yield
22
+ records = [
23
+ rec for rec in caplog.get_records("call") if rec.levelno >= logging.WARNING
24
+ ]
25
+ if records:
26
+ pytest.fail(f"Warning(s) encountered during test: {records}")
27
+
28
+
29
+ def test_validate_time_mode():
30
+ cp = IDSFactory().core_profiles()
31
+ with pytest.raises(ValidationError):
32
+ cp.validate()
33
+
34
+ for time_mode in [
35
+ IDS_TIME_MODE_HOMOGENEOUS,
36
+ IDS_TIME_MODE_HETEROGENEOUS,
37
+ IDS_TIME_MODE_INDEPENDENT,
38
+ ]:
39
+ cp.ids_properties.homogeneous_time = time_mode
40
+ cp.validate()
41
+
42
+
43
+ def test_validate_time_coordinate_homogeneous():
44
+ cp = IDSFactory("3.39.0").core_profiles()
45
+ cp.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
46
+ cp.time = np.array([1.0, 2.0])
47
+ cp.profiles_1d.resize(2)
48
+ cp.validate()
49
+
50
+ cp.profiles_1d.resize(3)
51
+ with pytest.raises(ValidationError):
52
+ # non-matching size
53
+ cp.validate()
54
+
55
+
56
+ def test_validate_time_coordinate_heterogeneous_core_profiles():
57
+ cp = IDSFactory("3.39.0").core_profiles()
58
+ cp.ids_properties.homogeneous_time = IDS_TIME_MODE_HETEROGENEOUS
59
+ cp.profiles_1d.resize(2)
60
+ with pytest.raises(ValidationError):
61
+ cp.validate() # Unset cp.profiles_1d.time
62
+ cp.profiles_1d[0].time = 1.0
63
+ with pytest.raises(ValidationError):
64
+ cp.validate() # Unset cp.profiles_1d.time
65
+ cp.profiles_1d[1].time = 2.0
66
+ cp.validate()
67
+
68
+
69
+ def test_validate_time_mode_heterogeneous_pf_active():
70
+ pfa = IDSFactory("3.39.0").pf_active()
71
+ pfa.ids_properties.homogeneous_time = IDS_TIME_MODE_HETEROGENEOUS
72
+ pfa.coil.resize(1)
73
+ pfa.coil[0].current.data = np.linspace(0, 1, 10)
74
+ with pytest.raises(ValidationError):
75
+ pfa.validate()
76
+ pfa.coil[0].current.time = np.linspace(0, 1, 9) # one too short
77
+ with pytest.raises(ValidationError):
78
+ pfa.validate()
79
+ pfa.coil[0].current.time = np.linspace(0, 1, 10)
80
+ pfa.validate()
81
+
82
+ pfa.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
83
+ with pytest.raises(ValidationError):
84
+ pfa.validate()
85
+ pfa.time = np.linspace(0, 1, 10)
86
+ pfa.validate()
87
+
88
+
89
+ def test_validate_time_mode_independent():
90
+ cp = IDSFactory("3.39.0").core_profiles()
91
+ cp.ids_properties.homogeneous_time = IDS_TIME_MODE_INDEPENDENT
92
+ cp.validate()
93
+ cp.profiles_1d.resize(1)
94
+ with pytest.raises(ValidationError):
95
+ cp.validate()
96
+
97
+
98
+ def test_fixed_size_coordinates_two():
99
+ mag = IDSFactory("3.39.0").magnetics()
100
+ mag.ids_properties.homogeneous_time = IDS_TIME_MODE_INDEPENDENT
101
+ mag.b_field_pol_probe.resize(1)
102
+ mag.validate()
103
+ for bandwidth_size in [0, 1, 2, 3, 4, 1000]:
104
+ mag.b_field_pol_probe[0].bandwidth_3db = np.linspace(0, 1, bandwidth_size)
105
+ if bandwidth_size in (0, 2):
106
+ mag.validate()
107
+ else: # coordinate1 = 1...2, so only size 0 or 2 is allowed
108
+ with pytest.raises(ValidationError):
109
+ mag.validate()
110
+
111
+
112
+ def test_fixed_size_coordinates_three():
113
+ wall = IDSFactory("3.39.0").wall()
114
+ wall.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
115
+ wall.time = np.linspace(0, 1, 10)
116
+ wall.global_quantities.electrons.particle_flux_from_wall = np.ones((3, 10))
117
+ wall.validate()
118
+ for size in [1, 2, 4, 5]:
119
+ wall.global_quantities.electrons.particle_flux_from_wall = np.ones((size, 10))
120
+ with pytest.raises(ValidationError):
121
+ wall.validate()
122
+
123
+
124
+ def test_validate_indirect_coordinates():
125
+ """Test indirect coordinates like
126
+ coordinate1=coordinate_system(process(i1)/coordinate_index)/coordinate(1)
127
+ """
128
+ amns = IDSFactory("3.39.0").amns_data()
129
+ amns.ids_properties.homogeneous_time = IDS_TIME_MODE_INDEPENDENT
130
+ amns.process.resize(1)
131
+ amns.process[0].charge_state.resize(1)
132
+ amns.process[0].charge_state[0].table_1d = np.ones(10)
133
+ with pytest.raises(ValidationError):
134
+ # unset amns.process[0].coordinate_index
135
+ amns.validate()
136
+
137
+ # create some coordinate systems
138
+ amns.coordinate_system.resize(3)
139
+ for i in range(3):
140
+ amns.coordinate_system[i].coordinate.resize(6)
141
+ for j in range(6):
142
+ amns.coordinate_system[i].coordinate[j].label = f"label_{i}_{j}"
143
+ values = np.linspace(0, 1, 1 + i + j)
144
+ amns.coordinate_system[i].coordinate[j].values = values
145
+
146
+ amns.process[0].coordinate_index = 1
147
+ amns.process[0].charge_state[0].table_1d = np.ones(1)
148
+ amns.validate()
149
+
150
+ for i in range(6):
151
+ shape = [1, 2, 3, 4, 5, 6]
152
+ shape[i] = shape[i] + 1
153
+ amns.process[0].charge_state[0].table_6d = np.ones(shape)
154
+ with pytest.raises(ValidationError):
155
+ amns.validate()
156
+ amns.process[0].charge_state[0].table_6d = np.ones((1, 2, 3, 4, 5, 6))
157
+ amns.validate()
158
+
159
+ amns.process[0].coordinate_index = 3
160
+ with pytest.raises(ValidationError):
161
+ amns.validate()
162
+ amns.process[0].charge_state[0].table_1d = np.ones(3)
163
+ amns.process[0].charge_state[0].table_6d = np.ones((3, 4, 5, 6, 7, 8))
164
+ amns.validate()
165
+
166
+
167
+ def test_validate_exclusive_references():
168
+ distr = IDSFactory("3.39.0").distributions()
169
+ distr.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
170
+ distr.time = np.array([1.0])
171
+ distr.distribution.resize(1)
172
+ distr.distribution[0].profiles_2d.resize(1)
173
+ distr.distribution[0].profiles_2d[0].density = np.ones((2, 3))
174
+ with pytest.raises(ValidationError):
175
+ distr.validate()
176
+
177
+ distr.distribution[0].profiles_2d[0].grid.r = np.linspace(0, 1, 2)
178
+ distr.distribution[0].profiles_2d[0].grid.z = np.linspace(0, 1, 3)
179
+ distr.validate()
180
+
181
+ distr.distribution[0].profiles_2d[0].grid.rho_tor_norm = np.linspace(0, 1, 2)
182
+ with pytest.raises(ValidationError):
183
+ distr.validate() # either grid/r or grid/rho_tor_norm can be defined
184
+
185
+ distr.distribution[0].profiles_2d[0].grid.r = np.array([])
186
+ distr.validate()
187
+
188
+
189
+ def test_validate_reference_or_fixed_size():
190
+ waves = IDSFactory("3.39.0").waves()
191
+ waves.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
192
+ waves.time = np.array([1.0])
193
+ waves.coherent_wave.resize(1)
194
+ waves.coherent_wave[0].beam_tracing.resize(1)
195
+ waves.coherent_wave[0].beam_tracing[0].beam.resize(1)
196
+ waves.validate()
197
+
198
+ beam = waves.coherent_wave[0].beam_tracing[0].beam[0]
199
+ # n_tor coordinate1=beam.length OR 1...1
200
+ beam.wave_vector.n_tor = np.array([1], dtype=np.int32)
201
+ waves.validate()
202
+ beam.wave_vector.n_tor = np.array([1, 2], dtype=np.int32)
203
+ with pytest.raises(ValidationError):
204
+ waves.validate() # beam.length has length 0
205
+ beam.length = np.array([0.4, 0.5])
206
+ waves.validate()
207
+
208
+
209
+ def test_validate_coordinate_same_as():
210
+ ml = IDSFactory("3.39.0").mhd_linear()
211
+ ml.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
212
+ ml.time = np.array([1.0])
213
+ ml.time_slice.resize(1)
214
+ ml.validate()
215
+
216
+ ml.time_slice[0].toroidal_mode.resize(1)
217
+ tor_mode = ml.time_slice[0].toroidal_mode[0]
218
+ tor_mode.plasma.grid.dim1 = np.ones(4)
219
+ tor_mode.plasma.stress_maxwell.imaginary = np.ones((4, 5, 6))
220
+ with pytest.raises(ValidationError):
221
+ # The imaginary component has coordinate2/3_same_as the real component
222
+ # but the real component is still empty
223
+ ml.validate()
224
+
225
+ tor_mode.plasma.stress_maxwell.real = np.ones((4, 5, 6))
226
+ ml.validate()
227
+
228
+ tor_mode.plasma.stress_maxwell.real = np.ones((4, 1, 6))
229
+ with pytest.raises(ValidationError):
230
+ ml.validate() # dimension 2 does not match
231
+
232
+ tor_mode.plasma.stress_maxwell.real = np.ones((4, 5, 1))
233
+ with pytest.raises(ValidationError):
234
+ ml.validate() # dimension 3 does not match
235
+
236
+
237
+ @pytest.mark.parametrize(
238
+ "env_value, should_validate",
239
+ [
240
+ ("1", False),
241
+ ("yes", False),
242
+ ("asdf", False),
243
+ ("0", True),
244
+ ("", True),
245
+ (None, True),
246
+ ],
247
+ )
248
+ def test_validate_on_put(monkeypatch, env_value, should_validate, requires_imas):
249
+ dbentry = DBEntry(MEMORY_BACKEND, "test", 1, 1)
250
+ dbentry.create()
251
+ ids = dbentry.factory.core_profiles()
252
+ ids.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
253
+ ids.time = np.array([1.0])
254
+
255
+ validate_mock = Mock()
256
+ monkeypatch.setattr("imas.ids_toplevel.IDSToplevel.validate", validate_mock)
257
+ if env_value is None:
258
+ monkeypatch.delenv("IMAS_AL_DISABLE_VALIDATE", raising=False)
259
+ else:
260
+ monkeypatch.setenv("IMAS_AL_DISABLE_VALIDATE", env_value)
261
+
262
+ dbentry.put(ids)
263
+ assert validate_mock.call_count == 1 * should_validate
264
+ dbentry.put_slice(ids)
265
+ assert validate_mock.call_count == 2 * should_validate
266
+
267
+
268
+ def test_validate_ignore_nested_aos():
269
+ # Ignore coordinates inside an AoS outside our tree, see IMAS-4675
270
+ equilibrium = IDSFactory("3.39.0").equilibrium()
271
+ equilibrium.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
272
+ equilibrium.time = np.array([1.0])
273
+ equilibrium.time_slice.resize(1)
274
+ equilibrium.validate()
275
+ equilibrium.time_slice[0].ggd.resize(1)
276
+ # Coordinate of equilibrium time_slice(itime)/ggd = grids_ggd(itime)/grid
277
+ # where grids_ggd is a (dynamic) AoS outside our tree, so this coordinate check
278
+ # should be ignored:
279
+ equilibrium.validate()
280
+
281
+
282
+ @pytest.fixture
283
+ def alternative_coordinates_cp():
284
+ """Test alternative coordinates introduced in DDv4 with IMAS-4725."""
285
+ cp = IDSFactory("4.0.0").new("core_profiles")
286
+ cp.ids_properties.homogeneous_time = IDS_TIME_MODE_HETEROGENEOUS
287
+ cp.profiles_1d.resize(1)
288
+ cp.profiles_1d[0].time = 1.0
289
+ cp.validate()
290
+ return cp
291
+
292
+
293
+ # Alternatives for core_profiles profiles_1d/grid/rho_tor_norm
294
+ ALTERNATIVES = ["rho_tor_norm", "rho_tor", "psi", "volume", "area", "surface"]
295
+ ALTERNATIVES += ["rho_pol_norm"]
296
+
297
+
298
+ @pytest.fixture(params=ALTERNATIVES)
299
+ def alternative(request):
300
+ return request.param
301
+
302
+
303
+ def test_single_alternative_coordinate_filled(alternative_coordinates_cp, alternative):
304
+ alternative_coordinates_cp.profiles_1d[0].grid[alternative] = np.ones(3)
305
+ alternative_coordinates_cp.validate()
306
+
307
+
308
+ def test_multiples_alternative_coordinates_filled(alternative_coordinates_cp):
309
+ grid = alternative_coordinates_cp.profiles_1d[0].grid
310
+ grid.rho_tor_norm = np.ones(3)
311
+ grid.rho_tor = np.ones(2)
312
+ with pytest.raises(ValidationError):
313
+ alternative_coordinates_cp.validate() # sizes don't match
314
+ grid.rho_tor = np.ones(3)
315
+ alternative_coordinates_cp.validate() # now they match again
316
+
317
+ # Add a third one
318
+ grid.volume = np.ones(5)
319
+ with pytest.raises(ValidationError):
320
+ alternative_coordinates_cp.validate() # sizes don't match
321
+ grid.volume = np.ones(3)
322
+ alternative_coordinates_cp.validate() # now they match again
323
+
324
+
325
+ def test_validate_with_alternative_coordinates(alternative_coordinates_cp, alternative):
326
+ grid = alternative_coordinates_cp.profiles_1d[0].grid
327
+ alternative_coordinates_cp.profiles_1d[0].electrons.temperature = np.ones(4)
328
+ with pytest.raises(ValidationError):
329
+ alternative_coordinates_cp.validate() # no coordinates allocated
330
+
331
+ # Set to wrong size:
332
+ grid[alternative] = np.ones(3)
333
+ with pytest.raises(ValidationError):
334
+ alternative_coordinates_cp.validate()
335
+ # Now set to correct size
336
+ grid[alternative] = np.ones(4)
337
+ alternative_coordinates_cp.validate()
338
+
339
+
340
+ def test_validate_random_fill(ids_name):
341
+ ids = IDSFactory().new(ids_name)
342
+ fill_consistent(ids)
343
+ ids.validate()
@@ -0,0 +1,74 @@
1
+ """A testcase checking if writing and then reading works for the latest full
2
+ data dictionary version.
3
+ """
4
+
5
+ import copy
6
+
7
+ import pytest
8
+
9
+ from imas.ids_defs import (
10
+ ASCII_SERIALIZER_PROTOCOL,
11
+ FLEXBUFFERS_SERIALIZER_PROTOCOL,
12
+ MEMORY_BACKEND,
13
+ )
14
+ from imas.ids_factory import IDSFactory
15
+ from imas.test.test_helpers import (
16
+ compare_children,
17
+ fill_with_random_data,
18
+ open_dbentry,
19
+ )
20
+ from imas.util import visit_children
21
+
22
+
23
+ def test_latest_dd_autofill_consistency(ids_name):
24
+ ids = IDSFactory().new(ids_name)
25
+ fill_with_random_data(ids)
26
+
27
+ # check that each element in ids has _parent set.
28
+ visit_children(has_parent, ids, leaf_only=False)
29
+
30
+
31
+ def has_parent(child):
32
+ """Check that the child has _parent set"""
33
+ assert child._parent is not None
34
+
35
+
36
+ def test_latest_dd_autofill(ids_name, backend, worker_id, tmp_path):
37
+ """Write and then read again all IDSToplevels."""
38
+ dbentry = open_dbentry(backend, "w", worker_id, tmp_path)
39
+ ids = IDSFactory().new(ids_name)
40
+ fill_with_random_data(ids)
41
+
42
+ dbentry.put(ids)
43
+ ids_ref = copy.deepcopy(ids)
44
+ # the deepcopy comes after the put() since that updates dd version and AL lang
45
+
46
+ dbentry2 = open_dbentry(backend, "a", worker_id, tmp_path)
47
+ ids = dbentry2.get(ids_name)
48
+ compare_children(ids, ids_ref)
49
+
50
+ dbentry.close()
51
+ if backend != MEMORY_BACKEND: # MEM backend already cleaned up, prevent SEGFAULT
52
+ dbentry2.close()
53
+
54
+
55
+ @pytest.mark.parametrize(
56
+ "serializer", [ASCII_SERIALIZER_PROTOCOL, FLEXBUFFERS_SERIALIZER_PROTOCOL]
57
+ )
58
+ def test_latest_dd_autofill_serialize(serializer, ids_name, has_imas):
59
+ """Serialize and then deserialize again all IDSToplevels"""
60
+ if serializer is None:
61
+ pytest.skip("Unsupported serializer")
62
+
63
+ factory = IDSFactory()
64
+ ids = factory.new(ids_name)
65
+ fill_with_random_data(ids)
66
+
67
+ if not has_imas:
68
+ return # rest of the test requires an IMAS install
69
+ data = ids.serialize(serializer)
70
+
71
+ ids2 = factory.new(ids_name)
72
+ ids2.deserialize(data)
73
+
74
+ compare_children(ids, ids2)
@@ -0,0 +1,38 @@
1
+ """A testcase checking if writing and then reading works for the latest full
2
+ data dictionary version.
3
+ """
4
+
5
+ from imas.ids_defs import IDS_TIME_MODE_HOMOGENEOUS, MEMORY_BACKEND
6
+ from imas.ids_factory import IDSFactory
7
+ from imas.test.test_helpers import open_dbentry
8
+
9
+
10
+ def test_latest_dd_manual(backend, worker_id, tmp_path):
11
+ """Write and then read again a single IDSToplevel."""
12
+ dbentry = open_dbentry(backend, "w", worker_id, tmp_path)
13
+ ids_name = "pulse_schedule"
14
+ ids = IDSFactory().new(ids_name)
15
+ ids.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
16
+ ids.ids_properties.comment = "test"
17
+
18
+ assert ids.ids_properties.comment.value == "test"
19
+
20
+ dbentry.put(ids)
21
+
22
+ dbentry2 = open_dbentry(backend, "a", worker_id, tmp_path)
23
+ ids2 = dbentry2.get(ids_name)
24
+ assert ids2.ids_properties.comment.value == "test"
25
+
26
+ dbentry.close()
27
+ if backend != MEMORY_BACKEND: # MEM backend already cleaned up, prevent SEGFAULT
28
+ dbentry2.close()
29
+
30
+
31
+ def test_dir():
32
+ """Test calling `dir()` on `IDSFactory` to test if we can see IDSes"""
33
+ factory = IDSFactory()
34
+ f_dir = dir(factory)
35
+ # Check if we can see the first and last stable IDS
36
+ assert "amns_data" in f_dir, "Could not find amns_data in dir(IDSFactory())"
37
+ assert "workflow" in f_dir, "Could not find workflow in dir(IDSFactory())"
38
+ assert "__init__" in f_dir, "Could not find base attributes in dir(IDSFactory())"