3838import numbers
3939import numpy as np
4040import os
41- import platform
42- import re
43- import subprocess
41+ import pathlib
4442import textwrap
4543from typing import Optional , Any
4644import warnings
4745import 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
5250logger = logging .getLogger (__name__ )
@@ -112,8 +110,15 @@ def __getitem__(self, index: int):
112110class 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