Nonlinear system solver could not converge - modelica

I am using the default dassl integrator. In my model a volume is controlled using Booleans to open or close 4 valves (2 work together). After the state of the boolean changes (from 1 to zero) with milliseconds I receive this error message:
Is there any way to find out more about what is causing the problem?
model CONTROLLER
Modelica.Blocks.Interfaces.RealInput V_LT_min;
Modelica.Blocks.Interfaces.RealInput V_LT_max;
Modelica.Blocks.Interfaces.RealInput V_LT_lev;
Modelica.Blocks.Interfaces.BooleanOutput open1(start=true);
Modelica.Blocks.Interfaces.BooleanOutput open2(start=false);
equation
when (V_LT_lev <= V_LT_max) then
open1 = true;
elsewhen (V_LT_lev < V_LT_min) then
open1 = false;
end when;
open2 = not open1;
end CONTROLLER;
model EV_LT
package SI = Modelica.SIunits;
package Medium = Modelica.Media.Water.WaterIF97_ph;
Thermofluid_connector port_e;
Thermofluid_connector port_s;
parameter Real Kv=3.79;
Modelica.Blocks.Interfaces.BooleanInput open;
Real dbM;
Real delta_p;
equation
//dbM=port_e.dbM;
delta_p = (port_e.p - port_s.p)/10^5;
if (delta_p >= 10^(-5)) then
dbM = Kv*sqrt(delta_p)*1000/3600;
else
dbM = 0;
end if;
port_e.dbM = if open then dbM else 0;
port_e.dbM + port_s.dbM = 0;
port_s.dbH = port_s.dbM*port_s.h;
port_e.h = port_s.h;
end EV_LT;
connector Thermofluid_connector
package SI = Modelica.SIunits;
SI.AbsolutePressure p;
flow SI.MassFlowRate dbM;
SI.SpecificEnthalpy h;
flow SI.EnthalpyFlowRate dbH;
equation
end Thermofluid_connector;

I looked a little bit deeper into this model and i don't know why any of this works on your system actually. I tried to simulate the model EV_LT and ran into a structural singularity which is quite obvious looking at the system.
You define the equation port_e.dbM + port_s.dbM = 0.0; and because neither port_e nor port_s are connected to anything the equations port_e.dbM = 0.0 and port_s.dbM = 0.0 are generated (Flow is set to zero for unconnected connectors). These are three equations with only 2 unknowns -> structural singularity. The compiler actually tries to resolve this by differentiating these (index reduction), but as you might imagine that does not yield any additional information whatsoever.
Are you sure you simulated the exact model stated above?
If you are talking about the simulation of only the controller, that does work but is pretty unexciting since it does not depend on time at all.
EDIT: Can you provide the omc version you are working with? I tested it with 1.14 and 1.16~dev. Maybe you have an older version and should upgrade.

Related

spatialDistribution()-Operator and non-scalar gradients in Modelica

I am using the spatialDistribution() Operator in Dymola and get the follwing message when using Hidden.PrintFailureToDifferentiate = true;
"Can only compute non-scalar gradients of functions specifying derivatives and not for: spatialDistribution"
I call the operator like this :
(time_rev,time_flow) = spatialDistribution(time,time,x/length,v_water>=0,{0.0,1.0}, {time,time});
and use it to calculate the outlet Temperature of my pipe.
Anyone got an idea where the issue lies? I don't really understand the error message.
More complete example:
cp_in = //Calculates specific Heatcap
cp_out = //Calculates specific Heatcap
cp = (cp_in+cp_out)*0.5;
C = (Modelica.Constants.pi*(1/4))*diameter_i^2*fluidInlet.d*cp;
R= // Calculates Heatresistance
//---------Conservation of mass flow and composition
//The usual stuff equal massflow,xi and p at both connectors
//----------Spatial
tau_nom = C*R;
v_water = //Calc Speed of water from Geometric data and inlet rho
der(x) = v_water;
(time_reversed,time_flow) = spatialDistribution(time,time,x/length,v_water>=0, {0.0,1.0}, {time,time});
tau_delay= time - time_flow;
tau_reversed= time - time_reversed; //Not used right now
if inlet.m_flow >= 0 then
T_out = (T_amb + (T_in - heat.T)*exp(-tau_delay/tau_nom));
heat.Q_flow = -inlet.m_flow*cp*(T_in - T_out);
inlet.h = inStream(outlet.h);
else
outlet.h = inStream(inlet.h);
T_in = T_out;
heat.Q_flow = -inlet.m_flow*cp*(T_in - T_out);
end if;
The reason for getting this error message is that Dymola cannot compute a gradient, that is likely used as part of computing a Jacobian for a non-linear system of equations.
If you look at the translation log I would expect that "Number of numerical Jacobians: " is non-zero.
A missing Jacobian for a non-linear system of equations is normally not a major issue.
However, that the non-linear system needs the gradient for spatialDistribution does not seem right, since it indicates that the delayed variables are implicitly given in some odd way.
It could be that the delay of the spatial distribution should solve that and in that case Dymola 2019 FD01 might remove the issue if you set Advanced.BreakDelayLoops=true; (but it is difficult to say without the complete model).
(It seems you have an earlier version, and the flag does not work there.)
I know it is a bit late answer, but it was difficult to investigate without a complete model.

issue generating triangular wave function in Modelica

I'm trying to create a model where one Modelica variable is a triangular wave of another variable. First I tried the floor() function as below:
model test1
final constant Real pi=2*Modelica.Math.asin(1.0);
parameter Real b = 1;
parameter Real a = 1;
Real x,p,u;
equation
if sign(sin(x*pi/b))>=0 then
p=a*(x-b*floor(x/b));
else
p=a*(b-(x-b*floor(x/b)));
end if;
x=time;
u = floor(x/b);
end test1
(x=time; is arbitrary so the model compiles)
but the result is weird, as you can see below
zoom in:
somehow 0.005 seconds before the next step floor function behaves unexpectedly and becomes a linear function ending by the next value.
then I tried the ceil() function. everything seemed right till I realised the same problem happens with ceil() function at other values (e.g. x=13)
I would appreciate if you could:
help me understand why this "glitch" happens and if it is intentional by design or a bug?
how I can fix this?
are there any alternatives to create a triangular wave function?
P.S. I am using this "wave function" to model the interaction between two jagged bodies"
If you are allowed to utilize the Modelica Standard Library, you can build up a parametrized, time-based zigzag signal using the CombiTimeTable block with linear interpolation and periodic extrapolation. For example,
model Test4
parameter Real a=2 "Amplitude";
parameter Real b=3 "Period";
Real y=zigzag.y[1] "Zigzag";
Modelica.Blocks.Sources.CombiTimeTable zigzag(
table=[0,0;b/4,a;b/4,a;b/2,0;b/2,0;3*b/4,-a;3*b/4,-a;b,0],
extrapolation=Modelica.Blocks.Types.Extrapolation.Periodic)
annotation(Placement(transformation(extent={{-80,60},{-60,80}})));
Modelica.Blocks.Sources.Trapezoid trapezoid(
amplitude=2*a,
rising=b/2,
width=0,
falling=b/2,
period=b,
offset=-a)
annotation(Placement(transformation(extent={{-80,25},{-60,45}})));
annotation(uses(Modelica(version="3.2.2")));
end Test4;
I don't have an explanation for the glitches in your simulation.
However, I would take another approach to the sawtooth function: I see it as an integrator integrating +1 and -1 upwards and downwards. The integration time determines the amplitude and period of the sawtooth function.
The pictures below show an implementation using MSL blocks and one using code. The simulation results below are the same for both implementations.
Best regards,
Rene Just Nielsen
Block diagram:
Code:
model test3
parameter Real a=2 "amplitude";
parameter Real b=3 "period";
Real u, y;
initial equation
u = 1;
y = 0;
equation
4*a/b*u = der(y);
when y > a then
u = -1;
elsewhen y < -a then
u = 1;
end when;
end test3;
Simulation result:
The problem I guess is due to floating point representation and events not occurring at exact times.
Consider x-floor(x) and 1-(x-floor(x)) at time=0.99, they are 0.99 and 0.01; at time=1.00 they are 0.0 and 1.0, which causes your problems.
For a=b=1, you can use the following equation for p:
p=min(mod(x,2),2-mod(x,2));. You can even add noEvent to it, and you can consider the signal continuous (but not differentiable).
model test
parameter Real b = 1;
parameter Real a = 3;
Real x, p;
equation
p = 2*a*min(1 / b * mod(x, b ),1 - 1/b * mod(x, b));
x = time;
end test;
My first advise would be to remove the sign-function, since there is no benefit of doing sign(foo)>=0 compared to foo>=0.
Interesting enough that seems to fix the problem in Dymola - and I assume also in OpenModelica:
model test1 "almost original"
final constant Real pi=2*Modelica.Math.asin(1.0);
parameter Real b = 1;
parameter Real a = 1;
Real x,p,u;
equation
if sin(x*pi/b)>=0 then
p=a*(x-b*floor(x/b));
else
p=a*(b-(x-b*floor(x/b)));
end if;
x=time;
u = floor(x/b);
end test1;
Now I only have to explain that - and the reason is that sin(x*pi/b) is slightly out of sync with the floor-function, but if you use sin(x*pi/b)>=0 that is within the root-finding epsilon and nothing strange happen.
When you use sign(sin(x*pi/b))>=0 that is no longer possible, instead of having sin(x*pi/b) an epsilon below zero it is now -1, and instead of epsilon above zero it is 1.
The real solution is thus slightly more complicated:
model test2 "working"
parameter Real b = 1;
parameter Real a = 1;
Real x,p,u;
Real phase=mod(x,b*2);
equation
if phase<b then
p=a/b*phase;
else
p=a-a/b*(phase-b);
end if;
x=time;
u = floor(x/b);
end test2;
which was improved based on a suggested solution:
model test3 "almost working"
parameter Real b = 1;
parameter Real a = 1;
Real x,p,u;
equation
if mod(x,2*b)<b then
p=a/b*mod(x,b);
else
p=a-a/b*mod(x,b);
end if;
x=time;
u = floor(x/b);
end test3;
The key point in this solution, test2, is that there is only one problematic event generating expression mod(x,2*b) - and the < will not get out of sync with this.
In practice test3 will almost certainly also work, but in unlikely cases the event generation might get out of sync between mod(x,2*b) and mod(x,b); with unknown consequences.
Note that all three examples are now modified to generate output that looks similar.

OpenModelica modelling Coulomb friction: Translation Error, post-optimization module findZeroCrossings (simulation) failed

I'm trying to simulate Coulomb friction in Modelica. The basic concept is to check if relative velocity speed between to surfaces is less than a constant and the external force which tried to slid surfaces against each other is less than maximum static friction force (normalForce * staticFrictionCoefficient) then the friction force is equal to negative of the external shear force. otherwise, the friction force is equal to the kinetic friction force (normalForce * kineticFrictionCoefficient)in the opposite direction of the sliding direction.
I implemented this concept in Modelica as below:
function coulombFriction
input Real relVel;
input Real shearForce;
input Real normalForce;
input Real statfricco;
input Real kinfricco;
output Real fricForce;
algorithm
if relVel==0 and abs(shearForce)<statfricco*normalForce then
fricForce:=shearForce;
else
fricForce:=kinfricco*normalForce*sign(relVel);
end if;
end coulombFriction;
but when I call this function from a model as below:
model fricexample_1
extends coulombFriction;
//parameters
parameter Real kco=0.3;
parameter Real sco=0.4;
parameter Real nfo=1.0;
Real sfo;
Real ffo;
Real x;
Real v;
initial equation
x=0;
v=0;
equation
v=der(x);
der(v)=sfo-ffo;
sfo=time;
ffo=coulombFriction(relVel=v, shearForce=sfo, normalForce=nfo, statfricco=sco, kinfricco=kco);
end fricexample_1;
I see the error:
Translation Error
post-optimization module findZeroCrossings (simulation) failed.
If I remove the abs function from the defined function, it solves the compiling problem, but the model is wrong! I would appreciate if you could help me know:
how can I solve this problem?
how to model friction otherwise?
You can use noEvent on the conditions that might generate events in the function. Note that you don't need to extend the model with the function.
It should actually not work (to extend a model from a function), but it seems we don't check for it.
The model that compiles for me is below:
package Friction
function coulombFriction
input Real relVel;
input Real shearForce;
input Real normalForce;
input Real statfricco;
input Real kinfricco;
output Real fricForce;
algorithm
if noEvent(relVel==0) and noEvent(abs(shearForce)<statfricco*normalForce) then
fricForce:=shearForce;
else
fricForce:=kinfricco*normalForce*sign(relVel);
end if;
end coulombFriction;
model fricexample_1
//parameters
parameter Real kco=0.3;
parameter Real sco=0.4;
parameter Real nfo=1.0;
Real sfo;
Real ffo;
Real x;
Real v;
initial equation
x = 0;
v = 0;
equation
v = der(x);
der(v) = sfo-ffo;
sfo = time;
ffo = coulombFriction(relVel=v, shearForce=sfo, normalForce=nfo, statfricco=sco, kinfricco=kco);
end fricexample_1;
end Friction;
Your model does work with the 1.11 release. The issue is the extends coulombFriction; statement. Once you removed it, it should work fine even without the noEvent calls:
package Friction
function coulombFriction
input Real relVel;
input Real shearForce;
input Real normalForce;
input Real statfricco;
input Real kinfricco;
output Real fricForce;
algorithm
if relVel==0 and abs(shearForce)<statfricco*normalForce then
fricForce:=shearForce;
else
fricForce:=kinfricco*normalForce*sign(relVel);
end if;
end coulombFriction;
model fricexample_1
parameter Real kco=0.3;
parameter Real sco=0.4;
parameter Real nfo=1.0;
Real sfo;
Real ffo;
Real x;
Real v;
initial equation
x = 0;
v = 0;
equation
v = der(x);
der(v) = sfo-ffo;
sfo = time;
ffo = coulombFriction(relVel=v, shearForce=sfo, normalForce=nfo, statfricco=sco, kinfricco=kco);
end fricexample_1;
end Friction;
I'd recommend to reuse the friction state machine available in the Modelica Standard Library. An example, that works in OpenModelica and other tools, is given by https://github.com/dzimmer/ZimmersModelicaTutorial/blob/master/Tutorial2015/BaseComponents/Friction/IdealDryFriction.mo.
Actually, the model I have developed above for Columb friction is wrong. Thanks to this post I could find the correct version:
package friction1D
final constant Real eps=1.e-15 "Biggest number such that 1.0 + eps = 1.0";
function sgn
input Real inputVar;
output Real outputVar;
algorithm
if noEvent(inputVar < 0) then
outputVar := -1;
else
outputVar := 1;
end if;
end sgn;
function coulombFriction
input Real relVel;
input Real shearForce;
input Real normalForce;
input Real statfricco;
input Real kinfricco;
output Real fricForce;
algorithm
if noEvent(abs(relVel) < eps) and noEvent(abs(shearForce) < statfricco * normalForce) then
fricForce := shearForce;
else
fricForce := kinfricco * normalForce * sgn(relVel);
end if;
end coulombFriction;
model fricexample_1
//parameters
parameter Real kco = 0.3;
parameter Real sco = 0.4;
parameter Real nfo = 1.0;
parameter Real mass = 1.0;
Real sfo;
Real ffo;
Real x;
Real v;
initial equation
x = 0;
v = 0;
algorithm
sfo := 0.7 * sin(time);
ffo := coulombFriction(relVel = v, shearForce = sfo, normalForce = nfo, statfricco = sco, kinfricco = kco);
equation
v = der(x);
mass * der(v) = sfo - ffo;
annotation(
experiment(StartTime = 0, StopTime = 10, Tolerance = 1e-8, Interval = 0.02),
__OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "dassl"));
end fricexample_1;
end friction1D;

Trouble balancing a simple power flow model in modelica

I try to set up a simple model with electrical or thermal power flows between sources and sinks.
I seem to have the same problem as treated in this topic although I used only one pair of flow and potential variables in my connector:
connector PowerPortE
flow SI.Power P;
SI.Voltage v "Dummy potential-variable to balance flow-variable P";
end PowerPortE;
A simple example with a signal responsed power sink looks like this:
model PowerSinkE
SimplePowerSystem.PowerPortE Port;
Modelica.Blocks.Interfaces.RealInput P(unit = "W");
SI.Voltage v(start = 230);
equation
Port.P = P;
Port.v = v;
end PowerSinkE;
model Test
SimplePowerSystem.PowerSinkE Verbraucher ;
Modelica.Blocks.Sources.Sine sine1(freqHz = 50) ;
equation
connect(sine1.y,Verbraucher.P);
end Test;
Checking PowerSinkE goes well, but when trying to simulate, I get the following errors:
Internal error pre-optimization module removeSimpleEquations failed.
Internal error Found Equation without time dependent variables Verbraucher.Port.P = const.k
An independent subset of the model has imbalanced number of equations (1) and variables (2).
variables:
Verbraucher.v
Verbraucher.Port.v
equations:
1 : Verbraucher.Port.v = Verbraucher.v
An independent subset of the model has imbalanced number of equations (4) and variables (3).
variables:
sine1.y
Verbraucher.P
Verbraucher.Port.P
equations:
1 : Verbraucher.Port.P = Verbraucher.P
2 : sine1.y = sine1.offset + (if time < sine1.startTime then 0.0 else sine1.amplitude * sin(6.283185307179586 * sine1.freqHz * (time - sine1.startTime) + sine1.phase))
3 : Verbraucher.Port.P = 0.0
4 : Verbraucher.P = sine1.y
Initially I wanted to leave the variable v completely out of the model (though I had to leave it in the connector to be balanced) but this didn't work out either:
Model is structurally singular, error found sorting equations
1: 0.0 = sine1.offset + (if time < sine1.startTime then 0.0 else sine1.amplitude * sin(6.283185307179586 * sine1.freqHz * (time - sine1.startTime) + sine1.phase));
for variables
Verbraucher.Port.v(1)
The problem seems to be that I need the flow variable power but don't have a corresponding potential variable. I am running out of ideas how to fix this, so thanks for the help.
Why do you try to use a connector in this case? If you don't need the "pyhsical meaning" of flow and potential variables inside the connector, you just can use real inputs and outputs to handle signals.
package SimplePowerSystem
model PowerSinkE
import SI = Modelica.SIunits;
SI.Power P;
Modelica.Blocks.Interfaces.RealInput P_in(unit="W");
equation
P = P_in;
end PowerSinkE;
model Test
SimplePowerSystem.PowerSinkE Verbraucher;
Modelica.Blocks.Sources.Sine sine1(freqHz = 50);
equation
connect(sine1.y, Verbraucher.P_in);
end Test;
end SimplePowerSystem;
My initial thought is that port in the consumer is unconnected. This adds the equation consumer.port.P = 0.0. But what you really need is an equation for the voltage in the port.
You need to use voltage and current on your electrical connector and you need an electrical ground. I suggest you have a look at Modelica by Example for more about both electrical and thermal component modeling.

Modelica: Calculating a variable using both der() and explicit declaration

I apologize for the poor title, but I found it hard to describe the problem in a comprehensible way.
What I want to do is to solve an ODE, but I don't want to start integrating at time = 0. I want the initial value, i.e. the starting point of the integration, to be accessible for changes until the integration starts. I'll try to illustrate this with a piece of code:
model testModel "A test"
parameter Real startTime = 10 "Starting time of integration";
parameter Real a = 0.1 "Some constant";
Real x;
input Real x_init = 3;
initial equation
x = x_init;
equation
if time <= startTime then
x = x_init;
else
der(x) = -a*x;
end if;
end testModel;
Notice that x_init is declared as input, and can be changed continuously. This code yields an error message, and as far as I can tell, this is due to the fact that I have declared x as both der(x) = and x =. The error message is:
Error: Singular inconsistent scalar system for der(x) = ( -(if time <= 10 then x-x_init else a*x))/((if time <= 10 then 0.0 else 1.0)) = -1e-011/0
I thought about writing
der(x) = 0
instead of
x = init_x
in the if-statement, which will avoid the error message. The problem in such an approach, however, is that I lose the ability to modify the x_init, i.e. the starting point of the integration, before the integration starts. Lets say, for instance, that x_init changes from 3 to 4 at time = 7.
Is there a work-around to perform what I want? Thanks.
(I'm gonna use this to simulate several submodels as part of a network, but the submodels are not going to be initiated at the same time, hence the startTime-variable and the ability to change the initial condition before integration.)
Suggested solution: I've tried out the following:
when time >= startTime
reinit(x,x_init);
end when;
in combination with the der(x) = 0 alternative. This seems to work. Other suggestions are welcome.
If your input is differentiable, this should work:
model testModel "A test"
parameter Real startTime = 10 "Starting time of integration";
parameter Real a = 0.1 "Some constant";
Real x;
input Real x_init = 3;
initial equation
x = x_init;
equation
if time <= startTime then
der(x) = der(x_init);
else
der(x) = -a*x;
end if;
end testModel;
Otherwise, I suspect the best you could do would be to have your x variable be a very fast first-order tracker before startTime.
The fundamental issue here is that you are trying to model a variable index DAE. None of the Modelica tools I'm aware of support variable index systems like this.