Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load user plugins with table containing reference #413

Merged
merged 1 commit into from
Jan 9, 2025
Merged
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
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
Loading