Skip to content
Open
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
242 changes: 178 additions & 64 deletions OMPython/ModelicaSystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,26 @@
"""

import logging
import numbers
import os
import pathlib
import platform
from typing import Any, Optional
import warnings

import numpy as np

from OMPython.model_execution import (
ModelExecutionConfig,
ModelExecutionException,
)
from OMPython.om_session_abc import (
OMPathABC,
)
from OMPython.om_session_omc import (
OMCSessionLocal,
)
from OMPython.modelica_system_abc import (
LinearizationResult,
ModelicaSystemError,
)
from OMPython.modelica_system_omc import (
Expand Down Expand Up @@ -72,19 +77,132 @@ def __init__(
def setCommandLineOptions(self, commandLineOptions: str):
super().set_command_line_options(command_line_option=commandLineOptions)

def _set_compatibility_helper(
def simulate_cmd( # type: ignore[override]
self,
result_file: OMPathABC,
simflags: Optional[str] = None,
simargs: Optional[dict[str, Optional[str | dict[str, Any] | numbers.Number]]] = None,
) -> ModelExecutionConfig:
"""
Compatibility layer for OMPython v4.0.0 - keep simflags available and use ModelicaSystemCmd!
"""

if simargs is None:
simargs = {}

if simflags is not None:
simargs_extra = parse_simflags(simflags=simflags)
simargs = simargs | simargs_extra

return super().simulate_cmd(
result_file=result_file,
simargs=simargs,
)

def simulate( # type: ignore[override]
self,
resultfile: Optional[str | os.PathLike] = None,
simflags: Optional[str] = None,
simargs: Optional[dict[str, Optional[str | dict[str, Any] | numbers.Number]]] = None,
) -> None:
"""
Compatibility layer for OMPython v4.0.0 - keep simflags available and use ModelicaSystemCmd!
"""

if simargs is None:
simargs = {}

if simflags is not None:
simargs_extra = parse_simflags(simflags=simflags)
simargs = simargs | simargs_extra

return super().simulate(
resultfile=resultfile,
simargs=simargs,
)

def linearize( # type: ignore[override]
self,
lintime: Optional[float] = None,
simflags: Optional[str] = None,
simargs: Optional[dict[str, Optional[str | dict[str, Any] | numbers.Number]]] = None,
) -> LinearizationResult:
"""
Compatibility layer for OMPython v4.0.0 - keep simflags available and use ModelicaSystemCmd!
"""
if simargs is None:
simargs = {}

if simflags is not None:
simargs_extra = parse_simflags(simflags=simflags)
simargs = simargs | simargs_extra

return super().linearize(
lintime=lintime,
simargs=simargs,
)

@staticmethod
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 +222,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 +242,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 +262,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 +282,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 +302,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 +322,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 Expand Up @@ -299,7 +399,12 @@ class ModelicaSystemDoE(ModelicaDoEOMC):
@depreciated_class(msg="Please use class ModelExecutionConfig instead!")
class ModelicaSystemCmd(ModelExecutionConfig):
"""
Compatibility class; in the new version it is renamed as ModelExecutionConfig.
Compatibility class; not much content.

Missing definitions:
* get_exe() - see self.definition.cmd_model_executable
* get_cmd() - use self.get_cmd_args() or self.definition().get_cmd()
* run() - use self.definition().run()
"""

def __init__(
Expand All @@ -315,35 +420,44 @@ def __init__(
model_name=modelname,
)

def get_exe(self) -> pathlib.Path:
"""Get the path to the compiled model executable."""

path_run = pathlib.Path(self._runpath)
if platform.system() == "Windows":
path_exe = path_run / f"{self._model_name}.exe"
else:
path_exe = path_run / self._model_name

if not path_exe.exists():
raise ModelicaSystemError(f"Application file path not found: {path_exe}")

return path_exe

def get_cmd(self) -> list:
"""
Get a list with the path to the executable and all command line args.

This can later be used as an argument for subprocess.run().
"""

cmdl = [self.get_exe().as_posix()] + self.get_cmd_args()

return cmdl
def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, Any] | numbers.Number]]:
"""
Parse a simflag definition; this is deprecated!

def run(self) -> int:
cmd_definition = self.definition()
try:
returncode = cmd_definition.run()
except ModelExecutionException as exc:
raise ModelicaSystemError(f"Cannot execute model: {exc}") from exc
return returncode
The return data can be used as input for self.args_set().
"""
warnings.warn(
message="The argument 'simflags' is depreciated and will be removed in future versions; "
"please use 'simargs' instead",
category=DeprecationWarning,
stacklevel=2,
)

simargs: dict[str, Optional[str | dict[str, Any] | numbers.Number]] = {}

args = [s for s in simflags.split(' ') if s]
for arg in args:
if arg[0] != '-':
raise ModelExecutionException(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 ModelExecutionException(f"Invalid value for '-override': {override}")
if kv[0]:
try:
override_dict[kv[0]] = kv[1]
except (KeyError, IndexError) as ex:
raise ModelExecutionException(f"Invalid value for '-override': {override}") from ex

simargs[parts[0]] = override_dict

return simargs
9 changes: 8 additions & 1 deletion OMPython/OMCSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import logging
from typing import Any, Optional
import warnings

import pyparsing

Expand Down Expand Up @@ -272,7 +273,13 @@ def omcpath_tempdir(self, tempdir_base: Optional[OMPathABC] = None) -> OMPathABC
return self.omc_process.omcpath_tempdir(tempdir_base=tempdir_base)

def execute(self, command: str):
return self.omc_process.execute(command=command)
warnings.warn(
message="This function is depreciated and will be removed in future versions; "
"please use sendExpression() instead",
category=DeprecationWarning,
stacklevel=2,
)
return self.omc_process.sendExpression(expr=command, parsed=False)

def sendExpression(
self,
Expand Down
4 changes: 2 additions & 2 deletions OMPython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
# the imports below are compatibility functionality (OMPython v4.0.0)
from OMPython.ModelicaSystem import (
ModelicaSystem,
ModelicaSystemCmd,
ModelicaSystemDoE,
parse_simflags,
)
from OMPython.OMCSession import (
OMCSessionCmd,
Expand Down Expand Up @@ -109,9 +109,9 @@
'OMPathRunnerLocal',
'OMSessionRunner',

'ModelicaSystemCmd',
'ModelicaSystem',
'ModelicaSystemDoE',
'parse_simflags',

'OMCSessionCmd',

Expand Down
Loading
Loading