def convertFromFmi(fmuFilename, fmi=None): ''' Returns data to initialize an MTSF result file from an FMU. The call to initialize an MTSF result file is pyMtsf.MTSF(resultFileName, modelDescription, modelVariables, experimentSetup, simpleTypes, units, enumerationsMatrix) The missing data is resultFileName and experimentSetup to be specified before initializing the MTSF object. Inputs Type: fmuFilename String fmi FMIDescription [optional] if fmi is given, then fmuFilename is ignored. Otherwise the FMI description is loaded from the given file. Outputs modelDescription pyMtsf.ModelDescription modelVariables pyMtsf.ModelVariables simpleTypes list of pyMtsf.SimpleType units list of pyMtsf.Unit enumerationsMatrix list of pyMtsf.Enumeration ''' def _None2Str(x): if x is None: return '' else: return x # Load FMIDescription if necessary if fmi is None: fmuFile = zipfile.ZipFile(os.getcwd() + u'\\' + fmuFilename + u'.fmu', 'r') fmi = FMIDescription(fmuFile.open('modelDescription.xml')) # Prepare some variables allSeriesNames = [x.name for x in StandardSeriesForFmi] variable = collections.OrderedDict() simpleTypes = [] units = [] enumerationsMatrix = [] variable['Time'] = pyMtsf.ScalarModelVariable('Continuous Time', 'input', 0, 'continuous', allSeriesNames.index('Continuous'), pyMtsf.StandardCategoryNames.index(pyMtsf.CategoryMapping['Real']), None, 0) variable['TimeDiscrete'] = pyMtsf.ScalarModelVariable('Discrete Time at events', 'input', 0, 'discrete', allSeriesNames.index('Discrete'), pyMtsf.StandardCategoryNames.index(pyMtsf.CategoryMapping['Real']), None, 0) # Alias for var in fmi.scalarVariables.values(): if var.alias is None or var.alias.lower() == "noalias": var.alias = 'NOAlias' # To guarantee that this variable is the first # one in sorted order referenceList = [(x, y.valueReference, y.alias) for x, y in fmi.scalarVariables.iteritems()] referenceList.sort(key=itemgetter(2)) referenceList.sort(key=itemgetter(1)) for index in xrange(len(referenceList)): variableName = referenceList[index][0] if referenceList[index][2] in ['alias', 'negatedAlias']: valueReference = referenceList[index][1] prevValueReference = referenceList[index - 1][1] if prevValueReference != valueReference: raise ValueError("No original variable found for alias " + variableName) if referenceList[index - 1][2] == "NOAlias": originName = referenceList[index - 1][0] else: originName = fmi.scalarVariables[referenceList[index - 1][0]].aliasName fmi.scalarVariables[variableName].aliasName = originName else: fmi.scalarVariables[variableName].aliasName = None # Types and display units uniqueSimpleType = [] for fmiVariableName, fmiVariable in fmi.scalarVariables.iteritems(): type = fmiVariable.type unitList = [_None2Str(type.unit) + _None2Str(type.displayUnit)] if fmi.units.has_key(type.unit): for displayUnitName, displayUnit in fmi.units[type.unit].iteritems(): if displayUnitName != type.unit: unitList.append(displayUnitName + '{:.16e}'.format(displayUnit.gain) + '{:.16e}'.format(displayUnit.offset)) # unitList.sort() dataType = type.type enumerations = '' if dataType == 'Enumeration': enumerations = ''.join([_None2Str(x[0]) + _None2Str(x[1]) for x in type.item]) uniqueSimpleType.append((fmiVariableName, type, _None2Str(type.name) + str(pyMtsf.DataType[dataType]) + _None2Str(type.quantity) + str(type.relativeQuantity), ''.join(unitList), enumerations)) # Simple Types uniqueSimpleType.sort(key=itemgetter(3)) uniqueSimpleType.sort(key=itemgetter(2)) lastUniqueStr = '' rowIndex = dict() lastIndex = -1 uniqueDisplayUnit = [] uniqueEnumerations = [] for s in uniqueSimpleType: fmiVariableName = s[0] type = s[1] uniqueStr = s[2] + s[3] + s[4] if uniqueStr == lastUniqueStr: rowIndex[fmiVariableName] = lastIndex else: lastUniqueStr = uniqueStr lastIndex += 1 rowIndex[fmiVariableName] = lastIndex uniqueDisplayUnit.append((type, lastIndex, s[3])) uniqueEnumerations.append((type, lastIndex, s[4])) dataType = type.type simpleTypes.append(pyMtsf.SimpleType(type.name, pyMtsf.DataType[dataType], type.quantity, type.relativeQuantity, -1, type.description)) # Units uniqueDisplayUnit.sort(key=itemgetter(2)) lastUniqueStr = '' startRow = -1 for s in uniqueDisplayUnit: type = s[0] k = s[1] uniqueStr = s[2] if uniqueStr == lastUniqueStr: simpleTypes[k].unitOrEnumerationRow = startRow else: lastUniqueStr = uniqueStr if uniqueStr != '': # There is a unit definition startRow = len(units) units.append(pyMtsf.Unit(type.unit, 1.0, 0.0, 0)) if fmi.units.has_key(type.unit): for displayUnitName, displayUnit in fmi.units[type.unit].iteritems(): if displayUnitName != type.unit: if type.displayUnit is not None and type.displayUnit != '' and type.displayUnit == displayUnitName: mode = 2 # DefaultDisplayUnit else: mode = 1 # DisplayUnit units.append(pyMtsf.Unit(displayUnitName, displayUnit.gain, displayUnit.offset, mode)) simpleTypes[k].unitOrEnumerationRow = startRow else: startRow = -1 # Enumerations uniqueEnumerations.sort(key=itemgetter(2)) lastUniqueStr = '' startRow = -1 for s in uniqueEnumerations: type = s[0] k = s[1] uniqueStr = s[2] if uniqueStr != '': if uniqueStr == lastUniqueStr: simpleTypes[k].unitOrEnumerationRow = startRow else: lastUniqueStr = uniqueStr startRow = len(enumerationsMatrix) j = 0 for enum in type.item: j += 1 if j == 1: firstEntry = 1 else: firstEntry = 0 enumerationsMatrix.append(pyMtsf.Enumeration(enum[0], j, enum[1], firstEntry)) simpleTypes[k].unitOrEnumerationRow = startRow # Iterate over all fmi-variables for fmiVariableName, fmiVariable in fmi.scalarVariables.iteritems(): variableType = fmiVariable.type.type if variableType != "String": # Do not support strings variability = fmiVariable.variability aliasNegated = 0 aliasName = fmiVariable.aliasName if aliasName is not None: if fmiVariable.alias == 'negatedAlias': aliasNegated = 1 # Due to possibly insufficient information in xml-file variability = fmi.scalarVariables[aliasName].variability categoryIndex = pyMtsf.StandardCategoryNames.index(pyMtsf.CategoryMapping[variableType]) if variability in ['constant', 'parameter']: seriesIndex = allSeriesNames.index('Fixed') elif variability == 'discrete': seriesIndex = allSeriesNames.index('Discrete') else: seriesIndex = allSeriesNames.index('Continuous') causality = fmiVariable.causality # Due to FMI 1.0; in vers. 2.0 this should not be necessary if causality is None: causality = 'local' if variability == 'parameter': causality = 'parameter' variability = 'fixed' if causality in ['internal', 'none']: causality = 'local' simpleTypeRow = rowIndex[fmiVariableName] variable[fmiVariableName] = pyMtsf.ScalarModelVariable(fmiVariable.description, causality, simpleTypeRow, variability, seriesIndex, categoryIndex, aliasName, aliasNegated) # Some basics for independent time variables startRow = len(units) units.append(pyMtsf.Unit('s', 1.0, 0.0, 0)) units.append(pyMtsf.Unit('ms', 0.001, 0.0, 1)) units.append(pyMtsf.Unit('min', 60.0, 0.0, 1)) units.append(pyMtsf.Unit('h', 3600.0, 0.0, 1)) units.append(pyMtsf.Unit('d', 86400.0, 0.0, 1)) simpleTypes.append(pyMtsf.SimpleType('Time', pyMtsf.DataType["Real"], 'Time', False, startRow, '')) variable['Time'].simpleTypeRow = len(simpleTypes) - 1 variable['TimeDiscrete'].simpleTypeRow = len(simpleTypes) - 1 modelDescription = pyMtsf.ModelDescription(fmi.modelName, fmi.description, fmi.author, fmi.version, fmi.generationTool, fmi.generationDateAndTime, fmi.variableNamingConvention) modelVariables = pyMtsf.ModelVariables(variable, StandardSeriesForFmi, pyMtsf.StandardCategoryNames) return modelDescription, modelVariables, simpleTypes, units, enumerationsMatrix
def convertFromDymolaMatFile(matFilename, mtsfFilename=None): ''' Converts a Dymola result file (in mat-format) into the MTSF format. Returns the filename of the new result file ''' # Define file name of result file if mtsfFilename is None: if len(matFilename) >= 4: if matFilename[-4:] == '.mat': resultFileName = matFilename[:-4] + '.mtsf' else: resultFileName = matFilename + '.mtsf' else: resultFileName = matFilename + '.mtsf' else: if '.mtsf' in mtsfFilename: if mtsfFilename[-5:] == '.mtsf': resultFileName = mtsfFilename else: resultFileName = mtsfFilename + '.mtsf' else: resultFileName = mtsfFilename + '.mtsf' from ..DymolaMat import DymolaMat # Load mat-file res = DymolaMat.Results(matFilename) # Define basic structure of result file variable = collections.OrderedDict() # Search for aliases sortedVariables = [(i, res._dataInfo[i, 0], abs(res._dataInfo[i, 1])) for i in xrange(len(res._name))] sortedVariables.sort(key=itemgetter(2)) sortedVariables.sort(key=itemgetter(1)) aliasName = [None for i in xrange(len(res._name))] for i, var in enumerate(sortedVariables): index = var[0] alias = None j = i while j > 0: if sortedVariables[j - 1][1] != var[1] or sortedVariables[ j - 1][2] != var[2]: break else: j -= 1 if j < i: alias = res._name[sortedVariables[j][0]] aliasName[index] = alias dataIndexFixed = [] dataIndexContinuous = [] categoryIndex = pyMtsf.StandardCategoryNames.index( pyMtsf.CategoryMapping['Real']) for index, variableName in enumerate(res._name): aliasNegated = False if res._dataInfo[index, 0] == 1: variability = 'fixed' seriesIndex = 0 # Fixed else: variability = 'continuous' seriesIndex = 1 # Continuous if res._dataInfo[index, 1] < 0: aliasNegated = True if aliasName[index] is None: if variability == 'fixed': dataIndexFixed.append(abs(res._dataInfo[index, 1]) - 1) else: dataIndexContinuous.append(abs(res._dataInfo[index, 1]) - 1) variable[variableName] = pyMtsf.ScalarModelVariable( res._description[index], 'option', 0, # may be set later variability, seriesIndex, categoryIndex, aliasName[index], aliasNegated) modelVariables = pyMtsf.ModelVariables(variable, MtsfFmi.StandardSeriesForFmi, pyMtsf.StandardCategoryNames) timeData = res.data("Time") modelVariables.allSeries[1].initialRows = len(timeData) # Continuous simpleTypes = [] units = [] enumerations = [] simpleTypes.append( pyMtsf.SimpleType('Real without unit', pyMtsf.DataType["Real"], '', False, -1, '')) # No unit unitList = [(index, unit) for index, unit in enumerate(res._unit)] unitList.sort(key=itemgetter(1)) preUnit = '' for x in unitList: index = x[0] unit = x[1] if unit != '': if preUnit != unit: units.append(pyMtsf.Unit(unit, 1.0, 0.0, 0)) simpleTypes.append( pyMtsf.SimpleType('Real, Unit = ' + unit, pyMtsf.DataType["Real"], '', False, len(units) - 1, '')) preUnit = unit modelVariables.variable[ res._name[index]].simpleTypeRow = len(simpleTypes) - 1 else: modelVariables.variable[ res._name[index]].simpleTypeRow = len(simpleTypes) - 1 experimentSetup = pyMtsf.ExperimentSetup( startTime=timeData[0], stopTime=timeData[-1], algorithm="", relativeTolerance='', author="", description="", generationDateAndTime=time.strftime("%a, %d %b %Y %H:%M:%S", time.gmtime()), generationTool="Python", machine=os.getenv('COMPUTERNAME'), cpuTime="") modelDescription = pyMtsf.ModelDescription(resultFileName[:-5], '', '', '', '', '', 'structured') # Create result object mtsf = pyMtsf.MTSF(resultFileName, modelDescription, modelVariables, experimentSetup, simpleTypes, units, enumerations) # Write numeric data fixedValues = numpy.ndarray((len(dataIndexFixed, ))) for i, index in enumerate(dataIndexFixed): fixedValues[i] = res._data[0][0, index] continuousValues = numpy.ndarray((len(timeData), len(dataIndexContinuous))) for i, index in enumerate(dataIndexContinuous): continuousValues[:, i] = res._data[1][:, index] mtsf.results.series['Fixed'].category[ pyMtsf.CategoryMapping['Real']].writeData(fixedValues) mtsf.results.series['Continuous'].category[ pyMtsf.CategoryMapping['Real']].writeData(continuousValues) # Close file mtsf.close() return resultFileName
def convertFromFmi(fmuFilename, fmi=None): ''' Returns data to initialize an MTSF result file from an FMU. The call to initialize an MTSF result file is pyMtsf.MTSF(resultFileName, modelDescription, modelVariables, experimentSetup, simpleTypes, units, enumerationsMatrix) The missing data is resultFileName and experimentSetup to be specified before initializing the MTSF object. Inputs Type: fmuFilename String fmi FMIDescription [optional] if fmi is given, then fmuFilename is ignored. Otherwise the FMI description is loaded from the given file. Outputs modelDescription pyMtsf.ModelDescription modelVariables pyMtsf.ModelVariables simpleTypes list of pyMtsf.SimpleType units list of pyMtsf.Unit enumerationsMatrix list of pyMtsf.Enumeration ''' def _None2Str(x): if x is None: return '' else: return x # Load FMIDescription if necessary if fmi is None: fmuFile = zipfile.ZipFile( os.path.join(os.getcwd(), fmuFilename + u'.fmu'), 'r') fmi = FMIDescription(fmuFile.open('modelDescription.xml')) # Prepare some variables allSeriesNames = [x.name for x in StandardSeriesForFmi] variable = collections.OrderedDict() simpleTypes = [] units = [] enumerationsMatrix = [] variable['Time'] = pyMtsf.ScalarModelVariable( 'Continuous Time', 'input', 0, 'continuous', allSeriesNames.index('Continuous'), pyMtsf.StandardCategoryNames.index(pyMtsf.CategoryMapping['Real']), None, 0) variable['TimeDiscrete'] = pyMtsf.ScalarModelVariable( 'Discrete Time at events', 'input', 0, 'discrete', allSeriesNames.index('Discrete'), pyMtsf.StandardCategoryNames.index(pyMtsf.CategoryMapping['Real']), None, 0) # Searching aliases referenceList = [(x, fmi.scalarVariables[x].valueReference) for x in fmi.scalarVariables.keys()] referenceList.sort(key=itemgetter(1)) alias = dict() if len(referenceList) > 1: origin = None alias[referenceList[0][0]] = None for index in xrange(len(referenceList) - 1): variableName = referenceList[index][0] valueReference = referenceList[index][1] nextVariableName = referenceList[index + 1][0] nextValueReference = referenceList[index + 1][1] if valueReference == nextValueReference: if origin is None: origin = variableName alias[nextVariableName] = origin else: origin = None alias[nextVariableName] = None ''' # Types and display units uniqueSimpleType = [] for fmiVariableName, fmiVariable in fmi.scalarVariables.iteritems(): type = fmiVariable.type unitList = [_None2Str(type.unit) + _None2Str(type.displayUnit)] if fmi.units.has_key(type.unit): for displayUnitName, displayUnit in fmi.units[type.unit].iteritems(): if displayUnitName != type.unit: unitList.append(displayUnitName + '{:.16e}'.format(displayUnit.factor) + '{:.16e}'.format(displayUnit.offset)) # unitList.sort() dataType = type.basicType enumerations = '' if dataType == 'Enumeration': enumerations = ''.join([_None2Str(x[0]) + _None2Str(x[1]) for x in type.item]) uniqueSimpleType.append((fmiVariableName, type, _None2Str(type.name) + str(pyMtsf.DataType[dataType]) + _None2Str(type.quantity) + str(type.relativeQuantity), ''.join(unitList), enumerations)) # Simple Types uniqueSimpleType.sort(key=itemgetter(3)) uniqueSimpleType.sort(key=itemgetter(2)) lastUniqueStr = '' rowIndex = dict() lastIndex = -1 uniqueDisplayUnit = [] uniqueEnumerations = [] for s in uniqueSimpleType: fmiVariableName = s[0] type = s[1] uniqueStr = s[2] + s[3] + s[4] if uniqueStr == lastUniqueStr: rowIndex[fmiVariableName] = lastIndex else: lastUniqueStr = uniqueStr lastIndex += 1 rowIndex[fmiVariableName] = lastIndex uniqueDisplayUnit.append((type, lastIndex, s[3])) uniqueEnumerations.append((type, lastIndex, s[4])) dataType = type.type simpleTypes.append(pyMtsf.SimpleType(type.name, pyMtsf.DataType[dataType], type.quantity, type.relativeQuantity, -1, type.description)) # Units uniqueDisplayUnit.sort(key=itemgetter(2)) lastUniqueStr = '' startRow = -1 for s in uniqueDisplayUnit: type = s[0] k = s[1] uniqueStr = s[2] if uniqueStr == lastUniqueStr: simpleTypes[k].unitOrEnumerationRow = startRow else: lastUniqueStr = uniqueStr if uniqueStr != '': # There is a unit definition startRow = len(units) units.append(pyMtsf.Unit(type.unit, 1.0, 0.0, 0)) if fmi.units.has_key(type.unit): for displayUnitName, displayUnit in fmi.units[type.unit].iteritems(): if displayUnitName != type.unit: if type.displayUnit is not None and type.displayUnit != '' and type.displayUnit == displayUnitName: mode = 2 # DefaultDisplayUnit else: mode = 1 # DisplayUnit units.append(pyMtsf.Unit(displayUnitName, displayUnit.gain, displayUnit.offset, mode)) simpleTypes[k].unitOrEnumerationRow = startRow else: startRow = -1 # Enumerations uniqueEnumerations.sort(key=itemgetter(2)) lastUniqueStr = '' startRow = -1 for s in uniqueEnumerations: type = s[0] k = s[1] uniqueStr = s[2] if uniqueStr != '': if uniqueStr == lastUniqueStr: simpleTypes[k].unitOrEnumerationRow = startRow else: lastUniqueStr = uniqueStr startRow = len(enumerationsMatrix) j = 0 for enum in type.item: j += 1 if j == 1: firstEntry = 1 else: firstEntry = 0 enumerationsMatrix.append(pyMtsf.Enumeration(enum[0], j, enum[1], firstEntry)) simpleTypes[k].unitOrEnumerationRow = startRow ''' simpleTypes.append( pyMtsf.SimpleType('Real', pyMtsf.DataType['Real'], 'Real', False, -1, '')) simpleTypes.append( pyMtsf.SimpleType('Integer', pyMtsf.DataType['Integer'], 'Integer', False, -1, '')) simpleTypes.append( pyMtsf.SimpleType('Boolean', pyMtsf.DataType['Boolean'], 'Boolean', False, -1, '')) # Iterate over all fmi-variables for fmiVariableName, fmiVariable in fmi.scalarVariables.iteritems(): variableType = fmiVariable.type.basicType if variableType != "String": # Do not support strings aliasNegated = 0 # Not supported in FMI 2.0 aliasName = alias[fmiVariableName] categoryIndex = pyMtsf.StandardCategoryNames.index( pyMtsf.CategoryMapping[variableType]) variability = fmiVariable.variability if variability == 'tunable': variability = 'fixed' if variability in ['constant', 'fixed']: seriesIndex = allSeriesNames.index('Fixed') elif variability in ['discrete']: seriesIndex = allSeriesNames.index('Discrete') else: seriesIndex = allSeriesNames.index('Continuous') causality = fmiVariable.causality if causality == 'calculatedParameter': causality = 'parameter' if causality == 'independent': causality = 'option' if variableType == 'Real': simpleTypeRow = 0 elif variableType == 'Integer': simpleTypeRow = 1 elif variableType == 'Boolean': simpleTypeRow = 2 elif variableType == 'Enumeration': simpleTypeRow = 1 # Integer variable[fmiVariableName] = pyMtsf.ScalarModelVariable( fmiVariable.description, causality, simpleTypeRow, variability, seriesIndex, categoryIndex, aliasName, aliasNegated) # Some basics for independent time variables startRow = len(units) units.append(pyMtsf.Unit('s', 1.0, 0.0, 0)) units.append(pyMtsf.Unit('ms', 0.001, 0.0, 1)) units.append(pyMtsf.Unit('min', 60.0, 0.0, 1)) units.append(pyMtsf.Unit('h', 3600.0, 0.0, 1)) units.append(pyMtsf.Unit('d', 86400.0, 0.0, 1)) simpleTypes.append( pyMtsf.SimpleType('Time', pyMtsf.DataType["Real"], 'Time', False, startRow, '')) variable['Time'].simpleTypeRow = len(simpleTypes) - 1 variable['TimeDiscrete'].simpleTypeRow = len(simpleTypes) - 1 modelDescription = pyMtsf.ModelDescription( _None2Str(fmi.modelName), _None2Str(fmi.description), _None2Str(fmi.author), _None2Str(fmi.version), _None2Str(fmi.generationTool), _None2Str(fmi.generationDateAndTime), fmi.variableNamingConvention) modelVariables = pyMtsf.ModelVariables(variable, StandardSeriesForFmi, pyMtsf.StandardCategoryNames) return modelDescription, modelVariables, simpleTypes, units, enumerationsMatrix