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,134 @@
1
+ import pytest
2
+
3
+ from imas.dd_helpers import find_saxon_classpath
4
+
5
+ # TODO: Write tests!
6
+ # def prepare_data_dictionaries():
7
+ # def get_saxon():
8
+ # def find_saxon_jar():
9
+
10
+ # Quadruplets of (cluster, module, real path, name)
11
+ saxon_binary_quadruplets = (
12
+ (
13
+ "SDCC",
14
+ "Saxon-HE/10.3-Java-1.8",
15
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-1.8/saxon-he-10.3.jar",
16
+ "saxon-he-10.3.jar",
17
+ ),
18
+ (
19
+ "SDCC",
20
+ "Saxon-HE/10.3-Java-11",
21
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-10.3.jar",
22
+ "saxon-he-10.3.jar",
23
+ ),
24
+ (
25
+ "HPC",
26
+ "Saxon-HE/9.7.0.14-Java-1.6.0_45",
27
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/9.7.0.14-Java-1.6.0_45/saxon9he.jar",
28
+ "saxon9he.jar",
29
+ ),
30
+ (
31
+ "HPC",
32
+ "Saxon-HE/9.7.0.4-Java-1.7.0_79",
33
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/9.7.0.4-Java-1.7.0_79/saxon9he.jar",
34
+ "saxon9he.jar",
35
+ ),
36
+ (
37
+ "HPC",
38
+ "Saxon-HE/9.7.0.21-Java-1.8.0_162",
39
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/9.7.0.21-Java-1.8.0_162/saxon9he.jar",
40
+ "saxon9he.jar",
41
+ ),
42
+ (
43
+ "HPC",
44
+ "Saxon-HE/9.9.1.7-Java-13",
45
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/9.9.1.7-Java-13/saxon9he.jar",
46
+ "saxon9he.jar",
47
+ ),
48
+ (
49
+ "HPC",
50
+ "Saxon-HE/10.3-Java-11",
51
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-10.3.jar",
52
+ "saxon-he-10.3.jar",
53
+ ),
54
+ )
55
+
56
+ saxon_nonmatches = (
57
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-test-10.3.jar",
58
+ )
59
+
60
+
61
+ # find_saxon_bin tries to find saxon in the CLASSPATH env variable
62
+ # It is thus per definition environment dependent
63
+ def test_empty_classpath(monkeypatch):
64
+ monkeypatch.setenv("CLASSPATH", "")
65
+ saxon_jar_path = find_saxon_classpath()
66
+ assert saxon_jar_path is None
67
+
68
+
69
+ @pytest.mark.parametrize("cluster,module,path,name", saxon_binary_quadruplets)
70
+ def test_classpath(monkeypatch, cluster, module, path, name):
71
+ monkeypatch.setenv("CLASSPATH", path)
72
+ saxon_jar_path = find_saxon_classpath()
73
+ assert saxon_jar_path == path
74
+
75
+
76
+ @pytest.mark.parametrize("path", saxon_nonmatches)
77
+ def test_classpath_do_not_match(monkeypatch, path):
78
+ monkeypatch.setenv("CLASSPATH", path)
79
+ saxon_jar_path = find_saxon_classpath()
80
+ assert saxon_jar_path is None
81
+
82
+
83
+ # ITER SDCC login01 20210617
84
+ # module load GCCcore/10.2.0
85
+ # module load Python/3.8.6-GCCcore-10.2.0
86
+ # module load MDSplus/7.96.17-GCCcore-10.2.0
87
+ # module load HDF5/1.10.7-iimpi-2020b # todo: Intel MPI version?
88
+ # module load Boost/1.74.0-GCCcore-10.2.0
89
+ # module load MDSplus-Java/7.96.17-GCCcore-10.2.0-Java-11
90
+ # module load Saxon-HE/10.3-Java-11
91
+ def test_classpath_sdcc(monkeypatch):
92
+ monkeypatch.setenv(
93
+ "CLASSPATH",
94
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-xqj-10.3.jar:"
95
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-test-10.3.jar:"
96
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/jline-2.9.jar:"
97
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-10.3.jar:"
98
+ "/work/imas/opt/EasyBuild/software/MDSplus-Java/7.96.17-GCCcore-10.2.0-Java-11/java/classes/*",
99
+ )
100
+ saxon_jar_path = find_saxon_classpath()
101
+ assert (
102
+ saxon_jar_path
103
+ == "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-10.3.jar"
104
+ )
105
+
106
+
107
+ # ITER HPC login01 20210617
108
+ # module load GCCcore/10.2.0
109
+ # module load Python/3.8.6-GCCcore-10.2.0
110
+ # module load MDSplus/7.96.17-GCCcore-10.2.0
111
+ # module load HDF5/1.10.7-iimpi-2020b # todo: Intel MPI version?
112
+ # module load Boost/1.74.0-GCCcore-10.2.0
113
+ # module load MDSplus-Java/7.96.17-GCCcore-10.2.0-Java-11
114
+ # module load Saxon-HE/10.3-Java-11
115
+ def test_classpath_hpc(monkeypatch):
116
+ monkeypatch.setenv(
117
+ "CLASSPATH",
118
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-xqj-10.3.jar:"
119
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-test-10.3.jar:"
120
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/jline-2.9.jar:"
121
+ "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-10.3.jar:"
122
+ "/work/imas/opt/EasyBuild/software/MDSplus-Java/7.96.17-GCCcore-10.2.0-Java-11/java/classes/*",
123
+ )
124
+ saxon_jar_path = find_saxon_classpath()
125
+ assert (
126
+ saxon_jar_path
127
+ == "/work/imas/opt/EasyBuild/software/Saxon-HE/10.3-Java-11/saxon-he-10.3.jar"
128
+ )
129
+
130
+
131
+ # TODO: Write tests!
132
+ # def find_saxon_bin():
133
+ # def get_data_dictionary_repo():
134
+ # def build_data_dictionary():
@@ -0,0 +1,29 @@
1
+ import pytest
2
+ from packaging.version import InvalidVersion
3
+
4
+ from imas.dd_zip import get_dd_xml, parse_dd_version
5
+ from imas.exception import UnknownDDVersion
6
+
7
+
8
+ def test_known_version():
9
+ """Test if 3.30.0 is part of the IDSDef.zip
10
+ Mostly this tests if IDSDef.zip has been made."""
11
+
12
+ get_dd_xml("3.30.0")
13
+
14
+
15
+ def test_known_failing_version():
16
+ """Test if 0.0 is not part of the IDSDef.zip"""
17
+
18
+ with pytest.raises(UnknownDDVersion):
19
+ get_dd_xml("0.0")
20
+
21
+
22
+ def test_parse_dd_version():
23
+ release_version = parse_dd_version("3.39.0")
24
+ dev_version = parse_dd_version("3.39.0-30-g7735675")
25
+ assert dev_version > release_version
26
+ dev_version2 = parse_dd_version("3.39.0-31-g7735675")
27
+ assert dev_version2 > dev_version
28
+ with pytest.raises(InvalidVersion):
29
+ parse_dd_version("garbage")
@@ -0,0 +1,25 @@
1
+ import copy
2
+
3
+ import imas
4
+ from imas.ids_struct_array import IDSStructArray
5
+ from imas.ids_structure import IDSStructure
6
+ from imas.test.test_helpers import compare_children, fill_with_random_data
7
+
8
+
9
+ def validate_parent(node):
10
+ for child in node:
11
+ assert child._parent is node
12
+ if isinstance(child, (IDSStructure, IDSStructArray)):
13
+ validate_parent(child)
14
+
15
+
16
+ def test_deepcopy():
17
+ factory = imas.IDSFactory()
18
+ cp = factory.core_profiles()
19
+ fill_with_random_data(cp)
20
+
21
+ cp2 = copy.deepcopy(cp)
22
+ compare_children(cp, cp2)
23
+
24
+ validate_parent(cp)
25
+ validate_parent(cp2)
@@ -0,0 +1,12 @@
1
+ import pytest
2
+
3
+ import imas
4
+ from imas.backends.imas_core.imas_interface import ll_interface
5
+
6
+
7
+ def test_catch_al_exception(requires_imas):
8
+ # Do something which lets the lowlevel Cython interface throw an ALException
9
+ # Ensure we can catch it:
10
+ with pytest.raises(imas.exception.ALException):
11
+ # Try to write an unknown data type (object)
12
+ ll_interface.write_data(-1, "X", "", object())
@@ -0,0 +1,388 @@
1
+ import numpy as np
2
+ import pytest
3
+
4
+ import imas
5
+ from imas.backends.imas_core.imas_interface import lowlevel
6
+ from imas.exception import DataEntryException
7
+ from imas.ids_defs import (
8
+ CLOSEST_INTERP,
9
+ HDF5_BACKEND,
10
+ IDS_TIME_MODE_HETEROGENEOUS,
11
+ IDS_TIME_MODE_HOMOGENEOUS,
12
+ LINEAR_INTERP,
13
+ MDSPLUS_BACKEND,
14
+ PREVIOUS_INTERP,
15
+ )
16
+
17
+
18
+ @pytest.fixture()
19
+ def test_db_uri(backend, worker_id, tmp_path_factory):
20
+ # Check if begin_timerange_action is available in imas_core
21
+ if not hasattr(lowlevel, "al_begin_timerange_action"):
22
+ pytest.skip("imas_core version doesn't support begin_timerange_action.")
23
+
24
+ # TODO: add MDSPLUS_BACKEND once implemented, see IMAS-5593
25
+ if backend not in [HDF5_BACKEND]:
26
+ pytest.skip("Backend doesn't support time range operations.")
27
+
28
+ tmp_path = tmp_path_factory.mktemp(f"testdb.{worker_id}")
29
+ backend_str = {HDF5_BACKEND: "hdf5", MDSPLUS_BACKEND: "mdsplus"}[backend]
30
+ uri = f"imas:{backend_str}?path={tmp_path}"
31
+ entry = imas.DBEntry(uri, "x", dd_version="4.0.0")
32
+
33
+ # Homogeneous core profiles:
34
+ cp = entry.factory.core_profiles()
35
+ cp.ids_properties.homogeneous_time = IDS_TIME_MODE_HOMOGENEOUS
36
+ N_time = 32
37
+ cp.time = np.linspace(0, 1, N_time)
38
+ cp.profiles_1d.resize(N_time)
39
+ for i in range(N_time):
40
+ # FLT_1D:
41
+ cp.profiles_1d[i].grid.rho_tor_norm = np.array([0.0, 1.0])
42
+ cp.profiles_1d[i].t_i_average = np.array([2.0, 1.0]) * (i + 1)
43
+ cp.profiles_1d[i].ion.resize(1)
44
+ # STR_0D:
45
+ cp.profiles_1d[i].ion[0].name = "D"
46
+ # FLT_0D
47
+ cp.profiles_1d[i].ion[0].z_ion = 1.0
48
+ cp.profiles_1d[i].ion[0].temperature = cp.profiles_1d[i].t_i_average
49
+ # INT_0D
50
+ cp.profiles_1d[i].ion[0].temperature_validity = 0
51
+ cp.global_quantities.ip = (2 - cp.time) ** 0.5
52
+ entry.put(cp)
53
+
54
+ # Inhomogeneous equilibrium
55
+ eq = entry.factory.equilibrium()
56
+ eq.ids_properties.homogeneous_time = IDS_TIME_MODE_HETEROGENEOUS
57
+ eq.time = np.linspace(0, 2, 512)
58
+ # GGD Grid with 1 time slice
59
+ eq.grids_ggd.resize(1)
60
+ eq.grids_ggd[0].time = 0.0
61
+ eq.grids_ggd[0].grid.resize(1)
62
+ eq.grids_ggd[0].grid[0].path = "wall:0/description_ggd(1)/grid_ggd"
63
+ # multiple time slices with data
64
+ N_time = 6
65
+ eq.time_slice.resize(N_time)
66
+ for i in range(N_time):
67
+ # FLT_0D
68
+ eq.time_slice[i].time = i / 5.0
69
+ eq.time_slice[i].profiles_2d.resize(1)
70
+ # FLT_1D
71
+ eq.time_slice[i].profiles_2d[0].grid.dim1 = np.array([0.0, 1.0])
72
+ eq.time_slice[i].profiles_2d[0].grid.dim2 = np.array([3.0, 4.0])
73
+ # STR_0D
74
+ eq.time_slice[i].profiles_2d[0].grid_type.name = f"test {i}"
75
+ eq.time_slice[i].profiles_2d[0].grid_type.description = "test description"
76
+ # INT_0D
77
+ eq.time_slice[i].profiles_2d[0].grid_type.index = -1
78
+ # FLT_2D
79
+ eq.time_slice[i].profiles_2d[0].r = np.array([[0.0, 0.0], [1.0, 1.0]])
80
+ eq.time_slice[i].profiles_2d[0].z = np.array([[3.0, 4.0], [3.0, 4.0]])
81
+ eq.time_slice[i].profiles_2d[0].psi = (
82
+ eq.time_slice[i].profiles_2d[0].r - eq.time_slice[i].profiles_2d[0].z
83
+ ) * (1 + eq.time_slice[i].time) ** 2
84
+ entry.put(eq)
85
+
86
+ # Equilibrium only has dynamic AOS and no other non-homogenous time nodes
87
+ # Use magnetics to test that case:
88
+ mag = entry.factory.magnetics()
89
+ mag.ids_properties.homogeneous_time = IDS_TIME_MODE_HETEROGENEOUS
90
+ mag.time = np.array([0.0])
91
+ mag.flux_loop.resize(3)
92
+ for i in range(3):
93
+ mag.flux_loop[i].flux.time = np.linspace(0.0123, 1, 5 + i)
94
+ mag.flux_loop[i].flux.data = 2 + 2 * mag.flux_loop[i].flux.time
95
+ mag.flux_loop[i].voltage.time = np.linspace(0.0123, 1, 8 + i)
96
+ mag.flux_loop[i].voltage.data = 2 - 5 * mag.flux_loop[i].voltage.time
97
+ entry.put(mag)
98
+
99
+ entry.close()
100
+ return uri
101
+
102
+
103
+ @pytest.fixture()
104
+ def entry(test_db_uri):
105
+ return imas.DBEntry(test_db_uri, "r", dd_version="4.0.0")
106
+
107
+
108
+ def test_invalid_arguments(entry):
109
+ with pytest.raises(ValueError):
110
+ entry.get_sample("core_profiles", 0.3, 0.2) # tmin > tmax
111
+ with pytest.raises(DataEntryException):
112
+ entry.get_sample("core_profiles", 0.1, 0.2, occurrence="invalid")
113
+ with pytest.raises(ValueError):
114
+ entry.get_sample("core_profiles", 0.1, 0.2, 0.05) # no interpolation method
115
+
116
+
117
+ def test_get_sample_homogeneous(entry):
118
+ cp = entry.get_sample("core_profiles", 0.3, 14 / 31)
119
+ assert np.array_equal(cp.time, np.linspace(0, 1, 32)[10:15])
120
+
121
+ for i, p1d in enumerate(cp.profiles_1d):
122
+ assert np.array_equal(p1d.grid.rho_tor_norm, [0.0, 1.0])
123
+ assert np.array_equal(p1d.t_i_average, np.array([2.0, 1.0]) * (i + 11))
124
+ assert len(p1d.ion) == 1
125
+ assert p1d.ion[0].name == "D"
126
+ assert p1d.ion[0].z_ion == 1
127
+ assert np.array_equal(p1d.ion[0].temperature, p1d.t_i_average)
128
+ assert p1d.ion[0].temperature_validity == 0
129
+
130
+ assert np.array_equal(cp.global_quantities.ip, (2 - cp.time) ** 0.5)
131
+
132
+
133
+ def test_get_sample_heterogeneous(entry):
134
+ eq = entry.get_sample("equilibrium", -1.0, 0.2)
135
+ # Main time array
136
+ assert np.array_equal(eq.time, np.linspace(0, 2, 512)[:52])
137
+ # grids_ggd AoS
138
+ assert len(eq.grids_ggd) == 1
139
+ assert eq.grids_ggd[0].time == 0.0
140
+ assert eq.grids_ggd[0].grid[0].path == "wall:0/description_ggd(1)/grid_ggd"
141
+ # time_slice AoS
142
+ assert len(eq.time_slice) == 2
143
+ assert eq.time_slice[0].time == 0.0
144
+ assert eq.time_slice[1].time == 0.2
145
+
146
+ for i in range(2):
147
+ p2d = eq.time_slice[i].profiles_2d[0]
148
+ assert np.array_equal(p2d.grid.dim1, [0.0, 1.0])
149
+ assert np.array_equal(p2d.grid.dim2, [3.0, 4.0])
150
+ assert p2d.grid_type.name == f"test {i}"
151
+ assert p2d.grid_type.index == -1
152
+ assert np.array_equal(p2d.r, [[0.0, 0.0], [1.0, 1.0]])
153
+ assert np.array_equal(p2d.z, [[3.0, 4.0], [3.0, 4.0]])
154
+ expected_psi = (p2d.r - p2d.z) * (1 + eq.time_slice[i].time) ** 2
155
+ assert np.array_equal(p2d.psi, expected_psi)
156
+
157
+ mag = entry.get_sample("magnetics", 0.25, 0.75)
158
+ assert mag.ids_properties.homogeneous_time == IDS_TIME_MODE_HETEROGENEOUS
159
+ assert len(mag.time) == 0
160
+ assert len(mag.flux_loop) == 3
161
+ for i in range(3):
162
+ fl = mag.flux_loop[i]
163
+
164
+ flux_time = np.linspace(0.0123, 1, 5 + i)
165
+ flux_time = flux_time[0.25 <= flux_time]
166
+ flux_time = flux_time[flux_time <= 0.75]
167
+ assert np.array_equal(fl.flux.time, flux_time)
168
+ assert np.array_equal(fl.flux.data, 2 + 2 * flux_time)
169
+
170
+ voltage_time = np.linspace(0.0123, 1, 8 + i)
171
+ voltage_time = voltage_time[0.25 <= voltage_time]
172
+ voltage_time = voltage_time[voltage_time <= 0.75]
173
+ assert np.array_equal(fl.voltage.time, voltage_time)
174
+ assert np.array_equal(fl.voltage.data, 2 - 5 * voltage_time)
175
+
176
+
177
+ def test_get_sample_homogeneous_linear_interp(entry):
178
+ # Note requesting 0.401 and not 0.4, since
179
+ # (0.3 + 0.02 + 0.02 + 0.02 + 0.02 + 0.02) = 0.4 + 5e-17
180
+ cp = entry.get_sample("core_profiles", 0.3, 0.401, 0.02, LINEAR_INTERP)
181
+ assert np.allclose(cp.time, np.linspace(0.3, 0.4, 6), rtol=1e-14, atol=0)
182
+
183
+ assert len(cp.profiles_1d) == 6
184
+ # Check some interpolated values
185
+ for i in range(6):
186
+ # Check rho_tor_norm
187
+ rho_tor_norm = cp.profiles_1d[i].grid.rho_tor_norm
188
+ assert np.array_equal(rho_tor_norm, np.array([0.0, 1.0]))
189
+ # Check t_i_average
190
+ expected = np.array([2.0, 1.0]) * (1 + 31 * cp.time[i])
191
+ t_i_average = cp.profiles_1d[i].t_i_average
192
+ assert np.allclose(t_i_average, expected, rtol=1e-14, atol=0)
193
+
194
+
195
+ def test_get_sample_homogeneous_explicit_timebase(entry):
196
+ times = [0.1, 0.2345, 0.5, np.sqrt(2) / 2]
197
+ cp = entry.get_sample("core_profiles", 0, 0, times, LINEAR_INTERP)
198
+ assert np.allclose(cp.time, times, rtol=1e-14, atol=0)
199
+
200
+ assert len(cp.profiles_1d) == 4
201
+ # Check some interpolated values
202
+ for i in range(4):
203
+ # Check rho_tor_norm
204
+ rho_tor_norm = cp.profiles_1d[i].grid.rho_tor_norm
205
+ assert np.array_equal(rho_tor_norm, np.array([0.0, 1.0]))
206
+ # Check t_i_average
207
+ expected = np.array([2.0, 1.0]) * (1 + 31 * cp.time[i])
208
+ t_i_average = cp.profiles_1d[i].t_i_average
209
+ assert np.allclose(t_i_average, expected, rtol=1e-14, atol=0)
210
+
211
+
212
+ def test_get_sample_homogeneous_previous_interp(entry):
213
+ # Note requesting 0.401 and not 0.4, since
214
+ # (0.3 + 0.02 + 0.02 + 0.02 + 0.02 + 0.02) = 0.4 + 5e-17
215
+ cp = entry.get_sample("core_profiles", 0.3, 0.401, 0.02, PREVIOUS_INTERP)
216
+ assert np.allclose(cp.time, np.linspace(0.3, 0.4, 6), rtol=1e-14, atol=0)
217
+
218
+ assert len(cp.profiles_1d) == 6
219
+ # Check some interpolated values
220
+ for i in range(6):
221
+ # Check rho_tor_norm
222
+ rho_tor_norm = cp.profiles_1d[i].grid.rho_tor_norm
223
+ assert np.array_equal(rho_tor_norm, np.array([0.0, 1.0]))
224
+ # Check t_i_average
225
+ expected = np.array([2.0, 1.0]) * [10, 10, 11, 12, 12, 13][i]
226
+ t_i_average = cp.profiles_1d[i].t_i_average
227
+ assert np.allclose(t_i_average, expected, rtol=1e-14, atol=0)
228
+
229
+
230
+ def test_get_sample_homogeneous_closest_interp(entry):
231
+ # Note requesting 0.401 and not 0.4, since
232
+ # (0.3 + 0.02 + 0.02 + 0.02 + 0.02 + 0.02) = 0.4 + 5e-17
233
+ cp = entry.get_sample("core_profiles", 0.3, 0.401, 0.02, CLOSEST_INTERP)
234
+ assert np.allclose(cp.time, np.linspace(0.3, 0.4, 6), rtol=1e-14, atol=0)
235
+
236
+ assert len(cp.profiles_1d) == 6
237
+ # Check some interpolated values
238
+ for i in range(6):
239
+ # Check rho_tor_norm
240
+ rho_tor_norm = cp.profiles_1d[i].grid.rho_tor_norm
241
+ assert np.array_equal(rho_tor_norm, np.array([0.0, 1.0]))
242
+ # Check t_i_average
243
+ expected = np.array([2.0, 1.0]) * [10, 11, 12, 12, 13, 13][i]
244
+ t_i_average = cp.profiles_1d[i].t_i_average
245
+ assert np.allclose(t_i_average, expected, rtol=1e-14, atol=0)
246
+
247
+
248
+ def test_get_sample_heterogeneous_linear_interp(entry):
249
+ eq = entry.get_sample("equilibrium", 0.2, 0.501, 0.05, LINEAR_INTERP)
250
+ N_samples = 7
251
+ # IDS becomes homogeneous after resampling
252
+ assert np.allclose(eq.time, np.linspace(0.2, 0.5, N_samples))
253
+ assert eq.ids_properties.homogeneous_time == IDS_TIME_MODE_HOMOGENEOUS
254
+
255
+ # Check interpolated grids_ggd
256
+ assert len(eq.grids_ggd) == N_samples
257
+ for i in range(N_samples):
258
+ # assert eq.grids_ggd[i].time == EMPTY_FLOAT
259
+ assert len(eq.grids_ggd[i].grid) == 1
260
+ assert eq.grids_ggd[i].grid[0].path == "wall:0/description_ggd(1)/grid_ggd"
261
+
262
+ # Check interpolated time_slice
263
+ assert len(eq.time_slice) == N_samples
264
+ for i in range(N_samples):
265
+ # assert eq.time_slice[i].time == EMPTY_FLOAT
266
+ assert len(eq.time_slice[i].profiles_2d) == 1
267
+ p2d = eq.time_slice[i].profiles_2d[0]
268
+ assert np.array_equal(p2d.grid.dim1, [0.0, 1.0])
269
+ assert np.array_equal(p2d.grid.dim2, [3.0, 4.0])
270
+
271
+ # Determine the data as we have stored it in test_db_uri()
272
+ time = eq.time[i]
273
+ original_times = [0, 0.2, 0.4, 0.6, 0.8, 1.0]
274
+ index = np.searchsorted(original_times, time)
275
+ prevtime = original_times[index - 1]
276
+ nexttime = original_times[index]
277
+ prevpsi = (p2d.r - p2d.z) * (1 + prevtime) ** 2
278
+ nextpsi = (p2d.r - p2d.z) * (1 + nexttime) ** 2
279
+ # Linear interpolation
280
+ expected_psi = (nextpsi * (time - prevtime) + prevpsi * (nexttime - time)) / (
281
+ nexttime - prevtime
282
+ )
283
+ assert np.allclose(p2d.psi, expected_psi, rtol=1e-14, atol=0)
284
+
285
+ mag = entry.get_sample("magnetics", 0.2, 0.501, 0.05, LINEAR_INTERP)
286
+ assert mag.ids_properties.homogeneous_time == IDS_TIME_MODE_HOMOGENEOUS
287
+ assert np.allclose(mag.time, np.linspace(0.2, 0.5, N_samples))
288
+
289
+ assert len(mag.flux_loop) == 3
290
+ for i in range(3):
291
+ fl = mag.flux_loop[i]
292
+ assert np.allclose(fl.flux.data, 2 + 2 * mag.time, rtol=1e-14, atol=0)
293
+ assert np.allclose(fl.voltage.data, 2 - 5 * mag.time, rtol=1e-14, atol=2e-16)
294
+
295
+
296
+ def test_get_sample_heterogeneous_previous_interp(entry):
297
+ eq = entry.get_sample("equilibrium", 0.2, 0.501, 0.05, PREVIOUS_INTERP)
298
+ N_samples = 7
299
+ # IDS becomes homogeneous after resampling
300
+ assert np.allclose(eq.time, np.linspace(0.2, 0.5, N_samples))
301
+ assert eq.ids_properties.homogeneous_time == IDS_TIME_MODE_HOMOGENEOUS
302
+
303
+ # Check interpolated grids_ggd
304
+ assert len(eq.grids_ggd) == N_samples
305
+ for i in range(N_samples):
306
+ # assert eq.grids_ggd[i].time == EMPTY_FLOAT
307
+ assert len(eq.grids_ggd[i].grid) == 1
308
+ assert eq.grids_ggd[i].grid[0].path == "wall:0/description_ggd(1)/grid_ggd"
309
+
310
+ # Check interpolated time_slice
311
+ assert len(eq.time_slice) == N_samples
312
+ for i in range(N_samples):
313
+ # assert eq.time_slice[i].time == EMPTY_FLOAT
314
+ assert len(eq.time_slice[i].profiles_2d) == 1
315
+ p2d = eq.time_slice[i].profiles_2d[0]
316
+ assert np.array_equal(p2d.grid.dim1, [0.0, 1.0])
317
+ assert np.array_equal(p2d.grid.dim2, [3.0, 4.0])
318
+
319
+ origtime = [0.2, 0.2, 0.2, 0.2, 0.4, 0.4, 0.4][i]
320
+ expected_psi = (p2d.r - p2d.z) * (1 + origtime) ** 2
321
+ assert np.allclose(p2d.psi, expected_psi, rtol=1e-14, atol=0)
322
+
323
+ mag = entry.get_sample("magnetics", 0.2, 0.501, 0.05, PREVIOUS_INTERP)
324
+ assert mag.ids_properties.homogeneous_time == IDS_TIME_MODE_HOMOGENEOUS
325
+ assert np.allclose(mag.time, np.linspace(0.2, 0.5, N_samples))
326
+
327
+ assert len(mag.flux_loop) == 3
328
+ for i in range(3):
329
+ fl = mag.flux_loop[i]
330
+
331
+ flux_time = np.linspace(0.0123, 1, 5 + i)
332
+ flux_time = flux_time[np.searchsorted(flux_time, mag.time, side="right") - 1]
333
+ assert np.array_equal(fl.flux.data, 2 + 2 * flux_time)
334
+
335
+ voltage_time = np.linspace(0.0123, 1, 8 + i)
336
+ voltage_time = voltage_time[
337
+ np.searchsorted(voltage_time, mag.time, side="right") - 1
338
+ ]
339
+ assert np.array_equal(fl.voltage.data, 2 - 5 * voltage_time)
340
+
341
+
342
+ def test_get_sample_heterogeneous_closest_interp(entry):
343
+ eq = entry.get_sample("equilibrium", 0.2, 0.501, 0.05, CLOSEST_INTERP)
344
+ N_samples = 7
345
+ # IDS becomes homogeneous after resampling
346
+ assert np.allclose(eq.time, np.linspace(0.2, 0.5, N_samples))
347
+ assert eq.ids_properties.homogeneous_time == IDS_TIME_MODE_HOMOGENEOUS
348
+
349
+ # Check interpolated grids_ggd
350
+ assert len(eq.grids_ggd) == N_samples
351
+ for i in range(N_samples):
352
+ # assert eq.grids_ggd[i].time == EMPTY_FLOAT
353
+ assert len(eq.grids_ggd[i].grid) == 1
354
+ assert eq.grids_ggd[i].grid[0].path == "wall:0/description_ggd(1)/grid_ggd"
355
+
356
+ # Check interpolated time_slice
357
+ assert len(eq.time_slice) == N_samples
358
+ for i in range(N_samples):
359
+ # assert eq.time_slice[i].time == EMPTY_FLOAT
360
+ assert len(eq.time_slice[i].profiles_2d) == 1
361
+ p2d = eq.time_slice[i].profiles_2d[0]
362
+ assert np.array_equal(p2d.grid.dim1, [0.0, 1.0])
363
+ assert np.array_equal(p2d.grid.dim2, [3.0, 4.0])
364
+
365
+ # Note: CLOSEST appears to round up: 0.4 is closer to 0.3 than 0.2
366
+ origtime = [0.2, 0.2, 0.4, 0.4, 0.4, 0.4, 0.6][i]
367
+ expected_psi = (p2d.r - p2d.z) * (1 + origtime) ** 2
368
+ assert np.allclose(p2d.psi, expected_psi, rtol=1e-14, atol=0)
369
+
370
+ mag = entry.get_sample("magnetics", 0.2, 0.501, 0.05, CLOSEST_INTERP)
371
+ assert mag.ids_properties.homogeneous_time == IDS_TIME_MODE_HOMOGENEOUS
372
+ assert np.allclose(mag.time, np.linspace(0.2, 0.5, N_samples))
373
+
374
+ assert len(mag.flux_loop) == 3
375
+ for i in range(3):
376
+ fl = mag.flux_loop[i]
377
+
378
+ flux_time = np.linspace(0.0123, 1, 5 + i)
379
+ flux_time = flux_time[
380
+ np.argmin(np.abs(flux_time[None, :] - mag.time[:, None]), axis=1)
381
+ ]
382
+ assert np.array_equal(fl.flux.data, 2 + 2 * flux_time)
383
+
384
+ voltage_time = np.linspace(0.0123, 1, 8 + i)
385
+ voltage_time = voltage_time[
386
+ np.argmin(np.abs(voltage_time[None, :] - mag.time[:, None]), axis=1)
387
+ ]
388
+ assert np.array_equal(fl.voltage.data, 2 - 5 * voltage_time)