Importing FMU From Dymola
Contents
Workflow
We support importing Dymola FMU into SimWB. To run the FMU in SimWB, we need binary for Linux 64-bit or 32-bit depending on the SimWB server. Dymola is currently only available in Windows and they are working towards having a Linux version as well. Meanwhile we need to follow the steps below to get a working FMU in SimWB. Following steps assume you are using Dymola 2015.
Create FMU in Dymola
- Create Model in Dymola 2015
- Go to 'Simulation' Panel of Dymola
- Setup the model for FMU export
- Open Setup Panel by clicking the 'Setup' option in 'Simulation' menu
- This will show the 'General' Setup tab as shown below
- Click on the 'FMI' Setup tab. Make sure to select 'Cosimulation' mode, Version '2.0', 'Include source code' in the options as shown below. We also support version '1.0'.
- Generate FMU using the 'Translate' option in 'Simulation' menu.
- The generated FMU file is usually located in 'Documents' folder.
Create binary for Linux
- Move the generated FMU to SimWB server (RedHawk) system.
- Expand and Save the following perl code into a location and invoke as follows:
./ccurSimWBBuildFMU.pl --fmu /PathToFMUFile/NameOfFMU.fmu
#!/usr/bin/perl # This program is property of Concurrent Computer corporation. # Copyright Concurrent Computer Corporation. # Author : Ramesh Praveenkumar # Summary: Tool to automatically compile the Linux binaries for FMUs. # Supported Tools: Dymola 2016 # Dymola 2015 (Only FMI 1.0 is supported) # MapleSim 2015 use strict ; use Getopt::Long ; use XML::Simple ; use Cwd qw(abs_path); use File::Basename qw(dirname) ; my $simwbVersion = '7.3'; my $tmpFolder = '/tmp'; my $fmu = 'TestFMU.fmu'; my $fmilDir = '/usr/local/ccursim/FMIL'; my $additionalCFlags = ''; my $additionalLinkFlags = ''; my $update = 1; my $help = 0; print "This tool supports creating FMUs for SimWB $simwbVersion!\n"; # Process the arguments my $result = GetOptions("fmu=s" => \$fmu, "tmpFolder=s" => \$tmpFolder, "fmilDir=s" => \$fmilDir, "additionalCFlags=s" => \$additionalCFlags, "additionalLinkFlags=s" => \$additionalLinkFlags, "update!" => \$update, "help!" => \$help); if (!$result) { print STDERR "ERROR: Parsing options'\n"; usage(); exit(); } if ($help) { usage(); exit(1); } if (!$fmu) { print STDERR "ERROR: Missing FMU file name or Cannot parse FMU name!\n"; exit(1); } my $currentDir =dirname(abs_path($0)); print "Removing and recreating the folder $tmpFolder/fmutemp1\n"; system("rm -rf $tmpFolder/fmutemp1"); if($?) { print STDERR "ERROR: Removing the folder $tmpFolder/fmutemp1 failed!\n"; exit(1); } system("mkdir -p $tmpFolder/fmutemp1");; if($?) { print STDERR "ERROR: Creating the folder $tmpFolder/fmutemp1 failed!\n"; exit(1); } print "Copying the file $fmu to $tmpFolder/fmutemp1 and extracting\n"; system("cp $fmu $tmpFolder/fmutemp1/"); if($?) { print STDERR "ERROR: Copying the file $fmu to $tmpFolder/fmutemp1 and extracting failed!\n"; exit(1); } chdir("$tmpFolder/fmutemp1"); system("unzip -qo $fmu"); if($?) { print STDERR "ERROR: Extracting the file $fmu failed!\n"; exit(1); } if ( ! -d "$tmpFolder/fmutemp1/sources") { print STDERR "ERROR: No sources in FMU file!\n"; exit(1); } my $modelDescFile = "modelDescription.xml"; my ($generationTool,$modelIdentifier, $fmiVersion) = getFMUInfo($modelDescFile); my ($fmuBinDir, $fmuLibDir) = getSysInfo(); # Prepare the source files. We need to create Makefile for compiling the FMU. But, we may also need # to edit some files depending the supported modeling environment like Dymola & MapleSim. chdir("$tmpFolder/fmutemp1/sources"); prepareSourceFolder($generationTool, $modelIdentifier, $fmiVersion, $fmilDir, $fmuBinDir, $fmuLibDir); # Create FMU system("make zip"); if($?) { print STDERR "ERROR: Invoking make command failed(\"make zip\")!\n"; exit(1); } system("cp $tmpFolder/fmutemp1/$modelIdentifier.fmu $currentDir/"); if($?) { print STDERR "ERROR: Copying the FMU file from $tmpFolder/fmutemp1/$modelIdentifier.fmu to $currentDir failed!\n"; exit(1); } exit; sub getFMUInfo { my $modelDescFile = $_[0]; my $xmlSimple = new XML::Simple; my $data = $xmlSimple->XMLin($modelDescFile, KeyAttr => {fmiModelDescription => 'modelIdentifier' }); my $genToolStr = $data->{generationTool}; my $modelIdentifier = $data->{CoSimulation}->{modelIdentifier}; if (!$modelIdentifier) { $modelIdentifier = $data->{modelIdentifier}; if (!$modelIdentifier) { print STDERR "ERROR: Can't find modelIdentifier in modelDescription.xml\n"; exit(1); } } my $fmiVersion = $data->{fmiVersion}; if (!$fmiVersion) { print STDERR "ERROR: Can't find fmiVersion in modelDescription.xml\n"; exit(1); } my $genTool = ''; if($genToolStr =~ m/Dymola/) { if($genToolStr =~ m/2016/) { $genTool = "Dymola2016"; } elsif($genToolStr =~ m/2015/) { $genTool = "Dymola2015"; } else { print "Only Dymola versions 2016 & 2015 are supported. Found $genToolStr.\n We will attempt to compile FMU. But it may not work."; $genTool = "Dymola"; } } elsif($genToolStr =~ m/MapleSim/) { if($genToolStr =~ m/2015/) { $genTool = "MapleSim2015"; } else { print "Only MapleSim version 2015 is supported. Found $genToolStr.\n We will attempt to compile FMU. But it may not work."; $genTool = "MapleSim"; } } return ($genTool,$modelIdentifier, $fmiVersion); } sub getSysInfo { my $arch=`uname -i`; my $fmuBinDir = ''; my $fmuLibDir = ''; if ($arch =~ /x86_64/) { $fmuBinDir = 'linux64'; $fmuLibDir = 'lib64'; } else { $fmuBinDir = 'linux32'; $fmuLibDir = 'lib'; } return ($fmuBinDir, $fmuLibDir); } sub prepareSourceFolder { my $genTool = $_[0]; my $modelIdentifier = $_[1]; my $fmiVersion = $_[2]; my $fmilDir = $_[3]; my $fmuBinDir = $_[4]; my $fmuLibDir = $_[5]; my $makefileString = ''; chdir("$tmpFolder/fmutemp1/sources"); if ($genTool =~ m/Dymola2016/) { print "Input FMU created by Dymola 2016!\n"; # This is a Dymola 2016 model if($fmiVersion =~ /2/) {# FMI 2.0 print "++++++++Found FMI 2.0++++++++\n"; # Start processing the Dymola 2016 model FMI 2.0 unlink('fmiPlatformTypes_.h'); unlink('fmiTypesPlatform_.h'); system("ln -sf $fmilDir/include/FMI2/fmiTypesPlatform.h fmiTypesPlatform_.h"); system("ln -sf $fmilDir/include/FMI1/fmiPlatformTypes.h fmiPlatformTypes_.h"); system("mv fmiModelIdentifier.h fmiModelIdentifier.h.bk && touch fmiModelIdentifier.h"); prepareAll_c(); if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -DDYM2CCUR -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI2 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = all.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the Dymola 2016 model FMI 2.0 } elsif($fmiVersion =~ /1/) { #FMI 1.0 print "++++++++Found FMI 1.0++++++++\n"; # Start processing the Dymola 2016 model FMI 1.0 unlink('fmiPlatformTypes_.h'); unlink('fmiTypesPlatform_.h'); system("ln -sf $fmilDir/include/FMI2/fmiTypesPlatform.h fmiTypesPlatform_.h"); system("ln -sf $fmilDir/include/FMI1/fmiPlatformTypes.h fmiPlatformTypes_.h"); preparefmiModelIdentifier(); prepareAll_c(); if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -DDYM2CCUR -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI1 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = all.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the Dymola 2016 model FMI 1.0 } else { #Unknown FMI print STDERR "ERROR: Unknown FMI version!\n"; exit(1); } }elsif($genTool =~ m/Dymola2015/) { print "Input FMU created by Dymola 2015!\n"; # This is a Dymola 2015 model if($fmiVersion =~ /2/) {# FMI 2.0 print "++++++++Found FMI 2.0++++++++\n"; # Start processing the Dymola 2015 model FMI 2.0 print STDERR "Only FMI 1.0 is supported with Dymola 2015!\n"; exit(1); # End processing the Dymola model 2015 FMI 2.0 } elsif($fmiVersion =~ /1/) { #FMI 1.0 print "++++++++Found FMI 1.0++++++++\n"; # Start processing the Dymola model 2015 FMI 1.0 unlink('fmiPlatformTypes_.h'); unlink('fmiTypesPlatform_.h'); system("ln -sf $fmilDir/include/FMI2/fmiTypesPlatform.h fmiTypesPlatform_.h"); system("ln -sf $fmilDir/include/FMI1/fmiPlatformTypes.h fmiPlatformTypes_.h"); preparefmiModelIdentifier(); prepareAll_c(); if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -DDYM2CCUR -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI1 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = all.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the Dymola model 2015 FMI 1.0 } else { #Unknown FMI print STDERR "ERROR: Unknown FMI version!\n"; exit(1); } }elsif($genTool =~ m/Dymola/) { print "Input FMU created by unknown version of Dymola. Will try compiling, but this may fail!\n"; # This is a FMU created by unknown Dymola if($fmiVersion =~ /2/) {# FMI 2.0 print "++++++++Found FMI 2.0.++++++++\n"; # Start processing the Dymola model FMI 2.0 unlink('fmiPlatformTypes_.h'); unlink('fmiTypesPlatform_.h'); system("ln -sf $fmilDir/include/FMI2/fmiTypesPlatform.h fmiTypesPlatform_.h"); system("ln -sf $fmilDir/include/FMI1/fmiPlatformTypes.h fmiPlatformTypes_.h"); system("mv fmiModelIdentifier.h fmiModelIdentifier.h.bk && touch fmiModelIdentifier.h"); prepareAll_c(); if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -DDYM2CCUR -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI2 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = all.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the Dymola model FMI 2.0 } elsif($fmiVersion =~ /1/) { #FMI 1.0 print "++++++++Found FMI 1.0++++++++\n"; # Start processing the Dymola model FMI 1.0 unlink('fmiPlatformTypes_.h'); unlink('fmiTypesPlatform_.h'); system("ln -sf $fmilDir/include/FMI2/fmiTypesPlatform.h fmiTypesPlatform_.h"); system("ln -sf $fmilDir/include/FMI1/fmiPlatformTypes.h fmiPlatformTypes_.h"); preparefmiModelIdentifier(); prepareAll_c(); if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -DDYM2CCUR -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI1 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = all.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the Dymola model FMI 1.0 } else { #Unknown FMI print STDERR "ERROR: Unknown FMI version!\n"; exit(1); } }elsif($genTool =~ m/MapleSim2015/) { print "Input FMU created by MapleSim 2015!\n"; # This is a MapleSim 2015 model if($fmiVersion =~ /2/) {# FMI 2.0 print "++++++++Found FMI 2.0++++++++\n"; # Start processing the MapleSim 2015 model FMI 2.0 if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI2 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = $modelIdentifier.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the MapleSim 2015 model FMI 2.0 }elsif($fmiVersion =~ /1/) { print "++++++++Found FMI 1.0++++++++\n"; # Start processing the MapleSim 2015 model FMI 1.0 if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI1 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = $modelIdentifier.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the MapleSim 2015 model FMI 1.0 } else { #Unknown FMI print STDERR "ERROR: Unknown FMI version!\n"; exit(1); } } elsif($genTool =~ m/MapleSim/) { print "Input FMU created by unknown version of MapleSim. Will try compiling, but it may fail!\n"; # This is a unknown MapleSim model if($fmiVersion =~ /2/) {# FMI 2.0 print "++++++++Found FMI 2.0++++++++\n"; # Start processing the MapleSim model FMI 2.0 if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI2 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = $modelIdentifier.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the MapleSim model FMI 2.0 } elsif($fmiVersion =~ /1/) { print "++++++++Found FMI 1.0++++++++\n"; # Start processing the MapleSim model FMI 1.0 if (open (OUT,">Makefile")) { print OUT <<EOF; FMILINSTALLPATH=$fmilDir CFLAGS=-fPIC -g -O2 -I. -I\$(FMILINSTALLPATH)/include/FMI1 -I\$(FMILINSTALLPATH)/include/FMI -I\$(FMILINSTALLPATH)/include $additionalCFlags objects = $modelIdentifier.o FMU=../binaries/$fmuBinDir/$modelIdentifier.so fmulib:\$(FMU) \$(FMU): \$(objects) mkdir -p ../binaries/$fmuBinDir ld -shared -o \$(FMU) \$(objects) -L\$(FMILINSTALLPATH)/$fmuLibDir -lfmilib -lrt -lm $additionalLinkFlags clean: rm -f *.o rm -f \$(FMU) zip: fmulib cd ../ && rm -f $modelIdentifier.fmu cd ../ && zip -q -r $modelIdentifier.fmu . -x temp.fmu EOF } else { print STDERR "ERROR: Can't create FMU makefile!\n"; exit(1); } # End processing the MapleSim model FMI 1.0 } else { #Unknown FMI print STDERR "ERROR: Unknown FMI version!\n"; exit(1); } } } sub preparefmiModelIdentifier { my $inFileName = "fmiModelIdentifier.h"; my $result = open INPUT, "<", $inFileName; if(!defined $result || !$result) { die "Error opening the file ", $inFileName, " for reading!"; } my @inFileContent = <INPUT>; close INPUT; $result = open OUTPUT, ">", $inFileName; if(!defined $result || !$result) { die "Error opening the file ", $inFileName, " for reading!"; } foreach my $inFileLine (@inFileContent) { if ($inFileLine =~ m/MODEL_IDENTIFIER/) { $inFileLine =~ s/_$//; print OUTPUT $inFileLine; } else { print OUTPUT $inFileLine; } } close OUTPUT; } sub prepareAll_c { my $inFileName = "all.c"; my $result = open INPUT, "<", $inFileName; if(!defined $result || !$result) { die "Error opening the file ", $inFileName, " for reading!"; } my @inFileContent = <INPUT>; close INPUT; system("mv all.c all.c.bk"); $result = open OUTPUT, ">", $inFileName; if(!defined $result || !$result) { die "Error opening the file ", $inFileName, " for reading!"; } foreach my $inFileLine (@inFileContent) { if ($inFileLine =~ m/#define\s+DYMOLA_STATIC\s+static/) { $inFileLine =~ s/#define/\/\/#define/; print OUTPUT $inFileLine; } else { print OUTPUT $inFileLine; } } close OUTPUT; } sub usage { print <<"END"; Tool to automatically compile the Linux binaries for FMUs. Only FMI CoSimulation is supported. Supported Tools: Dymola 2016 Dymola 2015 (Only FMI 1.0 is supported) MapleSim 2015 General Usage: ccurSimWBBuildFMU.pl --fmu NameofFMU.fmu The above command extracts the FMU named NameofFMU.fmu temporarily in /tmp/fmutemp1 folder and then compiles the FMU to have Linux binary. The resulting FMU will be copied to current working directory which can then be imported into SimWB. All available options: --fmu : Name of the FMU file that needs to be rebuilt for SimWB Please provide full path. (Required Parameter) --tmpFolder : The temporary location where the FMU will be extracted for rebuild. This script will create a temporary folder named 'fmutemp1' in this location. Default is '/tmp'. (Optional Parameter) --additionalCFlags : Use this to supply addtional C Flags to the GCC. Useful if extra source files and other information needed to be passed to GCC. (Optional Parameter) --additionalLinkFlags : Use this to supply addtional Flags to the Linker. Useful if extra source libraries and other information needed to be passed to GCC. (Optional Parameter) END }
- You may have to install perl module XML::Simple by executing the following:
</syntaxhighlight lang="bash"> cpan XML::Simple </syntaxhighlight>
- Above step will create an FMU that we can use in SimWB.
Import FMU to SimWB
- Open the 'FMU Models' pane in SimWB
- Click on Select FMU file' button and navigate to the location of FMU created above.
- Click on 'Parse FMU' button. This will show the input, output, and parameter variables available in FMU to be mapped to RTDB. Inputs and Outputs are selected by default. You can select other variables as required.
- Click on 'New RTDB' button, provide a name for the RTDB to be created, and click 'Generate RTDB'
- Click on the 'Install FMU' button to install the FMU.
- Click on the 'Create FMU Model' to create a FMU model object in SimWB
- Now we are ready to use this object in any test like any other model