“Variability” error in model with function call - modelica

The following code
model FunctionCall
Boolean result;
function F
input Real p1;
output Boolean result;
algorithm
result :=p1 < 0.5;
end F;
algorithm
result :=F(time);
end FunctionCall;
(also described in http://www.modelica-forum.com/forums/index.php?showtopic=2) still throws an error in Dymola 2018FD01, while in OpenModelica it is accepted.
Is this wrong Modelica code or a Dymola bug?
Thanks in advance.

The model is incorrect.
3.8 "For an assignment v:=expr or binding equation v=expr, v must be declared to be at least as variable as expr"
Boolean variables are discrete-time expressions according to 3.8.3 "Discrete-time variables, i.e., Integer, Boolean, String variables and enumeration variables, as well as Real variables assigned in when-clauses"
F(time) is not a discrete-time expression, since 3.8.3 only includes "Function calls where all input arguments of the function are discrete-time expressions"
All according to Modelica 3.4.
The reason is that Boolean variables in models should only change at events, and the result of a function such as F(time) can neither guarantee that nor reliably generate events.

Hans answer is the correct one for your question.
Your unasked question may be how one can get the same behavior within the language specifications. Below I have provided one possible solution.
model FunctionCall
Boolean result;
function F
input Real p1;
output Integer result;
algorithm
result := if p1 < 0.5 then 1 else 0;
end F;
algorithm
result := if F(time) < 0.5 then false else true;
end FunctionCall;

Related

Conditional declaration by array of records

I try to create many components depending on the value of constant elements. These elements are organized in an array of records.
Dymola prints the translation log for the example below:
But I'm sure to use fixed conditions because I only perform allowed operations on constant values.
Here is the simple example of what I wantet to do:
model ConditionalComponent
type Enum = enumeration(one,two,three);
record Tmp
parameter Integer ID;
parameter Boolean active;
end Tmp;
record TmpNamed
parameter Enum name;
extends Tmp;
end TmpNamed;
function reorder
input TmpNamed inp[:];
output Tmp out[size(inp,1)];
algorithm
for elem in inp loop
out[elem.name] := Tmp(elem.ID, elem.active);
end for;
end reorder;
constant TmpNamed testIn[:] = {
TmpNamed(Enum.two,20,true),
TmpNamed(Enum.one,10,true),
TmpNamed(Enum.three,30,true)};
constant Tmp testOut1[:] = reorder({
TmpNamed(Enum.two,20,true),
TmpNamed(Enum.one,10,true),
TmpNamed(Enum.three,30,true)});
constant Tmp testOut2[:] = reorder(testIn);
constant Boolean active1 = testOut1[Enum.one].active;
constant Boolean active2 = testOut2[Enum.one].active;
Real t1=0 if testOut1[Enum.one].active;
//Real t2=0 if testOut2[Enum.one].active;
//Real t3=0 if active1;
//Real t4=0 if active2;
end ConditionalComponent;
The function reorder is intended to ease the management of large lists of named active components. Normally the constant testOut2 is used and created within the package ConditionalComponent. But for testing purposes ConditionalComponent is a model here. Actually I only want to use the line
Real t2=0 if testOut2[choice].active;
parameter Enum choice = Enum.one;
within other components, that have a parameter of type Enum. The declarations for t1, t3, t4 are only some tests that work, depending on what is left uncommented.
For example leaving the declaration for t1 and t3 uncommented works. But if one uses only the declaration for t1, it is not translated by Dymola.
The difference between t1 and t2 is, that the argument for reorder is passed directly or via the constant testIn.
I'm sure, that most parameter and constant prefixes are unnecessary and I tried hard to figure out the problem. But unfortunately I cannot decide whether Dymola is not working correctly or I did something wrong. And I've got no idea how to debug the translation process to figure it out by myself.
Can anyone tell me, what am I doing wrong?
Not something wrong, but it's just currently seen as too complicated and not handled.
A work-around is to split subscripting and element access:
constant Tmp testOut1_one=testOut1[Enum.one];
Real t1=0 if testOut1_one.active;

Problems with record call in Dymola

The following package 'RecordTest' (example to reproduce an error of a bigger model) contains a Record to define the structure of some data. Further in package 'DataDefintion' two sets of data are defined. Finally this data should be used in package 'UseOfData'. Herein the data sets are read and the sum of all arrays A is evaluated in the function 'FunctionWithData'.
The simulation of model 'FunctionCall' works fine in OpenModelica. In Dymola I get the error: 'For variable package constant RecordTest.UseOfData.ReadData[1].A the subscript RecordTest.UseOfData.ReadData.Index of an array variable is not an integer.'
Do I miss anything? The constant 'Index' is defined as an integer in record 'DataStructure'. Further the model runs in OpenModelica. I don't understand the error of Dymola.
Thanks in advance.
package RecordTest
record DataStructure
constant Integer Index;
Real A[Index];
end DataStructure;
package DataDefinition
constant DataStructure Set1(Index=2, A={1,2});
constant DataStructure Set2(Index=2, A={3,4});
end DataDefinition;
package UseOfData
constant Integer N=2;
constant DataStructure ReadData[N]={DataDefinition.Set1, DataDefinition.Set2};
function FunctionWithData
input Real b;
output Real Result;
protected
Real Array[2];
algorithm
Array := {sum(ReadData[1].A), sum(ReadData[2].A)};
Result := b*sum(Array);
end FunctionWithData;
model FunctionCall
parameter Real b=2;
Real FunctionResult;
equation
FunctionResult = FunctionWithData(b);
end FunctionCall;
end UseOfData;
end RecordTest;
A work-around is to rewrite the package as follows:
package RecordTest
record DataStructure
constant Integer Index;
Real A[:];
end DataStructure;
package DataDefinition
constant DataStructure Set1=DataStructure(Index=2, A={1.0,2.0});
constant DataStructure Set2=DataStructure(Index=2, A={3.0,4.0});
end DataDefinition;
package UseOfData
constant Integer N=2;
constant DataStructure ReadData[N]={DataDefinition.Set1, DataDefinition.Set2};
function FunctionWithData
input Real b;
output Real Result;
protected
Real Array[2];
algorithm
Array := {sum(ReadData[1].A), sum(ReadData[2].A)};
Result := b*sum(Array);
end FunctionWithData;
model FunctionCall
parameter Real b=2;
Real FunctionResult;
equation
FunctionResult = FunctionWithData(b);
end FunctionCall;
end UseOfData;
end RecordTest;
The issues are the "Index" used in A inside a package-constant array of records, and the modifiers instead of binding equation for the package-constant records Set1 and Set2.
(It will also be handled in a future version of Dymola, and I understand the answer is a bit late.)

Loop through modelica array fails

I am using openmodelica and I am trying to loop through an array in order to find the maximum value. I was able to reduce my code to a very simple test case that still gives the error. Is this something that I am doing wrong, or is this a bug in openmodelica? Here is a very simple case that does give the error:
package TestLoop
model ItemA
Real p;
end ItemA;
model ItemB
ItemA a[n];
parameter Integer n = 5;
Real p;
equation
for i in 1:n loop
a[i].p = time;
end for;
algorithm
for i in 1:n loop
p := a[i].p;
end for;
end ItemB;
end TestLoop;
The problem is in my algorithm section. Here is the error that I am getting:
TestLoop.ItemB.c:155:13: warning: implicit declaration of function '$Pa$lB' is invalid in C99 [-Wimplicit-function-declaration]
$Pp = $Pa$lB(modelica_integer)$Pi$rB$Pp;
^
TestLoop.ItemB.c:155:20: error: unexpected type name 'modelica_integer': expected expression
$Pp = $Pa$lB(modelica_integer)$Pi$rB$Pp;
^
1 warning and 1 error generated.
Any suggestions for why this might be, or how I can work around it? If I replace the assignment with a fixed value, p:=a[1].p;, the code does run (although that is not useful to me). What I ultimately want to do in the algorithm section is find the largest value of a[n].p, where I do have an equation section that does useful calculations into the array of items.
Yes, the code generation is an error of OpenModelica (it does not like unknown array indexes). Your problem is very easy to solve in a single line though (one of the following):
p = max(r for r in a.p);
p = max(a.p);

OOP Matlab inheritance issue with Matlab coder (Simulink MATLAB Function block)

I have defined an abstract base class measurementHandler < handle which defines the interface for all inherited classes. Two subclasses of this class are a < measurementHandler and b < measurementHandler.
I now have a function which should return a handle to an instance of either of these subclasses (depending on the function arguments) to it's caller. Consider something like this:
function returnValue = foobar(index)
if index == 0
returnValue = a();
else
returnValue = b();
end
end
This function is enclosed in a MATLAB Function block in Simulink (2013a). When I try to simulate the system, I get the following error:
Type name mismatch (a ~= b).
Can anybody suggest a workaround for this which still allows me to take advantage of OOP & inheritance when using Simulink?
This kind of pattern is possible in MATLAB Function block only if the "if" condition can be evaluated at compile time. The types cannot be switched at run-time. Can you make the index value a constant at the call site?
The main reason to use this pattern was to iterate over a measurementHandler Array, while these all can have custom implementations. I was able to do this by unrolling the loop with the coder.unroll directive. Example for the enclosing MTALAB Function block:
function result = handleAllTheMeasurements(someInputs)
%#codegen
for index = coder.unroll(1:2)
measurementHandler = foobar(index);
measurementHandler.handleMeasurement(someInputs);
end
result = something;
end
This way, the for loop gets unrolled at compile time and the return type of the function is well defined for each separate call.

if-condition on array of booleans in Modelica

I'm sorry if this is a 'read the manual' question (I did but can't find an answer).
I have an array of Booleans and I want to test if any of them is true.
model TestArray
(...)
Boolean[:] booleanArray;
Real y;
equation
y = if [if any element in booleanArray is true] then ... else ...;
end TestArray;
How can I do this?
Thanks,
Roel
There are functions like the ones you are requesting in Modelica.Math.BooleanVectors.
Here you'll find allTrue(Boolean b[:]), anyTrue(Boolean b[:]) and oneTrue(Boolean b[:]).
This is an interesting question. Frankly, I'm not aware of any built-in capabilities for doing this (although the need for such capabilities is certainly valid).
What we've frequently done in the past is to write utility functions called "any" and "all", that look like this (untested, but you get the idea):
function any
input Boolean vals[:];
output Boolean result;
algorithm
result := max({if i==true then 1 else 0 for i in vals})==1;
end any;
function all
input Boolean vals[:];
output Boolean result;
algorithm
result := min({if i==true then 1 else 0 for i in vals})==1;
end all;
This is similar to what you did but using array comprehensions and then encapsulating that in functions. This allows you to write code like:
if any(conditions) then ... else ...;
Ideally, these functions could be added to the built-in set of "reduction operators" (like min and max), but the language group tends to be somewhat conservative about introducing such operators because they pollute the namespace and create potential collisions with existing code.
Note that things get a bit tricky when using when clauses. With when clauses, there is a vector construction, e.g.
when {cond1, cond2, cond3} then
...
end when;
Which has very useful semantics, but is not 100% analogous to either "any" or "all" as written above. So if you intend to use a vector of conditions in a when clause, then read up on how this is handled (in the specification) or ask a follow-up question on that and I can elaborate more (it is somewhat beyond the scope of this question).
Section 10.3.4 of Modelica Specification Version 4.3 allows Boolean arrays v as arguments of min(v) and max(v).
If all components of v are true then min(v) gives true, false otherwise.
If all components of v are false then max(v) gives false, true otherwise.
Example model:
model Test
Boolean anyFalseGivesFalse = min( { true, false } );
Boolean allTrueGivesTrue = min( { true, true } );
Boolean allFalseGivesFalse = max( { false, false } );
Boolean anyTrueGivesTrue = max( { false, true } );
end Test;
Now I found a workaround, but it must be possible to do it much nicer:
model TestArray
(...)
Boolean[:] booleanArray;
Real y;
Real[:] test;
equation
for i in 1:size(booleanArray):
test[i] = if booleanArray[i] then 1 else 0;
end for;
y = if sum(test) > 0 then ... else ...;
end TestArray;
You could use Modelica.Blocks.Math.BooleanToInteger to convert your Boolean-array to an Integer-array with which you can calculate ...