From 9251498ae1c7dca52fbd85faf0bea75a548a8460 Mon Sep 17 00:00:00 2001 From: dave <dave@dtu.dk> Date: Tue, 2 Aug 2016 13:57:04 +0200 Subject: [PATCH] refactor prepost.Simulations.ErrorLogs, inherit from prepost.windIO.LogFile --- wetb/prepost/Simulations.py | 321 ++-------------------------------- wetb/prepost/windIO.py | 332 ++++++++++++++++++++++++++++++++++++ 2 files changed, 345 insertions(+), 308 deletions(-) diff --git a/wetb/prepost/Simulations.py b/wetb/prepost/Simulations.py index 99fa1b1d..aeb56951 100755 --- a/wetb/prepost/Simulations.py +++ b/wetb/prepost/Simulations.py @@ -2929,7 +2929,7 @@ class PBS(object): # TODO: rewrite the error log analysis to something better. Take different # approach: start from the case and see if the results are present. Than we # also have the tags_dict available when log-checking a certain case -class ErrorLogs(object): +class ErrorLogs(windIO.LogFile): """ Analyse all HAWC2 log files in any given directory ================================================== @@ -2966,106 +2966,20 @@ class ErrorLogs(object): def __init__(self, silent=False, cases=None, resultfile='ErrorLog.csv'): - self.silent = silent - # specify folder which contains the log files + # call init from base class + super(ErrorLogs, self).__init__(silent=silent) + self.PathToLogs = '' self.ResultFile = resultfile - self.cases = cases - # the total message list log: - self.MsgListLog = [] - # a smaller version, just indication if there are errors: - self.MsgListLog2 = dict() - - # specify which message to look for. The number track's the order. - # this makes it easier to view afterwards in spreadsheet: - # every error will have its own column - - # error messages that appear during initialisation - self.err_init = {} - self.err_init[' *** ERROR *** Error in com'] = len(self.err_init) - self.err_init[' *** ERROR *** in command '] = len(self.err_init) - # *** WARNING *** A comma "," is written within the command line - self.err_init[' *** WARNING *** A comma ",'] = len(self.err_init) - # *** ERROR *** Not correct number of parameters - self.err_init[' *** ERROR *** Not correct '] = len(self.err_init) - # *** INFO *** End of file reached - self.err_init[' *** INFO *** End of file r'] = len(self.err_init) - # *** ERROR *** No line termination in command line - self.err_init[' *** ERROR *** No line term'] = len(self.err_init) - # *** ERROR *** MATRIX IS NOT DEFINITE - self.err_init[' *** ERROR *** MATRIX IS NO'] = len(self.err_init) - # *** ERROR *** There are unused relative - self.err_init[' *** ERROR *** There are un'] = len(self.err_init) - # *** ERROR *** Error finding body based - self.err_init[' *** ERROR *** Error findin'] = len(self.err_init) - # *** ERROR *** In body actions - self.err_init[' *** ERROR *** In body acti'] = len(self.err_init) - # *** ERROR *** Command unknown and ignored - self.err_init[' *** ERROR *** Command unkn'] = len(self.err_init) - # *** ERROR *** ERROR - More bodies than elements on main_body: tower - self.err_init[' *** ERROR *** ERROR - More'] = len(self.err_init) - # *** ERROR *** The program will stop - self.err_init[' *** ERROR *** The program '] = len(self.err_init) - # *** ERROR *** Unknown begin command in topologi. - self.err_init[' *** ERROR *** Unknown begi'] = len(self.err_init) - # *** ERROR *** Not all needed topologi main body commands present - self.err_init[' *** ERROR *** Not all need'] = len(self.err_init) - # *** ERROR *** opening timoschenko data file - self.err_init[' *** ERROR *** opening tim'] = len(self.err_init) - # *** ERROR *** Error opening AE data file - self.err_init[' *** ERROR *** Error openin'] = len(self.err_init) - # *** ERROR *** Requested blade _ae set number not found in _ae file - self.err_init[' *** ERROR *** Requested bl'] = len(self.err_init) - # Error opening PC data file - self.err_init[' Error opening PC data file'] = len(self.err_init) - # *** ERROR *** error reading mann turbulence - self.err_init[' *** ERROR *** error readin'] = len(self.err_init) - # *** INFO *** The DLL subroutine - self.err_init[' *** INFO *** The DLL subro'] = len(self.err_init) - # ** WARNING: FROM ESYS ELASTICBAR: No keyword - self.err_init[' ** WARNING: FROM ESYS ELAS'] = len(self.err_init) - # *** ERROR *** DLL ./control/killtrans.dll could not be loaded - error! - self.err_init[' *** ERROR *** DLL'] = len(self.err_init) - # *** ERROR *** The DLL subroutine - self.err_init[' *** ERROR *** The DLL subr'] = len(self.err_init) - # *** ERROR *** Mann turbulence length scale must be larger than zero! - # *** ERROR *** Mann turbulence alpha eps value must be larger than zero! - # *** ERROR *** Mann turbulence gamma value must be larger than zero! - self.err_init[' *** ERROR *** Mann turbule'] = len(self.err_init) - - # *** WARNING *** Shear center x location not in elastic center, set to zero - self.err_init[' *** WARNING *** Shear cent'] = len(self.err_init) - # Turbulence file ./xyz.bin does not exist - self.err_init[' Turbulence file '] = len(self.err_init) - self.err_init[' *** WARNING ***'] = len(self.err_init) - self.err_init[' *** ERROR ***'] = len(self.err_init) - self.err_init[' WARNING'] = len(self.err_init) - self.err_init[' ERROR'] = len(self.err_init) - - # error messages that appear during simulation - self.err_sim = {} - # *** ERROR *** Wind speed requested inside - self.err_sim[' *** ERROR *** Wind speed r'] = len(self.err_sim) - # Maximum iterations exceeded at time step: - self.err_sim[' Maximum iterations exceede'] = len(self.err_sim) - # Solver seems not to converge: - self.err_sim[' Solver seems not to conver'] = len(self.err_sim) - # *** ERROR *** Out of x bounds: - self.err_sim[' *** ERROR *** Out of x bou'] = len(self.err_sim) - # *** ERROR *** Out of limits in user defined shear field - limit value used - self.err_sim[' *** ERROR *** Out of limit'] = len(self.err_sim) - - # TODO: error message from a non existing channel output/input - # add more messages if required... - - self.init_cols = len(self.err_init) - self.sim_cols = len(self.err_sim) - # TODO: save this not a csv text string but a df_dict, and save as excel # and DataFrame! def check(self, appendlog=False, save_iter=False): + """Check all log files that are to be found in the directory + ErrorLogs.PathToLogs, or check the specific log file if + ErrorLogs.PathToLogs points to a specific log file. + """ # MsgListLog = [] @@ -3100,208 +3014,12 @@ class ErrorLogs(object): # open the current log file f_log = os.path.join(self.PathToLogs, str(fname_lower)) - with open(f_log, 'r') as f: - lines = f.readlines() - - # keep track of the messages allready found in this file - tempLog = [] - tempLog.append(fname) - exit_correct, found_error = False, False - - subcols_sim = 4 - subcols_init = 2 - # create empty list item for the different messages and line - # number. Include one column for non identified messages - for j in range(self.init_cols): - # 2 sub-columns per message: nr, msg - for k in range(subcols_init): - tempLog.append('') - for j in range(self.sim_cols): - # 4 sub-columns per message: first, last, nr, msg - for k in range(subcols_sim): - tempLog.append('') - # and two more columns at the end for messages of unknown origin - tempLog.append('') - tempLog.append('') - - # if there is a cases object, see how many time steps we expect - if self.cases is not None: - case = self.cases[fname.replace('.log', '.htc')] - dt = float(case['[dt_sim]']) - time_steps = int(float(case['[time_stop]']) / dt) - iterations = np.ndarray( (time_steps+1,3), dtype=np.float32 ) - else: - iterations = np.ndarray( (len(lines),3), dtype=np.float32 ) - dt = False - iterations[:,0:2] = -1 - iterations[:,2] = 0 - - # keep track of the time_step number - time_step, init_block = -1, True - # check for messages in the current line - # for speed: delete from message watch list if message is found - for j, line in enumerate(lines): - # all id's of errors are 27 characters long - msg = line[:27] - # remove the line terminator, this seems to take 2 characters - # on PY2, but only one in PY3 - line = line.replace('\n', '') - - # keep track of the number of iterations - if line[:12] == ' Global time': - time_step += 1 - iterations[time_step,0] = float(line[14:40]) - # for PY2, new line is 2 characters, for PY3 it is one char - iterations[time_step,1] = int(line[-6:]) - # time step is the first time stamp - if not dt: - dt = float(line[15:40]) - # no need to look for messages if global time is mentioned - continue - elif line[:20] == ' Starting simulation': - init_block = False - - elif init_block: - # if string is shorter, we just get a shorter string. - # checking presence in dict is faster compared to checking - # the length of the string - # first, last, nr, msg - if msg in self.err_init: - # icol=0 -> fname - icol = subcols_init*self.err_init[msg] + 1 - # 0: number of occurances - if tempLog[icol] == '': - tempLog[icol] = '1' - else: - tempLog[icol] = str(int(tempLog[icol]) + 1) - # 1: the error message itself - tempLog[icol+1] = line - found_error = True - - # find errors that can occur during simulation - elif msg in self.err_sim: - icol = subcols_sim*self.err_sim[msg] - icol += subcols_init*self.init_cols + 1 - # in case stuff already goes wrong on the first time step - if time_step == -1: - time_step = 0 - - # 1: time step of first occurance - if tempLog[icol] == '': - tempLog[icol] = '%i' % time_step - # 2: time step of last occurance - tempLog[icol+1] = '%i' % time_step - # 3: number of occurances - if tempLog[icol+2] == '': - tempLog[icol+2] = '1' - else: - tempLog[icol+2] = str(int(tempLog[icol+2]) + 1) - # 4: the error message itself - tempLog[icol+3] = line - - found_error = True - iterations[time_step,2] = 1 - - # method of last resort, we have no idea what message - elif line[:10] == ' *** ERROR' or line[:10]==' ** WARNING': - icol = subcols_sim*self.sim_cols - icol += subcols_init*self.init_cols + 1 - # line number of the message - tempLog[icol] = j - # and message - tempLog[icol+1] = line - found_error = True - # in case stuff already goes wrong on the first time step - if time_step == -1: - time_step = 0 - iterations[time_step,2] = 1 - - # simulation and simulation output time if self.cases is not None: - t_stop = float(case['[time_stop]']) - duration = float(case['[duration]']) - else: - t_stop = -1 - duration = -1 - - # see if the last line holds the sim time - if line[:15] == ' Elapsed time :': - exit_correct = True - elapsed_time = float(line[15:-1]) - tempLog.append( elapsed_time ) - # in some cases, Elapsed time is not given, and the last message - # might be: " Closing of external type2 DLL" - elif line[:20] == ' Closing of external': - exit_correct = True - elapsed_time = iterations[time_step,0] - tempLog.append( elapsed_time ) - elif np.allclose(iterations[time_step,0], t_stop): - exit_correct = True - elapsed_time = iterations[time_step,0] - tempLog.append( elapsed_time ) - else: - elapsed_time = -1 - tempLog.append('') - - # give the last recorded time step - tempLog.append('%1.11f' % iterations[time_step,0]) - - # simulation and simulation output time - tempLog.append('%1.01f' % t_stop) - tempLog.append('%1.04f' % (t_stop/elapsed_time)) - tempLog.append('%1.01f' % duration) - - # as last element, add the total number of iterations - itertotal = np.nansum(iterations[:,1]) - tempLog.append('%i' % itertotal) - - # the delta t used for the simulation - if dt: - tempLog.append('%1.7f' % dt) + case = self.cases[fname.replace('.log', '.htc')] else: - tempLog.append('failed to find dt') - - # number of time steps - tempLog.append('%i' % len(iterations) ) - - # if the simulation didn't end correctly, the elapsed_time doesn't - # exist. Add the average and maximum nr of iterations per step - # or, if only the structural and eigen analysis is done, we have 0 - try: - ratio = float(elapsed_time)/float(itertotal) - tempLog.append('%1.6f' % ratio) - except (UnboundLocalError, ZeroDivisionError, ValueError) as e: - tempLog.append('') - # when there are no time steps (structural analysis only) - try: - tempLog.append('%1.2f' % iterations[:,1].mean() ) - tempLog.append('%1.2f' % iterations[:,1].max() ) - except ValueError: - tempLog.append('') - tempLog.append('') - - # save the iterations in the results folder - if save_iter: - fiter = fname.replace('.log', '.iter') - fmt = ['%12.06f', '%4i', '%4i'] - if self.cases is not None: - fpath = os.path.join(case['[run_dir]'], case['[iter_dir]']) - # in case it has subdirectories - for tt in [3,2,1]: - tmp = os.path.sep.join(fpath.split(os.path.sep)[:-tt]) - if not os.path.exists(tmp): - os.makedirs(tmp) - if not os.path.exists(fpath): - os.makedirs(fpath) - np.savetxt(fpath + fiter, iterations, fmt=fmt) - else: - np.savetxt(os.path.join(self.PathToLogs, fiter), iterations, - fmt=fmt) - - # append the messages found in the current file to the overview log - self.MsgListLog.append(tempLog) - self.MsgListLog2[fname] = [found_error, exit_correct] + case = None + self.readlog(f_log, case=case, save_iter=save_iter) i += 1 # # if no messages are found for the current file, than say so: @@ -3321,21 +3039,8 @@ class ErrorLogs(object): def save(self, appendlog=False, suffix=None): - # write the results in a file, start with a header - contents = 'file name;' + 'nr;msg;'*(self.init_cols) - contents += 'first_tstep;last_tstep;nr;msg;'*(self.sim_cols) - contents += 'lnr;msg;' - # and add headers for elapsed time, nr of iterations, and sec/iteration - contents += 'Elapsted time;last time step;Simulation time;' - contents += 'real sim time;Sim output time;' - contents += 'total iterations;dt;nr time steps;' - contents += 'seconds/iteration;average iterations/time step;' - contents += 'maximum iterations/time step;\n' - for k in self.MsgListLog: - for n in k: - contents = contents + str(n) + ';' - # at the end of each line, new line symbol - contents = contents + '\n' + contents = self._header() + contents = self._msglistlog2csv(contents) # write csv file to disk, append to facilitate more logfile analysis if isinstance(suffix, str): diff --git a/wetb/prepost/windIO.py b/wetb/prepost/windIO.py index 323dbe44..afe37d1f 100755 --- a/wetb/prepost/windIO.py +++ b/wetb/prepost/windIO.py @@ -41,6 +41,338 @@ from wetb.hawc2.Hawc2io import ReadHawc2 from wetb.fatigue_tools.fatigue import eq_load +class LogFile(object): + """Check a HAWC2 log file for errors. + """ + + def __init__(self, silent=False): + + self.silent = silent + # the total message list log: + self.MsgListLog = [] + # a smaller version, just indication if there are errors: + self.MsgListLog2 = dict() + + # specify which message to look for. The number track's the order. + # this makes it easier to view afterwards in spreadsheet: + # every error will have its own column + + # error messages that appear during initialisation + self.err_init = {} + self.err_init[' *** ERROR *** Error in com'] = len(self.err_init) + self.err_init[' *** ERROR *** in command '] = len(self.err_init) + # *** WARNING *** A comma "," is written within the command line + self.err_init[' *** WARNING *** A comma ",'] = len(self.err_init) + # *** ERROR *** Not correct number of parameters + self.err_init[' *** ERROR *** Not correct '] = len(self.err_init) + # *** INFO *** End of file reached + self.err_init[' *** INFO *** End of file r'] = len(self.err_init) + # *** ERROR *** No line termination in command line + self.err_init[' *** ERROR *** No line term'] = len(self.err_init) + # *** ERROR *** MATRIX IS NOT DEFINITE + self.err_init[' *** ERROR *** MATRIX IS NO'] = len(self.err_init) + # *** ERROR *** There are unused relative + self.err_init[' *** ERROR *** There are un'] = len(self.err_init) + # *** ERROR *** Error finding body based + self.err_init[' *** ERROR *** Error findin'] = len(self.err_init) + # *** ERROR *** In body actions + self.err_init[' *** ERROR *** In body acti'] = len(self.err_init) + # *** ERROR *** Command unknown and ignored + self.err_init[' *** ERROR *** Command unkn'] = len(self.err_init) + # *** ERROR *** ERROR - More bodies than elements on main_body: tower + self.err_init[' *** ERROR *** ERROR - More'] = len(self.err_init) + # *** ERROR *** The program will stop + self.err_init[' *** ERROR *** The program '] = len(self.err_init) + # *** ERROR *** Unknown begin command in topologi. + self.err_init[' *** ERROR *** Unknown begi'] = len(self.err_init) + # *** ERROR *** Not all needed topologi main body commands present + self.err_init[' *** ERROR *** Not all need'] = len(self.err_init) + # *** ERROR *** opening timoschenko data file + self.err_init[' *** ERROR *** opening tim'] = len(self.err_init) + # *** ERROR *** Error opening AE data file + self.err_init[' *** ERROR *** Error openin'] = len(self.err_init) + # *** ERROR *** Requested blade _ae set number not found in _ae file + self.err_init[' *** ERROR *** Requested bl'] = len(self.err_init) + # Error opening PC data file + self.err_init[' Error opening PC data file'] = len(self.err_init) + # *** ERROR *** error reading mann turbulence + self.err_init[' *** ERROR *** error readin'] = len(self.err_init) + # *** INFO *** The DLL subroutine + self.err_init[' *** INFO *** The DLL subro'] = len(self.err_init) + # ** WARNING: FROM ESYS ELASTICBAR: No keyword + self.err_init[' ** WARNING: FROM ESYS ELAS'] = len(self.err_init) + # *** ERROR *** DLL ./control/killtrans.dll could not be loaded - error! + self.err_init[' *** ERROR *** DLL'] = len(self.err_init) + # *** ERROR *** The DLL subroutine + self.err_init[' *** ERROR *** The DLL subr'] = len(self.err_init) + # *** ERROR *** Mann turbulence length scale must be larger than zero! + # *** ERROR *** Mann turbulence alpha eps value must be larger than zero! + # *** ERROR *** Mann turbulence gamma value must be larger than zero! + self.err_init[' *** ERROR *** Mann turbule'] = len(self.err_init) + + # *** WARNING *** Shear center x location not in elastic center, set to zero + self.err_init[' *** WARNING *** Shear cent'] = len(self.err_init) + # Turbulence file ./xyz.bin does not exist + self.err_init[' Turbulence file '] = len(self.err_init) + self.err_init[' *** WARNING ***'] = len(self.err_init) + self.err_init[' *** ERROR ***'] = len(self.err_init) + self.err_init[' WARNING'] = len(self.err_init) + self.err_init[' ERROR'] = len(self.err_init) + + # error messages that appear during simulation + self.err_sim = {} + # *** ERROR *** Wind speed requested inside + self.err_sim[' *** ERROR *** Wind speed r'] = len(self.err_sim) + # Maximum iterations exceeded at time step: + self.err_sim[' Maximum iterations exceede'] = len(self.err_sim) + # Solver seems not to converge: + self.err_sim[' Solver seems not to conver'] = len(self.err_sim) + # *** ERROR *** Out of x bounds: + self.err_sim[' *** ERROR *** Out of x bou'] = len(self.err_sim) + # *** ERROR *** Out of limits in user defined shear field - limit value used + self.err_sim[' *** ERROR *** Out of limit'] = len(self.err_sim) + + # TODO: error message from a non existing channel output/input + # add more messages if required... + + self.init_cols = len(self.err_init) + self.sim_cols = len(self.err_sim) + + def readlog(self, fname, case=None, save_iter=False): + """ + """ + # open the current log file + with open(fname, 'r') as f: + lines = f.readlines() + + # keep track of the messages allready found in this file + tempLog = [] + tempLog.append(fname) + exit_correct, found_error = False, False + + subcols_sim = 4 + subcols_init = 2 + # create empty list item for the different messages and line + # number. Include one column for non identified messages + for j in range(self.init_cols): + # 2 sub-columns per message: nr, msg + for k in range(subcols_init): + tempLog.append('') + for j in range(self.sim_cols): + # 4 sub-columns per message: first, last, nr, msg + for k in range(subcols_sim): + tempLog.append('') + # and two more columns at the end for messages of unknown origin + tempLog.append('') + tempLog.append('') + + # if there is a cases object, see how many time steps we expect + if case is not None: + dt = float(case['[dt_sim]']) + time_steps = int(float(case['[time_stop]']) / dt) + iterations = np.ndarray( (time_steps+1,3), dtype=np.float32 ) + else: + iterations = np.ndarray( (len(lines),3), dtype=np.float32 ) + dt = False + iterations[:,0:2] = -1 + iterations[:,2] = 0 + + # keep track of the time_step number + time_step, init_block = -1, True + # check for messages in the current line + # for speed: delete from message watch list if message is found + for j, line in enumerate(lines): + # all id's of errors are 27 characters long + msg = line[:27] + # remove the line terminator, this seems to take 2 characters + # on PY2, but only one in PY3 + line = line.replace('\n', '') + + # keep track of the number of iterations + if line[:12] == ' Global time': + time_step += 1 + iterations[time_step,0] = float(line[14:40]) + # for PY2, new line is 2 characters, for PY3 it is one char + iterations[time_step,1] = int(line[-6:]) + # time step is the first time stamp + if not dt: + dt = float(line[15:40]) + # no need to look for messages if global time is mentioned + continue + + elif line[:20] == ' Starting simulation': + init_block = False + + elif init_block: + # if string is shorter, we just get a shorter string. + # checking presence in dict is faster compared to checking + # the length of the string + # first, last, nr, msg + if msg in self.err_init: + # icol=0 -> fname + icol = subcols_init*self.err_init[msg] + 1 + # 0: number of occurances + if tempLog[icol] == '': + tempLog[icol] = '1' + else: + tempLog[icol] = str(int(tempLog[icol]) + 1) + # 1: the error message itself + tempLog[icol+1] = line + found_error = True + + # find errors that can occur during simulation + elif msg in self.err_sim: + icol = subcols_sim*self.err_sim[msg] + icol += subcols_init*self.init_cols + 1 + # in case stuff already goes wrong on the first time step + if time_step == -1: + time_step = 0 + + # 1: time step of first occurance + if tempLog[icol] == '': + tempLog[icol] = '%i' % time_step + # 2: time step of last occurance + tempLog[icol+1] = '%i' % time_step + # 3: number of occurances + if tempLog[icol+2] == '': + tempLog[icol+2] = '1' + else: + tempLog[icol+2] = str(int(tempLog[icol+2]) + 1) + # 4: the error message itself + tempLog[icol+3] = line + + found_error = True + iterations[time_step,2] = 1 + + # method of last resort, we have no idea what message + elif line[:10] == ' *** ERROR' or line[:10]==' ** WARNING': + icol = subcols_sim*self.sim_cols + icol += subcols_init*self.init_cols + 1 + # line number of the message + tempLog[icol] = j + # and message + tempLog[icol+1] = line + found_error = True + # in case stuff already goes wrong on the first time step + if time_step == -1: + time_step = 0 + iterations[time_step,2] = 1 + + # simulation and simulation output time + if case is not None: + t_stop = float(case['[time_stop]']) + duration = float(case['[duration]']) + else: + t_stop = -1 + duration = -1 + + # see if the last line holds the sim time + if line[:15] == ' Elapsed time :': + exit_correct = True + elapsed_time = float(line[15:-1]) + tempLog.append( elapsed_time ) + # in some cases, Elapsed time is not given, and the last message + # might be: " Closing of external type2 DLL" + elif line[:20] == ' Closing of external': + exit_correct = True + elapsed_time = iterations[time_step,0] + tempLog.append( elapsed_time ) + elif np.allclose(iterations[time_step,0], t_stop): + exit_correct = True + elapsed_time = iterations[time_step,0] + tempLog.append( elapsed_time ) + else: + elapsed_time = -1 + tempLog.append('') + + # give the last recorded time step + tempLog.append('%1.11f' % iterations[time_step,0]) + + # simulation and simulation output time + tempLog.append('%1.01f' % t_stop) + tempLog.append('%1.04f' % (t_stop/elapsed_time)) + tempLog.append('%1.01f' % duration) + + # as last element, add the total number of iterations + itertotal = np.nansum(iterations[:,1]) + tempLog.append('%i' % itertotal) + + # the delta t used for the simulation + if dt: + tempLog.append('%1.7f' % dt) + else: + tempLog.append('failed to find dt') + + # number of time steps + tempLog.append('%i' % len(iterations) ) + + # if the simulation didn't end correctly, the elapsed_time doesn't + # exist. Add the average and maximum nr of iterations per step + # or, if only the structural and eigen analysis is done, we have 0 + try: + ratio = float(elapsed_time)/float(itertotal) + tempLog.append('%1.6f' % ratio) + except (UnboundLocalError, ZeroDivisionError, ValueError) as e: + tempLog.append('') + # when there are no time steps (structural analysis only) + try: + tempLog.append('%1.2f' % iterations[:,1].mean()) + tempLog.append('%1.2f' % iterations[:,1].max()) + except ValueError: + tempLog.append('') + tempLog.append('') + + # save the iterations in the results folder + if save_iter: + fiter = fname.replace('.log', '.iter') + fmt = ['%12.06f', '%4i', '%4i'] + if case is not None: + fpath = os.path.join(case['[run_dir]'], case['[iter_dir]']) + # in case it has subdirectories + for tt in [3,2,1]: + tmp = os.path.sep.join(fpath.split(os.path.sep)[:-tt]) + if not os.path.exists(tmp): + os.makedirs(tmp) + if not os.path.exists(fpath): + os.makedirs(fpath) + np.savetxt(fpath + fiter, iterations, fmt=fmt) + else: + logpath = os.path.dirname(fname) + np.savetxt(os.path.join(logpath, fiter), iterations, fmt=fmt) + + # append the messages found in the current file to the overview log + self.MsgListLog.append(tempLog) + self.MsgListLog2[fname] = [found_error, exit_correct] + + def _msglistlog2csv(self, contents): + """Write LogFile.MsgListLog to a csv file. Use LogFile._header to + create a header. + """ + for k in self.MsgListLog: + for n in k: + contents = contents + str(n) + ';' + # at the end of each line, new line symbol + contents = contents + '\n' + return contents + + def _header(self): + """Header for log analysis csv file + """ + + # write the results in a file, start with a header + contents = 'file name;' + 'nr;msg;'*(self.init_cols) + contents += 'first_tstep;last_tstep;nr;msg;'*(self.sim_cols) + contents += 'lnr;msg;' + # and add headers for elapsed time, nr of iterations, and sec/iteration + contents += 'Elapsted time;last time step;Simulation time;' + contents += 'real sim time;Sim output time;' + contents += 'total iterations;dt;nr time steps;' + contents += 'seconds/iteration;average iterations/time step;' + contents += 'maximum iterations/time step;\n' + + return contents + + class LoadResults(ReadHawc2): """Read a HAWC2 result data file -- GitLab