Openmodelica error: "The tearing heuristic was not able to avoid discrete iteration variables..." - modelica

I'm developing a simulation of a swarm of drones. I made a function for checking area in front of drones, but when i'm trying to use it it displays this error:
"The tearing heuristic was not able to avoid discrete iteration variables because otherwise the system could not have been torn".
This is the function:
function seeNearObject "Restituisce una lista contenente tutti gli oggetti rilevati dal sistema video del drone"
InputReal x;
InputReal y;
InputReal z;
InputReal x2[K.N];
InputReal y2[K.N];
InputReal z2[K.N];
InputReal destX;
InputReal destY;
InputReal destZ;
InputReal intrX[K.nIntr];
InputReal intrY[K.nIntr];
InputReal intrZ[K.nIntr];
InputReal missX[K.nRocket];
InputReal missY[K.nRocket];
InputReal missZ[K.nRocket];
InputReal statX[K.nStatObs];
InputReal statY[K.nStatObs];
InputReal statZ[K.nStatObs];
OutputBool outneighbours[K.N];
OutputBool outnearIntr[K.nIntr];
OutputBool outnearMissile[K.nRocket];
OutputBool outnearStatObs[K.nStatObs];
protected
Real viewField[3];
algorithm
//Imposto i limiti del campo visivo. Data la direzione del drone, ogni asse avrà il suo limite.
// viewField := findViewField(x,y,z, destX,destY,destZ);
viewField := zeros(3);
for j in 1:K.N loop
outneighbours[j] := false;
if((x2[j] >= x and x2[j] <= viewField[1]) or (x2[j] <= x and x2[j] >= viewField[1])) then
if((y2[j] >= y and y2[j] <= viewField[2]) or (y2[j] <= y and y2[j] >= viewField[2])) then
if((z2[j] >= z and z2[j] <= viewField[3]) or (z2[j] <= z and z2[j] >= viewField[3])) then
outneighbours[j] := true;
end if;
end if;
end if;
end for;
for j in 1:K.nIntr loop
outnearIntr[j] := false;
if((intrX[j] >= x and intrX[j] <= viewField[1]) or (intrX[j] <= x and intrX[j] >= viewField[1])) then
if((intrY[j] >= y and intrY[j] <= viewField[2]) or (intrY[j] <= y and intrY[j] >= viewField[2])) then
if((intrZ[j] >= z and intrZ[j] <= viewField[3]) or (intrZ[j] <= z and intrZ[j] >= viewField[3])) then
outnearIntr[j] := true;
end if;
end if;
end if;
end for;
for j in 1:K.nRocket loop
outnearMissile[j] := false;
if((missX[j] >= x and missX[j] <= viewField[1]) or (missX[j] <= x and missX[j] >= viewField[1])) then
if((missY[j] >= y and missY[j] <= viewField[2]) or (missY[j] <= y and missY[j] >= viewField[2])) then
if((missZ[j] >= z and missZ[j] <= viewField[3]) or (missZ[j] <= z and missZ[j] >= viewField[3])) then
outnearMissile[j] := true;
end if;
end if;
end if;
end for;
for j in 1:K.nStatObs loop
outnearStatObs[j] := false;
if((statX[j] >= x and statX[j] <= viewField[1]) or (statX[j] <= x and statX[j] >= viewField[1])) then
if((statY[j] >= y and statY[j] <= viewField[2]) or (statY[j] <= y and statY[j] >= viewField[2])) then
if((statZ[j] >= z and statZ[j] <= viewField[3]) or (statZ[j] <= z and statZ[j] >= viewField[3])) then
outnearStatObs[j] := true;
end if;
end if;
end if;
end for;
end seeNearObject;
All the inputs are point in a 3D space, and I have a similar function (written better than this) but it works clearly. Is there any error?

you probably solved this, but as far as I can see there are two issues with the code that may be causing the error.
(1) I don't see any initial condition in the algorithm. In OpenModelica you should always have a
when initial() then [...] end when;
in which you specify the starting values of each parameter (except for the ones in Input).
(2) When reading a status related variable var you should always use the pre(var) call, to read the last value of var, not the current. That is because OpenModelica uses algebraic formulas to solve the system and if your model has loops (all big models do) it may lead to this very issue in which the algebraic formula is inconsistent.
Like so
x := x + 2
It should always be something like
x := pre(x) + 2
Hope this helps. :)

Related

Maple error - "illegal use of a formal parameter"

I'M TRYIN TO CREATE A PROGRAM USING MAPLE FOR GAUSSING ELIMINATION BUT I KEEP GETTING THIS ERROR
Gauss := proc (n::posint, A::matrix, c::Vector)
local a, i, k, j, p;
with(MTM):
n := linalg[rowdim](A);
if det(A) = 0 then print('matrice*doit*etre*caree')
else if det(A) <> 0
then a := `<|>`(A, c);
for k to n-1 do
for i from k+1 to n do
if a[i, i] = 0 then swaprow(a, k, i)
else p = a[i, k]/a[k, k];
for j from k+1 to n+1 do a[i, j] = a[i, j]-p*a[k, j]
end do;
end if;
end do;
end do;
else print('rien')
end if; end if; end proc;
Error, (in Gauss) illegal use of a formal parameter
restart;
Gauss := proc(A::Matrix, c::Vector)
local a, i, k, j, m, n, p;
n := linalg[rowdim](A);
m := linalg[coldim](A);
if m <> n then
print("matrice doit etre caree");
else
a := `<|>`(A, c);
for k to n-1 do
for i from k+1 to n do
if a[i, i] = 0 then
a := linalg[swaprow](a, k, i);
else
p := a[i, k]/a[k, k];
for j from k to n+1 do
a[i, j] := a[i, j]-p*a[k, j];
end do;
end if;
end do;
end do;
end if;
return a;
end proc:
c := Vector([2, 3, 4]);
A := Matrix(3, 3, [4, 1, 2, 3, 6, 5, 2, 1, 9]);
Gauss(A, c);
LinearAlgebra:-LUDecomposition(<A|c>, output=U);
There were quite a few mistakes, so let's hope I get most of them.
I didn't bother doing 7. You should do it.
You cannot use with inside a procedure.
Your code uses commands from thelinalg
package, not the MTM package.
Ideally you'd use Matrix&Vector&LinearAlgebra
(instead of your mix of matrix&Vector&linalg(.
Your procedure has n as one of its
parameters, but inside it you also try to
assign a value to n, the argument for which
you passed in as the number 3. That's where
your error message is coming from. You can't
do that.
Several of you lines have just = instead of
:= for assignments. The = does nothing.
The test against det(A)=0 is wrong is wrong
in several ways. I'll just say that it doesn't
actually test whether the A is square.
Compare the row & column dimensions if you
want to test that A is square.
You should be using LinearAlgebra
equivalents instead of the linalg commands
commands swaprow, coldim.
You forgot to have your procedure actually
return the Matrix a.
When your code calls swaprow is was not
actually updating a. It was just throwing
way the result.
It's a sin to not indent your code. It will
lead you to overlook mistakes.

Modelica - iterator with exception?

Slightly generalised example:
How do I make a for loop with exceptions when I define model equations?
The following works:
model Test
Real[9] q;
equation
q[2] = 1.2;
q[4] = 1.4;
for i in {1,3,5,6,7,8,9} loop
q[i] = 0;
end for;
end Test;
But I would rather like to write something like:
model Test
Real[9] q;
equation
q[2] = 1.2;
q[4] = 1.4;
for i in 1:9 and not in {2,4} loop
q[i] = 0;
end for;
end Test;
Is this possible?
This should be possible, as long as you make sure to have an equation for every unknown.
Probably not the perfect solution, but actually pretty readable:
model LoopException
Real[9] q;
equation
q[2] = 1.2;
q[4] = 1.4;
for i in 1:9 loop
if Modelica.Math.Vectors.find(i, {2, 4}) == 0 then
q[i] = 0;
end if;
end for;
end LoopException;
As an alternative, you could also try to write an "Array Constructor with Iterators" (Modelica Language Spec. Sec. 10.4.1), but that probably gets a bit messy...
With 2 helper functions you can easily emulate what you want:
model Test
Real[9] q;
equation
q[2] = 1.2;
q[4] = 1.4;
for i in allExcept(1:9, {2,4}) loop
q[i] = 0;
end for;
end Test;
Here are the functions you need for that:
function contains
"Check if vector v contains any element with value e"
input Integer vec[:];
input Integer e;
output Boolean result;
algorithm
result := false;
for v in vec loop
if v == e then
result := true;
break;
end if;
end for;
end contains;
function allExcept
"Return all elements of vector v which are not part of vector ex"
input Integer all[:];
input Integer ex[:];
output Integer vals[size(all, 1) - size(ex, 1)];
protected
Integer i=1;
algorithm
for v in all loop
if not contains(ex, v) then
vals[i] := v;
i := i + 1;
end if;
end for;
end allExcept;
Note that Modelica tools usually need to know the size of vectors during translation, especially here when you generate equations. Hence, the following line is required:
output Integer vals[size(all, 1) - size(ex, 1)];
It will fail when all or ex contain duplicate elements.
Therefore the model will not translate, if you try something like
for i in allExcept(1:3, {2, 2}) loop

OpenModelica complains about a negative value which can't be negative

Following this question I have modified the energy based controller which I have described here to avoid negative values inside the sqrt:
model Model
//constants
parameter Real m = 1;
parameter Real k = 2;
parameter Real Fmax = 3;
parameter Real x0 = 1;
parameter Real x1 = 2;
parameter Real t1 = 5;
parameter Real v0 = -2;
//variables
Real x, v, a, xy, F, vm, K;
initial equation
x = x0;
v = v0;
equation
v = der(x);
a = der(v);
m * a + k * x = F;
algorithm
if time < t1 then
xy := x0;
else
xy := x1;
end if;
K := Fmax * abs(xy - x) + k * (xy^2 - x^2) / 2;
if abs(xy - x) < 1e-6 then
F := k * x;
else
if K > 0 then
vm := sign(xy - x) * sqrt(2 * K / m);
F := Fmax * sign(vm - v);
else
F := Fmax * sign(x - xy);
end if;
end if;
annotation(
experiment(StartTime = 0, StopTime = 20, Tolerance = 1e-06, Interval = 0.001),
__OpenModelica_simulationFlags(lv = "LOG_STATS", outputFormat = "mat", s = "euler"));
end Model;
However, it keeps giving me the error:
The following assertion has been violated at time 7.170000
Model error: Argument of sqrt(K / m) was -1.77973e-005 should be >= 0
Integrator attempt to handle a problem with a called assert.
The following assertion has been violated at time 7.169500
Model error: Argument of sqrt(K / m) was -6.5459e-006 should be >= 0
model terminate | Simulation terminated by an assert at the time: 7.1695
STATISTICS 
Simulation process failed. Exited with code -1.
I would appreciate if you could help me know what is the problem and how I can solve it.
The code you created does event localization to find out when the condition in the if-statements becomes true and/or false. During this search it is possible that the expression in the square-root becomes negative although you 'avoided' it with the if-statement.
Try reading this and to apply the solution presented there. Spoiler: It basically comes down to adding a noEvent() statement for you Boolean condition...

PL/SQL to PostgreSQL conversion

Please help me to convert this PL/SQL into PostgreSQL. Thank you very much.
Prime Numbers
CREATE TABLE n (n NUMBER);<br/>
CREATE OR REPLACE PROCEDURE prime_number (n NUMBER)<br/>
IS <br/>
prime_count NUMBER := 0;<br/>
y VARCHAR2 (1) := 'N';<br/>
BEGIN<br/>
IF n >= 1
THEN
prime_count := 1;
INSERT INTO n
VALUES (2);
END IF;
IF n >= 2
THEN
prime_count := 2;
INSERT INTO n
VALUES (2);
END IF;
IF n >= 3
THEN
FOR i IN 4 .. n * n * n
LOOP
y := 'N';
FOR j IN 2 .. CEIL (SQRT (i))
LOOP
IF (MOD (i, j) = 0)
THEN
y := 'Y';
EXIT;
END IF;
END LOOP;
IF (y = 'N')
THEN
INSERT INTO n
VALUES (i);
COMMIT;
prime_count := prime_count + 1;
EXIT WHEN prime_count = n;
END IF;
END LOOP;
END IF;<br/>
END;
BEGIN<br/>
prime_number (1000000);<br/>
END;

Can this algorithm be simplified (written cleaner)?

I have this algorithm, but I am not too keen on the many if-statements.
Can someone see if this function can be written in a cleaner way?
rand('twister',101)
n = 10;
f = A.^(0:n)./factorial(0:n);
f = f/sum(f);
n = 10000;
Xi = 2;
X = zeros(1,n);
for i =1:n,
dXi = (-1)^round(rand);
Yi = Xi + dXi;
if Yi > 0 & Yi <= length(f),
if f(Yi) >= f(Xi),
X(i) = Yi;
Xi = Yi;
else
if rand <= f(Yi)/f(Xi),
X(i) = Yi;
Xi = Yi;
else
X(i) = Xi;
end
end
end
X(i) = Xi;
end
I don't know Matlab syntax, but generally something like this:
if (cond1) then
mainAction
else if (cond2) then
mainAction
else
otherAction
can be simplified as:
if (cond1 OR cond2) then
mainAction
else
otherAction
The OR would have to be short-circuiting for exact equivalence, but if cond2 has no side-effects then it doesn't really matter.
This can be simplified by noting that whenever you do X(i) = Yi you also do Xi = Yi and therefore you could just assign X(i) once at the end of the loop. This allows a lot of the other logic to simplify.
Also note that the , at the end of an if-clause is really only necessary in one-line if statements, e.g.
if x < y, do_something, else do_something_else, end
Anyway I get this (you could simplify further into one if statement but perhaps that's less clear. Also having more than one if statement allows breakpoints on particular sections.):
for i =1:n,
dXi = (-1)^round(rand);
Yi = Xi + dXi;
if Yi > 0 & Yi <= length(f)
if f(Yi) >= f(Xi) || rand <= f(Yi)/f(Xi)
Xi = Yi;
end
end
X(i) = Xi;
end