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.
Related
I have a function that does or does not have a derivative and inverse, depending on values of some parameters/coefficients. Can I make the annotations derivative and inverse conditional somehow?
Something like
function y_from_x
input Real x;
input Boolean hasInverse;
output Real y;
...
equation
...
annotation(inverse(x=x_from_y(y=y) if hasInverse));
end y_from_x;
There is no direct support for that in the Modelica specification.
What you could do is something like:
function y_from_x
input Real x;
input Boolean hasInverse;
output Real y;
...
algorithm
y:=if hasInverse then y_from_x1(x) else y_from_x2(x);
annotation(Inline=true);
end y_from_x;
function y_from_x1
input Real x;
output Real y;
...
algorithm
y:=y_from_x2(x);
annotation(inverse(x=x_from_y(y=y)));
end y_from_x1;
function y_from_x2
input Real x;
output Real y;
...
algorithm
...
end y_from_x2;
I am trying to apply Newton's method in Matlab, and I wrote a script:
syms f(x)
f(x) = x^2-4
g = diff(f)
x_1=1 %initial point
while f(['x_' num2str(i+1)])<0.001;% tolerance
for i=1:1000 %it should be stopped when tolerance is reached
['x_' num2str(i+1)]=['x_' num2str(i)]-f(['x_' num2str(i)])/g(['x_' num2str(i)])
end
end
I am getting this error:
Error: An array for multiple LHS assignment cannot contain M_STRING.
Newton's Method formula is x_(n+1)= x_n-f(x_n)/df(x_n) that goes until f(x_n) value gets closer to zero.
All of the main pieces are present in the code present. However, there are some problems.
The main problem is assuming string concatenation makes a variable in the workspace; it does not. The primary culprit is this line is this one
['x_' num2str(i+1)]=['x_' num2str(i)]-f(['x_' num2str(i)])/g(['x_' num2str(i)])
['x_' num2str(i+1)] is a string, and the MATLAB language does not support assignment to character arrays (which is my interpretation of An array for multiple LHS assignment cannot contain M_STRING.).
My answer, those others' may vary, would be
Convert the symbolic functions to handles via matlabFunction (since Netwon's Method is almost always a numerical implementation, symbolic functions should be dropper once the result of their usage is completed)
Replace the string creations with a double array for x (much, much cleaner, faster, and overall better code).
Put a if-test with a break in the for-loop versus the current construction.
My suggestions, implemented, would look like this:
syms f(x)
f(x) = x^2-4;
g = diff(f);
f = matlabFunction(f);
g = matlabFunction(g);
nmax = 1000;
tol = 0.001;% tolerance
x = zeros(1, nmax);
x(1) = 1; %initial point
fk = f(x(1));
for k = 1:nmax
if (abs(fk) < tol)
break;
end
x(k+1) = x(k) - f(x(k))/g(x(k));
fk = f(x(k));
end
I am trying to solve a particular system of ODE's dF/dt = A*F, F_initial = eye(9). Being a Matlab novice, I am trying to somehow use the implemented ode45 function, and I found useful advises online. However, all of them assume A to be constant, while in my case the matrix A is a function of t, in other words, A changes with each time step.
I have solved A separately and stored it in a 9x9xN array (because my grid is t = 0:dt:2, N=2/dt is the number of time-steps, and A(:,:,i) corresponds to it's value at the i-th time step). But I can't implement this array in ode45 to eventually solve my ODE.
Any help is welcomed, and please tell me if I have missed anything important while explaining my problem. Thank you
First of all, F must be a column vector when using ode45. You won't ever get a result by setting F_initial = eye(9), you'd need F = ones(9,1).
Also, ode45 (documentation here, check tspan section) doesn't necessarily evaluate your function at the timesteps that you give it, so you can't pre-compute the A matrix. Here I'm going to assume that F is a column vector and A is a matrix which acts on it, which can be computed each timestep. If this is the case, then we can just include A in the function passed to ode45, like so:
F_initial = ones(9,1);
dt = 0.01;
tspan = 0:2/dt:2;
[t, F] = ode45(#(t,F) foo(t, F, Ainput), tspan, F_initial);
function f = foo(t, F, Ainput)
A = calculate_A(t, Ainput);
f = A*F;
end
function A = calculate_A(t, Ainput)
%some logic, calculate A based on inputs and timestep
A = ones(9,9)*sqrt(t)*Ainput;
end
The #(x) f(x,y) basically creates a new anonymous function which allows you to treat y as a constant in the calculation.
Hope this is helpful, let me know if I've misunderstood something or if you have other questions.
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;
I have an existing function of two variables (x,y) called discriminant defined in the following way:
discriminant = xSecondPart * ySecondPart - xySecondPart.^2;
Where xSecondPart and ySecondPart are the second partial derivatives of a function f. xySecondPart is the partial derivative with respect to x of the partial derivative with respect to y of the same function f.
I need to print out the values of discriminant at each value of x in the matrix xAns.
The below code is not working...
for idx = 1:numel(xAns)
disp(discriminant(xAns(idx)));
end
Hopefully someone can provide a solution. Thank you
Best...SL
If you define the function discriminant anonymously, like so:
descriminant = #(x) 24*x.^2 - 32;
Then all you have to do is type the following statement in the command line or function you're running:
D = discriminant(xAns)
If your function has been defined using the elementwise operator '.' wherever necessary, then the statement above will print out the discriminant function evaluated at every element of the matrix xAns, regardless of its size or shape. The values returned will be in the same shape as the matrix xAns. I think that would be the easiest way to solve your problem.