From d3d63d240156be981eff89f335d7eb38c21f942b Mon Sep 17 00:00:00 2001 From: abhilash-kumar-nair Date: Tue, 16 Jun 2026 09:46:58 +0530 Subject: [PATCH 1/2] refactor: extract FMU definition builder and simplify get_definition Move FMU experiment construction and extensions building into module-level functions parallel to _build_simple_modelica_experiment_definition, and consolidate expansion_from_dict to accept the full expansion dict --- .../client/entities/_initialize_from.py | 16 +- modelon/impact/client/entities/experiment.py | 149 +++++++++--------- .../client/experiment_definition/expansion.py | 6 +- .../experiment_definition/model_based.py | 5 +- 4 files changed, 88 insertions(+), 88 deletions(-) diff --git a/modelon/impact/client/entities/_initialize_from.py b/modelon/impact/client/entities/_initialize_from.py index 1feda3bf..dfe158dd 100644 --- a/modelon/impact/client/entities/_initialize_from.py +++ b/modelon/impact/client/entities/_initialize_from.py @@ -10,11 +10,11 @@ from modelon.impact.client.sal.service import Service -def _resolve_initialize_from( +def _resolve_extension_initialize_from( workspace_id: str, sal: Service, modifiers: Dict[str, Any], -) -> Optional[Union[Case, Experiment, ExternalResult]]: +) -> Optional[Union[Case, Experiment]]: if "initializeFrom" in modifiers: from modelon.impact.client.entities.experiment import Experiment @@ -27,8 +27,16 @@ def _resolve_initialize_from( case_id = modifiers["initializeFromCase"]["caseId"] case_data = sal.experiment.case_get(workspace_id, exp_id, case_id) return Case(case_data["id"], workspace_id, exp_id, sal, case_data) - elif "initializeFromExternalResult" in modifiers: + return None + + +def _resolve_initialize_from( + workspace_id: str, + sal: Service, + modifiers: Dict[str, Any], +) -> Optional[Union[Case, Experiment, ExternalResult]]: + if "initializeFromExternalResult" in modifiers: return ExternalResult( result_id=modifiers["initializeFromExternalResult"], service=sal ) - return None + return _resolve_extension_initialize_from(workspace_id, sal, modifiers) diff --git a/modelon/impact/client/entities/experiment.py b/modelon/impact/client/entities/experiment.py index fc7f710d..91d21227 100644 --- a/modelon/impact/client/entities/experiment.py +++ b/modelon/impact/client/entities/experiment.py @@ -6,14 +6,16 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union -from modelon.impact.client.entities._initialize_from import _resolve_initialize_from +from modelon.impact.client.entities._initialize_from import ( + _resolve_extension_initialize_from, + _resolve_initialize_from, +) from modelon.impact.client.entities.asserts import assert_variable_in_result from modelon.impact.client.entities.case import Case from modelon.impact.client.entities.custom_function import ( CustomFunction, _build_custom_function, ) -from modelon.impact.client.entities.external_result import ExternalResult from modelon.impact.client.entities.interfaces.experiment import ExperimentReference from modelon.impact.client.entities.model import ( Model, @@ -194,6 +196,62 @@ def label(self) -> Optional[str]: return self._meta_data.get("label") +def _build_extensions_from_dict( + extensions: List[Dict[str, Any]], + workspace_id: str, + sal: "Service", +) -> List[SimpleExperimentExtension]: + sim_exts = [] + for extension in extensions: + analysis = extension.get("analysis", {}) + ext_custom_function_params = { + param["name"]: param["value"] for param in analysis.get("parameters", []) + } + sim_ext = SimpleExperimentExtension( + parameter_modifiers=ext_custom_function_params, + solver_options=analysis.get("solverOptions"), + simulation_options=analysis.get("simulationOptions"), + simulation_log_level=analysis.get("simulationLogLevel"), + initialize_from=_resolve_extension_initialize_from( + workspace_id, sal, extension.get("modifiers", {}) + ), + ) + ext_modifiers = { + mod["name"]: to_domain_parameter_value(mod) + for mod in extension.get("modifiers", {}).get("variables", []) + } + sim_ext = sim_ext.with_modifiers(modifiers=ext_modifiers) + case_data = extension.get("caseData", []) + case_labels = [data.get("label") for data in case_data] + if case_labels: + sim_ext = sim_ext.with_case_label(case_labels[0]) + sim_exts.append(sim_ext) + return sim_exts + + +def _build_simple_fmu_experiment_definition( + base: Dict[str, Any], + custom_function: "CustomFunction", + workspace_id: str, + sal: "Service", +) -> SimpleFMUExperimentDefinition: + analysis = base["analysis"] + modifiers = base.get("modifiers", {}) + fmu_id = base["model"]["fmu"]["id"] + variable_modifiers = { + mod["name"]: get_operator_from_dict(mod) + for mod in modifiers.get("variables", []) + } + return SimpleFMUExperimentDefinition( + fmu=ModelExecutable(workspace_id, fmu_id, sal), + custom_function=custom_function, + solver_options=analysis.get("solverOptions", {}), + simulation_options=analysis.get("simulationOptions", {}), + simulation_log_level=analysis.get("simulationLogLevel", "WARNING"), + initialize_from=_resolve_initialize_from(workspace_id, sal, modifiers), + ).with_modifiers(modifiers=variable_modifiers) + + class Experiment(ExperimentReference): """Class containing Experiment functionalities.""" @@ -613,35 +671,6 @@ def get_solver_options(self) -> SolverOptions: analysis = self._get_info()["experiment"]["base"]["analysis"] return SolverOptions(analysis.get("solverOptions", {}), self.custom_function) - def _get_initialize_from_case(self, experiment_id: str, case_id: str) -> Case: - case_data = self._sal.experiment.case_get( - self._workspace_id, experiment_id, case_id - ) - return Case( - case_data["id"], self._workspace_id, experiment_id, self._sal, case_data - ) - - def _get_initialize_from_experiment(self, experiment_id: str) -> Experiment: - resp = self._sal.workspace.experiment_get(self._workspace_id, experiment_id) - return Experiment(self._workspace_id, resp["id"], self._sal, resp) - - def _get_initialize_from( - self, modifiers: Dict[str, Any] - ) -> Optional[Union[Case, Experiment, ExternalResult]]: - return _resolve_initialize_from(self._workspace_id, self._sal, modifiers) - - def _get_extension_initialize_from( - self, modifiers: Dict[str, Any] - ) -> Optional[Union[Case, Experiment]]: - if "initializeFrom" in modifiers: - exp_id = modifiers["initializeFrom"] - return self._get_initialize_from_experiment(exp_id) - elif "initializeFromCase" in modifiers: - case_id = modifiers["initializeFromCase"]["caseId"] - exp_id = modifiers["initializeFromCase"]["experimentId"] - return self._get_initialize_from_case(exp_id, case_id) - return None - def get_definition(self) -> ValidExperimentDefinitions: """Get an experiment definition that can be used to reproduce this experiment result. @@ -655,9 +684,12 @@ def get_definition(self) -> ValidExperimentDefinitions: definition = experiment.get_definition() """ - base = self._get_info(cached=False)["experiment"]["base"] + info = self._get_info(cached=False)["experiment"] + base = info["base"] + extensions_data = info.get("extensions", []) analysis = base["analysis"] custom_function = self._get_custom_function(analysis) + definition: ValidExperimentDefinitions if self._get_workflow() == _Workflow.CLASS_BASED: model = Model( self.get_model_name(), @@ -669,52 +701,15 @@ def get_definition(self) -> ValidExperimentDefinitions: model, base, custom_function, self._workspace_id, self._sal ) else: - fmu_id = base["model"]["fmu"]["id"] - definition = SimpleFMUExperimentDefinition( - fmu=ModelExecutable(self._workspace_id, fmu_id, self._sal), - custom_function=custom_function, - solver_options=self.get_solver_options(), - simulation_options=self.get_simulation_options(), - simulation_log_level=analysis["simulationLogLevel"], - initialize_from=self._get_initialize_from(base["modifiers"]), - ) # type: ignore - modifiers = { - mod["name"]: get_operator_from_dict(mod) - for mod in base["modifiers"]["variables"] - } - definition = definition.with_modifiers(modifiers=modifiers) - extensions = self._get_info()["experiment"].get("extensions") - if extensions: - sim_exts = [] - for extension in extensions: - analysis = extension.get("analysis", {}) - ext_custom_function_params = { - param["name"]: param["value"] - for param in analysis.get("parameters", []) - } - sim_ext = SimpleExperimentExtension( - parameter_modifiers=ext_custom_function_params, - solver_options=analysis.get("solverOptions"), - simulation_options=analysis.get("simulationOptions"), - simulation_log_level=analysis.get("simulationLogLevel"), - initialize_from=self._get_extension_initialize_from( - extension["modifiers"] - ) - if extension.get("modifiers") - else None, + definition = _build_simple_fmu_experiment_definition( + base, custom_function, self._workspace_id, self._sal + ) + if extensions_data: + definition = definition.with_extensions( + _build_extensions_from_dict( + extensions_data, self._workspace_id, self._sal ) - ext_modifiers = { - mod["name"]: to_domain_parameter_value(mod) - for mod in extension.get("modifiers", {}).get("variables", []) - } - sim_ext = sim_ext.with_modifiers(modifiers=ext_modifiers) - case_data = extension.get("caseData", []) - case_labels = [data.get("label") for data in case_data] - if case_labels: - case_label = case_labels[0] - sim_ext = sim_ext.with_case_label(case_label) - sim_exts.append(sim_ext) - definition = definition.with_extensions(sim_exts) + ) return definition def _get_custom_function(self, analysis: Dict[str, Any]) -> CustomFunction: diff --git a/modelon/impact/client/experiment_definition/expansion.py b/modelon/impact/client/experiment_definition/expansion.py index 09b0e04a..88f3fe9c 100644 --- a/modelon/impact/client/experiment_definition/expansion.py +++ b/modelon/impact/client/experiment_definition/expansion.py @@ -113,9 +113,9 @@ def get_parameters_as_dict(self) -> Optional[Dict[str, Any]]: return asdict(self) -def expansion_from_dict( - algorithm: str, parameters: Dict[str, Any] -) -> ExpansionAlgorithm: +def expansion_from_dict(expansion_dict: Dict[str, Any]) -> ExpansionAlgorithm: + algorithm = expansion_dict.get("algorithm", "") + parameters = expansion_dict.get("parameters", {}) if algorithm == "SOBOL": return Sobol(samples=parameters["samples"]) elif algorithm == "LATINHYPERCUBE": diff --git a/modelon/impact/client/experiment_definition/model_based.py b/modelon/impact/client/experiment_definition/model_based.py index f6f40143..8bd83e06 100644 --- a/modelon/impact/client/experiment_definition/model_based.py +++ b/modelon/impact/client/experiment_definition/model_based.py @@ -78,10 +78,7 @@ def _build_simple_modelica_experiment_definition( mod["name"]: get_operator_from_dict(mod) for mod in base.get("modifiers", {}).get("variables", []) } - expansion_dict = base.get("expansion", {}) - expansion = expansion_from_dict( - expansion_dict.get("algorithm", ""), expansion_dict.get("parameters", {}) - ) + expansion = expansion_from_dict(base.get("expansion", {})) return ( SimpleModelicaExperimentDefinition( model=model, From 64d3d4dc4524697da00dea0bb9b0d2793ca00cdd Mon Sep 17 00:00:00 2001 From: abhilash-kumar-nair Date: Wed, 5 Aug 2026 12:27:21 +0530 Subject: [PATCH 2/2] refactor: unify experiment definition building from dict Move the FMU and Modelica definition builders into a single 'experiment_definition/from_dict' module and expose one '_build_experiment_definition' function that takes the full experiment dict, picks the workflow inline and attaches the extensions, so both workflows go through the same dict -> entity path. 'Model.get_experiment_definitions' now goes through the same function and asserts that a class based definition is returned. --- ...on.impact.client.experiment_definition.rst | 8 + modelon/impact/client/entities/experiment.py | 112 +----------- modelon/impact/client/entities/model.py | 15 +- .../client/experiment_definition/from_dict.py | 171 ++++++++++++++++++ .../experiment_definition/model_based.py | 42 ----- 5 files changed, 198 insertions(+), 150 deletions(-) create mode 100644 modelon/impact/client/experiment_definition/from_dict.py diff --git a/docs/source/modelon.impact.client.experiment_definition.rst b/docs/source/modelon.impact.client.experiment_definition.rst index 11906802..f2d07a61 100644 --- a/docs/source/modelon.impact.client.experiment_definition.rst +++ b/docs/source/modelon.impact.client.experiment_definition.rst @@ -44,6 +44,14 @@ modelon.impact.client.experiment\_definition.fmu\_based module :undoc-members: :show-inheritance: +modelon.impact.client.experiment\_definition.from\_dict module +-------------------------------------------------------------- + +.. automodule:: modelon.impact.client.experiment_definition.from_dict + :members: + :undoc-members: + :show-inheritance: + modelon.impact.client.experiment\_definition.model\_based module ---------------------------------------------------------------- diff --git a/modelon/impact/client/entities/experiment.py b/modelon/impact/client/entities/experiment.py index 91d21227..29744b37 100644 --- a/modelon/impact/client/entities/experiment.py +++ b/modelon/impact/client/entities/experiment.py @@ -6,10 +6,6 @@ from dataclasses import dataclass from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union -from modelon.impact.client.entities._initialize_from import ( - _resolve_extension_initialize_from, - _resolve_initialize_from, -) from modelon.impact.client.entities.asserts import assert_variable_in_result from modelon.impact.client.entities.case import Case from modelon.impact.client.entities.custom_function import ( @@ -17,23 +13,11 @@ _build_custom_function, ) from modelon.impact.client.entities.interfaces.experiment import ExperimentReference -from modelon.impact.client.entities.model import ( - Model, - SimpleModelicaExperimentDefinition, - to_domain_parameter_value, -) -from modelon.impact.client.entities.model_executable import ( - ModelExecutable, - SimpleFMUExperimentDefinition, -) from modelon.impact.client.entities.status import ExperimentStatus -from modelon.impact.client.experiment_definition.extension import ( - SimpleExperimentExtension, +from modelon.impact.client.experiment_definition.from_dict import ( + ValidExperimentDefinitions, + _build_experiment_definition, ) -from modelon.impact.client.experiment_definition.model_based import ( - _build_simple_modelica_experiment_definition, -) -from modelon.impact.client.experiment_definition.operators import get_operator_from_dict from modelon.impact.client.operations import experiment from modelon.impact.client.options import ( CompilerOptions, @@ -49,10 +33,6 @@ logger = logging.getLogger(__name__) ScalarValue = Union[float, int, str] -ValidExperimentDefinitions = Union[ - SimpleModelicaExperimentDefinition, - SimpleFMUExperimentDefinition, -] @enum.unique @@ -196,62 +176,6 @@ def label(self) -> Optional[str]: return self._meta_data.get("label") -def _build_extensions_from_dict( - extensions: List[Dict[str, Any]], - workspace_id: str, - sal: "Service", -) -> List[SimpleExperimentExtension]: - sim_exts = [] - for extension in extensions: - analysis = extension.get("analysis", {}) - ext_custom_function_params = { - param["name"]: param["value"] for param in analysis.get("parameters", []) - } - sim_ext = SimpleExperimentExtension( - parameter_modifiers=ext_custom_function_params, - solver_options=analysis.get("solverOptions"), - simulation_options=analysis.get("simulationOptions"), - simulation_log_level=analysis.get("simulationLogLevel"), - initialize_from=_resolve_extension_initialize_from( - workspace_id, sal, extension.get("modifiers", {}) - ), - ) - ext_modifiers = { - mod["name"]: to_domain_parameter_value(mod) - for mod in extension.get("modifiers", {}).get("variables", []) - } - sim_ext = sim_ext.with_modifiers(modifiers=ext_modifiers) - case_data = extension.get("caseData", []) - case_labels = [data.get("label") for data in case_data] - if case_labels: - sim_ext = sim_ext.with_case_label(case_labels[0]) - sim_exts.append(sim_ext) - return sim_exts - - -def _build_simple_fmu_experiment_definition( - base: Dict[str, Any], - custom_function: "CustomFunction", - workspace_id: str, - sal: "Service", -) -> SimpleFMUExperimentDefinition: - analysis = base["analysis"] - modifiers = base.get("modifiers", {}) - fmu_id = base["model"]["fmu"]["id"] - variable_modifiers = { - mod["name"]: get_operator_from_dict(mod) - for mod in modifiers.get("variables", []) - } - return SimpleFMUExperimentDefinition( - fmu=ModelExecutable(workspace_id, fmu_id, sal), - custom_function=custom_function, - solver_options=analysis.get("solverOptions", {}), - simulation_options=analysis.get("simulationOptions", {}), - simulation_log_level=analysis.get("simulationLogLevel", "WARNING"), - initialize_from=_resolve_initialize_from(workspace_id, sal, modifiers), - ).with_modifiers(modifiers=variable_modifiers) - - class Experiment(ExperimentReference): """Class containing Experiment functionalities.""" @@ -685,32 +609,10 @@ def get_definition(self) -> ValidExperimentDefinitions: """ info = self._get_info(cached=False)["experiment"] - base = info["base"] - extensions_data = info.get("extensions", []) - analysis = base["analysis"] - custom_function = self._get_custom_function(analysis) - definition: ValidExperimentDefinitions - if self._get_workflow() == _Workflow.CLASS_BASED: - model = Model( - self.get_model_name(), - workspace_id=self._workspace_id, - project_id="", - service=self._sal, - ) - definition = _build_simple_modelica_experiment_definition( - model, base, custom_function, self._workspace_id, self._sal - ) - else: - definition = _build_simple_fmu_experiment_definition( - base, custom_function, self._workspace_id, self._sal - ) - if extensions_data: - definition = definition.with_extensions( - _build_extensions_from_dict( - extensions_data, self._workspace_id, self._sal - ) - ) - return definition + custom_function = self._get_custom_function(info["base"]["analysis"]) + return _build_experiment_definition( + info, custom_function, self._workspace_id, self._sal + ) def _get_custom_function(self, analysis: Dict[str, Any]) -> CustomFunction: meta = self._sal.custom_function.custom_function_get( diff --git a/modelon/impact/client/entities/model.py b/modelon/impact/client/entities/model.py index 6c2efbc5..406c33bd 100644 --- a/modelon/impact/client/entities/model.py +++ b/modelon/impact/client/entities/model.py @@ -13,9 +13,11 @@ from modelon.impact.client.entities.interfaces.model import ModelInterface from modelon.impact.client.entities.model_executable import ModelExecutable from modelon.impact.client.entities.project import Project +from modelon.impact.client.experiment_definition.from_dict import ( + _build_experiment_definition, +) from modelon.impact.client.experiment_definition.model_based import ( SimpleModelicaExperimentDefinition, - _build_simple_modelica_experiment_definition, ) from modelon.impact.client.experiment_definition.modifiers import Enumeration from modelon.impact.client.operations.fmu_import import FMUImportOperation @@ -266,9 +268,16 @@ def get_experiment_definitions( custom_function = _build_custom_function( self._workspace_id, cf_meta, self._sal ).with_parameters(**params) - definition = _build_simple_modelica_experiment_definition( - self, base, custom_function, self._workspace_id, self._sal + definition = _build_experiment_definition( + item["experiment"], + custom_function, + self._workspace_id, + self._sal, + model=self, ) + # Experiment definitions are always defined for a model, the API + # never returns an FMU based definition here. + assert isinstance(definition, SimpleModelicaExperimentDefinition) meta = item["metadata"] entries.append( ExperimentDefinitionEntry( diff --git a/modelon/impact/client/experiment_definition/from_dict.py b/modelon/impact/client/experiment_definition/from_dict.py new file mode 100644 index 00000000..4ea1bae1 --- /dev/null +++ b/modelon/impact/client/experiment_definition/from_dict.py @@ -0,0 +1,171 @@ +from __future__ import annotations + +import logging +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union + +from modelon.impact.client.entities._initialize_from import ( + _resolve_extension_initialize_from, + _resolve_initialize_from, +) +from modelon.impact.client.entities.model_executable import ModelExecutable +from modelon.impact.client.experiment_definition.expansion import expansion_from_dict +from modelon.impact.client.experiment_definition.extension import ( + SimpleExperimentExtension, +) +from modelon.impact.client.experiment_definition.fmu_based import ( + SimpleFMUExperimentDefinition, +) +from modelon.impact.client.experiment_definition.model_based import ( + SimpleModelicaExperimentDefinition, +) +from modelon.impact.client.experiment_definition.operators import get_operator_from_dict + +if TYPE_CHECKING: + from modelon.impact.client.entities.custom_function import CustomFunction + from modelon.impact.client.entities.model import Model + from modelon.impact.client.sal.service import Service + +logger = logging.getLogger(__name__) + +ValidExperimentDefinitions = Union[ + SimpleModelicaExperimentDefinition, + SimpleFMUExperimentDefinition, +] + + +def _create_model(class_name: str, workspace_id: str, sal: Service) -> Model: + # Imported here as the model entity module imports this module. + from modelon.impact.client.entities.model import Model + + return Model(class_name, workspace_id=workspace_id, project_id="", service=sal) + + +def _get_variable_modifiers(modifiers: Dict[str, Any]) -> Dict[str, Any]: + return { + mod["name"]: get_operator_from_dict(mod) + for mod in modifiers.get("variables", []) + } + + +def _build_extensions( + extensions: List[Dict[str, Any]], + workspace_id: str, + sal: Service, +) -> List[SimpleExperimentExtension]: + # Imported here as the model entity module imports this module. + from modelon.impact.client.entities.model import to_domain_parameter_value + + sim_exts = [] + for extension in extensions: + analysis = extension.get("analysis", {}) + modifiers = extension.get("modifiers", {}) + sim_ext = SimpleExperimentExtension( + parameter_modifiers={ + param["name"]: param["value"] + for param in analysis.get("parameters", []) + }, + solver_options=analysis.get("solverOptions"), + simulation_options=analysis.get("simulationOptions"), + simulation_log_level=analysis.get("simulationLogLevel"), + initialize_from=_resolve_extension_initialize_from( + workspace_id, sal, modifiers + ), + ).with_modifiers( + modifiers={ + mod["name"]: to_domain_parameter_value(mod) + for mod in modifiers.get("variables", []) + } + ) + case_labels = [data.get("label") for data in extension.get("caseData", [])] + if case_labels: + sim_ext = sim_ext.with_case_label(case_labels[0]) + sim_exts.append(sim_ext) + return sim_exts + + +def _build_modelica_definition( + base: Dict[str, Any], + custom_function: CustomFunction, + workspace_id: str, + sal: Service, + model: Optional[Model] = None, +) -> SimpleModelicaExperimentDefinition: + modelica = base["model"]["modelica"] + analysis = base["analysis"] + return ( + SimpleModelicaExperimentDefinition( + model=model or _create_model(modelica["className"], workspace_id, sal), + custom_function=custom_function, + compiler_options=modelica.get("compilerOptions", {}), + fmi_target=modelica.get("fmiTarget", "me"), + fmi_version=modelica.get("fmiVersion", "2.0"), + platform=modelica.get("platform", "auto"), + compiler_log_level=modelica.get("compilerLogLevel", "warning"), + runtime_options=modelica.get("runtimeOptions", {}), + solver_options=analysis.get("solverOptions", {}), + simulation_options=analysis.get("simulationOptions", {}), + simulation_log_level=analysis.get("simulationLogLevel", "WARNING"), + initialize_from=_resolve_initialize_from( + workspace_id, sal, base.get("modifiers", {}) + ), + ) + .with_modifiers(_get_variable_modifiers(base.get("modifiers", {}))) + .with_expansion(expansion_from_dict(base.get("expansion", {}))) + ) + + +def _build_fmu_definition( + base: Dict[str, Any], + custom_function: CustomFunction, + workspace_id: str, + sal: Service, +) -> SimpleFMUExperimentDefinition: + # Note: The FMU based experiment definition has no expansion support, + # so any expansion data in 'base' is not carried over here. + analysis = base["analysis"] + modifiers = base.get("modifiers", {}) + return SimpleFMUExperimentDefinition( + fmu=ModelExecutable(workspace_id, base["model"]["fmu"]["id"], sal), + custom_function=custom_function, + solver_options=analysis.get("solverOptions", {}), + simulation_options=analysis.get("simulationOptions", {}), + simulation_log_level=analysis.get("simulationLogLevel", "WARNING"), + initialize_from=_resolve_initialize_from(workspace_id, sal, modifiers), + ).with_modifiers(modifiers=_get_variable_modifiers(modifiers)) + + +def _build_experiment_definition( + info: Dict[str, Any], + custom_function: CustomFunction, + workspace_id: str, + sal: Service, + model: Optional[Model] = None, +) -> ValidExperimentDefinitions: + """Build an experiment definition entity from an experiment dictionary. + + Args: + info: The 'experiment' part of an experiment dictionary, holding the + 'base' definition and any 'extensions'. + custom_function: The custom function to use for the definition. + workspace_id: The workspace identifier. + sal: The service class. + model: The Model class object to use for class based experiments. If not + given, a Model is created from the class name in the dictionary. + + Returns: + An instance of SimpleModelicaExperimentDefinition for class based + experiments and SimpleFMUExperimentDefinition for FMU based experiments. + + """ + base = info["base"] + definition: ValidExperimentDefinitions = ( + _build_modelica_definition(base, custom_function, workspace_id, sal, model) + if base["model"].get("modelica") + else _build_fmu_definition(base, custom_function, workspace_id, sal) + ) + extensions = info.get("extensions", []) + if extensions: + definition = definition.with_extensions( + _build_extensions(extensions, workspace_id, sal) + ) + return definition diff --git a/modelon/impact/client/experiment_definition/model_based.py b/modelon/impact/client/experiment_definition/model_based.py index 8bd83e06..d11b32f9 100644 --- a/modelon/impact/client/experiment_definition/model_based.py +++ b/modelon/impact/client/experiment_definition/model_based.py @@ -3,7 +3,6 @@ import logging from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union -from modelon.impact.client.entities._initialize_from import _resolve_initialize_from from modelon.impact.client.entities.interfaces.case import CaseInterface from modelon.impact.client.entities.interfaces.experiment import ExperimentInterface from modelon.impact.client.entities.interfaces.external_result import ( @@ -18,7 +17,6 @@ from modelon.impact.client.experiment_definition.expansion import ( ExpansionAlgorithm, FullFactorial, - expansion_from_dict, ) from modelon.impact.client.experiment_definition.extension import ( SimpleExperimentExtension, @@ -31,7 +29,6 @@ ensure_as_modifier, modifiers_to_dict, ) -from modelon.impact.client.experiment_definition.operators import get_operator_from_dict from modelon.impact.client.experiment_definition.util import ( case_to_identifier_dict, custom_function_parameters_to_dict, @@ -50,7 +47,6 @@ SimulationOptions, SolverOptions, ) - from modelon.impact.client.sal.service import Service CaseOrExperimentOrExternalResult = Union[Case, Experiment, ExternalResult] RuntimeOptionsOrDict = Union[RuntimeOptions, Dict[str, Any]] @@ -61,44 +57,6 @@ logger = logging.getLogger(__name__) -def _build_simple_modelica_experiment_definition( - model: "Model", - base: Dict[str, Any], - custom_function: "CustomFunction", - workspace_id: str, - sal: "Service", -) -> "SimpleModelicaExperimentDefinition": - initialize_from = _resolve_initialize_from( - workspace_id, sal, base.get("modifiers", {}) - ) - - modelica = base["model"]["modelica"] - analysis = base["analysis"] - variable_modifiers = { - mod["name"]: get_operator_from_dict(mod) - for mod in base.get("modifiers", {}).get("variables", []) - } - expansion = expansion_from_dict(base.get("expansion", {})) - return ( - SimpleModelicaExperimentDefinition( - model=model, - custom_function=custom_function, - compiler_options=modelica.get("compilerOptions", {}), - fmi_target=modelica.get("fmiTarget", "me"), - fmi_version=modelica.get("fmiVersion", "2.0"), - platform=modelica.get("platform", "auto"), - compiler_log_level=modelica.get("compilerLogLevel", "warning"), - runtime_options=modelica.get("runtimeOptions", {}), - solver_options=analysis.get("solverOptions", {}), - simulation_options=analysis.get("simulationOptions", {}), - simulation_log_level=analysis.get("simulationLogLevel", "WARNING"), - initialize_from=initialize_from, - ) - .with_modifiers(variable_modifiers) - .with_expansion(expansion) - ) - - class SimpleModelicaExperimentDefinition(BaseExperimentDefinition): """A simple experiment definition class for defining experiments.