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,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():
|
imas/test/test_dd_zip.py
ADDED
|
@@ -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)
|