Is the non-discrete assignment of expressions to integers only possible within the algorithm
of a function
?
If many model parameters are needed within the algorithm it would be much simpler to calculate the output value directly in the algorithm section of the model.
If one uses a function one has to pass all needed parameter values from the environment as inputs to the function.
It seems to me that the Modelica specification forces one to encapsulate integers with non-discrete assignments locally within functions.
A possible use-case for such integer assignments is that one wants to represent transfer characteristics as the sum of smooth base functions with compact support.
For computing, the output value for a certain input value x one has to determine the indexes of the base functions whose supports contain x.
I include a more simple case of linear interpolation of tabulated data as a working example where the interpolation interval must be found (even if such an interpolation is not differentiable).
The noEvent(...)
within the code is not really needed since relations within the algorithm section of a function do not generate events if the annotation GenerateEvents=true
is not given.
Nevertheless, I included it to show where the non-discrete assignment to the integer i
results from.
model testInterpol
function interpol
input Real x;
input Real tab[:,2];
output Real y;
protected
Integer i;
algorithm
i:=size(tab,1);
for ii in 2:size(tab,1) loop
if noEvent(x < tab[ii,1]) then
i := ii;
break;
end if;
end for;
y := tab[i-1,2] + (tab[i,2]-tab[i-1,2])/(tab[i,1]-tab[i-1,1])*(x-tab[i-1,1]);
end interpol;
Real x = 10*sin(8*atan(1.0)*time);
parameter Real tab[:,2]={{1,1},{2,4},{3,9},{5,25},{6,36}};
Real y;
equation
y = interpol(x,tab);
end testInterpol;
In the following model, the type of Interpol
is changed from function
to model
.
Note, that this implies some modifications for the usage of Interpol
.
model testInterpolModel
model Interpol
input Real x;
input Real tab[:,2];
output Real y;
protected
Integer i;
algorithm
i:=size(tab,1);
for ii in 2:size(tab,1) loop
if noEvent(x < tab[ii,1]) then
i := ii;
break;
end if;
end for;
y := tab[i-1,2] + (tab[i,2]-tab[i-1,2])/(tab[i,1]-tab[i-1,1])*(x-tab[i-1,1]);
end Interpol;
Real x = 10*sin(8*atan(1.0)*time);
parameter Real tab[:,2]={{1,1},{2,4},{3,9},{5,25},{6,36}};
Real y;
Interpol interpol(x=x,tab=tab,y=y);
end testInterpolModel;
OpenModelica 1.9.3+dev (r25613) accepts
testInterpolModel
Dymola rejects the model with the following error message:
Trying to assign a discrete variable inside a loop controlled by higher variability: interpol.i = ii;
In Section 12.2 "Function as a Specialized Class" of the Modelica Specification 3.3 rev. 1 one finds the following statement:
Components of a function will inside the function behave as though they had discrete-time variability.
I am not quite sure what this means. If one only had this sentence from the specification and no experience with Modelica tools one could think that the statements from the algorithm section of a function are only evaluated at event instances because they behave as though they had discrete-time variability.
But, this impression is wrong. The statements of a function are always executed and relations within functions do not generate events if the annotation GenerateEvents
is not explicitly set to true
.
This is stated in Section 8.5 "Events and Synchronization" of the specification:
All equations and assignment statements within when-clauses and all assignment statements within function classes are implicitly treated as the
noEvent
function, i.e., relations within the scope of these operators never induce state or time events.
There exists already a related ticket in the Modelica bug-tracker: Ticket-Comment-Link
I have a vague idea what the actual reason for the differences in the treatment of integer variables in functions and models is.
Algorithms in models can conceptually be interpreted as anonymous functions in regard to inputs and outputs (see Section 11.1.2 "Execution of an algorithm in a model" of the Spec.). All variables that are assigned within the algorithm become outputs of the anonymous function and can be used in equations outside of the algorithm.
But, then these variables can introduce discontinuities in other parts of the model.
The situation is different in named functions. Variables that are not declared as input or as output cannot be accessed from the outside. Therefore, the function can safely be designed such that the integer variables do not introduce discontinuities within the overall model.
I've got the impression that the problem would be solved if it was possible to declare algorithm-local variables. For an instance, one could allow declaring algorithm
-local variables such as i
after the algorithm
-keyword.
An alternative solution would be the re-introduction of the keyword nondiscrete
of Modelica-Specification 1. There already exists an old Modelica ticket where such a re-introduction had been proposed in a comment. The proposal got only approval but nothing happened.
The keyword nondiscrete
could be used in front of Integer i;
in the second example code above. Since the variable i
and the assignment i:=ii;
would be nodiscrete
in this case the noEvent
would also be legal within the algorithm.