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,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())"
|