Skip to content
/ fmu.nim Public

create your own multiplatform FMU (Functional Mock-up Interface) models with Nim

License

Notifications You must be signed in to change notification settings

SciNim/fmu.nim

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

fmu.nim

Purpose

The purpose of this library is enabling the creation of FMU files that can be later used in many compatible simulation packages such as OpenModelica, Matlab, Dymola, ...

This library is heavily based on fmusdk.

Installing

You need Nim v2.0. You can use choosenim in order to install Nim.

To intall the fmu.nim library, as usual, with nimble:

nimble install https://github.com/SciNim/fmu.nim

Status

Right now, you can create both Model Exchange and Co-Simulation models using FMI2.0.

The five examples from fmusdk are working.

Besides, it can create easily multiplatform FMU's (they can work both in windows and linux).

How it works?

It creates:

  1. the libraries: .so and/or .dll
  2. the folder structure as per the specification
  3. the XML with the model details

Then it packs everything in a zip file and changes the extension into .fmu.

How to use it?

Go to the examples folder.

The following command will generate inc.so (in Linux) and embed it into inc.fmu as a Model Exchange:

$ nim c -r -d:fmu2me inc

In order to create a co-simulation replace -d:fmu2me with -d:fmu2cs. The source code using one or the other looks like:

when defined(fmu2me):
  values.exportFmu("values.fmu")

when defined(fmu2cs):
  values.exportFmu("values.fmu", fmi2CoSimulation)

In order to test the models, one can use FMUComplianceChecker:

$ .../fmuCheck.linux64 -h 1 -s 11 -f -l 6 -e values.log values.fmu

where:

  • -h 1: steps every second
  • -s 11: during 11 seconds
  • -f: forces showing all the values (inputs, outputs, locals)
  • -l 6: logs every detail
  • -e values.log: stores the logging under values.log
  • values.fmu: selects the FMU to be used

or with fmusim (from fmusdk package):

$ ./fmusim_me inc.fmu 5 0.1

this will simulate during 5seconds using 0.1 second steps. it will create the file results.csv.

FMU compatible with windows and linux

If you compile like this:

nim c -r -d:fmu2me inc

you will get a FMU that is compatible only with the platform in which it was compile.

But if you compile using zig:

nim c -r -d:fmu2me -d:zig inc

you will get a FMU compatible with windows and linux (amd64 in both cases).

Getting zig

Install zig as you would do in windows or linux. (In windows, you need to have the binary reachable in the path; in Linux your package manager will take care of that).

Then you need to install with nimble (Nim package manager) the package: zigcc.

nimble install zigcc

(this is the same for both windows and linux; in windows you might need to install git)

Details

Intro

In general terms, we are making Nim to export C functions fulfilling the naming conventions of the FMU standard.

Importing an FMU in OpenModelica

In Linux, open:

$ OMEdit

Then import the created FMU:

Create a new Model (we will use the imported FMU in it):

Then drag-n-drop the FMU into the model:

Add an output for the integer. For that, drag-n-drop IntegerOutput on the model:

and connect the FMU instance to IntegerOutput:

Configure the simulation:

At this point, OpenModelica ask you to store the model somewhere (example.mo file). Select whereever it suits you.

Model

A new model requires the info such as:

  id      = "inc"
  guid    = "{8c4e810f-3df3-4a00-8276-176fa3c9f008}"

We will call the model template with these values. The model template is defined in src/fmu.nim. This calls model2 template (another template within src/fmu.nim). They both are responsible for structuring the code: the custom defined functions plus the other functions required by the standard.

All this will create two modes of operations for the code:

  1. When compiled as a library, it will create a library such as inc.so.
  2. When compiled as an app it uses src/lib/fmubuilder.nim:
  • Creates the folder structure
  • Creates the XML
  • Compress everything into a .fmu file.

Manual

setStartValues

Called by fmi2Instantiate with signature setStartValues(comp:Fmu).

In fmusdk, it initialize everything. This is no needed here. Right now this would only be needed in case of requiring to setup something during the FMU instantiation phase.

calculateValues

Calculate the values of the FMU (Functional Mock-up Unit) variables at a specific time step during simulation.

This function is defined by the user and called from getters.nim (fmi2GetReal, fmi2GetInteger, fmi2GetBoolean, fmi2GetString) and common.nim (fmi2ExitInitializationMode).

Lazy set values (given it is only called when isDirtyValues == true in the model) for all variable that are computed from other variables.

Example: inc.nim

Defines:

  proc calculateValues*(comp: FmuRef) = 
    if comp.state == modelInitializationMode:
        # set first time event
        comp.eventInfo.nextEventTimeDefined = fmi2True
        comp.eventInfo.nextEventTime        = 1 + comp.time

In this case, calculateValues creates new temporal events. In particular, creates in the InitializationMode state a new event 1s after the start.

eventUpdate

Used to set the next time event, if any.

Example: inc.nim

Reacts to events. In the inc.nim example, the first event was created in calculateValues.

In the inc.nim case, eventUpdate reacts to the event by creating a new event.

  • TODO: To talk about:
    type
      fmi2EventInfo* {.bycopy.} = object
        newDiscreteStatesNeeded*: fmi2Boolean
        terminateSimulation*: fmi2Boolean
        nominalsOfContinuousStatesChanged*: fmi2Boolean
        valuesOfContinuousStatesChanged*: fmi2Boolean
        nextEventTimeDefined*: fmi2Boolean
        nextEventTime*: fmi2Real
    and about: comp.isNewEventIteration

getReal

This is a user defined function with signature proc getReal*(comp: FmuRef; key: string):float. It is called by getters.nim in fmi2GetReal.

It is responsible for calculating the float values.

Example: values.nim

Defined as:

  proc getReal*(comp: FmuRef;
                key: string): float =
    case key
    of "myFloat": comp["myfloat"].valueR
    of "myFloatDerivative": -comp["myfloat"].valueR
    else: 0.0

TODO

  • unit testing for the examples
  • To simulate within Nim. This would prevent the need for fmuChecker.

Interesting projects related to FMU

About

create your own multiplatform FMU (Functional Mock-up Interface) models with Nim

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages