Skip to content

Commit

Permalink
Merge pull request #413 from ESSS/fb-ASIM-5862-sdk-ref-inside-table
Browse files Browse the repository at this point in the history
Load user plugins with table containing reference
  • Loading branch information
prusse-martin authored Jan 9, 2025
2 parents 1eef148 + f6ce479 commit fcd48ee
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 158 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ CHANGELOG
* Changed the constructor of result metadata objects in ``alfasim_sdk.result_reader.aggregator`` from ``attr`` to ``dataclasses.dataclass`` to make then more easily integrated into the (de)serialization engine of popular packages such as ``pyserde`` and ``pydantic``.
* Changed function ``read_global_sensitivity_coefficients`` and ``read_uncertainty_propagation_results`` to accept multiple keys so it can perform bulk reads without having to open the result file every time.
* Added ``GlobalSensitivityAnalysisResults``, ``HistoryMatchingDeterministicResults``, ``HistoryMatchingProbabilisticResults`` and ``UncertaintyPropagationResults``, which are objects to read and interact with the Uncertainty Quantification analyses results in a more user-friendly way.
* Plugins can now define tables that contain references to other objects.

2024.2 (2024-09-10)
===================
Expand Down
Binary file modified docs/source/_static/images/api/table_field_example_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions src/alfasim_sdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ def get_alfasim_sdk_api_path():
from alfasim_sdk._internal.alfacase.case_description import (
PressureContainerDescription,
)
from alfasim_sdk._internal.alfacase.case_description import (
InternalReferencePluginTableColumn,
)
from alfasim_sdk._internal.alfacase.case_description import (
TracerReferencePluginTableColumn,
)
from alfasim_sdk._internal.alfacase.case_description import (
PressureNodePropertiesDescription,
)
Expand Down Expand Up @@ -431,6 +437,7 @@ def get_alfasim_sdk_api_path():
"InitialVelocitiesDescription",
"InitialVolumeFractionsDescription",
"InternalNodePropertiesDescription",
"InternalReferencePluginTableColumn",
"InterpolationType",
"LeakEquipmentDescription",
"LeakLocation",
Expand Down Expand Up @@ -516,6 +523,7 @@ def get_alfasim_sdk_api_path():
"TimeOptionsDescription",
"TracerModelConstantCoefficientsDescription",
"TracerModelType",
"TracerReferencePluginTableColumn",
"TracerType",
"TracersDescription",
"TracersMassFractionsContainerDescription",
Expand Down
33 changes: 33 additions & 0 deletions src/alfasim_sdk/_internal/alfacase/case_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from barril.units import Array
from barril.units import Scalar

from ..validators import non_empty_str
from .case_description_attributes import attrib_array
from .case_description_attributes import attrib_curve
from .case_description_attributes import attrib_dict_of
Expand All @@ -32,6 +33,7 @@
from .case_description_attributes import dict_of_array
from .case_description_attributes import dict_with_scalar
from .case_description_attributes import InvalidReferenceError
from .case_description_attributes import list_of_optional_integers
from .case_description_attributes import list_of_strings
from .case_description_attributes import Numpy1DArray
from .case_description_attributes import numpy_array_validator
Expand Down Expand Up @@ -86,6 +88,7 @@ class PluginTracerReference:
@attr.s(frozen=True, slots=True)
class PluginInternalReference:
plugin_item_id = attr.ib(default=None)
container_key = attr.ib(default=None)


@attr.s(frozen=True, slots=True)
Expand All @@ -94,6 +97,36 @@ class PluginMultipleReference:
item_id_list = attr.ib(default=attr.Factory(list))


@attr.s(frozen=True, slots=True)
class TracerReferencePluginTableColumn:
"""
A column holding tracer references.
:ivar tracer_ids:
A list of tracer indexes (by declaration order in the tracer container), entries with
the value `None` represent unset references.
"""

tracer_ids = attr.ib(validator=list_of_optional_integers)


@attr.s(frozen=True, slots=True)
class InternalReferencePluginTableColumn:
"""
A column holding internal references.
:ivar plugin_item_ids:
A list of item indexes (by declaration order in the relevant container), entries with
the value `None` represent unset references.
:ivar container_key:
The name of a class defined in the plugin decorated with `container_model`.
"""

plugin_item_ids = attr.ib(validator=list_of_optional_integers)
container_key = attr.ib(validator=non_empty_str)


@attr.s(frozen=True, slots=True)
class PluginTableContainer:
columns = attr.ib(default=attr.Factory(dict))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
list_of_strings = deep_iterable(
member_validator=optional(instance_of(str)), iterable_validator=instance_of(list)
)
list_of_optional_integers = deep_iterable(
member_validator=optional(instance_of(int)), iterable_validator=instance_of(list)
)
AttrNothingType = type(attr.NOTHING)
ScalarLike = Union[Tuple[Number, str], Scalar]
ArrayLike = Union[Tuple[Sequence[Number], str], Array]
Expand Down
56 changes: 43 additions & 13 deletions src/alfasim_sdk/_internal/alfacase/plugin_alfacase_to_case.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,18 @@
from alfasim_sdk._internal.alfacase.alfacase_to_case import load_value
from alfasim_sdk._internal.alfacase.alfacase_to_case import to_case_values
from alfasim_sdk._internal.alfacase.case_description import CaseDescription
from alfasim_sdk._internal.alfacase.case_description import (
InternalReferencePluginTableColumn,
)
from alfasim_sdk._internal.alfacase.case_description import PluginDescription
from alfasim_sdk._internal.alfacase.case_description import PluginFileContent
from alfasim_sdk._internal.alfacase.case_description import PluginInternalReference
from alfasim_sdk._internal.alfacase.case_description import PluginMultipleReference
from alfasim_sdk._internal.alfacase.case_description import PluginTableContainer
from alfasim_sdk._internal.alfacase.case_description import PluginTracerReference
from alfasim_sdk._internal.alfacase.case_description import (
TracerReferencePluginTableColumn,
)
from alfasim_sdk._internal.alfacase.case_description_attributes import (
InvalidPluginDataError,
)
Expand Down Expand Up @@ -311,8 +317,11 @@ def _convert_reference(
if is_dict_with_keys(value, "tracer_id"):
return PluginTracerReference(tracer_id=int(value["tracer_id"]))
else:
if is_dict_with_keys(value, "plugin_item_id"):
return PluginInternalReference(plugin_item_id=int(value["plugin_item_id"]))
if is_dict_with_keys(value, "plugin_item_id", strict=False):
return PluginInternalReference(
container_key=value.get("container_key"),
plugin_item_id=int(value["plugin_item_id"]),
)
raise InvalidPluginDataError(f"Can not convert to a reference: {value!r}")


Expand Down Expand Up @@ -341,6 +350,35 @@ def _convert_string(
raise InvalidPluginDataError(f"Can not convert to a string: {value!r}")


def _convert_table_column_contents(
raw_col: object,
) -> Union[Array, InternalReferencePluginTableColumn, TracerReferencePluginTableColumn]:
"""
Try to convert an object into a valid table column content.
This is a helper function to `_convert_table` and is not registered
in `_PLUGIN_FIELD_TO_CASEDESCRIPTION`.
"""
if is_dict_with_keys(raw_col, "values", "unit"):
# Quantity.
return Array([float(v) for v in raw_col["values"]], raw_col["unit"])
elif is_dict_with_keys(raw_col, "tracer_ids"):
# Reference to tracer.
return TracerReferencePluginTableColumn(
[(int(v) if v != "None" else None) for v in raw_col["tracer_ids"]]
)
elif is_dict_with_keys(raw_col, "plugin_item_ids", "container_key"):
# Reference to plugin model.
return InternalReferencePluginTableColumn(
container_key=raw_col["container_key"],
plugin_item_ids=[
(int(v) if v != "None" else None) for v in raw_col["plugin_item_ids"]
],
)
else:
raise InvalidPluginDataError(f"Can not convert table column: {raw_col!r}")


def _convert_table(
value: object, type_from_plugin: BaseField, alfacase_path: Path
) -> PluginTableContainer:
Expand All @@ -352,17 +390,9 @@ def _convert_table(
raw_columns = value["columns"]
col_ids = [col.id for col in type_from_plugin.rows]
if is_dict_with_keys(raw_columns, *col_ids):
columns = {}
for col in col_ids:
raw_col = raw_columns[col]
if is_dict_with_keys(raw_col, "values", "unit"):
columns[col] = Array(
[float(v) for v in raw_col["values"]], raw_col["unit"]
)
else:
raise InvalidPluginDataError(
f"Can not convert table column: {raw_col!r}"
)
columns = {
col: _convert_table_column_contents(raw_columns[col]) for col in col_ids
}
return PluginTableContainer(columns=columns)
raise InvalidPluginDataError(f"Can not convert to a table: {value!r}")

Expand Down
Loading

0 comments on commit fcd48ee

Please sign in to comment.