Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions tests/test_exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -647,6 +647,24 @@ def test_export_constant(tmp_path):
assert np.array_equal(ids.beam[2].phase.angle, [3.3e3] * 3)


def test_export_constant_static_field(tmp_path):
"""A constant waveform bound to a static DD node must export its single value."""

yaml_str = """
globals:
dd_version: 4.0.0
edge_profiles:
edge_profiles/midplane/name:
- {type: constant, value: asdf, duration: 2}
"""
file_path = f"{tmp_path}/test.nc"
times = np.array([0, 1, 2])
_export_ids(file_path, yaml_str, times)
with imas.DBEntry(file_path, "r", dd_version="4.0.0") as dbentry:
ids = dbentry.get("edge_profiles", autoconvert=False)
assert ids.midplane.name == "asdf"


def test_export_typed_waveforms(tmp_path):
"""Check that constant waveforms of each supported value type"""

Expand Down
51 changes: 51 additions & 0 deletions tests/test_waveform.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,57 @@ def test_dtype_str_dd_path():
assert waveform.annotations


def test_static_0d_dd_path():
"""A constant waveform may fill a static (non time-dependent) 0D DD node."""
waveform = Waveform(
waveform=[
{"user_type": "constant", "user_value": "a comment", "line_number": 1}
],
name="ec_launchers/ids_properties/comment",
dd_version=DD_VERSION,
)
assert not waveform.annotations


def test_static_0d_dd_path_rejects_varying_waveform():
"""A static DD node cannot hold different values at different times"""
waveform = Waveform(
waveform=[
{
"user_type": "constant",
"user_value": "a",
"user_duration": 1,
"line_number": 1,
},
{
"user_type": "constant",
"user_value": "b",
"user_duration": 1,
"line_number": 2,
},
],
name="ec_launchers/ids_properties/comment",
dd_version=DD_VERSION,
)
assert waveform.annotations


def test_1d_dd_path():
"""Tests 1D waveforms whose coordinate is and isn't time"""
waveform = Waveform(
waveform=[{"user_type": "constant", "user_value": 5, "line_number": 1}],
name="ec_launchers/beam(1)/phase/angle",
dd_version=DD_VERSION,
)
assert not waveform.annotations
waveform = Waveform(
waveform=[{"user_type": "constant", "user_value": 5, "line_number": 1}],
name="core_profiles/profiles_1d/electrons/temperature",
dd_version=DD_VERSION,
)
assert waveform.annotations


def test_no_metadata_allows_any_type():
"""A waveform whose path does not resolve to any DD node is not restricted
to any particular value type."""
Expand Down
9 changes: 9 additions & 0 deletions waveform_editor/export/exporter.py
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,15 @@ def _fill_nodes_recursively(self, node, path, values, path_index=0, fill=True):
"""
if path_index == len(path.parts):
if fill:
if (
not node.metadata.type.is_dynamic
and isinstance(values, np.ndarray)
and values.ndim > 0
):
# A static IDS node must be filled by a single constant tendency, so
# every entry of `values` should be identical. Collapse it to one
assert np.all(values == values[0])
values = values[0]
node.value = values
return
part = path.parts[path_index]
Expand Down
37 changes: 33 additions & 4 deletions waveform_editor/waveform.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,16 +221,45 @@ def _validate_value_type(self):
self.annotations.add(0, error_msg)
return

if self.metadata is None:
return

# If a valid DD path is chosen, check if the value_type matches the DD type
if (
self.metadata is not None
and self.metadata.data_type not in IDS_DATATYPES[self.value_type]
):
if self.metadata.data_type not in IDS_DATATYPES[self.value_type]:
error_msg = (
"Type is not valid here: this waveform expects a "
f"{self.metadata.data_type}.\n"
)
self.annotations.add(self.tendencies[0].line_number, error_msg)
return

if self.metadata.ndim > 1:
error_msg = (
f"{self.metadata.data_type.name}_{self.metadata.ndim}D quantities are "
"not supported.\n"
)
self.annotations.add(self.tendencies[0].line_number, error_msg)
return

if self.metadata.ndim == 1 and not self.metadata.timebasepath:
error_msg = (
"This 1D quantity's coordinate is not time, so it cannot be filled "
"by a waveform.\n"
)
self.annotations.add(self.tendencies[0].line_number, error_msg)
return

# A static DD node cannot hold different values, so it may only be filled
# with a single constant tendency
if not self.metadata.type.is_dynamic and (
len(self.tendencies) != 1
or not isinstance(self.tendencies[0], ConstantTendency)
):
error_msg = (
"This DD node does not vary in time, so it can only "
"be filled by a single constant tendency.\n"
)
self.annotations.add(self.tendencies[0].line_number, error_msg)

def update_annotations(self, event=None):
"""Merges the annotations of the individual tendencies into the annotations
Expand Down
Loading