Opened 9 years ago
Closed 7 years ago
#3778 closed defect (worksforme)
noEvent(x>0) fails to guard against sqrt(x) for x<0
Reported by: | mwetter | Owned by: | somebody |
---|---|---|---|
Priority: | high | Milestone: | Future |
Component: | *unknown* | Version: | |
Keywords: | Cc: |
Description (last modified by mwetter)
Hi
The regression test
Buildings.Fluid.FixedResistances.Examples.FixedResistancesExplicit
fails with "Model error: Argument of sqrt(res22.dp) was -5 should be >= 0"
This is triggered from
m_flow := if noEvent(dp>dp_turbulent) then k*sqrt(dp) elseif noEvent(dp<-dp_turbulent) then -k*sqrt(-dp) else (k^2*5/4/m_flow_turbulent)*dp-k/4/(m_flow_turbulent/k)^5*dp^3;
According to the Modelica specification, this is the correct implementation. However, when reformulating as
m_flow := if noEvent(dp>dp_turbulent) then k*sqrt(abs(dp)) elseif noEvent(dp<-dp_turbulent) then -k*sqrt(abs(-dp)) else (k^2*5/4/m_flow_turbulent)*dp-k/4/(m_flow_turbulent/k)^5*dp^3;
the example works. Hence, this looks like the implementation of noEvent is wrong in OpenModelica.
This fix makes the following tests work:
simulate(Buildings.Fluid.Examples.Performance.Example1v1); simulate(Buildings.Fluid.Examples.Performance.Example1v2); simulate(Buildings.Fluid.Examples.Performance.Example2); simulate(Buildings.Fluid.HeatExchangers.Examples.DryCoilCounterFlowPControl); simulate(Buildings.Fluid.FixedResistances.Examples.FixedResistancesExplicit); simulate(Buildings.Fluid.Examples.ResistanceVolumeFlowReversal);
Change History (8)
comment:1 Changed 9 years ago by mwetter
- Description modified (diff)
comment:2 Changed 9 years ago by sjoelund.se
comment:3 follow-up: ↓ 6 Changed 9 years ago by mwetter
dp is smaller than zero in the elseif branch, which is why there is a negative sign in sqrt(-dp).
It is true that we check against dp_turbulent, but because always dp_turbulent > 0, this guarantees
m_flow := if noEvent(dp>dp_turbulent /* > 0 */) then k*sqrt(dp) elseif noEvent(dp<-dp_turbulent /* < 0 */) then -k*sqrt(-dp) else (k^....
Hence, our implementation looks fine to me.
comment:4 follow-up: ↓ 5 Changed 9 years ago by rfranke
The code generation just takes away noEvent, see template daeExpCall in OMCompiler/Compiler/Template/CodegenCFunctions.tpl:
case CALL(path=IDENT(name="noEvent"), expLst={e1}) then daeExp(e1, context, &preExp, &varDecls, &auxFunction)
This means that either the backend has to generate specific code for expressions inside noEvent, or the code generation is wrong.
comment:5 in reply to: ↑ 4 Changed 9 years ago by sjoelund.se
Replying to rfranke:
This means that either the backend has to generate specific code for expressions inside noEvent, or the code generation is wrong.
The backend produces special code for relations that do not use noEvent.
comment:6 in reply to: ↑ 3 ; follow-up: ↓ 7 Changed 9 years ago by sjoelund.se
Replying to mwetter:
dp is smaller than zero in the elseif branch, which is why there is a negative sign in sqrt(-dp).
It is true that we check against dp_turbulent, but because always dp_turbulent > 0, this guarantees
m_flow := if noEvent(dp>dp_turbulent /* > 0 */) then k*sqrt(dp) elseif noEvent(dp<-dp_turbulent /* < 0 */) then -k*sqrt(-dp) else (k^....Hence, our implementation looks fine to me.
It's not the elseif branch being taken: Model error: Argument of sqrt(res22.dp) was -5 should be >= 0 suggests it is the if-branch and res22.dp_turbulent < -5. Needs some additional looking into.
comment:7 in reply to: ↑ 6 Changed 9 years ago by mwetter
Replying to sjoelund.se:
Replying to mwetter:
dp is smaller than zero in the elseif branch, which is why there is a negative sign in sqrt(-dp).
It is true that we check against dp_turbulent, but because always dp_turbulent > 0, this guarantees
m_flow := if noEvent(dp>dp_turbulent /* > 0 */) then k*sqrt(dp) elseif noEvent(dp<-dp_turbulent /* < 0 */) then -k*sqrt(-dp) else (k^....Hence, our implementation looks fine to me.
It's not the elseif branch being taken: Model error: Argument of sqrt(res22.dp) was -5 should be >= 0 suggests it is the if-branch and res22.dp_turbulent < -5. Needs some additional looking into.
Yes, it is the if branch. Of course m_flow := if noEvent(dp>dp_turbulent and dp>0) then k*sqrt(dp) ... does not work either (and the additional test is not needed as dp>0 whenever dp>dp_turbulent).
comment:8 Changed 7 years ago by casella
- Resolution set to worksforme
- Status changed from new to closed
The reports in https://test.openmodelica.org/libraries/Buildings/BuildModelRecursive.html indicate that the failure no longer takes place, possibly because of the implemented workaround.
I set up a simple test case to reproduce the problem
model Test Real x(start = 1, fixed = true); Real y; Real k = 3; equation der(x) = -2; y = if noEvent(x > 0) then k*sqrt(x) else 0; end Test;
which worked correctly without generating events, using OpenModelica-v1.13.0-dev-63-g453e1c7-64bit.
Feel free to reopen this ticket if the problem shows up again elsewhere.
Well... dp can be <0, right? The algorithm says it checks against dp_turbulent, which may be non-zero I assume?