python Library
ModelicaMatFilter
This script reads the 'result.mat' file of an OpenModelica simulation and returns dictionaries with the requested data only: parSelect,varSelect. The signal (solution) is selected by the keys of varSelect; if there is a value set to some key, that is taken as short name for the signal.
varSelect["firstModel.signalA"] = "a"
If you executed your 'model.exe' multiple times, with varrying parameters, this script operates on all '*.mat' files within the result path.
import numpy as np import scipy.io from operator import itemgetter class ModelicaMatFilter: """ Dr. Arne Jachens 2020-11-04 """ def __init__(self, matFile, debug=False): """ Generally, 'debug' is utilized to gain more insight in the processes. The result.mat of an OpenModelica simulation is optimized to store data only once: If there is the equation a=b, then there is only one data set, addressed by an index, and both a and b point to this index. Here we take the matFile to gain this association of variable names to idices. If there is a series of such result files, this matFile is one arbitrary out of this series to extract the association. """ self.debug = debug dataRaw = scipy.io.loadmat(matFile) self._parseDataStruct(dataRaw) def _parseDataStruct(self, dataRaw): """ Internal function to identify variables and parameters. Should only be used indirectly via the constructor. The 'name' block of the mat-file holds the data names, each name is in a column, the rows hold the characters of the names. The 'dataInfo' block indicates the type of the data: 0:time 1: parameter 2: variable """ name = dataRaw['name'] info = np.array(dataRaw['dataInfo']) #transpose and concatenate the data names dataNames = [""]*len(name[0]) for line in name: for j in range(len(line)): dataNames[j] = dataNames[j]+line[j] dataType = info[0,:] dataIndex = info[1,:] parNames = [] varNames = [] parIndex = {} varIndex = {} for i,thisName in enumerate(dataNames): thisName = thisName.replace('\x00','') if dataType[i]==0: varNames.append("time") varIndex[thisName] = 0 else dataType[i]==1: parNames.append(thisName) parIndex[thisName] = dataIndex[i]-1 else dataType[i]==2: varNames.append(thisName) if dataIndex[i]>0: varIndex[thisName] = dataIndex[i]-1 else: varIndex[thisName] = dataIndex[i]+1 #sort varIndex to have same variables together self.VI = dict(sorted(varIndex.items(), key=itemgetter(1))) self.PI = dict(sorted(parIndex.items(), key=itemgetter(1))) if self.debug: print("There are ",len(name[0]),"variables in the result.") print("Check variablesIndex.txt and parametersIndex.txt for available values.") with open("variablesIndex.txt", 'w', encoding='utf-8') as f: for v in self.VI: f.write(str(self.VI[v])+"\t\t"+v+"\n") with open("parametersIndex.txt", 'w', encoding='utf-8') as f: for p in self.PI: f.write(str(self.PI[p])+"\t\t"+p+"\n") return def selector(self,matFile,parSelect,varSelect): """ From all the data, extract the selected essence only. Accosiation works from variable name to index of data structure, if specified, the short name is used in the result. """ (parValues,varValues) = self._loadData(matFile) msg = "" self.parameters={} for p in parSelect: #take short name, if set if len(parSelect[p])>0: pName = parSelect[p] else: pName = p #for parameters, the initial and final values are identical try: self.parameters[pName] = parValues[self.PI[p]][0] except: msg = msg+"MDF: "+p+" not found in 'result.mat'\n" self.variables={} for v in varSelect: #take short name, if set if len(varSelect[v])>0: vName = varSelect[v] else: vName = v #If you connect flow variables, you have in+out=0 #therefore, two equal values with opposite sign. #In these cases, a negative index indicates to take #the negative value at the abs(index) try: if self.VI[v]>=0: myIndex = self.VI[v] self.variables[vName] = varValues[myIndex] else: myIndex = -self.VI[v] self.variables[vName] = -varValues[myIndex] except: msg = msg+"MMF:"+v+"not found in 'result.mat'\n" if self.debug: print(msg) def getParameters(self): return self.parameters def getVariables(self): return self.variables def _loadData(self, matFile, delimiter="\t"): """ Load all available data, internal use only. """ dataRaw = scipy.io.loadmat(matFile) parValues = np.array(dataRaw['data_1']) varValues = np.array(dataRaw['data_2']) return (parValues,varValues) #=========================================# def resultFiles(path, debug=False): """ If you did a simulation campaign, progably you have one path holding multiple .mat files? This function utilizes 'glob' to return a list of these files. """ import glob #look for alls files with a specific extension dosFiles = glob.glob(path+"*.mat") files = [] for f in dosFiles: files.append(f.replace("\\", "/")) if debug: print("In path",path) print("There are result files:") print(files) return files if __name__ == "__main__": """ For testing, execute python ModelicaMatFilter.py and enter path to some result.mat file(s). """ path = input("Enter data path: ") if(len(path)<1): path = "./" #1. check for available result.mat files resultFiles = resultFiles(path,True) #2. take any file to associate variable names MAT = ModelicaMatFilter(resultFiles[0],True) #3. specify parameters and variables, you are interested in, # the 'key' is the simulation variable, the optional 'value' a short name parSelect = {} parSelect["eta"] = "" varSelect = {} varSelect["time"] = "" varSelect["firstModel.signalA"] = "a" varSelect["secondModel.signalB"] = "b" varSelect["TAmbient"] = "" #loop over available result files for i,rf in enumerate(resultFiles): #4. associate data of interest with selected names MAT.selector(rf,parSelect,varSelect) #variant1 parameters = MAT.getParameters() print(parameters) #variant2 print(MAT.parameters) variables = MAT.getVariables() print(variables) hitTime=False for i,t in enumerate(variables['time']): if t>=200 and not hitTime: hitTime=True variablesKeys = list(variables.keys()) for k in variablesKeys: print(k,"\t\t",variables[k][i])
Index of Library
Der gesamte Sourcecode darf gemäß GNU General Public License weiterverbreitet werden.