How can I create an FMU with a large parameter array using Dymola? I discovered that when the array size exceeds 100 elements, the array loses the causality="parameter" and the start value attributes in the modelDescription.xml file. Is there a way to increase the max parameter array size from 100 to 10000?
Modelica model:
model Unnamed
parameter Real smallArray[:] = fill(3.,100);
parameter Real largeArray[:] = fill(3.,101);
equation
end Unnamed;
modelDescription.xml:
<!-- Index for next variable = 100 -->
<ScalarVariable
name="smallArray[100]"
valueReference="16777315"
causality="parameter"
variability="fixed">
<Real start="3.0"/>
</ScalarVariable>
<!-- Index for next variable = 101 -->
<ScalarVariable
name="largeArray[1]"
valueReference="100663296"
variability="fixed">
<Real/>
</ScalarVariable>
You can fix your issue by increasing the value of the global integer
Hidden.FMI.MaximumSizeOfInteractiveParameters
to a larger number, >201 in your case, this can be done in the Dymola command window.
It is an old quick fix for bloated modelStructure that unfortunately has not received a proper fix.
Related
I have a model using a timeTable which represents a variable evolution. I would like to initialize a subcomponent's parameter with the first value of the table (time = 0 second).
The table's values are read from a .txt file. The idea would be to have a command as follow :
parameter Real InitialValue = timeTable.y[2](for timeTable.y[1] = 0)
Is there a command to do so ?
In some cases another option is to initialize the parameter at the output value of that table-component when starting the simulation:
model Demo
Modelica.Blocks.Sources.TimeTable timeTable(table=[0,1; 2,3]);
parameter Real initialValue(fixed=false);
initial equation
initialValue = timeTable.y;
end Demo;
This works for all variants in the same way, but only for the initial value. It is triggered by having fixed=false for a parameter and then giving an initial equation for it.
The solution depends on the block you are using and how the data is defined. Note that there is no easy solution for .txt files, so I recommend using .mat files instead.
1. Data from model
If you don't read from a file it is quite easy.
The data is stored as matrix in the parameter table and we can use array indexing to access it:
model Demo
Modelica.Blocks.Sources.TimeTable timeTable(table=[0,1; 2,3]);
parameter Real initialValue = timeTable.table[1, 2];
end Demo;
This works for both, the Modelica.Blocks.Sources.TimeTable and the CombiTimeTable found in the same package.
2. Data from .mat file
The MSL provides functions to access .mat files. You have to get the table size before you can read the data.
See the code below how this can be done.
model Demo2
import Modelica.Utilities.Streams.{readMatrixSize, readRealMatrix};
parameter String fileName = "C:/tmp/table.mat";
parameter String tableName = "tab1";
parameter Real initialValue = (readRealMatrix(fileName=fileName, matrixName=tableName, nrow=matrixSize[1], ncol=matrixSize[2]))[1, 2];
Modelica.Blocks.Sources.CombiTimeTable combiTimeTable(
tableOnFile=true,
tableName=tableName,
fileName=fileName)
annotation (Placement(transformation(extent={{-10,-10},{10,10}})));
protected
final parameter Integer matrixSize[2] = readMatrixSize(fileName, tableName);
end Demo2;
Note that we don't store the whole table in a variable. Instead,
we read it and access the element of intereset with [1, 2]. This requires putting brackets around the function call.
I'm trying to create a model in OpenModelica which contains several other components (pipes, reservoirs). Currently I'm modifying a pipe in the Modelica.Fluid-library using a staggered grid, and need to determine the smallest step size dx in the entire model.
Is it possible to do the following?
Calculate dx_1 in pipe 1 and dx_2 in pipe 2.
Send dx_1 and dx_2 to an array in a global model (similar to Modelica.Fluid.System).
Determine the smallest dx = min(dx_1, dx_2) and send back to both pipe 1 and pipe 2.
I have calculated both dx_1 in pipe 1 and dx_2 in pipe 2, and created an array in a data storage model similar to Fluid.System. I am, however, struggling with sending the step sizes to the data storage model, and sending them back again after determining the smallest dx.
Is this even possible? How would one go about to do so?
Yes, there are several possibilities.
As you mention, the pipes can access variables/parameters in the data storage model if this is instantiated as inner in your global model and declared as outer in each pipe model. As with the Modelica.Fluid models referring to Fluid.System, the pipes can access dx_minin the data storage model.
This is a code example, loosely based on your question:
model Pipe
outer DataStorage dataStorage;
Real dx_min = dataStorage.dx_min;
Real dx "calculated in this model";
...
end Pipe;
model DataStorage
parameter Integer nPipes;
input Real dx_array[nPipes];
Real dx_min=min(dx_array);
...
end DataStorage;
model GlobalModel
Pipe pipe1;
Pipe pipe2;
inner DataStorage dataStorage(nPipes=2, dx_array={pipe1.dx, pipe2.dx});
...
end GlobalModel;
You should beware of the variability of the different "dx's" as you cannot assign a time-varying "dx" to a "dx" declared as a parameter.
If the only purpose of the DataStorage model is to take the minimum entry in an array then you could also put its three lines of code in GlobalModel, reducing the code to:
model Pipe
input Real dx_min;
Real dx "calculated in this model";
...
end Pipe;
model GlobalModel
parameter Integer nPipes=2;
Real dx_array[nPipes]={pipe1.dx, pipe2.dx};
Real dx_min=min(dx_array);
Pipe pipe1(dx_min=dx_min);
Pipe pipe2(dx_min=dx_min);
...
end GlobalModel;
I have implemented three similar publications in one Modelica model, using an enumeration type variable to select the publication. The goal is to switch between calculation methods (i.e. between publications) by changing the value of the enumeration type variable online.
The calculation consists of three steps, each of which has its own enumeration variable. This allows for mixed calculation methods, e.g. by setting step 1 to calculate according to publication 1 and steps 2 and 3 according to publication 2.
Each step reads something like this
model Calculation_step
type pubSelect = enumeration(
Publication_1,
Publication_2,
Publication_3);
// ####### Publication Selection #######
parameter pubSelect selection = pubSelect.Publication_2;
// ##### End Publication Selection #####
Modelica.Blocks.Interfaces.RealInput incoming;
Modelica.Blocks.Interfaces.RealOutput outgoing;
parameter Real factor = 5;
equation
if selection == pubSelect.Publication_1 then
outgoing = factor * sin(incoming);
elseif selection == pubSelect.Publication_2 then
outgoing = factor * sin(incoming)^2;
elseif selection == pubSelect.Publication_3 then
outgoing = factor * sin(incoming)^3;
else
outgoing = 99999;
end if;
annotation (uses(Publicationica(version="3.2.1"), Modelica(version="3.2.1")));
end Calculation_step;
The model will not be calculated in Dymola. Instead, a functional mock-up unit (FMU) is created using Dymola. This creates an XML file describing the model. In order to enable online changes, a variable has to have the attribute variability="tunable" set in this XML.
However, the variable selection is not tunable, as shown in the following excerpt of the XML:
-<ModelVariables>
<!-- Index for next variable = 1 -->
-<ScalarVariable name="selection" variability="constant" valueReference="100663296">
<Enumeration start="2" declaredType="Calculation_step"/>
</ScalarVariable>
Using the same code for the declaration of the variable factor yields a tunable FMU variable:
<!-- Index for next variable = 4 -->
-<ScalarVariable name="factor" variability="tunable" valueReference="16777216" causality="parameter">
<Real start="5"/>
</ScalarVariable>
tl;dr:
Is it possible to make a Modelica enumeration type variable "tunable" when exported as FMU / FMI?
Dymola Version 2015 FD01 (32-bit), 2014-11-04
I tried to add a start value to the selection parameter, and with annotation (Evaluate=false) it became tunable.
parameter pubSelect selection(start=pubSelect.Publication_2) annotation (Evaluate=false);
It will give you a warning about an unassigned parameter tho, I have not really tried if it really works(change the value at events/communication points), please let me know the result if you have a chance to give it a try. Thanks~
I am trying to find a better solution to calculation using data stored in table. I have a large table with many variables (100+) from which I select smaller sub-table with only two observations and their difference for smaller selection of variables. Thus, the resulting table looks for example similarly to this:
air bbs bri
_________ ________ _________
test1 12.451 0.549 3.6987
test2 10.2 0.47 3.99
diff 2.251 0.078999 -0.29132
Now, I need to multiply the ‘diff’ row with various coefficients that differ between variables. I can get the same result with the following code:
T(4,:) = array2table([T.air(3)*0.2*0.25, T.bbs(3)*0.1*0.25, T.bri(3)*0.7*0.6/2]);
However, I need more flexible solution since the selection of variables will differ between applications. I was thinking that better solution might be using either varfun or rowfun and speficic function that would assign correct coefficients/equations based on variable names:
T(4,:) = varfun(#func, T(3,:), 'InputVariables', {'air' 'bbs' 'bri'});
or
T(4,:) = rowfun(#func, T(3,:), 'OutputVariableNames', T.Properties.VariableNames);
However, the current solution I have is similarly inflexible as the basic calculation above:
function [air_out, bbs_out, bri_out] = func(air, bbs, bri)
air_out = air*0.2*0.25;
bbs_out = bbs*0.1*0.25;
bri_out = bri*0.7*0.6/2;
since I need to define every input/output variable. What I need is to assign in the function coefficients/equations for every variable and the ability of the function to apply it only to the variables that are present in the specific sub-table.
Any suggestions?
I have written a macro for ImageJ/FIJI to deconvolve my confocal microscopy images and run the "3D Object Counter" plugin. The macro successfully runs all required commands and saves all required data in the specified places.
However, I have found that the 3D-OC autothreshold (as shown in the plugin dialog box) is to stringent resulting in objects being lost or divided.
To remedy this I would like to reduce the autothreshold by a predetermined function something similar to what was done here (from:How to get threshold value used by auto threshold Plugin) which resulted in this code:
setAutoThreshold();
getThreshold(lower,upper);
v=setThreshold(lower,upper*0.5);
run("3D Objects Counter", "threshold="v" slice=10 min.=400 max.=20971520 objects statistics summary");
The idea was to call the AutoThreshold values, modify them and set them to a variable. However when these lines are run the following error is returned:
Number or numeric function expected in line 3.
v=<setThreshold>(lower,upper*0.5);
And if the variable is inserted directly into the threshold key for run(3D-OC) the following msg is encountered:
Numeric value expected in run() function
Key:"threshold"
Value or variable name:"setThreshold(lower,upper*0.5"
Any suggestions or help on how to designate the 3D-OC threshold value as a variable as described would be greatly appreciated (as would any work arounds of course :) ).
Cheers
Edit: After testing Jan's response below (which works perfectly), it appears I need to call the threshold set by the 3D-OC plugin. Anyone know how to do this?
The getThreshold(lower, upper) function returns the lower and upper threshold levels in the provided variables. There is no need to assign any value to a new variable, and as you observed, setThreshold does not have any return value.
Instead, you can use the value(s) returned from getThreshold and use them as parameters in the run method (in the correct way, by string concatenation, see here):
setAutoThreshold();
getThreshold(lower, v);
run("3D Objects Counter", "threshold=" + v + " slice=10 min.=400 max.=20971520 objects statistics summary");
Alternatively, you can use &v in the second parameter to avoid string concatenation in the last line (see the documentation for the run() macro function):
run("3D Objects Counter", "threshold=&v slice=10 min.=400 max.=20971520 objects statistics summary");
You might have to use the lower instead of the upper threshold value, depending on whether you count bright or dark objects.