2121import numpy as np
2222
2323from OMPython .OMCSession import (
24+ ModelExecutionData ,
25+ ModelExecutionException ,
26+
2427 OMCSessionException ,
25- OMCSessionRunData ,
2628 OMCSession ,
2729 OMCSessionLocal ,
2830 OMCPath ,
3436
3537class ModelicaSystemError (Exception ):
3638 """
37- Exception used in ModelicaSystem and ModelicaSystemCmd classes.
39+ Exception used in ModelicaSystem classes.
3840 """
3941
4042
@@ -89,7 +91,7 @@ def __getitem__(self, index: int):
8991 return {0 : self .A , 1 : self .B , 2 : self .C , 3 : self .D }[index ]
9092
9193
92- class ModelicaSystemCmd :
94+ class ModelExecutionCmd :
9395 """
9496 All information about a compiled model executable. This should include data about all structured parameters, i.e.
9597 parameters which need a recompilation of the model. All non-structured parameters can be easily changed without
@@ -98,16 +100,22 @@ class ModelicaSystemCmd:
98100
99101 def __init__ (
100102 self ,
101- session : OMCSession ,
102- runpath : OMCPath ,
103- modelname : Optional [str ] = None ,
103+ runpath : os .PathLike ,
104+ cmd_prefix : list [str ],
105+ cmd_local : bool = False ,
106+ cmd_windows : bool = False ,
107+ timeout : float = 10.0 ,
108+ model_name : Optional [str ] = None ,
104109 ) -> None :
105- if modelname is None :
106- raise ModelicaSystemError ("Missing model name!" )
110+ if model_name is None :
111+ raise ModelExecutionException ("Missing model name!" )
107112
108- self ._session = session
109- self ._runpath = runpath
110- self ._model_name = modelname
113+ self ._cmd_local = cmd_local
114+ self ._cmd_windows = cmd_windows
115+ self ._cmd_prefix = cmd_prefix
116+ self ._runpath = pathlib .PurePosixPath (runpath )
117+ self ._model_name = model_name
118+ self ._timeout = timeout
111119
112120 # dictionaries of command line arguments for the model executable
113121 self ._args : dict [str , str | None ] = {}
@@ -152,26 +160,26 @@ def override2str(
152160 elif isinstance (orval , numbers .Number ):
153161 val_str = str (orval )
154162 else :
155- raise ModelicaSystemError (f"Invalid value for override key { orkey } : { type (orval )} " )
163+ raise ModelExecutionException (f"Invalid value for override key { orkey } : { type (orval )} " )
156164
157165 return f"{ orkey } ={ val_str } "
158166
159167 if not isinstance (key , str ):
160- raise ModelicaSystemError (f"Invalid argument key: { repr (key )} (type: { type (key )} )" )
168+ raise ModelExecutionException (f"Invalid argument key: { repr (key )} (type: { type (key )} )" )
161169 key = key .strip ()
162170
163171 if isinstance (val , dict ):
164172 if key != 'override' :
165- raise ModelicaSystemError ("Dictionary input only possible for key 'override'!" )
173+ raise ModelExecutionException ("Dictionary input only possible for key 'override'!" )
166174
167175 for okey , oval in val .items ():
168176 if not isinstance (okey , str ):
169- raise ModelicaSystemError ("Invalid key for argument 'override': "
170- f"{ repr (okey )} (type: { type (okey )} )" )
177+ raise ModelExecutionException ("Invalid key for argument 'override': "
178+ f"{ repr (okey )} (type: { type (okey )} )" )
171179
172180 if not isinstance (oval , (str , bool , numbers .Number , type (None ))):
173- raise ModelicaSystemError (f"Invalid input for 'override'.{ repr (okey )} : "
174- f"{ repr (oval )} (type: { type (oval )} )" )
181+ raise ModelExecutionException (f"Invalid input for 'override'.{ repr (okey )} : "
182+ f"{ repr (oval )} (type: { type (oval )} )" )
175183
176184 if okey in self ._arg_override :
177185 if oval is None :
@@ -193,7 +201,7 @@ def override2str(
193201 elif isinstance (val , numbers .Number ):
194202 argval = str (val )
195203 else :
196- raise ModelicaSystemError (f"Invalid argument value for { repr (key )} : { repr (val )} (type: { type (val )} )" )
204+ raise ModelExecutionException (f"Invalid argument value for { repr (key )} : { repr (val )} (type: { type (val )} )" )
197205
198206 if key in self ._args :
199207 logger .warning (f"Override model executable argument: { repr (key )} = { repr (argval )} "
@@ -233,7 +241,7 @@ def get_cmd_args(self) -> list[str]:
233241
234242 return cmdl
235243
236- def definition (self ) -> OMCSessionRunData :
244+ def definition (self ) -> ModelExecutionData :
237245 """
238246 Define all needed data to run the model executable. The data is stored in an OMCSessionRunData object.
239247 """
@@ -242,18 +250,50 @@ def definition(self) -> OMCSessionRunData:
242250 if not isinstance (result_file , str ):
243251 result_file = (self ._runpath / f"{ self ._model_name } .mat" ).as_posix ()
244252
245- omc_run_data = OMCSessionRunData (
246- cmd_path = self ._runpath .as_posix (),
253+ # as this is the local implementation, pathlib.Path can be used
254+ cmd_path = self ._runpath
255+
256+ cmd_library_path = None
257+ if self ._cmd_local and self ._cmd_windows :
258+ cmd_library_path = ""
259+
260+ # set the process environment from the generated .bat file in windows which should have all the dependencies
261+ # for this pathlib.PurePosixPath() must be converted to a pathlib.Path() object, i.e. WindowsPath
262+ path_bat = pathlib .Path (cmd_path ) / f"{ self ._model_name } .bat"
263+ if not path_bat .is_file ():
264+ raise ModelExecutionException ("Batch file (*.bat) does not exist " + str (path_bat ))
265+
266+ content = path_bat .read_text (encoding = 'utf-8' )
267+ for line in content .splitlines ():
268+ match = re .match (pattern = r"^SET PATH=([^%]*)" , string = line , flags = re .IGNORECASE )
269+ if match :
270+ cmd_library_path = match .group (1 ).strip (';' ) # Remove any trailing semicolons
271+ my_env = os .environ .copy ()
272+ my_env ["PATH" ] = cmd_library_path + os .pathsep + my_env ["PATH" ]
273+
274+ cmd_model_executable = cmd_path / f"{ self ._model_name } .exe"
275+ else :
276+ # for Linux the paths to the needed libraries should be included in the executable (using rpath)
277+ cmd_model_executable = cmd_path / self ._model_name
278+
279+ # define local(!) working directory
280+ cmd_cwd_local = None
281+ if self ._cmd_local :
282+ cmd_cwd_local = cmd_path .as_posix ()
283+
284+ omc_run_data = ModelExecutionData (
285+ cmd_path = cmd_path .as_posix (),
247286 cmd_model_name = self ._model_name ,
248287 cmd_args = self .get_cmd_args (),
249- cmd_result_path = result_file ,
288+ cmd_result_file = result_file ,
289+ cmd_prefix = self ._cmd_prefix ,
290+ cmd_library_path = cmd_library_path ,
291+ cmd_model_executable = cmd_model_executable .as_posix (),
292+ cmd_cwd_local = cmd_cwd_local ,
293+ cmd_timeout = self ._timeout ,
250294 )
251295
252- omc_run_data_updated = self ._session .omc_run_data_update (
253- omc_run_data = omc_run_data ,
254- )
255-
256- return omc_run_data_updated
296+ return omc_run_data
257297
258298 @staticmethod
259299 def parse_simflags (simflags : str ) -> dict [str , Optional [str | dict [str , Any ] | numbers .Number ]]:
@@ -262,17 +302,19 @@ def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, Any] | n
262302
263303 The return data can be used as input for self.args_set().
264304 """
265- warnings .warn (message = "The argument 'simflags' is depreciated and will be removed in future versions; "
266- "please use 'simargs' instead" ,
267- category = DeprecationWarning ,
268- stacklevel = 2 )
305+ warnings .warn (
306+ message = "The argument 'simflags' is depreciated and will be removed in future versions; "
307+ "please use 'simargs' instead" ,
308+ category = DeprecationWarning ,
309+ stacklevel = 2 ,
310+ )
269311
270312 simargs : dict [str , Optional [str | dict [str , Any ] | numbers .Number ]] = {}
271313
272314 args = [s for s in simflags .split (' ' ) if s ]
273315 for arg in args :
274316 if arg [0 ] != '-' :
275- raise ModelicaSystemError (f"Invalid simulation flag: { arg } " )
317+ raise ModelExecutionException (f"Invalid simulation flag: { arg } " )
276318 arg = arg [1 :]
277319 parts = arg .split ('=' )
278320 if len (parts ) == 1 :
@@ -284,12 +326,12 @@ def parse_simflags(simflags: str) -> dict[str, Optional[str | dict[str, Any] | n
284326 for item in override .split (',' ):
285327 kv = item .split ('=' )
286328 if not 0 < len (kv ) < 3 :
287- raise ModelicaSystemError (f"Invalid value for '-override': { override } " )
329+ raise ModelExecutionException (f"Invalid value for '-override': { override } " )
288330 if kv [0 ]:
289331 try :
290332 override_dict [kv [0 ]] = kv [1 ]
291333 except (KeyError , IndexError ) as ex :
292- raise ModelicaSystemError (f"Invalid value for '-override': { override } " ) from ex
334+ raise ModelExecutionException (f"Invalid value for '-override': { override } " ) from ex
293335
294336 simargs [parts [0 ]] = override_dict
295337
@@ -549,15 +591,17 @@ def buildModel(self, variableFilter: Optional[str] = None):
549591 logger .debug ("OM model build result: %s" , build_model_result )
550592
551593 # check if the executable exists ...
552- om_cmd = ModelicaSystemCmd (
553- session = self ._session ,
594+ om_cmd = ModelExecutionCmd (
554595 runpath = self .getWorkDirectory (),
555- modelname = self ._model_name ,
596+ cmd_local = self ._session .model_execution_local ,
597+ cmd_windows = self ._session .model_execution_windows ,
598+ cmd_prefix = self ._session .model_execution_prefix (cwd = self .getWorkDirectory ()),
599+ model_name = self ._model_name ,
556600 )
557601 # ... by running it - output help for command help
558602 om_cmd .arg_set (key = "help" , val = "help" )
559603 cmd_definition = om_cmd .definition ()
560- returncode = self . _session . run_model_executable ( cmd_run_data = cmd_definition )
604+ returncode = cmd_definition . run ( )
561605 if returncode != 0 :
562606 raise ModelicaSystemError ("Model executable not working!" )
563607
@@ -1162,7 +1206,7 @@ def _parse_om_version(version: str) -> tuple[int, int, int]:
11621206
11631207 def _process_override_data (
11641208 self ,
1165- om_cmd : ModelicaSystemCmd ,
1209+ om_cmd : ModelExecutionCmd ,
11661210 override_file : OMCPath ,
11671211 override_var : dict [str , str ],
11681212 override_sim : dict [str , str ],
@@ -1198,7 +1242,7 @@ def simulate_cmd(
11981242 result_file : OMCPath ,
11991243 simflags : Optional [str ] = None ,
12001244 simargs : Optional [dict [str , Optional [str | dict [str , Any ] | numbers .Number ]]] = None ,
1201- ) -> ModelicaSystemCmd :
1245+ ) -> ModelExecutionCmd :
12021246 """
12031247 This method prepares the simulates model according to the simulation options. It returns an instance of
12041248 ModelicaSystemCmd which can be used to run the simulation.
@@ -1220,10 +1264,12 @@ def simulate_cmd(
12201264 An instance if ModelicaSystemCmd to run the requested simulation.
12211265 """
12221266
1223- om_cmd = ModelicaSystemCmd (
1224- session = self ._session ,
1267+ om_cmd = ModelExecutionCmd (
12251268 runpath = self .getWorkDirectory (),
1226- modelname = self ._model_name ,
1269+ cmd_local = self ._session .model_execution_local ,
1270+ cmd_windows = self ._session .model_execution_windows ,
1271+ cmd_prefix = self ._session .model_execution_prefix (cwd = self .getWorkDirectory ()),
1272+ model_name = self ._model_name ,
12271273 )
12281274
12291275 # always define the result file to use
@@ -1312,7 +1358,7 @@ def simulate(
13121358 self ._result_file .unlink ()
13131359 # ... run simulation ...
13141360 cmd_definition = om_cmd .definition ()
1315- returncode = self . _session . run_model_executable ( cmd_run_data = cmd_definition )
1361+ returncode = cmd_definition . run ( )
13161362 # and check returncode *AND* resultfile
13171363 if returncode != 0 and self ._result_file .is_file ():
13181364 # check for an empty (=> 0B) result file which indicates a crash of the model executable
@@ -1915,10 +1961,12 @@ def linearize(
19151961 "use ModelicaSystem() to build the model first"
19161962 )
19171963
1918- om_cmd = ModelicaSystemCmd (
1919- session = self ._session ,
1964+ om_cmd = ModelExecutionCmd (
19201965 runpath = self .getWorkDirectory (),
1921- modelname = self ._model_name ,
1966+ cmd_local = self ._session .model_execution_local ,
1967+ cmd_windows = self ._session .model_execution_windows ,
1968+ cmd_prefix = self ._session .model_execution_prefix (cwd = self .getWorkDirectory ()),
1969+ model_name = self ._model_name ,
19221970 )
19231971
19241972 self ._process_override_data (
@@ -1958,7 +2006,7 @@ def linearize(
19582006 linear_file .unlink (missing_ok = True )
19592007
19602008 cmd_definition = om_cmd .definition ()
1961- returncode = self . _session . run_model_executable ( cmd_run_data = cmd_definition )
2009+ returncode = cmd_definition . run ( )
19622010 if returncode != 0 :
19632011 raise ModelicaSystemError (f"Linearize failed with return code: { returncode } " )
19642012 if not linear_file .is_file ():
@@ -2129,7 +2177,7 @@ def __init__(
21292177 self ._parameters = {}
21302178
21312179 self ._doe_def : Optional [dict [str , dict [str , Any ]]] = None
2132- self ._doe_cmd : Optional [dict [str , OMCSessionRunData ]] = None
2180+ self ._doe_cmd : Optional [dict [str , ModelExecutionData ]] = None
21332181
21342182 def get_session (self ) -> OMCSession :
21352183 """
@@ -2248,7 +2296,7 @@ def get_doe_definition(self) -> Optional[dict[str, dict[str, Any]]]:
22482296 """
22492297 return self ._doe_def
22502298
2251- def get_doe_command (self ) -> Optional [dict [str , OMCSessionRunData ]]:
2299+ def get_doe_command (self ) -> Optional [dict [str , ModelExecutionData ]]:
22522300 """
22532301 Get the definitions of simulations commands to run for this DoE.
22542302 """
@@ -2294,13 +2342,13 @@ def worker(worker_id, task_queue):
22942342 if cmd_definition is None :
22952343 raise ModelicaSystemError ("Missing simulation definition!" )
22962344
2297- resultfile = cmd_definition .cmd_result_path
2345+ resultfile = cmd_definition .cmd_result_file
22982346 resultpath = self .get_session ().omcpath (resultfile )
22992347
23002348 logger .info (f"[Worker { worker_id } ] Performing task: { resultpath .name } " )
23012349
23022350 try :
2303- returncode = self . get_session (). run_model_executable ( cmd_run_data = cmd_definition )
2351+ returncode = cmd_definition . run ( )
23042352 logger .info (f"[Worker { worker_id } ] Simulation { resultpath .name } "
23052353 f"finished with return code: { returncode } " )
23062354 except ModelicaSystemError as ex :
0 commit comments