Запуск FMI модели в Engee¶
Запускаем FMU-модели в окружении Julia чтобы получить результаты симуляции и использовать их в дальнейших вычислениях.
Стандарт FMI (Functional Mockup Interface) подразумевает упаковку модели в файл FMU (Functional Mockup Unit), содержащий либо набор уравнений, либо код, моделирующий систему (предположительно, поддерживаются различные языки программирования, которые можно вызвать в Engee: Python, Java, Fortran, C++ и т.д. включая Julia).
Для примера рассмотрим модель пружины и маятника, собранной в Dymola. Чтобы ее запустить нам потребуется библиотека FMI.jl
и набор учебных моделей, которые собраны в пакете FMIZoo.jl
.
Подключим установленные библиотеки:
Мы собираемся провести симуляцию такой модели:
Библиотека FMI.jl
позволяет запускать FMI/FMU-модели несколькими способами, и мы покажем два из них:
- через команду
simulate
- через создание собственного цикла симуляции и команду
fmi2DoStep
.
Создадим временной вектор (зададим начало tStart
, окончание Stop
симуляции и временной шаг tStep
):
Простейший сценарий запуска FMU модели¶
Загрузим модель SpringFrictionPendulum1D
из пакета моделей FMIZoo.jl
.
#################### Begin information for FMU ####################
Model name: SpringFrictionPendulum1D
FMI-Version: 2.0
GUID: {2e178ad3-5e9b-48ec-a7b2-baa5669efc0c}
Generation tool: Dymola Version 2022x (64-bit), 2021-10-08
Generation time: 2022-05-19T06:54:12Z
Var. naming conv.: structured
Event indicators: 24
Inputs: 0
Outputs: 0
States: 2
33554432 ["mass.s"]
33554433 ["mass.v", "mass.v_relfric"]
Parameters: 12
16777216 ["fricScale"]
16777217 ["s0"]
16777218 ["v0"]
16777219 ["fixed.s0"]
...
16777223 ["mass.smin"]
16777224 ["mass.v_small"]
16777225 ["mass.L"]
16777226 ["mass.m"]
16777227 ["mass.fexp"]
Supports Co-Simulation: true
Model identifier: SpringFrictionPendulum1D
Get/Set State: true
Serialize State: true
Dir. Derivatives: true
Var. com. steps: true
Input interpol.: true
Max order out. der.: 1
Supports Model-Exchange: true
Model identifier: SpringFrictionPendulum1D
Get/Set State: true
Serialize State: true
Dir. Derivatives: true
##################### End information for FMU #####################
Запустим расчет этой модели, указав начало и конец времени симуляции и сохраняемую переменную mass.s
. Поскольку в модели есть трение, колебания происходят со снижающейся амплитудой, а спустя некоторое время груз приходит в состояние покоя.
После окончания расчета нужно выгрузить из памяти модель FMU и удалить все временные данные.
Создание собственого цикла симуляции¶
В более сложном случае, например когда вам нужно связать работу сразу нескольких моделей, можно организовать расчетный цикл, в котором модель будет осуществлять шаги в своем фазовом пространстве вдоль по некоторому временному вектору.
Out[0]:
Model name: SpringFrictionPendulum1D
Type: 1
Функция шага ожидает специально подготовленную модель (конкретную реализацию), которую мы создадим при помощи fmi2Instantiate
. Таким образом можно из одного FMU файла инициализировать сразу много моделей.
Out[0]:
FMU: SpringFrictionPendulum1D
InstanceName: SpringFrictionPendulum1D
Address: Ptr{Nothing} @0x000000001d62f8c0
State: 0
Logging: false
FMU time: -Inf
FMU states: nothing
В следующей ячейке мы осуществляем настройку эксперимента (fmi2SetupExperiment
), где указываем начало и конец временного интервала для симуляции, затем модель нужно перевести в режим инициализации (fmi2EnterInitializationMode
) и получить ее начальное состояние после инициализации (fmi2ExitInitializationMode
).
Теперь мы можем запустить модель в расчетном цикле. Функция fmi2DoStep
с фиксированным шагом tStep
позволяет осуществлять расчетные шаги этой модели. Если у модели есть входные параметры или принимаемые данные, их можно изменять в цикле.
В окончание расчета мы должны освободить память и удалить промежуточные файлы.
[OK][CvodeStatistics][SpringFrictionPendulum1D]: Sundials CVode Statistics
Stop time : 8.00 s
Simulation time : 1.42 s
Number of external steps : 80
Number of internal steps : 191
Number of non-linear iterations : 263
Number of non-linear convergence failures: 0
Number of f function evaluations : 291
Number of g function evaluations : 339
Number of Jacobian-evaluations (direct) : 7
Maximum integration order : 5
Suggested tolerance scale factor : 1.0
Grouping used : no
Мы запустили простую FMU модель при помощи одной команды, а также разобрались, как организовать расчетный цикл, где можно было бы обновлять входные параметры модели и принимать оперативные решения на основе выходных данных.
{"id": "9917cf3a-d645-4757-a825-2b12163dd952", "data": [{"showlegend": true, "mode": "lines", "xaxis": "x", "colorbar": {"y": 0.5329861111111112, "title": {"text": ""}, "len": 0.914342738407699, "x": 0.9934383202099737}, "name": "mass.s (33554432)", "yaxis": "y", "legendgroup": "mass.s (33554432)", "line": {"color": "rgba(0, 154, 250, 1.000)", "shape": "linear", "dash": "solid", "width": 1}, "y": [0.5, 0.5216337712911777, 0.585699537535943, 0.6869267320660232, 0.8156462828870731, 0.9593696988008208, 1.1038235061481492, 1.2345035186244255, 1.3383449823708398, 1.4047175326826922, 1.4259767999327344, 1.4058424621115875, 1.350661399642862, 1.264785776387944, 1.1562376966065413, 1.035647893976571, 0.9149490730690827, 0.8061436400267346, 0.7201658780009753, 0.6659782006197259, 0.6501284929655062, 0.6674924701309876, 0.7124002075443914, 0.7814278969372623, 0.868248508368866, 0.9644543123431987, 1.060623211645825, 1.1471304980815111, 1.2151148019617162, 1.2572804294599225, 1.268447227831807, 1.255176111341135, 1.2224415276083764, 1.1725647835518653, 1.1099163018610776, 1.0403857966275998, 0.9708094341895908, 0.9081585141814575, 0.858923759282897, 0.8285539819180577, 0.8209814422737365, 0.8285471613741592, 0.8466594580749613, 0.8742111147818488, 0.908928343023548, 0.9477135388442701, 0.9868159276361104, 1.0222939665425457, 1.050368613939233, 1.0677611528215483, 1.0722001103102978, 1.0722001103002896, 1.0722001102902814, 1.0722001102802734, 1.0722001102702652, 1.0722001102602572, 1.072200110250249, 1.072200110240241, 1.0722001102302328, 1.0722001102202245, 1.0722001102102166, 1.0722001102002083, 1.0722001101902003, 1.0722001101801921, 1.0722001101701841, 1.072200110160176, 1.072200110150168, 1.0722001101401597, 1.0722001101301515, 1.0722001101201435, 1.0722001101101353, 1.0722001101001273, 1.072200110090119, 1.072200110080111, 1.0722001100701029, 1.0722001100600949, 1.0722001100500866, 1.0722001100400784, 1.0722001100300704, 1.0722001100200622, 1.0722001100100542], "type": "scatter", "x": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8], "zaxis": null, "z": null, "metadata": {"shouldEnableSmartZoom": false, "smartZoomParams": {"minCount": 25000, "maxCount": 81, "currentCount": 81}}}], "config": {"showlegend": true, "xaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0, 2, 4, 6, 8], "range": [-0.2400000000000002, 8.24], "domain": [0.05100612423447069, 0.9934383202099737], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0", "2", "4", "6", "8"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "y", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "t [s]", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "paper_bgcolor": "rgba(255, 255, 255, 1.000)", "annotations": [], "height": 400, "margin": {"l": 0, "b": 20, "r": 0, "t": 20}, "plot_bgcolor": "rgba(255, 255, 255, 1.000)", "yaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0.6000000000000001, 0.8, 1, 1.2000000000000002, 1.4000000000000001], "range": [0.47222069600201794, 1.4537561039307165], "domain": [0.07581474190726165, 0.9901574803149606], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0.6", "0.8", "1.0", "1.2", "1.4"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "x", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "legend": {"yanchor": "auto", "xanchor": "auto", "bordercolor": "rgba(0, 0, 0, 1)", "bgcolor": "rgba(255, 255, 255, 1.000)", "borderwidth": 1, "tracegroupgap": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "title": {"font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}, "text": ""}, "traceorder": "normal", "x": 1}, "width": 1519.984375}}
{"id": "9feb99ee-c6e9-4fb1-a036-8848db92d9dc", "data": [{"showlegend": true, "mode": "lines", "xaxis": "x", "colorbar": {"y": 0.513888888888889, "title": {"text": ""}, "len": 0.9525371828521435, "x": 0.9934383202099737}, "name": "y1", "yaxis": "y", "legendgroup": "y1", "line": {"color": "rgba(0, 154, 250, 1.000)", "shape": "linear", "dash": "solid", "width": 1}, "y": [0.521617893337313, 0.5857403574487205, 0.6870806316419173, 0.8159118828873837, 0.9595494033091156, 1.1037259195636675, 1.2341352770315883, 1.3377773736721998, 1.4040715284592924, 1.4254203214015764, 1.4054151572683096, 1.3503197659321926, 1.2645501879051213, 1.156194440048218, 1.0358936843471542, 0.9155375100488806, 0.8071058211712159, 0.7214914488275355, 0.6675969594846171, 0.6518054894676271, 0.6690400876787104, 0.7137172559274544, 0.7824264966353125, 0.8688023224370243, 0.9644703694798775, 1.0599852848225226, 1.1458162549244963, 1.213249292866229, 1.2550887268873214, 1.2662249066932485, 1.253104708416079, 1.2206690257317532, 1.1712331039422006, 1.1091643750292035, 1.040395515011808, 0.9716854549857008, 0.9099221258877447, 0.8614911888975986, 0.831755052825566, 0.8244225626876394, 0.8317801640701884, 0.8493935612864197, 0.8761680200800709, 0.9099001972839909, 0.9475036225308328, 0.9853391533815364, 1.0195777074075896, 1.046563427330959, 1.063139013869552, 1.0672523633960693, 1.0672523633860627, 1.067252363376056, 1.0672523633660493, 1.0672523633560427, 1.067252363346036, 1.0672523633360294, 1.0672523633260227, 1.067252363316016, 1.0672523633060094, 1.0672523632960027, 1.067252363285996, 1.0672523632759894, 1.0672523632659827, 1.067252363255976, 1.0672523632459694, 1.0672523632359627, 1.067252363225956, 1.0672523632159494, 1.0672523632059427, 1.067252363195936, 1.0672523631859294, 1.0672523631759228, 1.067252363165916, 1.0672523631559094, 1.0672523631459028, 1.067252363135896, 1.0672523631258894, 1.0672523631158828, 1.0672523631058761, 1.0672523630958695, 1.0672523630958695], "type": "scatter", "x": [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6, 6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7, 7.1, 7.2, 7.3, 7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8], "zaxis": null, "z": null, "metadata": {"shouldEnableSmartZoom": false, "smartZoomParams": {"minCount": 25000, "maxCount": 81, "currentCount": 81}}}], "config": {"showlegend": true, "xaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0, 2, 4, 6, 8], "range": [-0.2400000000000002, 8.24], "domain": [0.05100612423447069, 0.9934383202099737], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0", "2", "4", "6", "8"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "y", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "paper_bgcolor": "rgba(255, 255, 255, 1.000)", "annotations": [], "height": 400, "margin": {"l": 0, "b": 20, "r": 0, "t": 20}, "plot_bgcolor": "rgba(255, 255, 255, 1.000)", "yaxis": {"showticklabels": true, "gridwidth": 0.5, "tickvals": [0.6000000000000001, 0.8, 1, 1.2000000000000002, 1.4000000000000001], "range": [0.4945038204953851, 1.4525343942435043], "domain": [0.03762029746281716, 0.9901574803149606], "mirror": false, "tickangle": 0, "showline": true, "ticktext": ["0.6", "0.8", "1.0", "1.2", "1.4"], "zeroline": false, "tickfont": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "zerolinecolor": "rgba(0, 0, 0, 1)", "anchor": "x", "visible": true, "ticks": "inside", "tickmode": "array", "linecolor": "rgba(0, 0, 0, 1)", "showgrid": true, "title": {"text": "", "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}}, "gridcolor": "rgba(0, 0, 0, 0.1)", "tickcolor": "rgb(0, 0, 0)", "type": "linear"}, "legend": {"yanchor": "auto", "xanchor": "auto", "bordercolor": "rgba(0, 0, 0, 1)", "bgcolor": "rgba(255, 255, 255, 1.000)", "borderwidth": 1, "tracegroupgap": 0, "y": 1, "font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 11}, "title": {"font": {"color": "rgba(0, 0, 0, 1)", "family": "sans-serif", "size": 15}, "text": ""}, "traceorder": "normal", "x": 1}, "width": 1509.984375}}