Skip to content
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
93 changes: 62 additions & 31 deletions OMPython/ModelicaSystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import pathlib
import platform
from typing import Any, Optional
import warnings

import numpy as np

Expand Down Expand Up @@ -77,14 +78,62 @@ def _set_compatibility_helper(
pkey: str,
args: Any,
kwargs: dict[str, Any],
) -> Any:
param = None
) -> dict[str, Any]:
input_args = []
if len(args) == 1:
param = args[0]
if param is None and pkey in kwargs:
param = kwargs[pkey]

return param
input_args.append(args[0])
elif pkey in kwargs:
input_args.append(kwargs[pkey])

# the code below is based on _prepare_input_data2()

def prepare_str(str_in: str) -> dict[str, str]:
str_in = str_in.replace(" ", "")
key_val_list: list[str] = str_in.split("=")
if len(key_val_list) != 2:
raise ModelicaSystemError(f"Invalid 'key=value' pair: {str_in}")
if len(key_val_list[0]) == 0:
raise ModelicaSystemError(f"Empty key: {str_in}")

input_data_from_str: dict[str, str] = {str(key_val_list[0]): str(key_val_list[1])}

return input_data_from_str

input_data: dict[str, str] = {}

if input_args is None:
return input_data

for input_arg in input_args:
if isinstance(input_arg, str):
warnings.warn(message="The definition of values to set should use a dictionary, "
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
category=DeprecationWarning,
stacklevel=3)
input_data = input_data | prepare_str(input_arg)
elif isinstance(input_arg, list):
warnings.warn(message="The definition of values to set should use a dictionary, "
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
category=DeprecationWarning,
stacklevel=3)

for item in input_arg:
if not isinstance(item, str):
raise ModelicaSystemError(f"Invalid input data type for set*() function: {type(item)}!")
input_data = input_data | prepare_str(item)
elif isinstance(input_arg, dict):
input_arg_str: dict[str, str] = {}
for key, val in input_arg.items():
if not isinstance(key, str) or len(key) == 0:
raise ModelicaSystemError(f"Invalid key for set*() functions: {repr(key)}")
input_arg_str[key] = str(val).replace(' ', '')
input_data = input_data | input_arg_str
else:
raise ModelicaSystemError(f"Invalid input data type for set*() function: {type(input_arg)}!")

return input_data

def setContinuous(
self,
Expand All @@ -104,10 +153,7 @@ def setContinuous(
```
"""
param = self._set_compatibility_helper(pkey='cvals', args=args, kwargs=kwargs)
if param is None:
raise ModelicaSystemError("Invalid input for setContinuous() (v4.0.0 compatibility mode).")

return super().setContinuous(param)
return super().setContinuous(**param)

def setParameters(
self,
Expand All @@ -127,10 +173,7 @@ def setParameters(
```
"""
param = self._set_compatibility_helper(pkey='pvals', args=args, kwargs=kwargs)
if param is None:
raise ModelicaSystemError("Invalid input for setParameters() (v4.0.0 compatibility mode).")

return super().setParameters(param)
return super().setParameters(**param)

def setOptimizationOptions(
self,
Expand All @@ -150,10 +193,7 @@ def setOptimizationOptions(
```
"""
param = self._set_compatibility_helper(pkey='optimizationOptions', args=args, kwargs=kwargs)
if param is None:
raise ModelicaSystemError("Invalid input for setOptimizationOptions() (v4.0.0 compatibility mode).")

return super().setOptimizationOptions(param)
return super().setOptimizationOptions(**param)

def setInputs(
self,
Expand All @@ -173,10 +213,7 @@ def setInputs(
```
"""
param = self._set_compatibility_helper(pkey='name', args=args, kwargs=kwargs)
if param is None:
raise ModelicaSystemError("Invalid input for setInputs() (v4.0.0 compatibility mode).")

return super().setInputs(param)
return super().setInputs(**param)

def setSimulationOptions(
self,
Expand All @@ -196,10 +233,7 @@ def setSimulationOptions(
```
"""
param = self._set_compatibility_helper(pkey='simOptions', args=args, kwargs=kwargs)
if param is None:
raise ModelicaSystemError("Invalid input for setSimulationOptions() (v4.0.0 compatibility mode).")

return super().setSimulationOptions(param)
return super().setSimulationOptions(**param)

def setLinearizationOptions(
self,
Expand All @@ -219,10 +253,7 @@ def setLinearizationOptions(
```
"""
param = self._set_compatibility_helper(pkey='linearizationOptions', args=args, kwargs=kwargs)
if param is None:
raise ModelicaSystemError("Invalid input for setLinearizationOptions() (v4.0.0 compatibility mode).")

return super().setLinearizationOptions(param)
return super().setLinearizationOptions(**param)

def getContinuous(
self,
Expand Down
2 changes: 1 addition & 1 deletion OMPython/modelica_doe_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ def prepare(self) -> int:
}
)

self._mod.setParameters(sim_param_non_structural)
self._mod.setParameters(**sim_param_non_structural)
mscmd = self._mod.simulate_cmd(
result_file=resultfile,
)
Expand Down
109 changes: 20 additions & 89 deletions OMPython/modelica_system_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import os
import re
from typing import Any, Optional
import warnings
import xml.etree.ElementTree as ET

import numpy as np
Expand Down Expand Up @@ -759,56 +758,13 @@ def simulate(

@staticmethod
def _prepare_input_data(
input_args: Any,
input_kwargs: dict[str, Any],
) -> dict[str, str]:
"""
Convert raw input to a structured dictionary {'key1': 'value1', 'key2': 'value2'}.
"""

def prepare_str(str_in: str) -> dict[str, str]:
str_in = str_in.replace(" ", "")
key_val_list: list[str] = str_in.split("=")
if len(key_val_list) != 2:
raise ModelicaSystemError(f"Invalid 'key=value' pair: {str_in}")
if len(key_val_list[0]) == 0:
raise ModelicaSystemError(f"Empty key: {str_in}")

input_data_from_str: dict[str, str] = {str(key_val_list[0]): str(key_val_list[1])}

return input_data_from_str

input_data: dict[str, str] = {}

for input_arg in input_args:
if isinstance(input_arg, str):
warnings.warn(message="The definition of values to set should use a dictionary, "
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
category=DeprecationWarning,
stacklevel=3)
input_data = input_data | prepare_str(input_arg)
elif isinstance(input_arg, list):
warnings.warn(message="The definition of values to set should use a dictionary, "
"i.e. {'key1': 'val1', 'key2': 'val2', ...}. Please convert all cases which "
"use a string ('key=val') or list ['key1=val1', 'key2=val2', ...]",
category=DeprecationWarning,
stacklevel=3)

for item in input_arg:
if not isinstance(item, str):
raise ModelicaSystemError(f"Invalid input data type for set*() function: {type(item)}!")
input_data = input_data | prepare_str(item)
elif isinstance(input_arg, dict):
input_arg_str: dict[str, str] = {}
for key, val in input_arg.items():
if not isinstance(key, str) or len(key) == 0:
raise ModelicaSystemError(f"Invalid key for set*() functions: {repr(key)}")
input_arg_str[key] = str(val)
input_data = input_data | input_arg_str
else:
raise ModelicaSystemError(f"Invalid input data type for set*() function: {type(input_arg)}!")

if len(input_kwargs):
for key, val in input_kwargs.items():
# ensure all values are strings to align it on one type: dict[str, str]
Expand Down Expand Up @@ -886,21 +842,17 @@ def isParameterChangeable(

def setContinuous(
self,
*args: Any,
**kwargs: dict[str, Any],
) -> bool:
"""
This method is used to set continuous values. It can be called:
with a sequence of continuous name and assigning corresponding values as arguments as show in the example below:
usage
>>> setContinuous("Name=value") # depreciated
>>> setContinuous(["Name1=value1","Name2=value2"]) # depreciated
This method is used to set continuous values.

usage:
>>> setContinuous(Name1="value1", Name2="value2")
>>> param = {"Name1": "value1", "Name2": "value2"}
>>> setContinuous(**param)
"""
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
inputdata = self._prepare_input_data(input_kwargs=kwargs)

return self._set_method_helper(
inputdata=inputdata,
Expand All @@ -910,21 +862,17 @@ def setContinuous(

def setParameters(
self,
*args: Any,
**kwargs: dict[str, Any],
) -> bool:
"""
This method is used to set parameter values. It can be called:
with a sequence of parameter name and assigning corresponding value as arguments as show in the example below:
usage
>>> setParameters("Name=value") # depreciated
>>> setParameters(["Name1=value1","Name2=value2"]) # depreciated
This method is used to set parameter values

usage:
>>> setParameters(Name1="value1", Name2="value2")
>>> param = {"Name1": "value1", "Name2": "value2"}
>>> setParameters(**param)
"""
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
inputdata = self._prepare_input_data(input_kwargs=kwargs)

return self._set_method_helper(
inputdata=inputdata,
Expand All @@ -934,22 +882,17 @@ def setParameters(

def setSimulationOptions(
self,
*args: Any,
**kwargs: dict[str, Any],
) -> bool:
"""
This method is used to set simulation options. It can be called:
with a sequence of simulation options name and assigning corresponding values as arguments as show in the
example below:
usage
>>> setSimulationOptions("Name=value") # depreciated
>>> setSimulationOptions(["Name1=value1","Name2=value2"]) # depreciated
This method is used to set simulation options.

usage:
>>> setSimulationOptions(Name1="value1", Name2="value2")
>>> param = {"Name1": "value1", "Name2": "value2"}
>>> setSimulationOptions(**param)
"""
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
inputdata = self._prepare_input_data(input_kwargs=kwargs)

return self._set_method_helper(
inputdata=inputdata,
Expand All @@ -959,22 +902,17 @@ def setSimulationOptions(

def setLinearizationOptions(
self,
*args: Any,
**kwargs: dict[str, Any],
) -> bool:
"""
This method is used to set linearization options. It can be called:
with a sequence of linearization options name and assigning corresponding value as arguments as show in the
example below
usage
>>> setLinearizationOptions("Name=value") # depreciated
>>> setLinearizationOptions(["Name1=value1","Name2=value2"]) # depreciated
This method is used to set linearization options.

usage:
>>> setLinearizationOptions(Name1="value1", Name2="value2")
>>> param = {"Name1": "value1", "Name2": "value2"}
>>> setLinearizationOptions(**param)
"""
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
inputdata = self._prepare_input_data(input_kwargs=kwargs)

return self._set_method_helper(
inputdata=inputdata,
Expand All @@ -984,22 +922,17 @@ def setLinearizationOptions(

def setOptimizationOptions(
self,
*args: Any,
**kwargs: dict[str, Any],
) -> bool:
"""
This method is used to set optimization options. It can be called:
with a sequence of optimization options name and assigning corresponding values as arguments as show in the
example below:
usage
>>> setOptimizationOptions("Name=value") # depreciated
>>> setOptimizationOptions(["Name1=value1","Name2=value2"]) # depreciated
This method is used to set optimization options.

usage:
>>> setOptimizationOptions(Name1="value1", Name2="value2")
>>> param = {"Name1": "value1", "Name2": "value2"}
>>> setOptimizationOptions(**param)
"""
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
inputdata = self._prepare_input_data(input_kwargs=kwargs)

return self._set_method_helper(
inputdata=inputdata,
Expand All @@ -1013,19 +946,17 @@ def setInputs(
**kwargs: dict[str, Any],
) -> bool:
"""
This method is used to set input values. It can be called with a sequence of input name and assigning
corresponding values as arguments as show in the example below. Compared to other set*() methods this is a
special case as value could be a list of tuples - these are converted to a string in _prepare_input_data()
and restored here via ast.literal_eval().
This method is used to set input values.

>>> setInputs("Name=value") # depreciated
>>> setInputs(["Name1=value1","Name2=value2"]) # depreciated
Compared to other set*() methods this is a special case as value could be a list of tuples - these are
converted to a string in _prepare_input_data() and restored here via ast.literal_eval().

usage:
>>> setInputs(Name1="value1", Name2="value2")
>>> param = {"Name1": "value1", "Name2": "value2"}
>>> setInputs(**param)
"""
inputdata = self._prepare_input_data(input_args=args, input_kwargs=kwargs)
inputdata = self._prepare_input_data(input_kwargs=kwargs)

for key, val in inputdata.items():
if key not in self._inputs:
Expand Down
6 changes: 2 additions & 4 deletions tests/test_ModelicaSystemOMC.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,8 @@ def test_setParameters():
model_name="BouncingBall",
)

# method 1 (test depreciated variants)
mod.setParameters("e=1.234")
mod.setParameters(["g=321.0"])
mod.setParameters(e=1.234)
mod.setParameters(g=321.0)
assert mod.getParameters("e") == ["1.234"]
assert mod.getParameters("g") == ["321.0"]
assert mod.getParameters() == {
Expand All @@ -76,7 +75,6 @@ def test_setParameters():
with pytest.raises(KeyError):
mod.getParameters("thisParameterDoesNotExist")

# method 2 (new style)
pvals = {"e": 21.3, "g": 0.12}
mod.setParameters(**pvals)
assert mod.getParameters() == {
Expand Down
Loading
Loading