Modelica coding standards / new OpenModelica compiler frontend - modelica

looks like a issue with new OpenModelica compiler frontend. I am using official release version of openmodelica 1.14 on windows-7 64bit OS.
package Test1_14
model M1
parameter Integer size = 2 "matrix size";
parameter Real A[size] = {1.0, 1.0};
Real B[size];
Real T = 1;
Real P = 2;
equation
B = A * (T/P);
end M1;
model M1_Extn
Real C[size];
Real D[size];
equation
for J in 1:size loop
C[J] = Func1(T);
D[J] = C[J] / P;
end for;
end M1_Extn;
function Func1
input Real a;
output Real b;
algorithm
b := a*a;
end Func1;
model M1_Combined
parameter Integer size = 2 "matrix size";
Real B[size];
Real T = 1;
Real P = 2;
extends M1_Extn;
equation
B = D;
end M1_Combined;
end Test1_14;
When I compile the model ‘M1_Combined’, the code generation fails with new OpenModelica compiler frontend. Export FMU also fails with the same error.
Is my code as per Modelica programing standards?
How do I declare variables - size, T, P in the model M1_Extn and still use keyword ‘extends’ in ‘M1_Combined’ ?

This is because the old frontend did not handle the "extends" correctly, according to the Modelica Specification. The new frontend does it correctly.
To be clear, you cannot define a variable in this class and then use it in the extends any other way than via a modification (and via inner/outer, via redeclare as element). An example is below, you cannot use a inside M1.
package TestExtends
model M1
parameter Real b = a;
end M1;
model M2
parameter Real a = 1;
extends M1;
end M2;
end TestExtends;
To fix your model so that is according to Modelica standards, you can do:
package Test1_14
model M1
parameter Integer size = 2 "matrix size";
parameter Real A[size] = {1.0, 1.0};
Real B[size];
Real T = 1;
Real P = 2;
equation
B = A * (T/P);
end M1;
model M1_Extn
parameter Integer size = 2;
Real T = 1;
Real P = 2;
Real C[size];
Real D[size];
equation
for J in 1:size loop
C[J] = Func1(T);
D[J] = C[J] / P;
end for;
end M1_Extn;
function Func1
input Real a;
output Real b;
algorithm
b := a*a;
end Func1;
model M1_Combined
extends M1_Extn(size=2, T = 1, P = 2);
Real B[size]; // this one works as you can use things defined in extends.
equation
B = D;
end M1_Combined;
end Test1_14;

Related

Continuous variable used in clocked when clause is automatically discretized

model test
import Modelica.Constants.pi;
Real f;
discrete Real g;
Clock clk=Clock(0.1);
equation
f = sin(pi*time);
when Clock(0.1) then
if f >= 0 then
g = (sin(pi*time)) - 0.1;
else
g = (sin(pi*time)) + 0.1;
end if;
end when;
end test;
f is assigned as a continuous function. I want to sample the value of g depended on f, but f also be changed to a discrete value. Is there anything wrong ?
The clock partitioning sees f as being used directly inside the when Clock and thus f is also seen as a clocked variable.
Use sample(f) if that is not desired:
model test
import Modelica.Constants.pi;
Real f;
discrete Real g;
Clock clk=Clock(0.1);
equation
f = sin(pi*time);
when Clock(0.1) then
if sample(f) >= 0 then
g = (sin(pi*time)) - 0.1;
else
g = (sin(pi*time)) + 0.1;
end if;
end when;
end test;
See also: Failure to handle clock inference in Dymola

getting the Translation Error Class not found when tryin gto generate random variable

I'm trying to follow this example to generate a random function of time:
model testData
extends Modelica.Icons.Example;
parameter Real k = 1.0;
Real theta1;
Real theta2;
parameter Real tau = 1.0;
parameter Modelica.SIunits.Period samplePeriod = 0.05;
parameter Integer globalSeed = 30020;
output Real omega1;
algorithm
when initial() then
state1024 := Generators.Xorshift1024star.initialState(localSeed, globalSeed);
omega1 := 0;
elsewhen sample(0,samplePeriod) then
(omega1,state1024) := Generators.Xorshift1024star.random(pre(state1024));
end when;
public
parameter Integer id = Utilities.initializeImpureRandom(globalSeed);
discrete Real rImpure;
Integer iImpure;
algorithm
when initial() then
rImpure := 0;
iImpure := 0;
elsewhen sample(0,samplePeriod) then
rImpure := Utilities.impureRandom(id=id);
iImpure := Utilities.impureRandomInteger(
id=id,
imin=-1234,
imax=2345);
end when;
initial equation
theta1 = 0;
theta2 = 0;
der(theta2) = 0;
equation
der(theta1) = omega1;
der(der(theta2)) = tau + k * (theta1 - theta2);
annotation(experiment(StartTime = 0, StopTime = 10, Tolerance = 1e-6, Interval = 0.02));
end testData;
however, I get the error message:
Translation Error
Class Utilities.initializeImpureRandom not found in scope testData (looking for a function or record).
Translation Error
Error occurred while flattening model testData
I would appreciate if you could help me understand what is the problem and how I can solve it.
You were missing some imports, see below, some variable declarations and you were using der(der(...)) which doesn't work, you need to bind the internal der to a variable. This model below compiles and simulates (I don't know if the results are fine or not).
model testData
extends Modelica.Icons.Example;
import Modelica.Math.Random.Generators;
import Modelica.Math.Random.Utilities;
parameter Real k = 1.0;
Real theta1;
Real theta2;
Real der_theta2;
parameter Real tau = 1.0;
parameter Modelica.SIunits.Period samplePeriod = 0.05;
parameter Integer globalSeed = 30020;
parameter Integer localSeed = 614657;
output Real omega1;
discrete Integer state1024[33](each start=0, each fixed = true);
algorithm
when initial() then
state1024 := Generators.Xorshift1024star.initialState(localSeed, globalSeed);
omega1 := 0;
elsewhen sample(0,samplePeriod) then
(omega1,state1024) := Generators.Xorshift1024star.random(pre(state1024));
end when;
public
parameter Integer id = Utilities.initializeImpureRandom(globalSeed);
discrete Real rImpure;
Integer iImpure;
algorithm
when initial() then
rImpure := 0;
iImpure := 0;
elsewhen sample(0,samplePeriod) then
rImpure := Utilities.impureRandom(id=id);
iImpure := Utilities.impureRandomInteger(
id=id,
imin=-1234,
imax=2345);
end when;
initial equation
theta1 = 0;
theta2 = 0;
der(theta2) = 0;
der_theta2 = 0;
equation
der(theta1) = omega1;
der(theta2) = der_theta2;
der(der_theta2) = tau + k * (theta1 - theta2);
annotation(experiment(StartTime = 0, StopTime = 10, Tolerance = 1e-6, Interval = 0.02));
end testData;
The example Modelica.Math.Random.Examples.GenerateRandomNumbers uses relative class paths.
Utilities.initializeImpureRandom for example points to Modelica.Math.Random.Utilities.initializeImpureRandom, which works due to the package hierarchy
Modelica
|- Math
|- Random
|- Examples
|- Utilities
If you copy the code of the example to a different location, the relative paths will not work anymore.
Dymola updates relative paths when models are duplicated (via New > Duplicate Class). Openmodelica apparently not.
Just add the following two imports to the top of your code and the class paths will work:
import Modelica.Math.Random.Generators;
import Modelica.Math.Random.Utilities;
But your model contains additonal errors:
The declaration of the variables localSeed and state1024 is missing. Just copy them from the original example
der(der(theta2)) is not supported. Create an intermediate variable der_theta2 = der(theta2)

Including a causal relation in a Modelica simulation leads to translation Error while flattening model

I want to simulate a controller for a mass-spring model which works based on energy:
model model
//parameters
parameter Real m = 1;
parameter Real k = 1;
parameter Real Fmax = 3;
parameter Real x0 = 1;
parameter Real x1 = 2;
parameter Real t1 = 1;
//variables
Real x, v, a, xy, vm;
initial equation
x = x0;
v = 2;
equation
v = der(x);
a = der(v);
m * a + k * x = F;
algorithm
vm := sign(xy - x)*sqrt(2 * (Fmax * abs(xy - x) + k * (xy^2 - x^2) / 2) / m);
// step signal
if time < t1 then
xy := x0;
else
xy := x1;
end if;
if xy == x then
F := k * x;
else
F := sign(vm - v) * Fmax;
end if;
end model;
But it leads to the error message:
Translation Error
Error occurred while flattening model
I would appreciate it if you could help me know what is the problem and how I can fix it.
P.S.1. SIMULINK is also not able to finish!
P.S.2. New version of the code can be seen here.
P.S.3. According to this discussion on Discord, the algorithm section was not really meant for casual relations. More information about the keyword is here.

Modelica: Mixing connectors and direct inputs

The following Modelica package - while neither being particularly useful nor interesting - does not yield any warnings.
package P
connector C
Real c;
end C;
model A
input C x;
output Real y;
equation
y = x.c;
end A;
model B
input C inp;
output C out;
A a;
equation
a.x = inp;
out.c = a.y;
end B;
end P;
However, when A does not use connectors as in the following case, there is a warning: The following input lacks a binding equation: a.x. Clearly, there is a binding equation for a.x. Why is there such a warning?
package P
connector C
Real c;
end C;
model A
input Real x;
output Real y;
equation
y = x;
end A;
model B
input C inp;
output C out;
A a;
equation
a.x = inp.c;
out.c = a.y;
end B;
end P;
The issue here is that there is not a binding equation. There is only an ordinary equation. A binding equation is one that is applied as a modification to the element, e.g.
model B
input C inp;
output C out;
A a(x=inp.c) "Binding equation";
equation
out.c = a.y;
end B;
Note that in general, if two things are connectors, they should not be equated, they should be connected. That will help you avoid this issue. So in your first version of B:
model B
input C inp;
output C out;
A a;
equation
connect(a.x, inp);
out.c = a.y;
end B;
The reason for the binding equation restriction has to do with making sure components are balanced. You can read more about that in the specification or in Modelica by Example. By using it as a binding equation, it makes it clear that this equation can be used to solve for this variable (i.e., the term in the equation containing that variable won't vanish or be ill-conditioned).

Abstract switch in Modelica

I would like to motivate a question I asked before about a Modelica array of partial model. Consider the following model of a switch between 2 controllers.
model Switch
input Real u;
input Integer sel;
output Real y;
protected
Real x;
equation
if sel == 1 then
y = 0.1 * (0 - u);
der(x) = 0;
else
y = 0.1 * (0 - u) + 0.2 * x;
der(x) = 0 - u;
end if;
end Switch;
Let's ignore the fact that the PI controller may break when it is not selected for some time due to divergence of x. This can be fixed by resetting x when the PI controller is selected. However, this is not the point here.
I want to abstract this switch in 2 ways. Firstly, to switch among a parametric number of controllers. Secondly, to abstract controllers using partial models. Let Ctrl be the partial model of a controller.
partial model Ctrl
input Real u;
output Real y;
end Ctrl;
We can instantiate the two controllers embedded in the switch as follows.
model P extends Ctrl;
equation
y = 0.1 * (0 - u);
end P;
model PI extends Ctrl;
protected
Real x;
equation
y = 0.1 * (0 - u) + 0.2 * x;
der(x) = 0 - u;
end PI;
The abstract version of the switch is supposed to be something like:
model Switch
parameter Integer N(min=1);
Ctrl c[N];
input Real u;
input Integer sel(min=1, max=N);
output Real y;
equation
for i in 1:N loop
c[i].u = u;
end for;
y = c[sel].y;
end Switch;
However, this model has some problems. Firstly, it is not clear how this model can be instantiated, e.g. with one P and one PI controller. Secondly, I get a warning which surprises me, namely: The following input lacks a binding equation: c[1].u
Is it possible to do express this abstract switch in Modelica in some way?
This doesn't work with an array of models as you cannot bind it to different models via a modification. You need to specify all the controllers you have inside the GenericSwitch. You could generate the GenericSwitch and Switch model automatically if needed.
partial model Ctrl
input Real u;
output Real y;
end Ctrl;
model P
extends Ctrl;
equation
y = 0.1 * (0 - u);
end P;
model PI
extends Ctrl;
protected
Real x;
equation
y = 0.1 * (0 - u) + 0.2 * x;
der(x) = 0 - u;
end PI;
model GenericSwitch
replaceable model MyCtrl1 = Ctrl;
replaceable model MyCtrl2 = Ctrl;
MyCtrl1 c1(u = u);
MyCtrl2 c2(u = u);
input Real u;
input Integer sel;
output Real y;
equation
y = if sel == 1 then c1.y else c2.y;
end GenericSwitch;
model Switch = GenericSwitch(
redeclare model MyCtrl1 = P,
redeclare model MyCtrl2 = PI);
I guess it should work with something like:
model GenericSwitch
parameter Integer N(min=1);
replaceable model MyCtlr = Ctrl constrainedby Ctrl;
MyCtlr c[N](each u = u);
input Real u;
input Integer sel(min=1, max=N);
output Real y;
equation
y = c[sel].y;
end GenericSwitch;
model PSwitch = GenericSwitch(redeclare model MyCtrl = P);
model PISwitch = GenericSwitch(redeclare model MyCtrl = PI);