4141import numpy as np
4242import os
4343import pathlib
44- import platform
4544import queue
46- import re
47- import subprocess
4845import tempfile
4946import textwrap
5047import threading
5148from typing import Any , Optional
5249import warnings
5350import xml .etree .ElementTree as ET
5451
55- from OMPython .OMCSession import OMCSessionException , OMCSessionZMQ , OMCProcessLocal
52+ from OMPython .OMCSession import OMCSessionException , OMCSessionRunData , OMCSessionZMQ , OMCProcessLocal
5653
5754# define logger using the current module name as ID
5855logger = logging .getLogger (__name__ )
@@ -118,7 +115,14 @@ def __getitem__(self, index: int):
118115class ModelicaSystemCmd :
119116 """A compiled model executable."""
120117
121- def __init__ (self , runpath : pathlib .Path , modelname : str , timeout : Optional [float ] = None ) -> None :
118+ def __init__ (
119+ self ,
120+ session : OMCSessionZMQ ,
121+ runpath : pathlib .Path ,
122+ modelname : str ,
123+ timeout : Optional [float ] = None ,
124+ ) -> None :
125+ self ._session = session
122126 self ._runpath = pathlib .Path (runpath ).resolve ().absolute ()
123127 self ._model_name = modelname
124128 self ._timeout = timeout
@@ -192,27 +196,12 @@ def args_set(self, args: dict[str, Optional[str | dict[str, Any]]]) -> None:
192196 for arg in args :
193197 self .arg_set (key = arg , val = args [arg ])
194198
195- def get_exe (self ) -> pathlib .Path :
196- """Get the path to the compiled model executable."""
197- if platform .system () == "Windows" :
198- path_exe = self ._runpath / f"{ self ._model_name } .exe"
199- else :
200- path_exe = self ._runpath / self ._model_name
201-
202- if not path_exe .exists ():
203- raise ModelicaSystemError (f"Application file path not found: { path_exe } " )
204-
205- return path_exe
206-
207- def get_cmd (self ) -> list :
208- """Get a list with the path to the executable and all command line args.
209-
210- This can later be used as an argument for subprocess.run().
199+ def get_cmd_args (self ) -> list [str ]:
200+ """
201+ Get a list with the command arguments for the model executable.
211202 """
212203
213- path_exe = self .get_exe ()
214-
215- cmdl = [path_exe .as_posix ()]
204+ cmdl = []
216205 for key in self ._args :
217206 if self ._args [key ] is None :
218207 cmdl .append (f"-{ key } " )
@@ -221,54 +210,26 @@ def get_cmd(self) -> list:
221210
222211 return cmdl
223212
224- def run (self ) -> int :
225- """Run the requested simulation.
226-
227- Returns
228- -------
229- Subprocess return code (0 on success).
213+ def definition (self ) -> OMCSessionRunData :
230214 """
215+ Define all needed data to run the model executable. The data is stored in an OMCSessionRunData object.
216+ """
217+ # ensure that a result filename is provided
218+ result_file = self .arg_get ('r' )
219+ if not isinstance (result_file , str ):
220+ result_file = (self ._runpath / f"{ self ._model_name } .mat" ).as_posix ()
221+
222+ omc_run_data = OMCSessionRunData (
223+ cmd_path = self ._runpath .as_posix (),
224+ cmd_model_name = self ._model_name ,
225+ cmd_args = self .get_cmd_args (),
226+ cmd_result_path = result_file ,
227+ cmd_timeout = self ._timeout ,
228+ )
231229
232- cmdl : list = self .get_cmd ()
233-
234- logger .debug ("Run OM command %s in %s" , repr (cmdl ), self ._runpath .as_posix ())
235-
236- if platform .system () == "Windows" :
237- path_dll = ""
238-
239- # set the process environment from the generated .bat file in windows which should have all the dependencies
240- path_bat = self ._runpath / f"{ self ._model_name } .bat"
241- if not path_bat .exists ():
242- raise ModelicaSystemError ("Batch file (*.bat) does not exist " + str (path_bat ))
243-
244- with open (file = path_bat , mode = 'r' , encoding = 'utf-8' ) as fh :
245- for line in fh :
246- match = re .match (r"^SET PATH=([^%]*)" , line , re .IGNORECASE )
247- if match :
248- path_dll = match .group (1 ).strip (';' ) # Remove any trailing semicolons
249- my_env = os .environ .copy ()
250- my_env ["PATH" ] = path_dll + os .pathsep + my_env ["PATH" ]
251- else :
252- # TODO: how to handle path to resources of external libraries for any system not Windows?
253- my_env = None
254-
255- try :
256- cmdres = subprocess .run (cmdl , capture_output = True , text = True , env = my_env , cwd = self ._runpath ,
257- timeout = self ._timeout , check = True )
258- stdout = cmdres .stdout .strip ()
259- stderr = cmdres .stderr .strip ()
260- returncode = cmdres .returncode
261-
262- logger .debug ("OM output for command %s:\n %s" , repr (cmdl ), stdout )
263-
264- if stderr :
265- raise ModelicaSystemError (f"Error running command { repr (cmdl )} : { stderr } " )
266- except subprocess .TimeoutExpired as ex :
267- raise ModelicaSystemError (f"Timeout running command { repr (cmdl )} " ) from ex
268- except subprocess .CalledProcessError as ex :
269- raise ModelicaSystemError (f"Error running command { repr (cmdl )} " ) from ex
230+ omc_run_data_updated = self ._session .omc_run_data_update (omc_run_data )
270231
271- return returncode
232+ return omc_run_data_updated
272233
273234 @staticmethod
274235 def parse_simflags (simflags : str ) -> dict [str , Optional [str | dict [str , str ]]]:
@@ -983,6 +944,7 @@ def simulate_cmd(
983944 """
984945
985946 om_cmd = ModelicaSystemCmd (
947+ session = self ._getconn ,
986948 runpath = self .getWorkDirectory (),
987949 modelname = self ._model_name ,
988950 timeout = timeout ,
@@ -1074,7 +1036,8 @@ def simulate(
10741036 if self ._result_file .is_file ():
10751037 self ._result_file .unlink ()
10761038 # ... run simulation ...
1077- returncode = om_cmd .run ()
1039+ cmd_definition = om_cmd .definition ()
1040+ returncode = self ._getconn .run_model_executable (cmd_run_data = cmd_definition )
10781041 # and check returncode *AND* resultfile
10791042 if returncode != 0 and self ._result_file .is_file ():
10801043 # check for an empty (=> 0B) result file which indicates a crash of the model executable
@@ -1592,6 +1555,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15921555 )
15931556
15941557 om_cmd = ModelicaSystemCmd (
1558+ session = self ._getconn ,
15951559 runpath = self .getWorkDirectory (),
15961560 modelname = self ._model_name ,
15971561 timeout = timeout ,
@@ -1631,7 +1595,8 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
16311595
16321596 linear_file .unlink (missing_ok = True )
16331597
1634- returncode = om_cmd .run ()
1598+ cmd_definition = om_cmd .definition ()
1599+ returncode = self ._getconn .run_model_executable (cmd_run_data = cmd_definition )
16351600 if returncode != 0 :
16361601 raise ModelicaSystemError (f"Linearize failed with return code: { returncode } " )
16371602 if not linear_file .exists ():
0 commit comments