Using Variant Source and Variant Sink blocks
In this example we will show the work of blocks Variant Source and Variant Sink. These blocks allow you to switch between different realisations of models that are generators of input data or consumers of output data of some subsystem.
Introduction
Suppose you need to calculate the performance of a model with different input sensors, different cyclograms, or different output data filtering algorithms. For such testing, you could build several separate models, the number of which would quickly become impractically large. Or you can collect all the models into one and switch conditions using variables.
In this simplified example, the model configuration will be specified by two scalar variables:
Pkg.add(["Combinatorics"])
V = 1;
W = 1;
The model has several signal line switches controlled by external variables.
The signal selection conditions in each block Variant Source or Variant Sink are specified using expressions.
The expression that first takes the true value determines the port number through which the data will go from or to some subsystem. Let us interpret the different variants of the systems that are realised in this diagram:
- If
W==1is a true expression thenVariant Source1activates inputSine3, and atV==4it activates inputSine4. - If
V==1blockVariant Source 2skips the signal from blockSine1, and ifV==2skips the signal from blockAdd1. - If
Add1block is inactive,Variant Source 1will also be inactive, and thenSine3andSine4blocks will be disabled (Sine3block is active atV==2 && W==1, andSine4block is active atV==2 && W==2). - The
Gain3block is active either atV==1or atV==2; under other conditions (for example atV=4) we will get an error because no output signal will be supplied to the output portOut1. - The blocks at the output
Variant Sink1become active atW==1 (Gain5)or atW==2 (Gain2, Substract, Terminator). - Finally, the blocks
Sine6,SumandOut2are always active and are not subject to the system option conditions. To ensure that these blocks are only executed under certain conditions, you can precede and follow them with the blocksVariant Source/Sinkboth with a single input and output.
Under some combinations of conditions, this model returns an error because the output ports of a subsystem must receive an active signal regardless of the subsystem option. It is not possible to supply any block with both active and inactive signals at the same time, you must explicitly design the output ports of such a system using Variant Source/Sink blocks to set default values.
Running the scenario
mName = "variant_source_sink"
model = mName in [m.name for m in engee.get_all_models()] ? engee.open( mName ) : engee.load( "$(@__DIR__)/$(mName).engee" );
data = engee.run( mName )
plot( data["Gain3.1"].time, data["Gain3.1"].value )
Running multiple scenarios
We will now run several variations of the model in a loop, switching state variables to show how the system performs in different scenarios using a combination of input conditions.
using Combinatorics
# Зададим все интересующие нас входные условия
vV = [1,2,4];
vW = [1,2,4];
# Загрузим модель
mName = "variant_source_sink"
model = mName in [m.name for m in engee.get_all_models()] ? engee.open( mName ) : engee.load( "$(@__DIR__)/$(mName).engee" );
# Успех выполнения мы будем хранить в матрице, которую инициализируем пропущенными значениями
run_success = NaN .* zeros(length(vV), length(vW))
# Пройдемся по всем комбинациям входных условий и проверим, выполнится ли модель
for c in combinations( vcat( vV,vW ), 2 )
V,W = c[1],c[2]
i = findfirst( vV.==c[1] )
j = findfirst( vW.==c[2] )
try
# Запустим модель на выполнение
data = engee.run( mName )
catch e
# Если модель выполнилась с ошибкой, запишем 0 в выходную матрицу
run_success[i,j] = 0
else
# Запишем единицу только если условие catch не сработало
run_success[i,j] = 1
end
end
We will display a graph that will show the statistics on the runs of different variants of our model.
gr()
# Вывод не интерактивной карты, отражающей успех выполнения модели
heatmap( run_success, xticks=(range(1,length(vV)), vV), yticks=(range(1,length(vW)), vW),
xlabel = 'V', ylabel='W', title="Успех выполнения модели", yflip = true, cbar=false, c=:Blues )
# Аннотация поверх каждой ячейки
annotate!( vec(tuple.((1:length(vV))', (1:length(vW)), string.(Int32.(run_success)))) )
Conclusion
We have seen that it is possible to build multiple variants of a system on a single canvas. This method simplifies testing and allows generating many code variants at once to further automate semi-natural modelling.