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__ )
@@ -385,9 +383,9 @@ def __init__(
385383
386384 self ._lmodel = lmodel # may be needed if model is derived from other model
387385 self ._model_name = modelName # Model class name
388- self ._file_name = pathlib . Path (fileName ).resolve () if fileName is not None else None # Model file/package name
386+ self ._file_name : Optional [ OMCPath ] = self . _getconn . omcpath (fileName ).resolve () if fileName is not None else None # Model file/package name
389387 self ._simulated = False # True if the model has already been simulated
390- self ._result_file : Optional [pathlib . Path ] = None # for storing result file
388+ self ._result_file : Optional [OMCPath ] = None # for storing result file
391389 self ._variable_filter = variableFilter
392390
393391 if self ._file_name is not None and not self ._file_name .is_file (): # if file does not exist
@@ -399,7 +397,7 @@ def __init__(
399397 self .setCommandLineOptions ("--linearizationDumpLanguage=python" )
400398 self .setCommandLineOptions ("--generateSymbolicLinearization" )
401399
402- self ._tempdir = self .setTempDirectory (customBuildDirectory )
400+ self ._tempdir : OMCPath = self .setTempDirectory (customBuildDirectory )
403401
404402 if self ._file_name is not None :
405403 self ._loadLibrary (lmodel = self ._lmodel )
@@ -419,7 +417,7 @@ def setCommandLineOptions(self, commandLineOptions: Optional[str] = None):
419417 exp = f'setCommandLineOptions("{ commandLineOptions } ")'
420418 self .sendExpression (exp )
421419
422- def _loadFile (self , fileName : pathlib . Path ):
420+ def _loadFile (self , fileName : OMCPath ):
423421 # load file
424422 self .sendExpression (f'loadFile("{ fileName .as_posix ()} ")' )
425423
@@ -447,14 +445,14 @@ def _loadLibrary(self, lmodel: list):
447445 '1)["Modelica"]\n '
448446 '2)[("Modelica","3.2.3"), "PowerSystems"]\n ' )
449447
450- def setTempDirectory (self , customBuildDirectory : Optional [str | os .PathLike | pathlib .Path ] = None ) -> pathlib . Path :
448+ def setTempDirectory (self , customBuildDirectory : Optional [str | os .PathLike | pathlib .Path ] = None ) -> OMCPath :
451449 # create a unique temp directory for each session and build the model in that directory
452450 if customBuildDirectory is not None :
453451 if not os .path .exists (customBuildDirectory ):
454452 raise IOError (f"{ customBuildDirectory } does not exist" )
455- tempdir = pathlib . Path (customBuildDirectory ).absolute ()
453+ tempdir = self . _getconn . omcpath (customBuildDirectory ).absolute ()
456454 else :
457- tempdir = pathlib . Path ( tempfile . mkdtemp () ).absolute ()
455+ tempdir = self . _getconn . omcpath_tempdir ( ).absolute ()
458456 if not tempdir .is_dir ():
459457 raise IOError (f"{ tempdir } could not be created" )
460458
@@ -464,7 +462,7 @@ def setTempDirectory(self, customBuildDirectory: Optional[str | os.PathLike | pa
464462
465463 return tempdir
466464
467- def getWorkDirectory (self ) -> pathlib . Path :
465+ def getWorkDirectory (self ) -> OMCPath :
468466 return self ._tempdir
469467
470468 def buildModel (self , variableFilter : Optional [str ] = None ):
@@ -479,7 +477,7 @@ def buildModel(self, variableFilter: Optional[str] = None):
479477 buildModelResult = self ._requestApi ("buildModel" , self ._model_name , properties = varFilter )
480478 logger .debug ("OM model build result: %s" , buildModelResult )
481479
482- xml_file = pathlib . Path (buildModelResult [0 ]).parent / buildModelResult [1 ]
480+ xml_file = self . _getconn . omcpath (buildModelResult [0 ]).parent / buildModelResult [1 ]
483481 self ._xmlparse (xml_file = xml_file )
484482
485483 def sendExpression (self , expr : str , parsed : bool = True ):
@@ -506,7 +504,7 @@ def _requestApi(self, apiName, entity=None, properties=None): # 2
506504
507505 return self .sendExpression (exp )
508506
509- def _xmlparse (self , xml_file : pathlib . Path ):
507+ def _xmlparse (self , xml_file : OMCPath ):
510508 if not xml_file .is_file ():
511509 raise ModelicaSystemError (f"XML file not generated: { xml_file } " )
512510
@@ -926,7 +924,7 @@ def getOptimizationOptions(self, names: Optional[str | list[str]] = None) -> dic
926924
927925 def simulate_cmd (
928926 self ,
929- result_file : pathlib . Path ,
927+ result_file : OMCPath ,
930928 simflags : Optional [str ] = None ,
931929 simargs : Optional [dict [str , Optional [str | dict [str , str ]]]] = None ,
932930 timeout : Optional [float ] = None ,
@@ -953,7 +951,11 @@ def simulate_cmd(
953951 An instance if ModelicaSystemCmd to run the requested simulation.
954952 """
955953
956- om_cmd = ModelicaSystemCmd (runpath = self ._tempdir , modelname = self ._model_name , timeout = timeout )
954+ om_cmd = ModelicaSystemCmd (
955+ runpath = pathlib .Path (self .getWorkDirectory ()),
956+ modelname = self ._model_name ,
957+ timeout = timeout ,
958+ )
957959
958960 # always define the result file to use
959961 om_cmd .arg_set (key = "r" , val = result_file .as_posix ())
@@ -965,15 +967,13 @@ def simulate_cmd(
965967 if simargs :
966968 om_cmd .args_set (args = simargs )
967969
968- overrideFile = self ._tempdir / f"{ self ._model_name } _override.txt"
970+ overrideFile = self .getWorkDirectory () / f"{ self ._model_name } _override.txt"
969971 if self ._override_variables or self ._simulate_options_override :
970972 tmpdict = self ._override_variables .copy ()
971973 tmpdict .update (self ._simulate_options_override )
972- # write to override file
973- with open (file = overrideFile , mode = "w" , encoding = "utf-8" ) as fh :
974- for key , value in tmpdict .items ():
975- fh .write (f"{ key } ={ value } \n " )
976974
975+ override_content = "\n " .join ([f"{ key } ={ value } " for key , value in tmpdict .items ()]) + "\n "
976+ overrideFile .write_text (override_content )
977977 om_cmd .arg_set (key = "overrideFile" , val = overrideFile .as_posix ())
978978
979979 if self ._inputs : # if model has input quantities
@@ -1024,11 +1024,14 @@ def simulate(
10241024
10251025 if resultfile is None :
10261026 # default result file generated by OM
1027- self ._result_file = self ._tempdir / f"{ self ._model_name } _res.mat"
1027+ self ._result_file = self .getWorkDirectory () / f"{ self ._model_name } _res.mat"
10281028 elif os .path .exists (resultfile ):
1029- self ._result_file = pathlib . Path (resultfile )
1029+ self ._result_file = self . _getconn . omcpath (resultfile )
10301030 else :
1031- self ._result_file = self ._tempdir / resultfile
1031+ self ._result_file = self .getWorkDirectory () / resultfile
1032+
1033+ if not isinstance (self ._result_file , OMCPath ):
1034+ raise ModelicaSystemError (f"Invalid result file path: { self ._result_file } - must be an OMCPath object!" )
10321035
10331036 om_cmd = self .simulate_cmd (
10341037 result_file = self ._result_file ,
@@ -1047,7 +1050,7 @@ def simulate(
10471050 # check for an empty (=> 0B) result file which indicates a crash of the model executable
10481051 # see: https://github.com/OpenModelica/OMPython/issues/261
10491052 # https://github.com/OpenModelica/OpenModelica/issues/13829
1050- if self ._result_file .stat (). st_size == 0 :
1053+ if self ._result_file .size () == 0 :
10511054 self ._result_file .unlink ()
10521055 raise ModelicaSystemError ("Empty result file - this indicates a crash of the model executable!" )
10531056
@@ -1092,7 +1095,7 @@ def getSolutions(self, varList: Optional[str | list[str]] = None, resultfile: Op
10921095 raise ModelicaSystemError ("No result file found. Run simulate() first." )
10931096 result_file = self ._result_file
10941097 else :
1095- result_file = pathlib . Path (resultfile )
1098+ result_file = self . _getconn . omcpath (resultfile )
10961099
10971100 # check for result file exits
10981101 if not result_file .is_file ():
@@ -1388,7 +1391,7 @@ def setInputs(
13881391
13891392 return True
13901393
1391- def _createCSVData (self , csvfile : Optional [pathlib . Path ] = None ) -> pathlib . Path :
1394+ def _createCSVData (self , csvfile : Optional [OMCPath ] = None ) -> OMCPath :
13921395 """
13931396 Create a csv file with inputs for the simulation/optimization of the model. If csvfile is provided as argument,
13941397 this file is used; else a generic file name is created.
@@ -1434,11 +1437,12 @@ def _createCSVData(self, csvfile: Optional[pathlib.Path] = None) -> pathlib.Path
14341437 csv_rows .append (row )
14351438
14361439 if csvfile is None :
1437- csvfile = self ._tempdir / f'{ self ._model_name } .csv'
1440+ csvfile = self .getWorkDirectory () / f'{ self ._model_name } .csv'
1441+
1442+ # basic definition of a CSV file using csv_rows as input
1443+ csv_content = "\n " .join (["," .join (map (str , row )) for row in csv_rows ]) + "\n "
14381444
1439- with open (file = csvfile , mode = "w" , encoding = "utf-8" , newline = "" ) as fh :
1440- writer = csv .writer (fh )
1441- writer .writerows (csv_rows )
1445+ csvfile .write_text (csv_content )
14421446
14431447 return csvfile
14441448
@@ -1557,17 +1561,21 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15571561 "use ModelicaSystem() to build the model first"
15581562 )
15591563
1560- om_cmd = ModelicaSystemCmd (runpath = self ._tempdir , modelname = self ._model_name , timeout = timeout )
1561-
1562- overrideLinearFile = self ._tempdir / f'{ self ._model_name } _override_linear.txt'
1564+ om_cmd = ModelicaSystemCmd (
1565+ runpath = pathlib .Path (self .getWorkDirectory ()),
1566+ modelname = self ._model_name ,
1567+ timeout = timeout ,
1568+ )
15631569
1564- with open (file = overrideLinearFile , mode = "w" , encoding = "utf-8" ) as fh :
1565- for key1 , value1 in self ._override_variables .items ():
1566- fh .write (f"{ key1 } ={ value1 } \n " )
1567- for key2 , value2 in self ._linearization_options .items ():
1568- fh .write (f"{ key2 } ={ value2 } \n " )
1570+ override_content = (
1571+ "\n " .join ([f"{ key } ={ value } " for key , value in self ._override_variables .items ()])
1572+ + "\n " .join ([f"{ key } ={ value } " for key , value in self ._linearization_options .items ()])
1573+ + "\n "
1574+ )
1575+ override_file = self .getWorkDirectory () / f'{ self ._model_name } _override_linear.txt'
1576+ override_file .write_text (override_content )
15691577
1570- om_cmd .arg_set (key = "overrideFile" , val = overrideLinearFile .as_posix ())
1578+ om_cmd .arg_set (key = "overrideFile" , val = override_file .as_posix ())
15711579
15721580 if self ._inputs :
15731581 for key in self ._inputs :
@@ -1589,7 +1597,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15891597 om_cmd .args_set (args = simargs )
15901598
15911599 # the file create by the model executable which contains the matrix and linear inputs, outputs and states
1592- linear_file = self ._tempdir / "linearized_model.py"
1600+ linear_file = self .getWorkDirectory () / "linearized_model.py"
15931601
15941602 linear_file .unlink (missing_ok = True )
15951603
@@ -1599,7 +1607,7 @@ def linearize(self, lintime: Optional[float] = None, simflags: Optional[str] = N
15991607
16001608 self ._simulated = True
16011609
1602- if not linear_file .exists ():
1610+ if not linear_file .is_file ():
16031611 raise ModelicaSystemError (f"Linearization failed: { linear_file } not found!" )
16041612
16051613 # extract data from the python file with the linearized model using the ast module - this allows to get the
0 commit comments