Search code examples
pythonmodelicafmiunit-conversionpyfmi

How to handle unit conversions while interacting with FMUs?


I have a python script that filters and lists the parameters, their units and default values from a fmu using the read_model_description function from FMPy library and writes in an excel sheet (related discussion). Then using the simulate_fmu function the script simulates the fmu and writes the results with units back in the excel sheet.

In filtering the parameters and output variable, I use this line to get their units.
unit = variable.declaredType.unit if hasattr(variable.declaredType,'unit') else '-'

While interacting with the fmu, the parameter and variable values are in default SI units. I guess this is according to the FMI standard. However, in the modelDescription.xml under <UnitDefinitions> I see that there is information regarding the default SI unit to displayUnit conversion. For example:

<Unit
      name="Pa">
      <BaseUnit kg="1"
        m="-1"
        s="-2"/>
      <DisplayUnit
        name="bar"
        factor="1E-05"/>
      <DisplayUnit
        name="ftH2O"
        factor="0.0003345525633129686"/>
</Unit> 

Is there a way to be able to get the parameter values and output variables in displayUnits if the conversion factors are already available in the modelDescription.xml?

Or is there a easier solution using python libraries like pint that can act as a wrapper around fmu to convert the units in desired unit system (i.e. SI to IP) while interacting with it?


Solution

  • In the FMPy source I did not find any place where unit conversion is implemented.

    But all the relevant information is read in model_description.py.

    The display unit information ends up in modelDescription.unitDefinitions. E.g. to convert a value val = 1.013e5 # Pa to all defined display units, the following might work:

    for unit in modelDescription.unitDefinitions:
      if unit.name == "Pa":
        for display_unit in unit.displayUnits:
          print(display_unit.name)
          # not sure about the brackets here
          print( (val - display_unit.offset)/display_unit.factor ) 
        break
    

    Take a look at the FMI Specification 2.01, chapter 2.2.2 Definition of Units (UnitDefinitions) to get the full picture.