FMU-Export in Dymola: Is it possible to make a Modelica enumeration type variable "tunable" when exported as FMU / FMI - modelica

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~

Related

Modelica (Dymola) : get a particular value of a timetable?

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.

How to define a Dialog for a connector with an array of parameters

Let say that I have a connector with a few number parameters (whose number can change). Those parameters are elements of an array.
Would it be possible to have a dialog box to enter each parameter value rather than an array constructor like {1,2,3, ....}?
It's unclear what you mean with entering each parameter in the array.
Modelica does not have a standard mechanism for entering array elements.
Some tools allow you to enter the parameters one by one - e.g. if you do
model M "Example model"
parameter Real r3[:] = zeros(0) "Array parameter";
end M;
Then Dymola (standalone and as part of 3D Experience platform) will show a dialog box for M and then a sub-dialog for r3 allowing you to enter each element:
Not sure, if I understood correctly, but you can use final to declare parameters that should not be modified by users. See for example
partial model M "Example model"
parameter Real r1 = 1 "First parameter";
parameter Real r2 = 2 "Second parameter";
final parameter Real r[:] = {r1, r2} "Assembled array parameter";
end M;

Export FMU with large parameter array from Dymola

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.

How do I create arbitrary parameterized layers in DiffEqFlux.lj neuralODE? Julia Julialang Flux.jl

I am able to create and optimize neuralODEs in julia(1.3 and 1.2) using Flux.jl and DiffEqFlux.jl but it fails under a crucial important general case.
what works:
I can train the Neural net parameters if it is built out of the
provided Flux.jl layers like Dense().
I can include an arbitrary function as a layer in the network chain, e.g. x -> x.*x
What fails:
However if the arbitrary function has parameters I want to train then Flux. Train will not adjust these parameters causing it to fail.
I have tried making these added parameters Tracked and included in the list of parameters given to the training system but it ignores them and they remain unvaried.
The documentation says very cryptically that one can use Flux.#functor on a layer to make sure it's parameters get tracked. However functor was not included in Flux till version 0.10.0 and the only version of Flux compatible with NeuralODEs in DiffEqFlux is 0.9.0
So here's an toy example of a 2 layer neural net I want to use
p = param([1.0])
dudt = chain( x -> p[1]*x.*x, Dense(2,2) )
ps = Flux.params(dudt)
then I use the flux train on this. when I do this the parameter p is not varied, but the parameters in the Dense layer are.
I have tried explicitly including like this
ps = Flux.Params([p,dudt])
but that has the same result and the same problem
I think what I need to do is build a struct with an associted function that implements the
x->p[1]*x*x
then call #functor on this. That struct can then be used in the chain.
But as I noted the version of Flux with #functor is not compatible with DiffEqFlux of any version.
So I need a way to make flux pay attention to my custom parameters, not just the ones in Dense()
How???
I think I get what your question is, but please clarify if I am answering the wrong question here. The issue is that the p is only grabbing from a global reference and thus not differentiated during adjoints. A much better way to handle this in 2020 is to use FastChain. The FastChan interface lets you define layer functions and their parameter dependencies, so this is a nice way to make your neural network incorporate arbitrary functions with parameters. Here's what that looks like:
using DifferentialEquations
using Flux, Zygote
using DiffEqFlux
x = Float32[2.; 0.]
p = Float32[2.0]
tspan = (0.0f0,1.0f0)
mylayer(x,p) = p[1]*x
DiffEqFlux.paramlength(::typeof(mylayer)) = 1
DiffEqFlux.initial_params(::typeof(mylayer)) = rand(Float32,1)
dudt = FastChain(FastDense(2,50,tanh),FastDense(50,2),mylayer)
p = DiffEqFlux.initial_params(dudt)
function f(u,p,t)
dudt(u,p)
end
ex_neural_ode(x,p) = solve(ODEProblem(f,x,tspan,p),Tsit5())
solve(ODEProblem(f,x,tspan,p),Tsit5())
du0,dp = Zygote.gradient((x,p)->sum(ex_neural_ode(x,p)),x,p)
where the last value of p is the one parameter for p in mylayer. Or you can directly use Flux:
using DifferentialEquations
using Flux, Zygote
using DiffEqFlux
x = Float32[2.; 0.]
p2 = Float32[2.0]
tspan = (0.0f0,1.0f0)
dudt = Chain(Dense(2,50,tanh),Dense(50,2))
p,re = Flux.destructure(dudt)
function f(u,p,t)
re(p[1:end-1])(u) |> x-> p[end]*x
end
ex_neural_ode() = solve(ODEProblem(f,x,tspan,[p;p2]),Tsit5())
grads = Zygote.gradient(()->sum(ex_neural_ode()),Flux.params(x,p,p2))
grads[x]
grads[p]
grads[p2]

Calculations in table based on variable names in matlab

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?