Skip to content

Commit a6fa95e

Browse files
committed
Merge branch 'OMCSession_executable' into ModelicaSystemCmd_use_OMCPath
2 parents 082be04 + 7f75ccb commit a6fa95e

4 files changed

Lines changed: 208 additions & 77 deletions

File tree

OMPython/ModelicaSystem.py

Lines changed: 38 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,13 @@
3838
import numbers
3939
import numpy as np
4040
import os
41-
import platform
42-
import re
43-
import subprocess
41+
import pathlib
4442
import textwrap
4543
from typing import Optional, Any
4644
import warnings
4745
import xml.etree.ElementTree as ET
4846

49-
from OMPython.OMCSession import OMCSessionException, OMCSessionZMQ, OMCProcessLocal, OMCPath
47+
from OMPython.OMCSession import OMCSessionException, OMCSessionRunData, OMCSessionZMQ, OMCProcessLocal, OMCPath
5048

5149
# define logger using the current module name as ID
5250
logger = logging.getLogger(__name__)
@@ -112,8 +110,15 @@ def __getitem__(self, index: int):
112110
class ModelicaSystemCmd:
113111
"""A compiled model executable."""
114112

115-
def __init__(self, runpath: OMCPath, modelname: str, timeout: Optional[float] = None) -> None:
116-
self._runpath = runpath
113+
def __init__(
114+
self,
115+
session: OMCSessionZMQ,
116+
runpath: OMCPath,
117+
modelname: str,
118+
timeout: Optional[float] = None,
119+
) -> None:
120+
self._session = session
121+
self._runpath = pathlib.Path(runpath).resolve().absolute()
117122
self._model_name = modelname
118123
self._timeout = timeout
119124
self._args: dict[str, str | None] = {}
@@ -173,27 +178,12 @@ def args_set(self, args: dict[str, Optional[str | dict[str, str]]]) -> None:
173178
for arg in args:
174179
self.arg_set(key=arg, val=args[arg])
175180

176-
def get_exe(self) -> OMCPath:
177-
"""Get the path to the compiled model executable."""
178-
if platform.system() == "Windows":
179-
path_exe = self._runpath / f"{self._model_name}.exe"
180-
else:
181-
path_exe = self._runpath / self._model_name
182-
183-
if not path_exe.exists():
184-
raise ModelicaSystemError(f"Application file path not found: {path_exe}")
185-
186-
return path_exe
187-
188-
def get_cmd(self) -> list:
189-
"""Get a list with the path to the executable and all command line args.
190-
191-
This can later be used as an argument for subprocess.run().
181+
def get_cmd_args(self) -> list[str]:
182+
"""
183+
Get a list with the command arguments for the model executable.
192184
"""
193185

194-
path_exe = self.get_exe()
195-
196-
cmdl = [path_exe.as_posix()]
186+
cmdl = []
197187
for key in self._args:
198188
if self._args[key] is None:
199189
cmdl.append(f"-{key}")
@@ -202,54 +192,26 @@ def get_cmd(self) -> list:
202192

203193
return cmdl
204194

205-
def run(self) -> int:
206-
"""Run the requested simulation.
207-
208-
Returns
209-
-------
210-
Subprocess return code (0 on success).
195+
def definition(self) -> OMCSessionRunData:
211196
"""
197+
Define all needed data to run the model executable. The data is stored in an OMCSessionRunData object.
198+
"""
199+
# ensure that a result filename is provided
200+
result_file = self.arg_get('r')
201+
if not isinstance(result_file, str):
202+
result_file = (self._runpath / f"{self._model_name}.mat").as_posix()
203+
204+
omc_run_data = OMCSessionRunData(
205+
cmd_path=self._runpath.as_posix(),
206+
cmd_model_name=self._model_name,
207+
cmd_args=self.get_cmd_args(),
208+
cmd_result_path=result_file,
209+
cmd_timeout=self._timeout,
210+
)
212211

213-
cmdl: list = self.get_cmd()
214-
215-
logger.debug("Run OM command %s in %s", repr(cmdl), self._runpath.as_posix())
216-
217-
if platform.system() == "Windows":
218-
path_dll = ""
219-
220-
# set the process environment from the generated .bat file in windows which should have all the dependencies
221-
path_bat = self._runpath / f"{self._model_name}.bat"
222-
if not path_bat.exists():
223-
raise ModelicaSystemError("Batch file (*.bat) does not exist " + str(path_bat))
224-
225-
with open(file=path_bat, mode='r', encoding='utf-8') as fh:
226-
for line in fh:
227-
match = re.match(r"^SET PATH=([^%]*)", line, re.IGNORECASE)
228-
if match:
229-
path_dll = match.group(1).strip(';') # Remove any trailing semicolons
230-
my_env = os.environ.copy()
231-
my_env["PATH"] = path_dll + os.pathsep + my_env["PATH"]
232-
else:
233-
# TODO: how to handle path to resources of external libraries for any system not Windows?
234-
my_env = None
235-
236-
try:
237-
cmdres = subprocess.run(cmdl, capture_output=True, text=True, env=my_env, cwd=self._runpath,
238-
timeout=self._timeout, check=True)
239-
stdout = cmdres.stdout.strip()
240-
stderr = cmdres.stderr.strip()
241-
returncode = cmdres.returncode
242-
243-
logger.debug("OM output for command %s:\n%s", repr(cmdl), stdout)
244-
245-
if stderr:
246-
raise ModelicaSystemError(f"Error running command {repr(cmdl)}: {stderr}")
247-
except subprocess.TimeoutExpired as ex:
248-
raise ModelicaSystemError(f"Timeout running command {repr(cmdl)}") from ex
249-
except subprocess.CalledProcessError as ex:
250-
raise ModelicaSystemError(f"Error running command {repr(cmdl)}") from ex
212+
omc_run_data_updated = self._session.omc_run_data_update(omc_run_data=omc_run_data)
251213

252-
return returncode
214+
return omc_run_data_updated
253215

254216
@staticmethod
255217
def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, str]]]:
@@ -964,6 +926,7 @@ def simulate_cmd(
964926
"""
965927

966928
om_cmd = ModelicaSystemCmd(
929+
session=self._getconn,
967930
runpath=self.getWorkDirectory(),
968931
modelname=self._model_name,
969932
timeout=timeout,
@@ -1061,7 +1024,8 @@ def simulate(
10611024
if self._result_file.is_file():
10621025
self._result_file.unlink()
10631026
# ... run simulation ...
1064-
returncode = om_cmd.run()
1027+
cmd_definition = om_cmd.definition()
1028+
returncode = self._getconn.run_model_executable(cmd_run_data=cmd_definition)
10651029
# and check returncode *AND* resultfile
10661030
if returncode != 0 and self._result_file.is_file():
10671031
# check for an empty (=> 0B) result file which indicates a crash of the model executable
@@ -1578,6 +1542,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15781542
)
15791543

15801544
om_cmd = ModelicaSystemCmd(
1545+
session=self._getconn,
15811546
runpath=self.getWorkDirectory(),
15821547
modelname=self._model_name,
15831548
timeout=timeout,
@@ -1616,7 +1581,8 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
16161581
linear_file = self.getWorkDirectory() / "linearized_model.py"
16171582
linear_file.unlink(missing_ok=True)
16181583

1619-
returncode = om_cmd.run()
1584+
cmd_definition = om_cmd.definition()
1585+
returncode = self._getconn.run_model_executable(cmd_run_data=cmd_definition)
16201586
if returncode != 0:
16211587
raise ModelicaSystemError(f"Linearize failed with return code: {returncode}")
16221588
if not linear_file.is_file():

0 commit comments

Comments
 (0)