diff --git a/OMPython/ModelicaSystem.py b/OMPython/ModelicaSystem.py index e9c247b3..6e53954f 100644 --- a/OMPython/ModelicaSystem.py +++ b/OMPython/ModelicaSystem.py @@ -32,6 +32,7 @@ CONDITIONS OF OSMC-PL. """ +import ast import csv from dataclasses import dataclass import importlib @@ -45,8 +46,7 @@ import subprocess import tempfile import textwrap -from typing import Optional, Any -import warnings +from typing import Any, Optional import xml.etree.ElementTree as ET from OMPython.OMCSession import OMCSessionException, OMCSessionZMQ @@ -275,52 +275,6 @@ def run(self) -> int: return returncode - @staticmethod - def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, str]]]: - """ - Parse a simflag definition; this is depreciated! - - The return data can be used as input for self.args_set(). - - Parameters - ---------- - simflags : str - - Returns - ------- - dict - """ - warnings.warn("The argument 'simflags' is depreciated and will be removed in future versions; " - "please use 'simargs' instead", DeprecationWarning, stacklevel=2) - - simargs: dict[str, Optional[str | dict[str, str]]] = {} - - args = [s for s in simflags.split(' ') if s] - for arg in args: - if arg[0] != '-': - raise ModelicaSystemError(f"Invalid simulation flag: {arg}") - arg = arg[1:] - parts = arg.split('=') - if len(parts) == 1: - simargs[parts[0]] = None - elif parts[0] == 'override': - override = '='.join(parts[1:]) - - override_dict = {} - for item in override.split(','): - kv = item.split('=') - if not 0 < len(kv) < 3: - raise ModelicaSystemError(f"Invalid value for '-override': {override}") - if kv[0]: - try: - override_dict[kv[0]] = kv[1] - except (KeyError, IndexError) as ex: - raise ModelicaSystemError(f"Invalid value for '-override': {override}") from ex - - simargs[parts[0]] = override_dict - - return simargs - class ModelicaSystem: def __init__( @@ -867,9 +821,12 @@ def getOptimizationOptions(self, names=None): # 10 raise ModelicaSystemError("Unhandled input for getOptimizationOptions()") - def simulate(self, resultfile: Optional[str] = None, simflags: Optional[str] = None, - simargs: Optional[dict[str, Optional[str | dict[str, str]]]] = None, - timeout: Optional[int] = None): # 11 + def simulate( + self, + resultfile: Optional[str] = None, + simargs: Optional[dict[str, Optional[str | dict[str, str]]]] = None, + timeout: Optional[int] = None + ): # 11 """ This method simulates model according to the simulation options. usage @@ -891,11 +848,7 @@ def simulate(self, resultfile: Optional[str] = None, simflags: Optional[str] = N # always define the resultfile to use om_cmd.arg_set(key="r", val=self.resultfile.as_posix()) - # allow runtime simulation flags from user input - if simflags is not None: - om_cmd.args_set(args=om_cmd.parse_simflags(simflags=simflags)) - - if simargs: + if simargs is not None: om_cmd.args_set(args=simargs) overrideFile = self.tempdir / f"{self.modelName}_override.txt" @@ -992,164 +945,209 @@ def getSolutions(self, varList=None, resultfile=None): # 12 return np_res @staticmethod - def _strip_space(name): - if isinstance(name, str): - return name.replace(" ", "") + def _prepare_input_data( + raw_input: dict[str, Any], + ) -> dict[str, str]: + """ + Convert raw input to a structured dictionary {'key1': 'value1', 'key2': 'value2'}. + """ - if isinstance(name, list): - return [x.replace(" ", "") for x in name] + input_data: dict[str, str] = {} + if isinstance(raw_input, dict): + for key, val in raw_input.items(): + # convert all values to strings to align it on one type: dict[str, str] + # spaces have to be removed as setInput() could take list of tuples as input and spaces would + str_val = str(val).replace(' ', '') + if ' ' in key or ' ' in str_val: + raise ModelicaSystemError(f"Spaces not allowed in key/value pairs: {repr(key)} = {repr(val)}!") + input_data[key] = str_val - raise ModelicaSystemError("Unhandled input for strip_space()") + return input_data - def setMethodHelper(self, args1, args2, args3, args4=None): + raise ModelicaSystemError(f"Invalid type of input: {type(raw_input)}") + + def _set_method_helper( + self, + inputdata: dict[str, str], + classdata: dict[str, Any], + datatype: str, + overwritedata: Optional[dict[str, str]] = None, + ) -> bool: """ - Helper function for setParameter(),setContinuous(),setSimulationOptions(),setLinearizationOption(),setOptimizationOption() - args1 - string or list of string given by user - args2 - dict() containing the values of different variables(eg:, parameter,continuous,simulation parameters) - args3 - function name (eg; continuous, parameter, simulation, linearization,optimization) - args4 - dict() which stores the new override variables list, + Helper function for: + * setParameter() + * setContinuous() + * setSimulationOptions() + * setLinearizationOption() + * setOptimizationOption() + * setInputs() + + Parameters + ---------- + inputdata + string or list of string given by user + classdata + dict() containing the values of different variables (eg: parameter, continuous, simulation parameters) + datatype + type identifier (eg; continuous, parameter, simulation, linearization, optimization) + overwritedata + dict() which stores the new override variables list, """ - def apply_single(args1): - args1 = self._strip_space(args1) - value = args1.split("=") - if value[0] in args2: - if args3 == "parameter" and self.isParameterChangeable(value[0], value[1]): - args2[value[0]] = value[1] - if args4 is not None: - args4[value[0]] = value[1] - elif args3 != "parameter": - args2[value[0]] = value[1] - if args4 is not None: - args4[value[0]] = value[1] - - return True - else: + inputdata_status: dict[str, bool] = {} + for key, val in inputdata.items(): + if key not in classdata: raise ModelicaSystemError("Unhandled case in setMethodHelper.apply_single() - " - f"{repr(value[0])} is not a {repr(args3)} variable") + f"{repr(key)} is not a {repr(datatype)} variable") + + status = False + if datatype == "parameter" and not self.isParameterChangeable(key): + logger.debug(f"It is not possible to set the parameter {repr(key)}. It seems to be " + "structural, final, protected, evaluated or has a non-constant binding. " + "Use sendExpression(...) and rebuild the model using buildModel() API; example: " + "sendExpression(\"setParameterValue(" + f"{self.modelName}, {key}, {val if val is not None else ''}" + ")\") ") + else: + classdata[key] = val + if overwritedata is not None: + overwritedata[key] = val + status = True - result = [] - if isinstance(args1, str): - result = [apply_single(args1)] + inputdata_status[key] = status - elif isinstance(args1, list): - result = [] - args1 = self._strip_space(args1) - for var in args1: - result.append(apply_single(var)) + return all(inputdata_status.values()) - return all(result) + def isParameterChangeable( + self, + name: str, + ) -> bool: + q = self.getQuantities(name) + if q[0]["changeable"] == "false": + return False + return True - def setContinuous(self, cvals): # 13 + def setContinuous(self, cvals: 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") - >>> setContinuous(["Name1=value1","Name2=value2"]) + >>> setContinuous(cvals={"Name1": "value1", "Name2": "value2"}) """ - return self.setMethodHelper(cvals, self.continuouslist, "continuous", self.overridevariables) + inputdata = self._prepare_input_data(raw_input=cvals) - def setParameters(self, pvals): # 14 + return self._set_method_helper( + inputdata=inputdata, + classdata=self.continuouslist, + datatype="continuous", + overwritedata=self.overridevariables) + + def setParameters(self, pvals: 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") - >>> setParameters(["Name1=value1","Name2=value2"]) + >>> setParameters(pvals={"Name1": "value1", "Name2": "value2"}) """ - return self.setMethodHelper(pvals, self.paramlist, "parameter", self.overridevariables) + inputdata = self._prepare_input_data(raw_input=pvals) - def isParameterChangeable(self, name, value): - q = self.getQuantities(name) - if q[0]["changeable"] == "false": - logger.debug(f"setParameters() failed : It is not possible to set the following signal {repr(name)}. " - "It seems to be structural, final, protected or evaluated or has a non-constant binding, " - f"use sendExpression(\"setParameterValue({self.modelName}, {name}, {value})\") " - "and rebuild the model using buildModel() API") - return False - return True + return self._set_method_helper( + inputdata=inputdata, + classdata=self.paramlist, + datatype="parameter", + overwritedata=self.overridevariables) - def setSimulationOptions(self, simOptions): # 16 + def setSimulationOptions(self, simOptions: 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") - >>> setSimulationOptions(["Name1=value1","Name2=value2"]) + >>> setSimulationOptions(simOptions={"Name1": "value1", "Name2": "value2"}) """ - return self.setMethodHelper(simOptions, self.simulateOptions, "simulation-option", self.simoptionsoverride) + inputdata = self._prepare_input_data(raw_input=simOptions) + + return self._set_method_helper( + inputdata=inputdata, + classdata=self.simulateOptions, + datatype="simulation-option", + overwritedata=self.simoptionsoverride) - def setLinearizationOptions(self, linearizationOptions): # 18 + def setLinearizationOptions(self, linearizationOptions: 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") - >>> setLinearizationOptions(["Name1=value1","Name2=value2"]) + >>> setLinearizationOptions(linearizationOtions={"Name1": "value1", "Name2": "value2"}) """ - return self.setMethodHelper(linearizationOptions, self.linearOptions, "Linearization-option", None) + inputdata = self._prepare_input_data(raw_input=linearizationOptions) - def setOptimizationOptions(self, optimizationOptions): # 17 + return self._set_method_helper( + inputdata=inputdata, + classdata=self.linearOptions, + datatype="Linearization-option", + overwritedata=None) + + def setOptimizationOptions(self, optimizationOptions: 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") - >>> setOptimizationOptions(["Name1=value1","Name2=value2"]) + >>> setOptimizationOptions(optimizationOptions={"Name1": "value1", "Name2": "value2"}) """ - return self.setMethodHelper(optimizationOptions, self.optimizeOptions, "optimization-option", None) + inputdata = self._prepare_input_data(raw_input=optimizationOptions) + + return self._set_method_helper( + inputdata=inputdata, + classdata=self.optimizeOptions, + datatype="optimization-option", + overwritedata=None) - def setInputs(self, name): # 15 + def setInputs(self, name: 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: - usage - >>> setInputs("Name=value") - >>> setInputs(["Name1=value1","Name2=value2"]) + 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(). + + >>> setInputs(name={"Name1": "value1", "Name2": "value2"}) """ - if isinstance(name, str): - name = self._strip_space(name) - value = name.split("=") - if value[0] in self.inputlist: - tmpvalue = eval(value[1]) - if isinstance(tmpvalue, (int, float)): - self.inputlist[value[0]] = [(float(self.simulateOptions["startTime"]), float(value[1])), - (float(self.simulateOptions["stopTime"]), float(value[1]))] - elif isinstance(tmpvalue, list): - self.checkValidInputs(tmpvalue) - self.inputlist[value[0]] = tmpvalue - self.inputFlag = True - else: - raise ModelicaSystemError(f"{value[0]} is not an input") - elif isinstance(name, list): - name = self._strip_space(name) - for var in name: - value = var.split("=") - if value[0] in self.inputlist: - tmpvalue = eval(value[1]) - if isinstance(tmpvalue, (int, float)): - self.inputlist[value[0]] = [(float(self.simulateOptions["startTime"]), float(value[1])), - (float(self.simulateOptions["stopTime"]), float(value[1]))] - elif isinstance(tmpvalue, list): - self.checkValidInputs(tmpvalue) - self.inputlist[value[0]] = tmpvalue - self.inputFlag = True - else: - raise ModelicaSystemError(f"{value[0]} is not an input!") - - def checkValidInputs(self, name): - if name != sorted(name, key=lambda x: x[0]): - raise ModelicaSystemError('Time value should be in increasing order') - for l in name: - if isinstance(l, tuple): - # if l[0] < float(self.simValuesList[0]): - if l[0] < float(self.simulateOptions["startTime"]): - raise ModelicaSystemError('Input time value is less than simulation startTime') - if len(l) != 2: - raise ModelicaSystemError(f'Value for {l} is in incorrect format!') + inputdata = self._prepare_input_data(raw_input=name) + + for key, val in inputdata.items(): + if key not in self.inputlist: + raise ModelicaSystemError(f"{key} is not an input") + + if not isinstance(val, str): + raise ModelicaSystemError(f"Invalid data in input for {repr(key)}: {repr(val)}") + + val_evaluated = ast.literal_eval(val) + + if isinstance(val_evaluated, (int, float)): + self.inputlist[key] = [(float(self.simulateOptions["startTime"]), float(val)), + (float(self.simulateOptions["stopTime"]), float(val))] + elif isinstance(val_evaluated, list): + if not all([isinstance(item, tuple) for item in val_evaluated]): + raise ModelicaSystemError("Value for setInput() must be in tuple format; " + f"got {repr(val_evaluated)}") + if val_evaluated != sorted(val_evaluated, key=lambda x: x[0]): + raise ModelicaSystemError("Time value should be in increasing order; " + f"got {repr(val_evaluated)}") + + for item in val_evaluated: + if item[0] < float(self.simulateOptions["startTime"]): + raise ModelicaSystemError(f"Time value in {repr(item)} of {repr(val_evaluated)} is less " + "than the simulation start time") + if len(item) != 2: + raise ModelicaSystemError(f"Value {repr(item)} of {repr(val_evaluated)} " + "is in incorrect format!") + + self.inputlist[key] = val_evaluated else: - raise ModelicaSystemError('Error!!! Value must be in tuple format') + raise ModelicaSystemError(f"Data cannot be evaluated for {repr(key)}: {repr(val)}") + + self.inputFlag = True + + return True def createCSVData(self) -> pathlib.Path: start_time: float = float(self.simulateOptions["startTime"]) @@ -1258,15 +1256,16 @@ def optimize(self): # 21 return optimizeResult - def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = None, - simargs: Optional[dict[str, Optional[str | dict[str, str]]]] = None, - timeout: Optional[int] = None) -> LinearizationResult: + def linearize( + self, + lintime: Optional[float] = None, + simargs: Optional[dict[str, Optional[str | dict[str, str]]]] = None, + timeout: Optional[int] = None, + ) -> LinearizationResult: """Linearize the model according to linearOptions. Args: lintime: Override linearOptions["stopTime"] value. - simflags: A string of extra command line flags for the model - binary. - depreciated in favor of simargs simargs: A dict with command line flags and possible options; example: "simargs={'csvInput': 'a.csv'}" timeout: Possible timeout for the execution of OM. @@ -1319,11 +1318,7 @@ def load_module_from_path(module_name, file_path): om_cmd.arg_set(key="l", val=str(lintime or self.linearOptions["stopTime"])) - # allow runtime simulation flags from user input - if simflags is not None: - om_cmd.args_set(args=om_cmd.parse_simflags(simflags=simflags)) - - if simargs: + if simargs is not None: om_cmd.args_set(args=simargs) returncode = om_cmd.run() diff --git a/OMPython/OMCSession.py b/OMPython/OMCSession.py index ac99dc05..66038d47 100644 --- a/OMPython/OMCSession.py +++ b/OMPython/OMCSession.py @@ -50,7 +50,6 @@ import time from typing import Any, Optional, Tuple import uuid -import warnings import zmq # TODO: replace this with the new parser @@ -322,12 +321,6 @@ def __del__(self): self.omc_zmq = None - def execute(self, command: str): - warnings.warn("This function is depreciated and will be removed in future versions; " - "please use sendExpression() instead", DeprecationWarning, stacklevel=2) - - return self.sendExpression(command, parsed=False) - def sendExpression(self, command: str, parsed: bool = True) -> Any: if self.omc_zmq is None: raise OMCSessionException("No OMC running. Create a new instance of OMCSessionZMQ!") diff --git a/tests/test_ModelicaSystem.py b/tests/test_ModelicaSystem.py index 156dde03..ef1dccf8 100644 --- a/tests/test_ModelicaSystem.py +++ b/tests/test_ModelicaSystem.py @@ -35,8 +35,8 @@ def test_setParameters(): mod = OMPython.ModelicaSystem(model_path + "BouncingBall.mo", "BouncingBall") # method 1 - mod.setParameters("e=1.234") - mod.setParameters("g=321.0") + mod.setParameters(pvals={"e": 1.234}) + mod.setParameters(pvals={"g": 321.0}) assert mod.getParameters("e") == ["1.234"] assert mod.getParameters("g") == ["321.0"] assert mod.getParameters() == { @@ -47,7 +47,7 @@ def test_setParameters(): mod.getParameters("thisParameterDoesNotExist") # method 2 - mod.setParameters(["e=21.3", "g=0.12"]) + mod.setParameters(pvals={"e": 21.3, "g": 0.12}) assert mod.getParameters() == { "e": "21.3", "g": "0.12", @@ -64,8 +64,8 @@ def test_setSimulationOptions(): mod = OMPython.ModelicaSystem(fileName=model_path + "BouncingBall.mo", modelName="BouncingBall") # method 1 - mod.setSimulationOptions("stopTime=1.234") - mod.setSimulationOptions("tolerance=1.1e-08") + mod.setSimulationOptions(simOptions={"stopTime": 1.234}) + mod.setSimulationOptions(simOptions={"tolerance": 1.1e-08}) assert mod.getSimulationOptions("stopTime") == ["1.234"] assert mod.getSimulationOptions("tolerance") == ["1.1e-08"] assert mod.getSimulationOptions(["tolerance", "stopTime"]) == ["1.1e-08", "1.234"] @@ -77,7 +77,7 @@ def test_setSimulationOptions(): mod.getSimulationOptions("thisOptionDoesNotExist") # method 2 - mod.setSimulationOptions(["stopTime=2.1", "tolerance=1.2e-08"]) + mod.setSimulationOptions(simOptions={"stopTime": 2.1, "tolerance": "1.2e-08"}) d = mod.getSimulationOptions() assert d["stopTime"] == "2.1" assert d["tolerance"] == "1.2e-08" @@ -119,7 +119,7 @@ def test_getSolutions(model_firstorder): a = -1 tau = -1 / a stopTime = 5*tau - mod.setSimulationOptions([f"stopTime={stopTime}", "stepSize=0.1", "tolerance=1e-8"]) + mod.setSimulationOptions(simOptions={"stopTime": stopTime, "stepSize": 0.1, "tolerance": 1e-8}) mod.simulate() x = mod.getSolutions("x") @@ -298,7 +298,7 @@ def test_getters(tmp_path): x0 = 1.0 x_analytical = -b/a + (x0 + b/a) * np.exp(a * stopTime) dx_analytical = (x0 + b/a) * a * np.exp(a * stopTime) - mod.setSimulationOptions(f"stopTime={stopTime}") + mod.setSimulationOptions(simOptions={"stopTime": stopTime}) mod.simulate() # getOutputs after simulate() @@ -327,7 +327,7 @@ def test_getters(tmp_path): mod.getContinuous("a") # a is a parameter with pytest.raises(OMPython.ModelicaSystemError): - mod.setSimulationOptions("thisOptionDoesNotExist=3") + mod.setSimulationOptions(simOptions={"thisOptionDoesNotExist": 3}) def test_simulate_inputs(tmp_path): @@ -345,7 +345,7 @@ def test_simulate_inputs(tmp_path): """) mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="M_input") - mod.setSimulationOptions("stopTime=1.0") + mod.setSimulationOptions(simOptions={"stopTime": 1.0}) # integrate zero (no setInputs call) - it should default to None -> 0 assert mod.getInputs() == { @@ -357,7 +357,7 @@ def test_simulate_inputs(tmp_path): assert np.isclose(y[-1], 0.0) # integrate a constant - mod.setInputs("u1=2.5") + mod.setInputs(name={"u1": 2.5}) assert mod.getInputs() == { "u1": [ (0.0, 2.5), @@ -370,7 +370,7 @@ def test_simulate_inputs(tmp_path): assert np.isclose(y[-1], 2.5) # now let's integrate the sum of two ramps - mod.setInputs("u1=[(0.0, 0.0), (0.5, 2), (1.0, 0)]") + mod.setInputs(name={"u1": [(0.0, 0.0), (0.5, 2), (1.0, 0)]}) assert mod.getInputs("u1") == [[ (0.0, 0.0), (0.5, 2.0), @@ -383,19 +383,17 @@ def test_simulate_inputs(tmp_path): # let's try some edge cases # unmatched startTime with pytest.raises(OMPython.ModelicaSystemError): - mod.setInputs("u1=[(-0.5, 0.0), (1.0, 1)]") + mod.setInputs(name={"u1": [(-0.5, 0.0), (1.0, 1)]}) mod.simulate() # unmatched stopTime with pytest.raises(OMPython.ModelicaSystemError): - mod.setInputs("u1=[(0.0, 0.0), (0.5, 1)]") + mod.setInputs(name={"u1": [(0.0, 0.0), (0.5, 1)]}) mod.simulate() # Let's use both inputs, but each one with different number of of # samples. This has an effect when generating the csv file. - mod.setInputs([ - "u1=[(0.0, 0), (1.0, 1)]", - "u2=[(0.0, 0), (0.25, 0.5), (0.5, 1.0), (1.0, 0)]", - ]) + mod.setInputs(name={"u1": [(0.0, 0), (1.0, 1)], + "u2": [(0.0, 0), (0.25, 0.5), (0.5, 1.0), (1.0, 0)]}) mod.simulate() assert pathlib.Path(mod.csvFile).read_text() == """time,u1,u2,end 0.0,0.0,0.0,0 diff --git a/tests/test_ModelicaSystemCmd.py b/tests/test_ModelicaSystemCmd.py index 420193df..8c99550d 100644 --- a/tests/test_ModelicaSystemCmd.py +++ b/tests/test_ModelicaSystemCmd.py @@ -23,11 +23,10 @@ def test_simflags(model_firstorder): "noRestart": None, "override": {'b': 2} }) - with pytest.deprecated_call(): - mscmd.args_set(args=mscmd.parse_simflags(simflags="-noEventEmit -noRestart -override=a=1,x=3")) assert mscmd.get_cmd() == [ mscmd.get_exe().as_posix(), - '-noEventEmit', '-noRestart', - '-override=b=2,a=1,x=3' + '-noEventEmit', + '-noRestart', + '-override=b=2' ] diff --git a/tests/test_ZMQ.py b/tests/test_ZMQ.py index 30bf78e7..0ae91b29 100644 --- a/tests/test_ZMQ.py +++ b/tests/test_ZMQ.py @@ -36,9 +36,7 @@ def test_Simulate(om, model_time_str): assert om.sendExpression('res.resultFile') -def test_execute(om): - with pytest.deprecated_call(): - assert om.execute('"HelloWorld!"') == '"HelloWorld!"\n' +def test_sendExpression(om): assert om.sendExpression('"HelloWorld!"', parsed=False) == '"HelloWorld!"\n' assert om.sendExpression('"HelloWorld!"', parsed=True) == 'HelloWorld!' diff --git a/tests/test_linearization.py b/tests/test_linearization.py index 2c79190c..6af565c6 100644 --- a/tests/test_linearization.py +++ b/tests/test_linearization.py @@ -62,10 +62,10 @@ def test_getters(tmp_path): assert "startTime" in d assert "stopTime" in d assert mod.getLinearizationOptions(["stopTime", "startTime"]) == [d["stopTime"], d["startTime"]] - mod.setLinearizationOptions("stopTime=0.02") + mod.setLinearizationOptions(linearizationOptions={"stopTime": 0.02}) assert mod.getLinearizationOptions("stopTime") == ["0.02"] - mod.setInputs(["u1=10", "u2=0"]) + mod.setInputs(name={"u1": 10, "u2": 0}) [A, B, C, D] = mod.linearize() g = float(mod.getParameters("g")[0]) l = float(mod.getParameters("l")[0]) diff --git a/tests/test_optimization.py b/tests/test_optimization.py index aa74df79..b4164397 100644 --- a/tests/test_optimization.py +++ b/tests/test_optimization.py @@ -35,13 +35,15 @@ def test_optimization_example(tmp_path): mod = OMPython.ModelicaSystem(fileName=model_file.as_posix(), modelName="BangBang2021") - mod.setOptimizationOptions(["numberOfIntervals=16", "stopTime=1", - "stepSize=0.001", "tolerance=1e-8"]) + mod.setOptimizationOptions(optimizationOptions={"numberOfIntervals": 16, + "stopTime": 1, + "stepSize": 0.001, + "tolerance": 1e-8}) # test the getter assert mod.getOptimizationOptions()["stopTime"] == "1" assert mod.getOptimizationOptions("stopTime") == ["1"] - assert mod.getOptimizationOptions(["tolerance", "stopTime"]) == ["1e-8", "1"] + assert mod.getOptimizationOptions(["tolerance", "stopTime"]) == ["1e-08", "1"] r = mod.optimize() # it is necessary to specify resultfile, otherwise it wouldn't find it.