modelica / ModelicaStandardLibrary

Free (standard conforming) library to model mechanical (1D/3D), electrical (analog, digital, machines), magnetic, thermal, fluid, control systems and hierarchical state machines. Also numerical functions and functions for strings, files and streams are included.
https://doc.modelica.org
BSD 3-Clause "New" or "Revised" License
479 stars 169 forks source link

Two AST_BatchPlant examples have no margin of error in initial tank levels #3799

Open henrikt-ma opened 3 years ago

henrikt-ma commented 3 years ago

Among the AST_BatchPlant examples, I've encountered two tanks where the level_start is equal to the height.

This gives no margin of error in the TankWithTopPorts assert:

  assert(level <= height, "Tank starts to overflow (level = height = " + String(level) + ")");

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 computed level. I believe the correct thing to do would be to introduce some margin, either by increasing height or by decreasing level_start.

In case more detail is needed, this is how we compute level in System Modeler.

In the initialization problem:

  1. Initialize V based on level_start: tank1.V = tank1.V0 + (tank1.crossArea * tank1.level_start)
  2. Initialize state m based on V: tank1.m = 995.586 * tank1.V

In the integration problem

  1. Determine V based on m: tank1.V = tank1.m / 995.586
  2. Determine level based on V: tank1.level = (tank1.V - tank1.V0) / tank1.crossArea

The detour from level_start to level via m and V involves numeric computation that cannot be assumed to produce level exactly equal to level_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 of m (seen in translate_passed.log), which could explain why they actually get the infinite precision result for level. Still, is there anything in the model that would make m a less valid choice of state?

henrikt-ma commented 2 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:

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.