Open henrikt-ma opened 3 years ago
We have now discovered several additional models suffering from the same kind of lack of margin of error, mainly within Thermal.FluidHeatFlow
. For example, take Modelica.Thermal.FluidHeatFlow.Examples.OneMass
.
The following assert in SimpleFriction
is where the margin of error is lacking:
assert(dpNominal>=dpNomMin,
"SimpleFriction: dpNominal has to be > dpLaminar/V_flowLaminar*V_flowNominal!");
Here we have:
dpNominal
: 1.0V_flowNominal
: 1.0dpLaminar
: 0.1… (floating point approximation of 0.1)V_flowLaminar
: 0.1… (floating point approximation of 0.1)Further, dpNomMin
is defined like so:
protected
parameter SI.Pressure dpNomMin=dpLaminar/V_flowLaminar*V_flowNominal;
If the definition of dpNomMin
is evaluated exactly as written, the expected result must be obtained:
1.0 >= (0.1... / 0.1...) * 1.0
→ 1.0 >= 1.0 / 1.0
→ 1.0 >= 1.0
→ true
However, all it takes to risk ending up on the wrong side is a seemingly sane symbolic rewrite:
1.0 >= (0.1... * (1.0 / 0.1...)) * 1.0
→ 1.0 >= (0.1... * 10.0) * 1.0
→ 1.0 >= 1.0… * 1.0
→ 1.0 >= 1.0…
→ false
In my opinion, this is too little margin of error.
Among the
AST_BatchPlant
examples, I've encountered two tanks where thelevel_start
is equal to theheight
.Modelica.Fluid.Examples.AST_BatchPlant.Test.TankWithEmptyingPipe2
:tank1
(2.0 = 2.0)Modelica.Fluid.Examples.AST_BatchPlant.Test.TanksWithEmptyingPipe1
:tank1
(2.0 = 2.0)This gives no margin of error in the
TankWithTopPorts
assert:While I can see that the assert should hold for the initial value of the
level
in infinite precision arithmetic, the fact that there is no margin of error means that one can end up with a lottery where the assert will pass or fail depending on the last bits of the computedlevel
. I believe the correct thing to do would be to introduce some margin, either by increasingheight
or by decreasinglevel_start
.In case more detail is needed, this is how we compute
level
in System Modeler.In the initialization problem:
V
based onlevel_start
:tank1.V = tank1.V0 + (tank1.crossArea * tank1.level_start)
m
based onV
:tank1.m = 995.586 * tank1.V
In the integration problem
V
based onm
:tank1.V = tank1.m / 995.586
level
based onV
:tank1.level = (tank1.V - tank1.V0) / tank1.crossArea
The detour from
level_start
tolevel
viam
andV
involves numeric computation that cannot be assumed to producelevel
exactly equal tolevel_start
. (I actually get a passed assertion with the computations above, but changing the division by 995.586 to multiplication by 1.0 / 995.586 makes the assertion fail.)I note that Dymola selects
level
as state instead ofm
(seen in translate_passed.log), which could explain why they actually get the infinite precision result forlevel
. Still, is there anything in the model that would makem
a less valid choice of state?