@@ -1201,7 +1201,7 @@ def _verify_model_exists(model_name):
1201
1201
1202
1202
if self ._modelica_tool == 'dymola' :
1203
1203
for ent in self ._data :
1204
- ent ['dymola' ]['time_out' ] = 300
1204
+ ent ['dymola' ]['time_out' ] = 10 #fixme 300
1205
1205
else : # Non-dymola
1206
1206
def_dic = {}
1207
1207
def_dic [self ._modelica_tool ] = {
@@ -1441,7 +1441,7 @@ def _getDymolaTranslationStatistics(self, data, warnings, errors):
1441
1441
:param warning: A list to which all warnings will be appended.
1442
1442
:param errors: A list to which all errors will be appended.
1443
1443
:return: The translation log from the `*.translation.log` file as
1444
- a list of dictionaries.
1444
+ a list of dictionaries, or `None` if `*.translation.log` does not exist .
1445
1445
1446
1446
Extracts and returns the translation log from the `*.translation.log` file as
1447
1447
a list of dictionaries.
@@ -1450,7 +1450,10 @@ def _getDymolaTranslationStatistics(self, data, warnings, errors):
1450
1450
# Get the working directory that contains the ".log" file
1451
1451
fulFilNam = os .path .join (data ['ResultDirectory' ],
1452
1452
self .getLibraryName (), data ['dymola' ]['TranslationLogFile' ])
1453
- return of .get_model_statistics (fulFilNam , self ._modelica_tool )
1453
+ if os .path .exists (fulFilNam ):
1454
+ return of .get_model_statistics (fulFilNam , self ._modelica_tool )
1455
+ else :
1456
+ return None
1454
1457
1455
1458
def _legacy_comp (self , tOld , yOld , tNew , yNew , tGriOld , tGriNew , varNam , filNam , tol ):
1456
1459
# Interpolate the new variables to the old time stamps
@@ -2898,23 +2901,28 @@ def _checkSimulationError(self, errorFile):
2898
2901
else :
2899
2902
key = 'FMUExport'
2900
2903
2904
+ logFil = None
2901
2905
if key in ele :
2902
- logFil = ele [key ][ "translationLog" ]
2903
- ele [ key ] = self . _performTranslationErrorChecks ( logFil , ele [key ])
2904
- for k , v in list ( self ._error_dict . get_dictionary (). items ()):
2905
- # For OPTIMICA, we neither have simulate nor FMUExport
2906
- if ele [ key ][ k ] > 0 :
2907
- self . _reporter . writeWarning ( v [ "model_message" ]. format ( ele [key ]["command" ]))
2908
- self ._error_dict . increment_counter ( k )
2909
-
2910
- if hasTranslationError :
2911
- hasTranslationErrors = True
2906
+ if "translationLog" in ele [key ]:
2907
+ logFil = ele [key ][ "translationLog" ]
2908
+ ele [ key ] = self ._performTranslationErrorChecks ( logFil , ele [ key ])
2909
+ for k , v in list ( self . _error_dict . get_dictionary (). items ()):
2910
+ # For OPTIMICA, we neither have simulate nor FMUExport
2911
+ if ele [key ][k ] > 0 :
2912
+ self ._reporter . writeWarning ( v [ "model_message" ]. format ( ele [ key ][ "command" ]) )
2913
+ self . _error_dict . increment_counter ( k )
2914
+
2915
+ if hasTranslationError and logFil is not None :
2912
2916
with open (self ._failed_simulator_log_file , "a" ) as f :
2913
2917
f .write ("===============================\n " )
2914
2918
f .write ("=====START OF NEW LOG FILE=====\n " )
2915
2919
f .write ("===============================\n " )
2916
- with open (logFil , "r" ) as f2 :
2917
- f .write (f2 .read ())
2920
+ if os .path .exists (logFil ):
2921
+ with open (logFil , "r" ) as f2 :
2922
+ f .write (f2 .read ())
2923
+ else :
2924
+ # Logfile does not exists, which may be because simulation was terminated due to time out
2925
+ f .write (f"Log file { logFil } does not exist, this can happen if the process was terminated due to time out." )
2918
2926
f .write ("\n \n \n " )
2919
2927
2920
2928
if iChe > 0 :
@@ -3717,6 +3725,13 @@ def _setTemporaryDirectories(self):
3717
3725
def _run_simulation_info (self ):
3718
3726
""" Extract simulation data from statistics.json when run unit test with dymola
3719
3727
"""
3728
+
3729
+ def _get (model , key , data ):
3730
+ for ent in data :
3731
+ if ent ['model_name' ] == model :
3732
+ return ent [key ]
3733
+ return 0
3734
+
3720
3735
with open (self ._statistics_log , 'r' ) as f :
3721
3736
staVal = simplejson .loads (f .read ())
3722
3737
data = []
@@ -3731,11 +3746,11 @@ def _run_simulation_info(self):
3731
3746
temp = {}
3732
3747
temp ['model' ] = case ['model' ]
3733
3748
temp ['simulation' ] = {}
3734
- temp ['simulation' ]['elapsed_time' ] = case ['simulate' ]['elapsed_time' ]
3735
- temp ['simulation' ]['start_time' ] = case ['simulate' ]['start_time' ]
3736
- temp ['simulation' ]['final_time' ] = case ['simulate' ]['final_time' ]
3737
- temp ['simulation' ]['jacobians' ] = case ['simulate' ]['jacobians' ]
3738
- temp ['simulation' ]['state_events' ] = case ['simulate' ]['state_events' ]
3749
+ temp ['simulation' ]['elapsed_time' ] = case ['simulate' ]['elapsed_time' ] if 'elapsed_time' in case [ 'simulate' ] else 0
3750
+ temp ['simulation' ]['start_time' ] = case ['simulate' ]['start_time' ] if 'start_time' in case [ 'simulate' ] else _get ( case [ 'model' ], 'startTime' , self . _data )
3751
+ temp ['simulation' ]['final_time' ] = case ['simulate' ]['final_time' ] if 'final_time' in case [ 'simulate' ] else _get ( case [ 'model' ], 'stopTime' , self . _data )
3752
+ temp ['simulation' ]['jacobians' ] = case ['simulate' ]['jacobians' ] if 'jacobians' in case [ 'simulate' ] else 0
3753
+ temp ['simulation' ]['state_events' ] = case ['simulate' ]['state_events' ] if 'state_events' in case [ 'simulate' ] else 0
3739
3754
temp ['simulation' ]['success' ] = case ['simulate' ]['result' ]
3740
3755
data .append (temp )
3741
3756
dataJson = simplejson .dumps (data )
@@ -3889,9 +3904,50 @@ def run(self):
3889
3904
# Iterate over all test cases of this output file
3890
3905
for ele in cas :
3891
3906
stat .append (ele )
3907
+ except json .decoder .JSONDecodeError as e :
3908
+ # If a run timed out, then temLogFilNam is not a valid json file
3909
+ # because the file is written on the fly, and dymola did not finish
3910
+ # writing all of it, which results in an invalid file.
3911
+ # Check if /tmp/tmp-Buildings-1-o_m7nj7p/Buildings_Examples_VAVReheat_ASHRAE2006_buildingspy.json
3912
+ # exists
3913
+ modelName = os .path .split (temLogFilNam )[1 ].replace ('.statistics.log' , '' )
3914
+ buiLogNam = os .path .join (
3915
+ d ,
3916
+ f"{ modelName .replace ('.' , '_' )} _buildingspy.json" )
3917
+ if os .path .exists (buiLogNam ):
3918
+ # Read the log file of the python script that invoked dymola
3919
+ with open (buiLogNam , mode = "r" , encoding = "utf-8-sig" ) as buiLog :
3920
+ jsonBui = json .load (buiLog )
3921
+ # Build up the entry for reporting the case
3922
+ if "simulation" in jsonBui and "exception" in jsonBui ["simulation" ]:
3923
+ exception = '' .join (jsonBui ['simulation' ]['exception' ])
3924
+ else :
3925
+ exception = f"JSONDecodeError in { temLogFilNam } : { str (e )} "
3926
+ ele = {
3927
+ "model" : modelName ,
3928
+ "simulate" : {
3929
+ "command" : '' .join (jsonBui ['simulation' ]['cmd' ]),
3930
+ "result" : False ,
3931
+ "exception" : exception
3932
+ }
3933
+ }
3934
+ self ._reporter .writeError (
3935
+ f"Model '{ modelName } ' failed: { exception } " )
3936
+ stat .append (ele )
3937
+ # Add the failure also to self._data so that _checkReferencePoints is not trying to read the output.
3938
+ for ele in self ._data :
3939
+ if ele ['model_name' ] == modelName :
3940
+ if "simulation" in ele [self ._modelica_tool ]:
3941
+ ele [self ._modelica_tool ]['simulation' ]['success' ] = False
3942
+ else :
3943
+ ele [self ._modelica_tool ]['simulation' ] = {'success' : False }
3944
+ else :
3945
+ self ._reporter .writeError (
3946
+ f"Decoding '{ temLogFilNam } ' failed and '{ buiLogNam } ' does not exist: { e } " )
3947
+ raise
3892
3948
except ValueError as e :
3893
3949
self ._reporter .writeError (
3894
- "Decoding '%s' failed: %s" % (temLogFilNam , e ))
3950
+ "Loading '%s' failed: %s" % (temLogFilNam , e ))
3895
3951
raise
3896
3952
else :
3897
3953
self ._reporter .writeError (
0 commit comments