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
19 changes: 12 additions & 7 deletions OMPython/ModelicaSystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import numpy as np

from OMPython.model_execution import (
ModelExecutionCmd,
ModelExecutionConfig,
ModelExecutionException,
)
from OMPython.om_session_omc import (
Expand Down Expand Up @@ -140,7 +140,7 @@ def getContinuous(
retval3.append(str(val))
return retval3

raise ModelExecutionException("Invalid data!")
raise ModelicaSystemError("Invalid data!")

def getOutputs(
self,
Expand All @@ -167,7 +167,7 @@ def getOutputs(
retval3.append(str(val))
return retval3

raise ModelExecutionException("Invalid data!")
raise ModelicaSystemError("Invalid data!")


class ModelicaSystemDoE(ModelicaDoEOMC):
Expand All @@ -176,7 +176,7 @@ class ModelicaSystemDoE(ModelicaDoEOMC):
"""


class ModelicaSystemCmd(ModelExecutionCmd):
class ModelicaSystemCmd(ModelExecutionConfig):
"""
Compatibility class; in the new version it is renamed as ModelExecutionCmd.
"""
Expand Down Expand Up @@ -209,7 +209,8 @@ def get_exe(self) -> pathlib.Path:
return path_exe

def get_cmd(self) -> list:
"""Get a list with the path to the executable and all command line args.
"""
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().
"""
Expand All @@ -218,6 +219,10 @@ def get_cmd(self) -> list:

return cmdl

def run(self):
def run(self) -> int:
cmd_definition = self.definition()
return cmd_definition.run()
try:
returncode = cmd_definition.run()
except ModelExecutionException as exc:
raise ModelicaSystemError(f"Cannot execute model: {exc}") from exc
return returncode
8 changes: 5 additions & 3 deletions OMPython/OMCSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -282,12 +282,14 @@ def omcpath_tempdir(self, tempdir_base: Optional[OMPathABC] = None) -> OMPathABC
def execute(self, command: str):
return self.omc_process.execute(command=command)

def sendExpression(self, command: str, parsed: bool = True) -> Any:
def sendExpression(self, command: str, parsed: bool = True) -> Any: # pylint: disable=W0237
"""
Send an expression to the OMC server and return the result.

The complete error handling of the OMC result is done within this method using '"getMessagesStringInternal()'.
Caller should only check for OMSessionException.
The complete error handling of the OMC result is done within this method using 'getMessagesStringInternal()'.
Caller should only check for OMCSessionException.

Compatibility: 'command' was renamed to 'expr'
"""
return self.omc_process.sendExpression(expr=command, parsed=parsed)

Expand Down
15 changes: 8 additions & 7 deletions OMPython/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@
```
import OMPython
omc = OMPython.OMCSessionLocal()
omc.sendExpression("command")
omc.sendExpression("getVersion()")
```

"""

from OMPython.model_execution import (
ModelExecutionCmd,
ModelExecutionData,
ModelExecutionConfig,
ModelExecutionRun,
ModelExecutionException,
)
from OMPython.om_session_abc import (
Expand Down Expand Up @@ -58,15 +58,16 @@
ModelicaDoERunner,
)

# the imports below are compatibility functionality (OMPython v4.0.0)
from OMPython.ModelicaSystem import (
ModelicaSystem,
ModelicaSystemDoE,
ModelicaSystemCmd,
ModelicaSystemDoE,
)
from OMPython.OMCSession import (
OMCSessionCmd,
OMCSessionZMQ,
OMCSessionException,
OMCSessionZMQ,

OMCProcessLocal,
OMCProcessPort,
Expand All @@ -80,8 +81,8 @@

'LinearizationResult',

'ModelExecutionCmd',
'ModelExecutionData',
'ModelExecutionConfig',
'ModelExecutionRun',
'ModelExecutionException',

'ModelicaDoEABC',
Expand Down
24 changes: 12 additions & 12 deletions OMPython/model_execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,13 @@ class ModelExecutionException(Exception):


@dataclasses.dataclass
class ModelExecutionData:
class ModelExecutionRun:
"""
Data class to store the command line data for running a model executable in the OMC environment.
Data class to store the command line data for running a model executable. This definition is independent of the OMC
environment as only the executable is needed.

All data should be defined for the environment, where OMC is running (local, docker or WSL)

To use this as a definition of an OMC simulation run, it has to be processed within
OMCProcess*.self_update(). This defines the attribute cmd_model_executable.
All data should be defined for the environment, where the executable was defined / is located. This is especially
important if OMPython and the executable are defined in different environments (docker or WSL).
"""
# cmd_path is the expected working directory
cmd_path: str
Expand Down Expand Up @@ -105,11 +104,12 @@ def run(self) -> int:
return returncode


class ModelExecutionCmd:
class ModelExecutionConfig:
"""
All information about a compiled model executable. This should include data about all structured parameters, i.e.
parameters which need a recompilation of the model. All non-structured parameters can be easily changed without
the need for recompilation.
This class collects all information about a compiled model executable. This includes data about all structured
parameters, i.e. parameters which need a recompilation of the model. All non-structured parameters can be easily
changed without the need for recompilation. The final result is an instance of class ModelExecutionRun - a
definition to run one simulation based on the compiled model executable.
"""

def __init__(
Expand Down Expand Up @@ -261,7 +261,7 @@ def get_cmd_args(self) -> list[str]:

return cmdl

def definition(self) -> ModelExecutionData:
def definition(self) -> ModelExecutionRun:
"""
Define all needed data to run the model executable. The data is stored in an OMCSessionRunData object.
"""
Expand Down Expand Up @@ -301,7 +301,7 @@ def definition(self) -> ModelExecutionData:
if self._cmd_local:
cmd_cwd_local = cmd_path.as_posix()

omc_run_data = ModelExecutionData(
omc_run_data = ModelExecutionRun(
cmd_path=cmd_path.as_posix(),
cmd_model_name=self._model_name,
cmd_args=self.get_cmd_args(),
Expand Down
11 changes: 6 additions & 5 deletions OMPython/modelica_doe_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
from typing import Any, cast, Optional, Tuple

from OMPython.model_execution import (
ModelExecutionData,
ModelExecutionRun,
ModelExecutionException,
)
from OMPython.om_session_abc import (
OMPathABC,
Expand Down Expand Up @@ -138,7 +139,7 @@ def __init__(
self._parameters = {}

self._doe_def: Optional[dict[str, dict[str, Any]]] = None
self._doe_cmd: Optional[dict[str, ModelExecutionData]] = None
self._doe_cmd: Optional[dict[str, ModelExecutionRun]] = None

def get_session(self) -> OMSessionABC:
"""
Expand Down Expand Up @@ -255,7 +256,7 @@ def get_doe_definition(self) -> Optional[dict[str, dict[str, Any]]]:
"""
return self._doe_def

def get_doe_command(self) -> Optional[dict[str, ModelExecutionData]]:
def get_doe_command(self) -> Optional[dict[str, ModelExecutionRun]]:
"""
Get the definitions of simulations commands to run for this DoE.
"""
Expand Down Expand Up @@ -310,8 +311,8 @@ def worker(worker_id, task_queue):
returncode = cmd_definition.run()
logger.info(f"[Worker {worker_id}] Simulation {resultpath.name} "
f"finished with return code: {returncode}")
except ModelicaSystemError as ex:
logger.warning(f"Simulation error for {resultpath.name}: {ex}")
except ModelExecutionException as exc:
logger.warning(f"Simulation error for {resultpath.name}: {exc}")

# Mark the task as done
task_queue.task_done()
Expand Down
41 changes: 29 additions & 12 deletions OMPython/modelica_system_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@
import numpy as np

from OMPython.model_execution import (
ModelExecutionCmd,
ModelExecutionConfig,
ModelExecutionException,
)
from OMPython.om_session_abc import (
OMPathABC,
Expand Down Expand Up @@ -189,7 +190,7 @@ def check_model_executable(self):
Check if the model executable is working
"""
# check if the executable exists ...
om_cmd = ModelExecutionCmd(
om_cmd = ModelExecutionConfig(
runpath=self.getWorkDirectory(),
cmd_local=self._session.model_execution_local,
cmd_windows=self._session.model_execution_windows,
Expand All @@ -200,7 +201,10 @@ def check_model_executable(self):
# ... by running it - output help for command help
om_cmd.arg_set(key="help", val="help")
cmd_definition = om_cmd.definition()
returncode = cmd_definition.run()
try:
returncode = cmd_definition.run()
except ModelExecutionException as exc:
raise ModelicaSystemError(f"Cannot execute model: {exc}") from exc
if returncode != 0:
raise ModelicaSystemError("Model executable not working!")

Expand Down Expand Up @@ -579,7 +583,7 @@ def _parse_om_version(version: str) -> tuple[int, int, int]:

def _process_override_data(
self,
om_cmd: ModelExecutionCmd,
om_cmd: ModelExecutionConfig,
override_file: OMPathABC,
override_var: dict[str, str],
override_sim: dict[str, str],
Expand Down Expand Up @@ -619,7 +623,7 @@ def simulate_cmd(
result_file: OMPathABC,
simflags: Optional[str] = None,
simargs: Optional[dict[str, Optional[str | dict[str, Any] | numbers.Number]]] = None,
) -> ModelExecutionCmd:
) -> ModelExecutionConfig:
"""
This method prepares the simulates model according to the simulation options. It returns an instance of
ModelicaSystemCmd which can be used to run the simulation.
Expand All @@ -641,7 +645,7 @@ def simulate_cmd(
An instance if ModelicaSystemCmd to run the requested simulation.
"""

om_cmd = ModelExecutionCmd(
om_cmd = ModelExecutionConfig(
runpath=self.getWorkDirectory(),
cmd_local=self._session.model_execution_local,
cmd_windows=self._session.model_execution_windows,
Expand Down Expand Up @@ -736,7 +740,10 @@ def simulate(
self._result_file.unlink()
# ... run simulation ...
cmd_definition = om_cmd.definition()
returncode = cmd_definition.run()
try:
returncode = cmd_definition.run()
except ModelExecutionException as exc:
raise ModelicaSystemError(f"Cannot execute model: {exc}") from exc
# and check returncode *AND* resultfile
if returncode != 0 and self._result_file.is_file():
# check for an empty (=> 0B) result file which indicates a crash of the model executable
Expand Down Expand Up @@ -764,8 +771,10 @@ def prepare_str(str_in: str) -> dict[str, str]:
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] = {key_val_list[0]: key_val_list[1]}
input_data_from_str: dict[str, str] = {str(key_val_list[0]): str(key_val_list[1])}

return input_data_from_str

Expand All @@ -791,7 +800,12 @@ def prepare_str(str_in: str) -> dict[str, 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_data = input_data | input_arg
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)}!")

Expand Down Expand Up @@ -1026,7 +1040,7 @@ def setInputs(
self._inputs[key] = [(float(self._simulate_options["startTime"]), float(val)),
(float(self._simulate_options["stopTime"]), float(val))]
elif isinstance(val_evaluated, list):
if not all([isinstance(item, tuple) for item in val_evaluated]):
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]):
Expand Down Expand Up @@ -1134,7 +1148,7 @@ def linearize(
"use ModelicaSystemOMC() to build the model first"
)

om_cmd = ModelExecutionCmd(
om_cmd = ModelExecutionConfig(
runpath=self.getWorkDirectory(),
cmd_local=self._session.model_execution_local,
cmd_windows=self._session.model_execution_windows,
Expand Down Expand Up @@ -1180,7 +1194,10 @@ def linearize(
linear_file.unlink(missing_ok=True)

cmd_definition = om_cmd.definition()
returncode = cmd_definition.run()
try:
returncode = cmd_definition.run()
except ModelExecutionException as exc:
raise ModelicaSystemError(f"Cannot execute model: {exc}") from exc
if returncode != 0:
raise ModelicaSystemError(f"Linearize failed with return code: {returncode}")
if not linear_file.is_file():
Expand Down
12 changes: 6 additions & 6 deletions OMPython/om_session_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ def with_segments(self, *pathsegments) -> OMPathABC:
return type(self)(*pathsegments, session=self._session)

@abc.abstractmethod
def is_file(self) -> bool:
def is_file(self, *, follow_symlinks=True) -> bool:
"""
Check if the path is a regular file.
"""

@abc.abstractmethod
def is_dir(self) -> bool:
def is_dir(self, *, follow_symlinks: bool = True) -> bool:
"""
Check if the path is a directory.
"""
Expand All @@ -115,19 +115,19 @@ def is_absolute(self) -> bool:
"""

@abc.abstractmethod
def read_text(self) -> str:
def read_text(self, encoding=None, errors=None, newline=None) -> str:
"""
Read the content of the file represented by this path as text.
"""

@abc.abstractmethod
def write_text(self, data: str) -> int:
def write_text(self, data: str, encoding=None, errors=None, newline=None) -> int:
"""
Write text data to the file represented by this path.
"""

@abc.abstractmethod
def mkdir(self, parents: bool = True, exist_ok: bool = False) -> None:
def mkdir(self, mode=0o777, parents: bool = False, exist_ok: bool = False) -> None:
"""
Create a directory at the path represented by this class.

Expand All @@ -137,7 +137,7 @@ def mkdir(self, parents: bool = True, exist_ok: bool = False) -> None:
"""

@abc.abstractmethod
def cwd(self) -> OMPathABC:
def cwd(self) -> OMPathABC: # pylint: disable=W0221 # is @classmethod in the original; see pathlib.PathBase
"""
Returns the current working directory as an OMPathABC object.
"""
Expand Down
Loading
Loading