FMU Prep: Change Model Parameters for Model Input
I would like to export a Modelica model as FMU for Co-modeling using Dymola 2014. I am planning to complete the co-modeling with pyfmi.
To test this, I am trying to simulate the flow of a fluid through a pipe between two fluid boundaries. I would like the pressure of the fluid source to be the input to the model. My plan is to calculate this external pressure and enter a Modelica model at each timestamp.
My initial model with all the standard library components:
model SE_BVP "BVP for stack exchange."
inner Modelica.Fluid.System system;
Modelica.Fluid.Pipes.StaticPipe pipe(
redeclare package Medium = Modelica.Media.Air.MoistAir,
length=1,
diameter=1);
Modelica.Fluid.Sources.Boundary_pT boundary1(nPorts=1, redeclare package
Medium = Modelica.Media.Air.MoistAir);
Modelica.Fluid.Sources.Boundary_pT boundary(nPorts=1, redeclare package Medium=
Modelica.Media.Air.MoistAir, use_p_in=true);
Modelica.Blocks.Interfaces.RealInput p_in1;
equation
connect(pipe.port_b, boundary1.ports[1]);
connect(boundary.ports[1], pipe.port_a);
connect(boundary.p_in, p_in1);
end SE_BVP;
Which I then wrapped with two test models:
model SE_BVP_test_1
Real preVal = 101335;
SE_BVP SE_BVP_1;
equation
SE_BVP_1.p_in1 = preVal;
end SE_BVP_test_1;
and with parameter type which was made based on @Thierry's suggestion
model SE_BVP_test_2
parameter Real preVal = 101335;
SE_BVP SE_BVP_1;
equation
SE_BVP_1.p_in1 = preVal;
end SE_BVP_test_2;
Running these models gives me the same results:
and
Both models work at Dymola.
Now I want to load fmu and simulate with pyfmi, so I wrote this script:
import pyfmi
import numpy as np
import pylab as P
import os
# Define the FMU to test
fmuDirNam = "SE_BVP_Test_1" # CS 2.0 type FMU
fmuNam = fmuDirNam + ".fmu"
# Define the input var
inVar = "preVal"
# Get the path to the FMU
curr_dir = os.path.dirname(os.path.abspath(__file__))
par_dir = os.path.dirname(curr_dir)
path_to_fmu = os.path.join(par_dir, "projectFMUs", fmuDirNam)
# Load the model
model = pyfmi.load_fmu(os.path.join(path_to_fmu, fmuNam))
Which fails and gives me the following error:
FMIL: module = FMI2XML, log level = 2: XML element
'Real': could not parse value for real attribute
'start'='pipMod.pipe.flowModel.states[1].p/(gasConstant_Unique7(
Modelica.Media.Air.MoistAir.ThermodynamicState(
p =
FMIL: module = FMI2XML, log level = 2: XML element
'Real': could not parse value for real attribute
'start'='pipMod.pipe.flowModel.states[2].p/(gasConstant_Unique7(
Modelica.Media.Air.MoistAir.ThermodynamicState(
p =
FMIL: module = FMI2XML, log level = 2: XML element
'Real': could not parse value for real attribute
'start'='Modelica.Media.Incompressible.TableBased.Polynomials_Temp.evaluate({-4.96717436974791E-11, 5.06626785714286E-08, 1.72937731092437
FMIL: module = FMI2XML, log level = 2: XML element 'Real': could not parse value for real attribute
'start'='Modelica.Media.Incompressible.TableBased.Polynomials_Temp.evaluate({-4.96717436974791E-11, 5.06626785714286E-08, 1.72937731092437
FMIL: module = FMI2XML, log level = 1: No model structure information available.
Cannot continue.
FMIL: module = FMI2XML, log level = 1: Parse error at line 2703:
parsing aborted
From Traceback:
pyfmi.fmi.FMUException: The XML-could not be read. Parse error at line 2703:
parsing aborted
What could be causing this parsing error, given that the model mimics Dymola correctly?
-
I tried this also with a CS 1.0 export and raised the same exception, albeit with a different module reading fmu this time.
-
I figured there was a mysterious variable problem by removing the
input
and tagsparameter
, but no. Even with a tagparameter
like inTest_2
, I am throwing the same exception (CS 2.0).
Summary: Dymola 2014, python 2.7.x, FMI for CO Modeling 2.0
source to share
The problem is related to the selected media model. Modelica.Media.Air.MoistAir
is a model of air condition and temperature. Therefore, the initial values of liquid density, enthalpy, etc. They are functions of boundary pressure. During export to FMU, the value start
for the fluid state variables inside the pipe is written to an XML file as expressions:
<ScalarVariable
name="SE_BVP_1.pipe.flowModel.rhos[1]"
valueReference="100663348"
variability="constant">
<Real
unit="kg/m3"
min="0.0"
start="SE_BVP_1.pipe.flowModel.states[1].p/(gasConstant_Unique7(
Modelica.Media.Air.MoistAir.ThermodynamicState(
p = SE_BVP_1.pipe.flowModel.states[1].p,
T = SE_BVP_1.pipe.flowModel.states[1].T,
X = {SE_BVP_1.pipe.flowModel.states[1].X[1],
SE_BVP_1.pipe.flowModel.states[1].X[2]}
))*SE_BVP_1.pipe.flowModel.states[1].T)"/>
Changing the fluid to Buildings.Media.GasesPTDecoupled.MoistAirUnsaturated
removes the computation of the value start
, and the XML reads:
<ScalarVariable
name="SE_BVP_1.pipe.flowModel.rhos[1]"
valueReference="100663345"
variability="fixed">
<Real
unit="kg/m3"
min="0.0"/>
pyfmi
does not evaluate expressions during parsing and instead expects a string that can be formatted to float.
source to share
@RwardBound: If you want to change the parameters during simulation, I suggest using FMI 2.0 instead of FMI 1.0 FMU. This feature is supported in FMI 2.0. The latest version of Dymola, for example, is capable of generating such FMUs. I think PyFMI also supports FMI 2.0.
All the best, Thierry
source to share
The best practice for testing a Dymola model for export as FMU (or as a Modelica library) is to create a top model for testing. Then, you can create a modeling environment for the exported model.
Let's take a simple example of the "divide 10 / u" model:
model div10
Modelica.Blocks.Math.Division division;
Modelica.Blocks.Interfaces.RealInput u(start=10);
equation
division.u1 = 10;
connect(division.u2, u);
end div10;
Then you need to create this top model to test your div10 model :
model div10_tester
parameter Real default_u = 2.0;
div10 div10_1;
equation
div10_1.u = default_u;
end div10_tester;
Another solution could be to use "dsu.txt" (Note: if you are simulating only div10, the start = 10 statement will have no effect as indicated in your error log: if there is no "dsu.txt" "file => all inputs set to 0 ) But this is very limited as it only defines initial values.
source to share
an easy way to get around this input = 0 on initialization is probably to add a max () block to compare your input with some very small number.
For example:
input = max(a very small positive number, input) if your input is always greater than zero.
If your parameter (input) switches the signs, I think you are smart enough to find similar ways to do it.
source to share
The problem is that the XML generated by Dymola is not correct. The start attribute for a scalar variable must be a value, not an expression, as per the specification. The spec states that for a real scalar variable, the initial value must be float, and for integer values, the initial value must be int, etc. This is also true for FMI 1.0 and FMI 2.0 (the specification can be read at https://fmi-standard.org/downloads ).
To ensure that the FMU you receive is correct according to the standard, there is a tool called the Compliance Checker which is also available on the aforementioned site. This is a great tool to use if you are facing these types of problems, to rule out that the cause is a problem with the export tool.
As of Dymola 2015, XML is correctly generated for the SE_BVP_test_1 model and can be modeled using PyFMI.
source to share