Is there any other elegant way to redeclare both type AND values in nested modelica models - modelica

I have a set of nested models and sub-models, as well as records. Here is the simple example:
package Unnamed1
record A
Real a;
end A;
record B
extends A;
Real b;
end B;
record C
extends B;
Real c;
end C;
model M
replaceable record Data = A;
parameter Data data;
end M;
model H
replaceable record Data = A;
parameter Data data;
protected
M m(redeclare replaceable record Data = Data, data=data);
end H;
model R
parameter B bb(b=5, a=2.0);
parameter A aa(a=4.0);
parameter C cc(a=0.0, b=0.2, c=0.8);
H h(redeclare record Data = B, data=bb);
H g(redeclare record Data = A, data = aa);
H f(redeclare record Data = C, data = cc);
end R;
end Unnamed1;
They are 3 sets of nested records (A, B, C), and 3 nested models (R, H, M). I want to pass an instance of a record from R to M through H, with instances having different types. That way of doing I found sounds heavy, passing both type of record AND its content through a different variable. When I have 2 levels, no problem, I can use redeclare that is fine. When I have more than two levels of nested classes (let say 5), I don't know how to pass both Type and instance at the same time. Note, in H, m is protected.
Any though on doing in a different way ?

One solution I found is by passing a record encapsulating an instance of record (called component in Modelica terminology). The new code is:
package Unnamed1
record A
Real a=0.0; // value for Dymola... don't know why yet
end A;
record B
extends A;
Real b;
end B;
record C
extends B;
Real c;
end C;
model M
replaceable record Data = A;
Data data;
end M;
model H
replaceable record Data = A;
M m(redeclare record Data = Data);
end H;
model R
record AA
extends A(a=5);
end AA;
record BB
extends B(b=5, a=2.0);
end BB;
record CC
extends C(a=0.0, b=0.2, c=0.8);
end CC;
H f(redeclare record Data = AA);
H g(redeclare record Data = BB);
H h(redeclare record Data = CC);
end R;
end Unnamed1;
The main difference being instead of passing a component B parameter B bb(b=5, a=2.0); to the various sub-models, one passes a record BB
containing values of B
record BB
extends B(b=5, a=2.0);
end BB;
One then have to redeclare the record in the sub-classe definition, which can be repetated again and again.
Dummy values have to defined in the base record A, let say a=0.0 for Dymola to accept the code, while OpenModelica and SimulationX does not need it.

I want to present a slight variation of the other answer and then explain how it is often solved.
The variation is that you can modify value and class in the redeclare without having explicit record declarations.
package Unnamed1
record A
parameter Real a;
end A;
record B
extends A;
parameter Real b;
end B;
record C
extends B;
parameter Real c;
end C;
model M
replaceable record Data = A;
parameter Data data;
end M;
model H
replaceable record Data = A;
protected
M m(redeclare replaceable record Data = Data);
end H;
model R
H h(redeclare record Data = B(b=5,a=2.0));
H g(redeclare record Data = A(a=4.0));
H f(redeclare record Data = C(a=0, b=0.2, c=0.8));
end R;
end Unnamed1;
However, when looking inside H we see that even if the model is legal the new parameters cannot be used. Thus a more normal case is that it is a model with some parameters in it leading to:
package Unnamed2
partial model SO
output Real y;
end SO;
model Constant
extends SO;
parameter Real b;
equation
y=b;
end Constant;
model Ramp
extends SO;
parameter Real b;
parameter Real k;
equation
y=b+time*k;
end Ramp;
model Other
extends SO;
parameter Real offset;
equation
y=time+offset;
end Other;
model M
replaceable model Source = SO;
Source source;
protected
Real x;
equation
der(x)=source.y;
end M;
model H
replaceable model Source = SO;
protected
M m(redeclare replaceable model Source = Source);
end H;
model R
H h(redeclare model Source = Constant(b=5));
H g(redeclare model Source = Other(offset=4.0));
H f(redeclare model Source = Ramp(b=0.2, k=0.8));
end R;
end Unnamed2;

Related

Accessing record parameters in Modelica without declaring a record instance

In Modelica, I'm able to access the contents of a record instance like so:
model Unnamed1
record Example
parameter Real x = 5;
end Example;
Example ex;
Real test;
equation
test = ex.x;
end Unnamed1;
However, I'd like to access the contents of the record without declaring an instance of the record, like so:
model Unnamed1
record Example
parameter Real x = 5;
end Example;
Real test;
equation
test = Example().x;
end Unnamed1;
...but this doesn't work. Is there some way to achieve what I'm trying to do?
Yes, it is possible without having an actual instance in the model but it requires some extra code.
model Unnamed1
record Example
parameter Real x = 5;
end Example;
function getX
input Example r;
output Real x;
algorithm
x:=r.x;
end getX;
Real test;
equation
test = getX(Example());
end Unnamed1;
(I'm aware that it is cheating by having the instance in the function, but....)
Another option is
for r in {Example()} loop
test=r.x;
end for;
(allowed according to https://github.com/modelica/ModelicaSpecification/issues/1521 )
This is not possible (even from a grammar point of view). The right hand side of dot (.) needs to be a class or component reference. You can only access constants/parameters in packages via the dot notation.
package X
constant Real x = 1;
end X;
model M
Real x = X.x
end M;

How to parametrise a redeclaration?

I have a package for representing certain media, built similar to but not exactly like Modelica.Media. I want to allow the user to choose between different functions for a particular property without having to change the way the remaining properties are calculated.
The package is:
package myPac
replaceable function prop = F1 constrainedby partialF
annotation (choicesAllMatching=true);
function partialF
input Real x;
output Real y;
end partialF;
function F1
extends partialF;
algorithm
y := x;
end F1;
function F2
extends partialF;
algorithm
y := 2*x;
end F2;
end myPac;
I want to then choose F1 or F2 from inside a model.
model myModel
replaceable package pack1 = myPac(redeclare function prop = pack1.F2);
Real x;
Real y;
equation
y = pack1.prop(x);
end myModel;
works as expected. How can I parametrise the redeclaration of prop so that it can be set from the parameters dialog box?
I was looking of something like:
model myModel2
replaceable package pack1 = myPac(redeclare function prop = if a == 1 then pack1.F1 else pack1.F2);
parameter Integer a = 1;
Real x;
Real y;
equation
y = pack1.prop(x);
end myModel2;
which is clearly incorrect syntax. Also, the choicesAllMatching=true in the declaration of prop does show me a drop-down menu, but there are no choices listed.
How can I parametrise the redeclaration of prop so that it can be set
from the parameters dialog box?
You don't need the additional parameter a to select the functions. Simply click the edit button of prop to get the parameter window of the selected replaceable package, where you can choose between F1 and F2.
I added an animation below to make this clearer.
Also, the choicesAllMatching=true in the declaration of prop does show
me a drop-down menu, but there are no choices listed.
This works for me, as you can see in the animation. Note that I declared the function partialF as partial, so it is not included in the drop-down menu. And I added another choicesAllMatching annotation to the replaceable package pack1 in myModel to create another drop-down for the selection of pack1 (like Hans did in his answer).
You cannot currently have redeclarations depending on parameter-values.
However, you can make a choice between two packages that will appear in the dialog box:
package myPac
replaceable function prop = F1 constrainedby partialF
annotation (choicesAllMatching=true);
function partialF
input Real x;
output Real y;
end partialF;
function F1
extends partialF;
algorithm
y := x;
end F1;
function F2
extends partialF;
algorithm
y := 2*x;
end F2;
end myPac;
package myPac1=myPac(redeclare function prop=myPac.F1);
package myPac2=myPac(redeclare function prop=myPac.F2);
model myModel
replaceable package pack1 = myPac annotation(choicesAllMatching=true);
Real x;
Real y;
equation
y = pack1.prop(x);
end myModel;

Setting enumeration-indexed vector in derived model

I define
type Enum = enumeration(A, B, C);
and
partial model PM
parameter Real[Enum] a;
...
end PM;
and
model M
extends PM(a = {1, 2, 3});
...
end M;
which gives an error. My best guess is that the a = {1, 2, 3} is the culprit. Is this indeed illegal, and if so, how can I set a in M?
UPDATE
Upon further examination I've found that everything above is indeed legal. Let me just go the whole hog:
type Enum = enumeration(A, B, C);
connector Conn
Real[Enum] a;
flow Real[Enum] f;
end Conn;
model M1
Conn conn;
equation
conn.f = -conn.a;
end M1;
model M2
Conn conn;
initial equation
conn.a = {1, 2, 3};
equation
der(conn.a) = conn.f;
end M2;
model M3
M1 m1;
M2 m2;
equation
connect(m1.conn, m2.conn);
end M3;
This fails to build. But if I just change each Enum in the connector class to 3, then it works.
The example is (as far as I can tell) legal, and some tools already handle it (assuming there is nothing else hidden).
Since you need a tool-specific work-around you need to specify which tool.
The legality will be clarified further in later versions of the Modelica specification since it was unclear - https://trac.modelica.org/Modelica/ticket/2212#comment:3

Replaceable function and function calls from strings

The following three questions are tied together so please forgive the length of the post.
Using Dymola 2016.
Using a replaceable function call within a model provides the opportunity for the user to have the drop down options. Example below:
model Test1
parameter Real x = 1;
Real y;
replaceable function a=b constrainedby d annotation(choicesAllMatching=true);
equation
y = a(x);
end Test1;
Doing the same replaceable function call within a function seems to not permit the same drop down functionality with the the function is called (i.e. right click call function in package browser. I assume this is intentional as a function is typically called within other functions/models. Example below:
function Test2
input Real x;
output Real y;
replaceable function a=b constrainedby d annotation(choicesAllMatching=true);
algorithm
y :=a(x);
end Test2;
Question #1. Is it possible to use a replaceable function call within a function in the same way you do a model? If so, what is the appropriate syntax? Alternative approach?
Alternatively, a different option would be to perform the replaceable function call in the model and then pass the result to another function that then makes the appropriate call. Example shown below:
model Test3mod
parameter Real x = 1;
Real y;
replaceable function a=b constrainedby d annotation(choicesAllMatching=true);
equation
y = Test3func(x,a);
end Test3mod;
Which passes parameter x and function handle a to:
function Test3func
input Real x;
input ???? a;
output Real y;
algorithm
y :=a(x);
end Test3func;
Question #2. Is this allowable in Modelica and if so, how? Alternative approach?
Question #3. Is it possible to define a string and turn that into a the name of a function. Example below:
model Test4
parameter String 'functionname';
parameter Real x = 1;
Real y;
equation
y = functionname(x);
end Test4;
Thank you in advance! I appreciate your feedback as I continue to explore the use of Modelica.
This should work fine:
model Test3mod
parameter Real x = 1;
Real y;
replaceable function a=b constrainedby d annotation(choicesAllMatching=true);
equation
y = Test3Func(x,a);
end blah;
function Test3func
input Real x;
input d f;
output Real y;
algorithm
y := f(x);
end Test3func;

Extract array from connector array

It seems that it is at least not encouraged to write Modelica functions with connectors as arguments. I get a warning if I try it.
Assume I have a connector
connector con
Real x;
Real y;
end con;
a record
record rec
Real x;
Real y;
end rec;
and a function
function f
input rec r[:];
output Real z;
algorithm
...
end f;
Given an array of connectors, i.e. con c[N], how can I convert it into an array of records rec?
One approach would be to use a function
function convert
input Integer N;
input Real x[N];
input Real y[N];
output rec z[N];
algorithm
z.x := x;
z.y := y;
end convert;
and call it via convert(size(c, 1), c.x, c.y).
Is there a simpler way?