Redeclare model with "outer" parameters - modelica

I tried redeclare model that contain global (outer) parameter. Here simple example of my code:
package tests
model M0
inner parameter Real a = 1;
end M0;
model M1
extends tests.M0;
replaceable tests.M3 c;
end M1;
model M2
outer constant Real a;
end M2;
model M3
extends tests.M2;
Real b;
equation
b = a;
end M3;
model M4
extends tests.M2;
Real b2;
equation
b2 = a;
end M4;
model test1
tests.M1 X;
end test1;
model test2
tests.M1 X(redeclare each tests.M4 c);
end test2;
end tests;
Test1 works fine, but with test2 I have warning An inner declaration for outer component a could not be found and was automatically generated.
Without "inner/outer" all works fine.
The warning occurs even if M3 and model M4 have identically code
model M3 // and M4
outer constant Real a;
Real b;
equation
b = a;
end M3;
or if redeclare the same model
model test3
tests.M1 X(redeclare tests.M3 c);
end test3;
I am using OM 1.18

The issue seems to be that b is defined in M3 but not in M4. Modifying M4 to
model M4
extends tests.M2;
Real b, b2;
equation
b = a;
b2 = a;
end M4;
or
model M4
extends tests.M2;
Real b;
equation
b = a;
end M4;
removes the respective warnings in Dymola.
This comes down to plug-compatibility, which in this example means, that every public variable in M3 must be present in M4 as well.
As plug-compatibility only refers to public variables, defining b to be protected in M3 should also resolve the issue:
model M3
extends tests.M2;
protected
Real b;
equation
b = a;
end M3;
Note: I didn't test it with OpenModelica...

Your code works in Dymola, even though there is one issue:
In M0 you declared a as a parameter
inner parameter Real a = 1;
But in M2 you are looking for a constant
outer constant Real a;
Both tools don't care much about that fact, which seems strange.
In OpenModelica I guess you have hit a bug. You are using inner/outer in an uncommon way. Changing your setup to a more common style with the inner variable defined in a top-level-component (now named World) works:
package tests
model World
inner parameter Real a = 1;
end World;
model M1
replaceable tests.M3 c;
end M1;
model M2
outer World w;
parameter Real a = w.a;
end M2;
model M3
extends tests.M2;
Real b;
equation
b = a;
end M3;
model M4
extends tests.M2;
Real b2;
equation
b2 = a;
end M4;
model test1
inner World w;
tests.M1 X;
end test1;
model test2
inner World w;
tests.M1 X(redeclare each tests.M4 c);
end test2;
end tests;

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

Modelica coding standards / new OpenModelica compiler frontend

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;

Effective creation of Subclasses which have four (2 x 2) options

I am very new to OOP in Matlab. Let's say I have a super class with one property, X. Next I want to define subclasses that has properties V, A, and B, where V is some manipulation of X, with four options:
V = A1*X - B1;
V = A1*X - B2;
V = A2*X - B1;
V = A2*X - B2;
In the actual code the options are something completely different, and it takes quite some time to calculate V, so once it is calculated I definitely want to store it. (In fact my options for A and B are actually discrete choices, so there are really just four possible combinations).
So what I did is: I created a subclass, VClass, with properties A, B, V (and X).
The SuperClass has methods:
function obj = SuperClass(X)
obj.XX = XX;
end
function add_V(obj,A,B)
if A == A1 && B == B1;
obj.A1B1 = VClass();
obj.A1B1.init_V(X,A,B);
elseif A == A2 && B == B1;
obj.A2B1 = VClass();
obj.A2B1.init_V(X,A,B);
et cetera...
end
The VClass has method:
function init_V(obj,X,A,B)
obj.V = A*X - B;
obj.A = A;
obj.B = B;
obj.X = X;
end
The thing that I don't like is that I created subclasses with names A1B1, A1B2, A2B1, and A2B2, so in every method I repeat a lot of code. I suppose I could use 'eval' with creation of a name for the subclass:
if A == A1 && B == B1;
name = 'A1B1';
.....
and in combination with:
eval(['obj.',name,' = VClass();']);
eval(['obj.',name,'.init_V(X,A,B);']);
But I am not too happy about that either, since it makes the code difficult to read.
Does anybody have another suggestion? (and any other comments of course also very welcome, since I just started with OOP)

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);