Internal error in code generation for pre - modelica

I try to avoid the algebraic loop in Modelica by using pre operator, but when I use something like pre(x>0.5), there will be an error of Internal error in code generation for pre.
And if I use pre(cond), where cond is a boolean type variable, there won't be any error.
My question is: Is there some regulation of pre operator which requires that I could NOT use expressions within pre operator.
Here are the code and screenshot:
model WithAlgebraicLoop_Wrong2
"Demonstration of how to avoid generating algebraic loop,
but end up with internal error in code generation for pre"
Real x,y(start=1,fixed=true);
equation
when pre(x>0.5) then
y=1*time;
end when;
x=sin(y*10*time);
end WithAlgebraicLoop_Wrong2;
model WithAlgebraicLoop_Right "Demonstration of how to avoid generating algebraic loop"
Real x,y(start=1,fixed=true);
Boolean cond;
equation
cond=x>0.5;
when pre(cond) then
y=1*time;
end when;
x=sin(y*10*time);
end WithAlgebraicLoop_Right;

You can read in the Modelica Language Specification (section 3.7.3 on event related operators -> table) that the argument of pre needs to be a variable, but not an expression.

Related

Connect parameter variables in expandable connector

Two models are connected via an (empty) expandable connector.
One of the two, makes a connection between the expandable connector and a parameter variable.
I didn't expect any issue. On the contrary, I had some issues:
OpenModelica compiles Version 2, but not Version 1
[bus_param_out]: Failed to instantiate equation connect(controlBus.num, numberPar);
Translation Error: Error occurred while flattening model bus_param
Dymola does not compile either Version 1 or Version 2
Connect does not refer to connectors in connect(bus_in.controlBus.num, bus_in.num);
but bus_in.num is a Real and Modelica Specifications says
All components in an expandable connector are seen as connector instances even if they are not declared as such [i.e. it is possible to connect to e.g. a Real variable].
What am I doing wrong? Am I missing something?
My final goal is to link a parameter variable to an expandable connector (e.g. inform different vehicle components about the number of battery cells, let's say) without the need of an additional redundant variable. Is this possible?
The test code is the following:
bus_param.mo
model bus_param
bus_param_in bus_in;
bus_param_out bus_out;
equation
connect(bus_in.controlBus, bus_out.controlBus);
end bus_param_custom;
bus_param_in.mo
model bus_param_in
Real num;
bus controlBus;
equation
connect(controlBus.num, num);
end bus_param_in;
bus_param_out.mo - Version 1
model bus_param_out
parameter Real numberPar = 3.0;
bus controlBus;
equation
connect(controlBus.num, numberPar);
end bus_param_out;
bus_param_out.mo - Version 2
model bus_param_out
parameter Real numberPar = 3.0;
Real number;
bus controlBus;
equation
number = numberPar;
connect(controlBus.num, numberPar);
end bus_param_out;
bus.mo
expandable connector bus
end bus;
f.wue already showed how to write a parameter to the bus.
This post additionally explains how to read the value without increasing the variability (so it stays a parameter).
To make its usage easier, here is the complete code of a demo package to show how to read and write parameters on busses.
It works with Dymola 2019 FD01 in pedantic mode and OMEdit v1.13.2.
package ParmeterToBus
expandable connector bus
end bus;
model bus_param_out
parameter Real numberPar;
Modelica.Blocks.Sources.Constant helper(k=numberPar);
bus controlBus;
equation
connect(controlBus.number, helper.y);
end bus_param_out;
model bus_param_in
Modelica.Blocks.Interfaces.RealOutput buffer;
bus controlBus;
final parameter Real num(fixed=false); // users should not modify it, hence its final
initial equation
num = buffer;
equation
connect(buffer, controlBus.number);
end bus_param_in;
model example
bus_param_in bus_in;
bus_param_out bus_out(numberPar=7);
equation
connect(bus_in.controlBus, bus_out.controlBus);
end example;
end ParmeterToBus;
Note that the implementation is far from being straightforward.
Some tweaks are necessary along with helper classes to overcome the following restrictions:
Only connectors can be used in connect statements.
So we need
an instance of an constant block to write the value
(helper in the code above)
an instance of an RealOutput connector to read the value
(buffer in the code above)
Models and blocks are not allowed to have the prefix parameter.
Therefore wee need the constant block to write the value, we cannot use a RealOutput connector here.
For parameters usually an initial equation is automatically generated from its binding equation.
To prevent this, we have to set (fixed=false). This allows us to assign the parameter in the initialization phase with the value of a variable of higher variability - in our case the buffer.
You could use
Modelica.Blocks.Interfaces.RealOutput num
to declare a Real that can be used in a connect statement.
EDIT:
As far as i know, connecting a parameter to a connector is not possible. Dymola will yield the error:
Connect does not refer to connectors in connect
The official way would be to use Modelica.Blocks.Sources.Constant, which is equivalent to RealOutput. You can directly use a parameter like this:
model bus_param_out
parameter Real number = 3;
Modelica.Blocks.Sources.Constant num_con(k=number);
bus controlBus;
equation
connect(controlBus.num, num_con.y);
end bus_param_out;
When using expandable connectors and connect these connectors, you have to make sure to set bus.numonly once. Everything else will result in an error.
Try connecting everything with the graphical interface, that will maybe clear things up.
You can use the expandable connector outside of connect like this:
model bus_param_out
Real number_of_bus;
parameter Real number = 3;
Modelica.Blocks.Sources.Constant num_con(k=number);
bus controlBus;
equation
connect(controlBus.num, num_con.y);
number_of_bus = controlBus.num;
end bus_param_out;
But trying to declare parameter Real number_of_bus will result in the following error:
The variability of the definition equation: number_of_bus =
controlBus.num; is higher than the declared variability of the
variables.
because the connector is time-variant and the parameter constant.

Creating a function handle to an overloaded `end` function

MATLAB allows overloading various operators for custom classes. One of the unlisted overloadable operators is end, as can be learned from \matlab\lang\end.m:
% END(A,K,N) is called for indexing expressions involving the object A
% when END is part of the K-th index out of N indices. For example,
% the expression A(end-1,:) calls A's END method with END(A,1,2).
An example of such a method is table.end (paste in the MATLAB command line and press "Open Selection" to go to its definition; it is defined in ...\matlab\datatypes\#tabular\end.m).
Unlike a normal method, one cannot simply write hEnd = #end, because this gives the error:
>> hEnd = #end;
hEnd = #end;
↑
Error: Illegal use of reserved keyword "end".
On the other hand, writing e = str2func('end'); works, but it links to the default end function (even when temporarily switching to the folder where the desired end.m is found).
Failed attempts include str2func('table>end');, str2func('table\end');, str2func('table.end'); and #(a,b,c)table.end(a,b,c);.
My question: How do I create a handle to the end function of a specific class?
Overloading — If the function you specify overloads a function in a class that is not a fundamental MATLAB class, the function is not associated with the function handle at the time it is constructed. Instead, MATLAB considers the input arguments and determines which implementation to call at the time of evaluation.
Function handles store their absolute path, so when you have a valid handle, you can invoke the function from any location. You do not have to specify the path to the function when creating the handle, only the function name.
so if your 'end' function is in matlab path , matlab consider it as a candidate for evaluation depending on the inputs,in your case if input object is of 'table' class type the feval(str2func('end'),i,j) evaluate the end function which is defined in the folder #table/end.m

Julia - n-nested loops

Im trying to make a n-nested loop method in Julia
function fun(n::Int64)
#nloops n i d->1:3 begin\n
#nexprs n j->(print(i_j))\n
end
end
But the #nloops definition is limited to
_nloops(::Int64, ::Symbol, ::Expr, ::Expr...)
and I get the error
_nloops(::Symbol, ::Symbol, ::Expr, ::Expr)
Is there any way to make this work? Any help greatly appreciated
EDIT:
What I ended up doing was using the combinations method
For my problem, I needed to get all k-combinations of indices to pull values from an array, so the loops would had to look like
for i_1 in 1:100
for i_2 in i_1:100
...
for i_k in i_[k-1]:100
The number of loops needs to be a compile-time constant – a numeric literal, in fact: the code generated for the function body cannot depend on a function argument. Julia's generated functions won't help either since n is just a plain value and not part of the type of any argument. Your best bet for having the number of nested loops depend on a runtime value like n is to use recursion.
In julia-0.4 and above, you can now do this:
function fun(n::Int)
for I in CartesianRange(ntuple(d->1:3, n))
#show I
end
end
In most cases you don't need the Base.Cartesian macros anymore (although there are still some exceptions). It's worth noting that, just as described in StefanKarpinski's answer, this loop will not be "type stable" because n is not a compile-time constant; if performance matters, you can use the "function barrier technique." See http://julialang.org/blog/2016/02/iteration for more information about all topics related to these matters.

Calling Julia macro with runtime-dependent argument

I would like to call a macro in a Julia package (#defNLExpr in JuMP) using an argument that is runtime dependent. The argument is an expression that depends on the runtime parameter n. The only way that I can think of doing this is something like the following:
macro macro1(x)
y=length(x.args);
return esc(:(k=$y-1))
end
macro macro2(n)
x="0";
for i=1:n
x="$x+$i"
end
x=parse(x);
return :(#macro1($x))
end
n=rand(1:3)
println(n)
if (n==1)
#macro2(1)
elseif (n==2)
#macro2(2)
elseif (n==3)
#macro2(3)
else
error("expected n in 1:3")
end
println(k)
Here I have assumed that my runtime n will always be in the range 1-3. I use macro2 to build-up all possible expressions for these different possible values of n, and call the external macro (which I have replaced by the simplified macro1 here) for each of them. The calls to macro1 are in if statements, so only the correct one (determined from the value of n at runtime) will actually be executed.
Although this seems to work, is there a more efficient way of achieving this?
Seems that you might be looking for eval? Be aware that it should be used with care though, and that it not very fast since it has to income the compiler each time it is called.
If it's a limitation to you that it evaluates the expression in global scope then, there are some ways to work around that.

How to safely manipulate MATLAB anonymous functions in string form

I have an anonymous function that I would like to manipulate in string form then use with fsolve.
When I do this the references in the anonymous function to constants are lost and fsolve fails.
The problem is easily illustrated.
The following works:
A=3;
myfun=#(x)sin(A*x);
x = fsolve(#(x)myfun(x),[1 4],optimoptions('fsolve','Display','off'))
The following throws an error as explained here:
A=3;
myfun=#(x)sin(A*x);
mystring=func2str(myfun);
%string operations would go here such as strrep(mystring,'A','A^2') or whatever
myfun2=str2func(mystring);
x = fsolve(#(x)myfun2(x),[1 4],optimoptions('fsolve','Display','off'))
Is there some way I CAN safely manipulate an anonymous function while retaining references to constant parameters?
more info
Specifically I'm writing a simple wrapper to allow fsolve to accept imaginary numbers for simple cases. The following illustrates a working example without a constant parameter:
myeqn=#(x)0.5*x^2-5*x+14.5;
cX0=1+1*1i;
f1=strrep(func2str(myeqn),'#(x)','');
f2=strrep((f1),'x','(x(1)+(x(2))*1i)');
f3=strcat('#(x)[real(',f2,'); imag(',f2,')]');
fc=str2func(f3);
opts=optimoptions('fsolve','Display','off');
result=arrayfun(#(cinput)[1 1i]*(real(fsolve(fc,[real(cinput);imag(cinput)],opts))),cX0)
As in the failed example above if I include a parameter in my wrapper the process fails with the same error as above.
I originally suggested to use the symbolic math toolbox, but reading your question again I realized it's just a simple substitution of input parameters. You can achieve this using function handles without any string processing.
myeqn=#(x)0.5*x^2-5*x+14.5;
cX0=1+1*1i;
wrapper=#(x,f)([real(f(x(1)+x(2)*i)),imag(f(x(1)+x(2)*i))])
opts=optimoptions('fsolve','Display','off');
result=arrayfun(#(cinput)[1 1i]*(real(fsolve(#(x)wrapper(x,myeqn),[real(cinput);imag(cinput)],opts))),cX0)
As much as I hate to suggest using the eval function, you could do:
myfun2 = eval(mystring);
Using eval is kinda frowned upon because it makes code hard to analyze (since arbitrary nastiness could be going on in that string), but don't let other people's coding style stop you from doing what works :)
In your longer example, this would correspond to changing the line:
fc=str2func(f3);
to:
fc=eval(f3);
Again, the use of eval is strongly discouraged, so you should consider alternatives to this type of string manipulation of function definitions.