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;
Related
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;
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;
Problem: the inverse annotation of a function is ignored and the inverse is computed numerically.
According to Modelica Specifications it is possible to specify an inverse of a given function.
In order to test this functionallity I tried with a very trivial model with two functions:
the direct function y(x) = sin(x)
function y_from_x
input Real x;
output Real y;
algorithm
y:=sin(x);
annotation(inverse(x = x_from_y(y)));
end y_from_x;
its inverse function x(y) = asin(y)
function x_from_y
input Real y;
output Real x;
algorithm
x:=asin(y);
end x_from_y;
a couple of releveant equations
y = time;
y = y_from_x(x);
As you may see, in order to retrieve the value of variable x, the function y_from_x should be inverted; consequently, since the inverse annotation explicitly tells how to invert the function, I expect x_from_y to be called.
No, that's not what happens. Even just at the flattening step the inverse function is discarded and the solution of y_from_x is computed numerically with an iteration loop. This happens with both OpenModelica v1.14 and Dymola 2018.
Is this the expected behaviour?
How does this inverse annotation should be used?
Is there a way to avoid such inefficient iterative solution?
Full code
model test_inverse
Real y, x;
function y_from_x
input Real x;
output Real y;
algorithm
y:=sin(x);
annotation(inverse(x = x_from_y(y)));
end y_from_x;
function x_from_y
input Real y;
output Real x;
algorithm
x:=asin(y);
end x_from_y;
equation
y = time;
y = y_from_x(x);
end test_inverse;
The problem in Dymola (and likely also in OpenModelica) is that the function is inlined before the inverse is used, but your syntax is correct.
The inlining can be avoided using:
function y_from_x
input Real x;
output Real y;
algorithm
y:=sin(x);
annotation(LateInline=true, inverse(x = x_from_y(y)));
end y_from_x;
However, note that Dymola does not numerically invert the sine function - instead it uses the built-in inverse for the sine-function; which is similar to asin.
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.
I would like to use a class function/method in my Modelica model as follows:
optimization Moo(objective=-x(finalTime), startTime = 0, finalTime = 12)
parameter Real e = 0.05;
Real x(start=2, fixed=true, min=0, max=100);
input Real v (min=0, max=1);
function omega
input Real t;
output Real y;
algorithm
y := e;
end omega;
equation
der(x) = v*omega(time);
constraint
v<=1;
end Moo;
I would like the variable e in the function omega to be a variable so that I can easily change its value at a later point in time when I am doing a parameter sweep. Unfortunately, the function omega does not seem to know about the variable e and the JModelica compiler returns the error:
Cannot find class or component declaration for e
I would naïvely expect that since omega and e belong to the same class omega would be able to see e.
Is there a way to achieve this?
Member functions are not supported in Modelica, so a function declared inside a model acts like a standalone function without having access to the surrounding model variables.
Member functions are not allowed due to functions need to be pure, i.e. they are not allowed to have any side effect. This is a fundamental assumption in Modelica that makes it possible for a tool to apply symbolic transformation and rearrange calculations.
You can have something like a member function, if you explicitly pass the needed variables as additional input to the function. See this example:
package MemberFunction
model A
Real x=1;
function get_x = MemberFunction.get(u=x);
end A;
function get
input Real u;
output Real y;
algorithm
y := u;
end get;
model Test
A a;
Real x;
equation
x = a.get_x();
end Test;
end MemberFunction;