4040import numpy as np
4141import os
4242import pathlib
43- import platform
44- import re
45- import subprocess
4643import tempfile
4744import textwrap
4845from typing import Optional , Any
4946import warnings
5047import xml .etree .ElementTree as ET
5148
52- from OMPython .OMCSession import OMCSessionException , OMCSessionZMQ , OMCProcessLocal
49+ from OMPython .OMCSession import OMCSessionException , OMCSessionRunData , OMCSessionZMQ , OMCProcessLocal
5350
5451# define logger using the current module name as ID
5552logger = logging .getLogger (__name__ )
@@ -115,7 +112,14 @@ def __getitem__(self, index: int):
115112class ModelicaSystemCmd :
116113 """A compiled model executable."""
117114
118- def __init__ (self , runpath : pathlib .Path , modelname : str , timeout : Optional [float ] = None ) -> None :
115+ def __init__ (
116+ self ,
117+ session : OMCSessionZMQ ,
118+ runpath : pathlib .Path ,
119+ modelname : str ,
120+ timeout : Optional [float ] = None ,
121+ ) -> None :
122+ self ._session = session
119123 self ._runpath = pathlib .Path (runpath ).resolve ().absolute ()
120124 self ._model_name = modelname
121125 self ._timeout = timeout
@@ -176,27 +180,12 @@ def args_set(self, args: dict[str, Optional[str | dict[str, str]]]) -> None:
176180 for arg in args :
177181 self .arg_set (key = arg , val = args [arg ])
178182
179- def get_exe (self ) -> pathlib .Path :
180- """Get the path to the compiled model executable."""
181- if platform .system () == "Windows" :
182- path_exe = self ._runpath / f"{ self ._model_name } .exe"
183- else :
184- path_exe = self ._runpath / self ._model_name
185-
186- if not path_exe .exists ():
187- raise ModelicaSystemError (f"Application file path not found: { path_exe } " )
188-
189- return path_exe
190-
191- def get_cmd (self ) -> list :
192- """Get a list with the path to the executable and all command line args.
193-
194- This can later be used as an argument for subprocess.run().
183+ def get_cmd_args (self ) -> list [str ]:
184+ """
185+ Get a list with the command arguments for the model executable.
195186 """
196187
197- path_exe = self .get_exe ()
198-
199- cmdl = [path_exe .as_posix ()]
188+ cmdl = []
200189 for key in self ._args :
201190 if self ._args [key ] is None :
202191 cmdl .append (f"-{ key } " )
@@ -205,54 +194,26 @@ def get_cmd(self) -> list:
205194
206195 return cmdl
207196
208- def run (self ) -> int :
209- """Run the requested simulation.
210-
211- Returns
212- -------
213- Subprocess return code (0 on success).
197+ def definition (self ) -> OMCSessionRunData :
214198 """
199+ Define all needed data to run the model executable. The data is stored in an OMCSessionRunData object.
200+ """
201+ # ensure that a result filename is provided
202+ result_file = self .arg_get ('r' )
203+ if not isinstance (result_file , str ):
204+ result_file = (self ._runpath / f"{ self ._model_name } .mat" ).as_posix ()
205+
206+ omc_run_data = OMCSessionRunData (
207+ cmd_path = self ._runpath .as_posix (),
208+ cmd_model_name = self ._model_name ,
209+ cmd_args = self .get_cmd_args (),
210+ cmd_result_path = result_file ,
211+ cmd_timeout = self ._timeout ,
212+ )
215213
216- cmdl : list = self .get_cmd ()
217-
218- logger .debug ("Run OM command %s in %s" , repr (cmdl ), self ._runpath .as_posix ())
219-
220- if platform .system () == "Windows" :
221- path_dll = ""
222-
223- # set the process environment from the generated .bat file in windows which should have all the dependencies
224- path_bat = self ._runpath / f"{ self ._model_name } .bat"
225- if not path_bat .exists ():
226- raise ModelicaSystemError ("Batch file (*.bat) does not exist " + str (path_bat ))
227-
228- with open (file = path_bat , mode = 'r' , encoding = 'utf-8' ) as fh :
229- for line in fh :
230- match = re .match (r"^SET PATH=([^%]*)" , line , re .IGNORECASE )
231- if match :
232- path_dll = match .group (1 ).strip (';' ) # Remove any trailing semicolons
233- my_env = os .environ .copy ()
234- my_env ["PATH" ] = path_dll + os .pathsep + my_env ["PATH" ]
235- else :
236- # TODO: how to handle path to resources of external libraries for any system not Windows?
237- my_env = None
238-
239- try :
240- cmdres = subprocess .run (cmdl , capture_output = True , text = True , env = my_env , cwd = self ._runpath ,
241- timeout = self ._timeout , check = True )
242- stdout = cmdres .stdout .strip ()
243- stderr = cmdres .stderr .strip ()
244- returncode = cmdres .returncode
245-
246- logger .debug ("OM output for command %s:\n %s" , repr (cmdl ), stdout )
247-
248- if stderr :
249- raise ModelicaSystemError (f"Error running command { repr (cmdl )} : { stderr } " )
250- except subprocess .TimeoutExpired as ex :
251- raise ModelicaSystemError (f"Timeout running command { repr (cmdl )} " ) from ex
252- except subprocess .CalledProcessError as ex :
253- raise ModelicaSystemError (f"Error running command { repr (cmdl )} " ) from ex
214+ omc_run_data_updated = self ._session .omc_run_data_update (omc_run_data )
254215
255- return returncode
216+ return omc_run_data_updated
256217
257218 @staticmethod
258219 def parse_simflags (simflags : str ) -> dict [str , Optional [str | dict [str , str ]]]:
@@ -943,7 +904,12 @@ def simulate_cmd(
943904 An instance if ModelicaSystemCmd to run the requested simulation.
944905 """
945906
946- om_cmd = ModelicaSystemCmd (runpath = self ._tempdir , modelname = self ._model_name , timeout = timeout )
907+ om_cmd = ModelicaSystemCmd (
908+ session = self ._getconn ,
909+ runpath = self .getWorkDirectory (),
910+ modelname = self ._model_name ,
911+ timeout = timeout ,
912+ )
947913
948914 # always define the result file to use
949915 om_cmd .arg_set (key = "r" , val = result_file .as_posix ())
@@ -1033,7 +999,8 @@ def simulate(
1033999 if self ._result_file .is_file ():
10341000 self ._result_file .unlink ()
10351001 # ... run simulation ...
1036- returncode = om_cmd .run ()
1002+ cmd_definition = om_cmd .definition ()
1003+ returncode = self ._getconn .run_model_executable (cmd_run_data = cmd_definition )
10371004 # and check returncode *AND* resultfile
10381005 if returncode != 0 and self ._result_file .is_file ():
10391006 # check for an empty (=> 0B) result file which indicates a crash of the model executable
@@ -1452,7 +1419,12 @@ def load_module_from_path(module_name, file_path):
14521419 "use ModelicaSystem() to build the model first"
14531420 )
14541421
1455- om_cmd = ModelicaSystemCmd (runpath = self ._tempdir , modelname = self ._model_name , timeout = timeout )
1422+ om_cmd = ModelicaSystemCmd (
1423+ session = self ._getconn ,
1424+ runpath = self ._tempdir ,
1425+ modelname = self ._model_name ,
1426+ timeout = timeout ,
1427+ )
14561428
14571429 overrideLinearFile = self ._tempdir / f'{ self ._model_name } _override_linear.txt'
14581430
@@ -1484,7 +1456,8 @@ def load_module_from_path(module_name, file_path):
14841456 if simargs :
14851457 om_cmd .args_set (args = simargs )
14861458
1487- returncode = om_cmd .run ()
1459+ cmd_definition = om_cmd .definition ()
1460+ returncode = self ._getconn .run_model_executable (cmd_run_data = cmd_definition )
14881461 if returncode != 0 :
14891462 raise ModelicaSystemError (f"Linearize failed with return code: { returncode } " )
14901463
0 commit comments