3333"""
3434
3535import ast
36- import csv
3736from dataclasses import dataclass
3837import logging
3938import numbers
4342import platform
4443import re
4544import subprocess
46- import tempfile
4745import textwrap
4846from typing import Optional , Any
4947import warnings
5048import xml .etree .ElementTree as ET
5149
52- from OMPython .OMCSession import OMCSessionException , OMCSessionZMQ , OMCProcessLocal
50+ from OMPython .OMCSession import OMCSessionException , OMCSessionZMQ , OMCProcessLocal , OMCPath
5351
5452# define logger using the current module name as ID
5553logger = logging .getLogger (__name__ )
@@ -398,9 +396,9 @@ def __init__(
398396
399397 self ._lmodel = lmodel # may be needed if model is derived from other model
400398 self ._model_name = modelName # Model class name
401- self ._file_name = pathlib . Path (fileName ).resolve () if fileName is not None else None # Model file/package name
399+ self ._file_name : Optional [ OMCPath ] = self . _getconn . omcpath (fileName ).resolve () if fileName is not None else None # Model file/package name
402400 self ._simulated = False # True if the model has already been simulated
403- self ._result_file : Optional [pathlib . Path ] = None # for storing result file
401+ self ._result_file : Optional [OMCPath ] = None # for storing result file
404402 self ._variable_filter = variableFilter
405403
406404 if self ._file_name is not None and not self ._file_name .is_file (): # if file does not exist
@@ -412,7 +410,7 @@ def __init__(
412410 self .setCommandLineOptions ("--linearizationDumpLanguage=python" )
413411 self .setCommandLineOptions ("--generateSymbolicLinearization" )
414412
415- self ._tempdir = self .setTempDirectory (customBuildDirectory )
413+ self ._tempdir : OMCPath = self .setTempDirectory (customBuildDirectory )
416414
417415 if self ._file_name is not None :
418416 self ._loadLibrary (lmodel = self ._lmodel )
@@ -432,7 +430,7 @@ def setCommandLineOptions(self, commandLineOptions: Optional[str] = None):
432430 exp = f'setCommandLineOptions("{ commandLineOptions } ")'
433431 self .sendExpression (exp )
434432
435- def _loadFile (self , fileName : pathlib . Path ):
433+ def _loadFile (self , fileName : OMCPath ):
436434 # load file
437435 self .sendExpression (f'loadFile("{ fileName .as_posix ()} ")' )
438436
@@ -460,14 +458,14 @@ def _loadLibrary(self, lmodel: list):
460458 '1)["Modelica"]\n '
461459 '2)[("Modelica","3.2.3"), "PowerSystems"]\n ' )
462460
463- def setTempDirectory (self , customBuildDirectory : Optional [str | os .PathLike | pathlib .Path ] = None ) -> pathlib . Path :
461+ def setTempDirectory (self , customBuildDirectory : Optional [str | os .PathLike | pathlib .Path ] = None ) -> OMCPath :
464462 # create a unique temp directory for each session and build the model in that directory
465463 if customBuildDirectory is not None :
466464 if not os .path .exists (customBuildDirectory ):
467465 raise IOError (f"{ customBuildDirectory } does not exist" )
468- tempdir = pathlib . Path (customBuildDirectory ).absolute ()
466+ tempdir = self . _getconn . omcpath (customBuildDirectory ).absolute ()
469467 else :
470- tempdir = pathlib . Path ( tempfile . mkdtemp () ).absolute ()
468+ tempdir = self . _getconn . omcpath_tempdir ( ).absolute ()
471469 if not tempdir .is_dir ():
472470 raise IOError (f"{ tempdir } could not be created" )
473471
@@ -477,7 +475,7 @@ def setTempDirectory(self, customBuildDirectory: Optional[str | os.PathLike | pa
477475
478476 return tempdir
479477
480- def getWorkDirectory (self ) -> pathlib . Path :
478+ def getWorkDirectory (self ) -> OMCPath :
481479 return self ._tempdir
482480
483481 def buildModel (self , variableFilter : Optional [str ] = None ):
@@ -492,7 +490,7 @@ def buildModel(self, variableFilter: Optional[str] = None):
492490 buildModelResult = self ._requestApi (apiName = "buildModel" , entity = self ._model_name , properties = varFilter )
493491 logger .debug ("OM model build result: %s" , buildModelResult )
494492
495- xml_file = pathlib . Path (buildModelResult [0 ]).parent / buildModelResult [1 ]
493+ xml_file = self . _getconn . omcpath (buildModelResult [0 ]).parent / buildModelResult [1 ]
496494 self ._xmlparse (xml_file = xml_file )
497495
498496 def sendExpression (self , expr : str , parsed : bool = True ) -> Any :
@@ -524,7 +522,7 @@ def _requestApi(
524522
525523 return self .sendExpression (exp )
526524
527- def _xmlparse (self , xml_file : pathlib . Path ):
525+ def _xmlparse (self , xml_file : OMCPath ):
528526 if not xml_file .is_file ():
529527 raise ModelicaSystemError (f"XML file not generated: { xml_file } " )
530528
@@ -944,7 +942,7 @@ def getOptimizationOptions(self, names: Optional[str | list[str]] = None) -> dic
944942
945943 def simulate_cmd (
946944 self ,
947- result_file : pathlib . Path ,
945+ result_file : OMCPath ,
948946 simflags : Optional [str ] = None ,
949947 simargs : Optional [dict [str , Optional [str | dict [str , str ]]]] = None ,
950948 timeout : Optional [float ] = None ,
@@ -971,7 +969,11 @@ def simulate_cmd(
971969 An instance if ModelicaSystemCmd to run the requested simulation.
972970 """
973971
974- om_cmd = ModelicaSystemCmd (runpath = self ._tempdir , modelname = self ._model_name , timeout = timeout )
972+ om_cmd = ModelicaSystemCmd (
973+ runpath = pathlib .Path (self .getWorkDirectory ()),
974+ modelname = self ._model_name ,
975+ timeout = timeout ,
976+ )
975977
976978 # always define the result file to use
977979 om_cmd .arg_set (key = "r" , val = result_file .as_posix ())
@@ -983,15 +985,13 @@ def simulate_cmd(
983985 if simargs :
984986 om_cmd .args_set (args = simargs )
985987
986- overrideFile = self ._tempdir / f"{ self ._model_name } _override.txt"
988+ overrideFile = self .getWorkDirectory () / f"{ self ._model_name } _override.txt"
987989 if self ._override_variables or self ._simulate_options_override :
988990 tmpdict = self ._override_variables .copy ()
989991 tmpdict .update (self ._simulate_options_override )
990- # write to override file
991- with open (file = overrideFile , mode = "w" , encoding = "utf-8" ) as fh :
992- for key , value in tmpdict .items ():
993- fh .write (f"{ key } ={ value } \n " )
994992
993+ override_content = "\n " .join ([f"{ key } ={ value } " for key , value in tmpdict .items ()]) + "\n "
994+ overrideFile .write_text (override_content )
995995 om_cmd .arg_set (key = "overrideFile" , val = overrideFile .as_posix ())
996996
997997 if self ._inputs : # if model has input quantities
@@ -1042,11 +1042,14 @@ def simulate(
10421042
10431043 if resultfile is None :
10441044 # default result file generated by OM
1045- self ._result_file = self ._tempdir / f"{ self ._model_name } _res.mat"
1045+ self ._result_file = self .getWorkDirectory () / f"{ self ._model_name } _res.mat"
10461046 elif os .path .exists (resultfile ):
1047- self ._result_file = pathlib . Path (resultfile )
1047+ self ._result_file = self . _getconn . omcpath (resultfile )
10481048 else :
1049- self ._result_file = self ._tempdir / resultfile
1049+ self ._result_file = self .getWorkDirectory () / resultfile
1050+
1051+ if not isinstance (self ._result_file , OMCPath ):
1052+ raise ModelicaSystemError (f"Invalid result file path: { self ._result_file } - must be an OMCPath object!" )
10501053
10511054 om_cmd = self .simulate_cmd (
10521055 result_file = self ._result_file ,
@@ -1065,7 +1068,7 @@ def simulate(
10651068 # check for an empty (=> 0B) result file which indicates a crash of the model executable
10661069 # see: https://github.com/OpenModelica/OMPython/issues/261
10671070 # https://github.com/OpenModelica/OpenModelica/issues/13829
1068- if self ._result_file .stat (). st_size == 0 :
1071+ if self ._result_file .size () == 0 :
10691072 self ._result_file .unlink ()
10701073 raise ModelicaSystemError ("Empty result file - this indicates a crash of the model executable!" )
10711074
@@ -1110,7 +1113,7 @@ def getSolutions(self, varList: Optional[str | list[str]] = None, resultfile: Op
11101113 raise ModelicaSystemError ("No result file found. Run simulate() first." )
11111114 result_file = self ._result_file
11121115 else :
1113- result_file = pathlib . Path (resultfile )
1116+ result_file = self . _getconn . omcpath (resultfile )
11141117
11151118 # check for result file exits
11161119 if not result_file .is_file ():
@@ -1406,7 +1409,7 @@ def setInputs(
14061409
14071410 return True
14081411
1409- def _createCSVData (self , csvfile : Optional [pathlib . Path ] = None ) -> pathlib . Path :
1412+ def _createCSVData (self , csvfile : Optional [OMCPath ] = None ) -> OMCPath :
14101413 """
14111414 Create a csv file with inputs for the simulation/optimization of the model. If csvfile is provided as argument,
14121415 this file is used; else a generic file name is created.
@@ -1452,11 +1455,12 @@ def _createCSVData(self, csvfile: Optional[pathlib.Path] = None) -> pathlib.Path
14521455 csv_rows .append (row )
14531456
14541457 if csvfile is None :
1455- csvfile = self ._tempdir / f'{ self ._model_name } .csv'
1458+ csvfile = self .getWorkDirectory () / f'{ self ._model_name } .csv'
1459+
1460+ # basic definition of a CSV file using csv_rows as input
1461+ csv_content = "\n " .join (["," .join (map (str , row )) for row in csv_rows ]) + "\n "
14561462
1457- with open (file = csvfile , mode = "w" , encoding = "utf-8" , newline = "" ) as fh :
1458- writer = csv .writer (fh )
1459- writer .writerows (csv_rows )
1463+ csvfile .write_text (csv_content )
14601464
14611465 return csvfile
14621466
@@ -1576,17 +1580,21 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15761580 "use ModelicaSystem() to build the model first"
15771581 )
15781582
1579- om_cmd = ModelicaSystemCmd (runpath = self ._tempdir , modelname = self ._model_name , timeout = timeout )
1580-
1581- overrideLinearFile = self ._tempdir / f'{ self ._model_name } _override_linear.txt'
1583+ om_cmd = ModelicaSystemCmd (
1584+ runpath = pathlib .Path (self .getWorkDirectory ()),
1585+ modelname = self ._model_name ,
1586+ timeout = timeout ,
1587+ )
15821588
1583- with open (file = overrideLinearFile , mode = "w" , encoding = "utf-8" ) as fh :
1584- for key1 , value1 in self ._override_variables .items ():
1585- fh .write (f"{ key1 } ={ value1 } \n " )
1586- for key2 , value2 in self ._linearization_options .items ():
1587- fh .write (f"{ key2 } ={ value2 } \n " )
1589+ override_content = (
1590+ "\n " .join ([f"{ key } ={ value } " for key , value in self ._override_variables .items ()])
1591+ + "\n " .join ([f"{ key } ={ value } " for key , value in self ._linearization_options .items ()])
1592+ + "\n "
1593+ )
1594+ override_file = self .getWorkDirectory () / f'{ self ._model_name } _override_linear.txt'
1595+ override_file .write_text (override_content )
15881596
1589- om_cmd .arg_set (key = "overrideFile" , val = overrideLinearFile .as_posix ())
1597+ om_cmd .arg_set (key = "overrideFile" , val = override_file .as_posix ())
15901598
15911599 if self ._inputs :
15921600 for key in self ._inputs :
@@ -1608,7 +1616,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
16081616 om_cmd .args_set (args = simargs )
16091617
16101618 # the file create by the model executable which contains the matrix and linear inputs, outputs and states
1611- linear_file = self ._tempdir / "linearized_model.py"
1619+ linear_file = self .getWorkDirectory () / "linearized_model.py"
16121620
16131621 linear_file .unlink (missing_ok = True )
16141622
@@ -1618,7 +1626,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
16181626
16191627 self ._simulated = True
16201628
1621- if not linear_file .exists ():
1629+ if not linear_file .is_file ():
16221630 raise ModelicaSystemError (f"Linearization failed: { linear_file } not found!" )
16231631
16241632 # extract data from the python file with the linearized model using the ast module - this allows to get the
0 commit comments