I think Nim could shine for simulations.
People use Simulink or OpenModelica with Modelica language. There are many softwares that can export those physical models as FMU files which follow the FMI standard.
FMU are .zip files which contain libraries (.dll or .so) and some .xml description files. As far as I know, neither Python nor Julia can export those models easily to FMU files. Julia has the problem that the runtime is pretty big, so even when done manually, it requires more than 100Mb files.
I am trying to do this in Nim. To achive it I would like to use: fmusdk <https://github.com/qtronic/fmusdk>. As an example, I would like to port the following example: bouncingBall. But I am not sure about what should I do.
Looking at bouncingBall.c, it follows the following structure::
#include "fmuTemplate.h"
/*
...
define a few C functions which represent the model
...
*/
#include "fmuTemplate.c"
Which one of the following approaches would be better?
Regards
It seems like you could just use nimterop or c2nim to create nim bindings for the .h and .c file.
https://github.com/nimterop/nimterop
Also, ping @shashlick, the author of that library.
My first little success doing this. It is something probably very easy for you guys, but I have struggle A LOT (no pro-dev speaking).
First I create bindings to fmuTemplate.h. I did so with a wrapper similar to the following:
import os
import nimterop/cimport
const
base = currentSourcePath.parentDir()
static:
cDebug()
cDefine("DISABLE_PREFIX")
cIncludeDir(base/"src/shared/include")
cIncludeDir(base/"src/shared")
cIncludeDir(base/"src")
cImport(base/"src/fmuTemplate.h", recurse=true)
I did:$ nim c wrapper.nim > fmutemplate.nim
I had to manually modify fmutemplate.nim as suggested here.
Then I ported a model. As an example I ported the inc model. I convert the file inc.c into:
# nim c --nimcache:.cache --app:lib -o:inc.so inc.nim
import fmuTemplate
import strformat
# Porting inc.c (a particular model)
const
MODEL_IDENTIFIER="inc"
MODEL_GUID="{8c4e810f-3df3-4a00-8276-176fa3c9f008}"
#define model size
NUMBER_OF_REALS= 0
NUMBER_OF_INTEGERS=1
NUMBER_OF_BOOLEANS=0
NUMBER_OF_STRINGS=0
NUMBER_OF_STATES=0
NUMBER_OF_EVENT_INDICATORS=0
const
counter = 0
proc setStartValues(comp:ptr ModelInstance) {.exportc: "$1".} =
comp.i[counter] = 1
proc calculateValues(comp:ptr ModelInstance) {.exportc: "$1".}=
if comp.state == modelInitializationMode:
# set first time event
comp.eventInfo.nextEventTimeDefined = fmi2True
comp.eventInfo.nextEventTime = 1 + comp.time
proc eventUpdate(comp:ptr ModelInstance, eventInfo:ptr fmi2EventInfo, timeEvent:cint, isNewEventIteration:cint) {.exportc: "$1".} =
if timeEvent != 0:
comp.i[counter] += 1;
if comp.i[counter] == 13:
eventInfo.terminateSimulation = fmi2True
eventInfo.nextEventTimeDefined = fmi2False
else:
eventInfo.nextEventTimeDefined = fmi2True
eventInfo.nextEventTime = 1 + comp.time
{.passC: "-Ifmi/shared/include -w -fmax-errors=5".}
{.passC: "-DMODEL_IDENTIFIER=\\\"" & MODEL_IDENTIFIER & "\\\"".}
{.passC: "-DMODEL_GUID=\\\"" & MODEL_GUID & "\\\"".}
{.passC: "-DNUMBER_OF_REALS=" & $NUMBER_OF_REALS .}
{.passC: "-DNUMBER_OF_INTEGERS=" & $NUMBER_OF_INTEGERS .}
{.passC: "-DNUMBER_OF_BOOLEANS=" & $NUMBER_OF_BOOLEANS .}
{.passC: "-DNUMBER_OF_STRINGS=" & $NUMBER_OF_STRINGS .}
{.passC: "-DNUMBER_OF_STATES=" & $NUMBER_OF_STATES .}
{.passC: "-DNUMBER_OF_EVENT_INDICATORS=" & $NUMBER_OF_EVENT_INDICATORS .}
{.compile: "./src/fmuTemplate.c".}
I manually modified added to fmuTemplate.c the line:
include "fmuTemplate.h"
I compiled the model into a library as follows:nim c --nimcache:.cache --app:lib -o:inc.so inc.nim
This produced the file inc.so.
Later, I used directly the fmusdk to create all the model's folder structure with all the files by doing:
build_fmu me inc
This creates a Model Exchange model for inc.
I replaced the file inc.so created with fmusdk with the one created using inc.nim. The file is stored in fmu/binaries/linux64/inc.so.
The whole folder structure is stored as:
cd fmu zip -r ../inc.fmu ./
The file inc.fmu is the model that can be integrated in OpenModelica, Dymola, Simulink, ...
I have only tested it with FMUComplianceChecker and it looks good.
As a proof of concept, I am happy.
The way forward:
I don't think I will be capable of doing the last bullet, but I will try.