- Index
- » Developer
- » OpenModelica development
- » Code generation for non-linear systems
Code generation for non-linear systems
Code generation for non-linear systems
Hi,
I am not sure wheter I am correct, but it appears as OpenModelica generates inccorect code for the solving of non-linear systems.
In the generated C code a function is called from "functionAlgebraics" which calls a macro (start_nonlinear_system(68)) leading to the definition of the variable: double nls_fvec[68].
Later on a solver macro (solve_nonlinear_system) is called with a function pointer to some function which apperas to calculate some residual values. In this functions the results are written to a pointer pointing to nls_fvec. Here seems to be the problem, as some values are written beyond the allocated space (in my case up to index 74). I am not sure wheter I am correct here, as in some models the simulation runs correctly. However, I have a model where this seems to cause a segmentation fault crashing the simulation program.
Im am using OpenModelica (r11077).
Regards,
Michael
Re: Code generation for non-linear systems
Could you provide a model that shows this behaviour? I have not seen this in any code myself and need a starting point if I'm going to fix it.
Writing to a variable beyond this limit is pointless since the nonlinear solver will not consider this and you will either get wrong result or a crash.
- sjoelund.se
- 1700 Posts
Re: Code generation for non-linear systems
I was able to create a small model which reproduces the error. In my case the generated function "eqFunction_6" declares a non-linear system with with an array of size 12. In "residualFunc6", however, this array is accessed at index 15. Although for me this does not give a run-time error, it does corrupts the stack.
As uploading does not work for me, I post the model here:
Code:
package Medium
function h_pt
input Real p;
input Real t;
output Real h;
algorithm
h := t;
end h_pt;
function d_ph
input Real p;
input Real h;
output Real d;
algorithm
d := h;
end d_ph;
end Medium;
connector Port
flow Real mf;
Real p;
stream Real h;
end Port;
model Pipe
Port port_a, port_b;
Real loopPressure;
protected
Real density;
Real outputPressure;
function func
input Real inputPressure;
input Real density;
output Real outputPressure;
output Real loopPressure;
algorithm
loopPressure := inputPressure;
outputPressure := inputPressure;
end func;
equation
density = Medium.d_ph(port_a.p, port_a.h);
(outputPressure, loopPressure) = func(port_a.p, density);
port_a.mf + port_b.mf = 0;
port_b.p = outputPressure;
port_a.h = inStream(port_b.h);
port_b.h = inStream(port_a.h);
end Pipe;
model Split
Port port_a, port_b, port_c;
equation
connect(port_a, port_b);
connect(port_a, port_c);
end Split;
model Join
Port port_a, port_b, port_c;
final parameter Real epsFlow = 1e-15;
equation
port_a.mf + port_b.mf + port_c.mf = 0;
port_b.p = min(port_a.p, port_c.p);
port_a.h = (max(port_b.mf, epsFlow) * inStream(port_b.h) + max(port_c.mf, epsFlow) * inStream(port_c.h)) / (max(port_b.mf, epsFlow) + max(port_c.mf, epsFlow));
port_b.h = (max(port_a.mf, epsFlow) * inStream(port_a.h) + max(port_c.mf, epsFlow) * inStream(port_c.h)) / (max(port_a.mf, epsFlow) + max(port_c.mf, epsFlow));
port_c.h = (max(port_a.mf, epsFlow) * inStream(port_a.h) + max(port_b.mf, epsFlow) * inStream(port_b.h)) / (max(port_a.mf, epsFlow) + max(port_b.mf, epsFlow));
end Join;
model Boundary
Port port;
Real t;
Real mf;
Real p;
equation
port.mf = mf;
port.p = p;
port.h = Medium.h_pt(p, t);
end Boundary;
model Test
Split[numberOfSplits - 1] split;
Join[numberOfSplits - 1] join;
Pipe[numberOfSplits] pipe;
Boundary source;
Boundary sink;
parameter Integer numberOfSplits = 2;
parameter Integer numberOfLoops = 10;
equation
source.mf = -10;
source.p = 100000;
source.t = 300;
sink.t = 300;
// Grid:
// split
// --+--+---
// | | | pipe
// --+--+---
// join
connect(source.port, split[1].port_a);
for i in 1:numberOfSplits - 1 loop
connect(split[i].port_c, pipe[i].port_a);
connect(pipe[i].port_b, join[i].port_c);
split[i].port_c.mf = -source.port.mf / numberOfSplits;
end for;
for i in 1:numberOfSplits - 2 loop
connect(split[i].port_b, split[i + 1].port_a);
connect(join[i + 1].port_b, join[i].port_a);
end for;
connect(split[numberOfSplits - 1].port_b, pipe[numberOfSplits].port_a);
connect(pipe[numberOfSplits].port_b, join[numberOfSplits - 1].port_a);
connect(join[1].port_b, sink.port);
end Test;
I am using OpenModelica for Windows (r11098)
Regards,
Michael
Re: Code generation for non-linear systems
- sjoelund.se
- 1700 Posts
Re: Code generation for non-linear systems
Seems to work with the new tearing implementation: https://trac.openmodelica.org/OpenModelica/ticket/1692
- sjoelund.se
- 1700 Posts
- Index
- » Developer
- » OpenModelica development
- » Code generation for non-linear systems