Engee documentation
Notebook

Model Reference

In this demonstration we will use a simple example to show how to use the Model block in Engee.

A model reference itself is a reference to another model using a Model block. Such models are used to create the hierarchy of a system model. Reference models are ideal for subsystem reuse, unit testing, parallel builds, and large systems.

To implement our demonstration, we will need two models: a master model and a reference model.

image.png

In our example, we have implemented with simple elements a counter with two input ports that define the step and maximum values of the counter.

image.png

After that, we can move on to developing the main model, where we will reference the implemented counter using the Model block.

To connect the model we will use the function of model selection.

image_4.png

Now in the opened window of the file manager select the model of the counter we have implemented.

image_3.png

As a result, we have a basic model with a subsystem, which is stored in a separate file. With this implementation we can reuse this counter many times within one project. At the same time, having changed the logic in the reference subsystem, we will apply these changes to all blocks referring to the original model.

image.png

Now let's run our model and analyse the correctness of the counter operation.

In [ ]:
function run_model( name_model, path_to_folder )
    
    Path = path_to_folder * "/" * name_model * ".engee"
    
    if name_model in [m.name for m in engee.get_all_models()] # Проверка условия загрузки модели в ядро
        model = engee.open( name_model ) # Открыть модель
        model_output = engee.run( model, verbose=true ); # Запустить модель
    else
        model = engee.load( Path, force=true ) # Загрузить модель
        model_output = engee.run( model, verbose=true ); # Запустить модель
        engee.close( name_model, force=true ); # Закрыть модель
    end

    return model_output
end
Out[0]:
run_model (generic function with 1 method)
In [ ]:
run_model("model", @__DIR__)
Building...
Progress 100%
Progress 100%
Out[0]:
Dict{String, DataFrame} with 1 entry:
  "Model.Cnt" => 11×2 DataFrame

Counting the logged data.

In [ ]:
Data = collect(simout["model/Model.Cnt"]);

Display the results of the simulation.

In [ ]:
using Plots
plot(Data.time, Data.value, linetype=:steppre)
Out[0]:

As we can see from the graph above, the counter does indeed increment in increments of one, and the maximum value of the counter is 5.

An infinite number of such counters can be added. The example below shows a model with two parallel counters.

image_2.png

In this case, when the block is added again, it is necessary to update the connectors for further work with the duplicate subsystem.

image.png

In [ ]:
run_model("model_2", @__DIR__)
Building...
Progress 100%
Progress 100%
Out[0]:
Dict{String, DataFrame} with 2 entries:
  "Model.Cnt"   => 11×2 DataFrame…
  "Model-1.Cnt" => 11×2 DataFrame
In [ ]:
Data_1 = collect(simout["model_2/Model.Cnt"]);
Data_2 = collect(simout["model_2/Model-1.Cnt"]);

plot(Data_1.time, Data_1.value, linetype=:steppre)
plot!(Data_2.time, Data_2.value, linetype=:steppre)
Out[0]:

As we can see, in this case the two counters work in parallel and have different maximum values.

Conclusion

In this example, we have broken down the possibilities of using model-references and shown how to apply them to your projects. This method of system design greatly simplifies the work on projects and also reduces the time spent on editing blocks in case of changes in the project.

Blocks used in example