Анализ чувствительности с использованием PyFMI - FMU в цикле for
Основная цель
Анализ чувствительности сети централизованного теплоснабжения.
Подход
Модель Modelica системы (в Dymola) с использованием библиотек AixLib и BuildingSystem
Экспорт модели в качестве симулятора FMU
Используйте SALib (библиотека Python для анализа чувствительности), чтобы определить образцы (параметр развертки)
Используйте PyFMI для запуска модели в цикле for в Python для всех отдельных выборок (и распараллеливание цикла for, возможно, с использованием JobLib для выполнения моделирования на нескольких процессорах)
SALib для выполнения анализа чувствительности на основе дисперсии ( http://salib.readthedocs.io/en/latest/basics.html)
Первый шаг
Простая модельная модель функции Исигами (не зависящая от времени). Эта функция часто используется для проверки методов анализа чувствительности ( https://www.sfu.ca/~ssurjano/ishigami.html).
Код Python (включая загрузку FMU с PyFMI и развертку параметров) работает нормально.
Эта проблема
После определенного количества симуляции мы получаем ошибку. Вывод ошибки выглядит не всегда одинаково. Иногда мы получаем
FMUException: Ошибка загрузки двоичного файла. Не удалось загрузить DLL: Eine DLL-Initialisierungsroutine ist fehlgeschlagen.
Перевод: процедура инициализации DLL не выполнена.
И иногда мы получаем:
FMUException: Ошибка загрузки двоичного файла. Не удалось загрузить DLL: Für diesen Befehl ist nicht genügend Speicher verfügbar.
Перевод: Недостаточно памяти для этой команды.
Ошибка возникает после примерно 650 прогонов симуляции. Это не зависит от того, выполняются ли симуляции в меньших блоках циклов, которые повторяются один за другим, или один цикл for проходит через все симуляции. Перезапустив консоль / процесс python, можно снова запустить новое моделирование.
Рабочая обстановка:
Windows 10, Python 2.7, PyFMI, установленный с использованием pip (не JModelica), Python-кодирование на ноутбуке Jupyther (на Mozilla Firefox)
У нас есть только базовые знания Python и PyFMI, и мы действительно боремся с этой ошибкой!
прикрепление
Ниже вы можете найти
Модель Modelica, используемая для экспорта совместного моделирования FMU из Dymola (с использованием CVode)
Код Python в виде файла py
Выходной точечный график кода питона.
Я также сделал сообщение на форуме JModelica, где вы можете загрузить файлы напрямую (FMU, блокнот Jupyter и т. Д.): http://www.jmodelica.org/27925
Моделька модель
model IshigamiFunction
final parameter Real a = 7;
final parameter Real b = 0.05;
parameter Real x1 = 1;
parameter Real x2 = 1;
parameter Real x3 = 1;
Real f;
equation
f = sin(x1) + a * sin(x2)^2 + b * x3^4 * sin(x1);
end IshigamiFunction;
Код Python
import numpy as np
import pylab as pl
from pyfmi import load_fmu
from SALib.sample import saltelli
from SALib.analyze import sobol
from ipywidgets import FloatProgress
from IPython.display import display
n = 100
problem = {
'num_vars': 3,
'names': ['x1', 'x2', 'x3'],
'bounds': [[-np.pi, np.pi],
[-np.pi, np.pi],
[-np.pi, np.pi]]
}
param_values = saltelli.sample(problem, n)
fmu = 'Model\IshigamiFunction\IshigamiFunction.fmu'
n_sim = param_values.shape[0]
# Progress bar
f = FloatProgress(min = 0, max = n_sim, description='Progress:')
display(f)
# Numpy array to save results
y = np.zeros([param_values.shape[0]])
x1 = np.zeros([param_values.shape[0]])
x2 = np.zeros([param_values.shape[0]])
x3 = np.zeros([param_values.shape[0]])
for i, X in enumerate(param_values):
model = load_fmu(fmu)
model.set(problem['names'], X)
res = model.simulate(final_time = 1)
y[i] = res['f'][-1]
x1[i] = res['x1'][-1]
x2[i] = res['x2'][-1]
x3[i] = res['x3'][-1]
f.value += 1
# Scatter plots
fig = pl.figure(figsize=(20, 5))
pl.clf()
pl.subplot(1,3,1)
pl.plot(x1, y, 'or')
pl.ylabel('x1')
pl.xlabel('f')
pl.subplot(1,3,2)
pl.plot(x2, y, 'ob')
pl.ylabel('x2')
pl.xlabel('f')
pl.subplot(1,3,3)
pl.plot(x3, y, 'og')
pl.ylabel('x3')
pl.xlabel('f')
pl.suptitle('Scatter plots')
pl.show()
# Sensitivity analysis
Si = sobol.analyze(problem, y, print_to_console=True)
Выходной сюжет из скрипта Python
Обновить
Я сделал еще несколько тестов, и вот что я нашел:
В зависимости от того, экспортируется ли FMU из Dymola или из JModelica, поведение может быть другим:
Использование FMU, экспортированного из Dymola:
- Принимая
load_fmu
линия из цикла for, кажется, работает - Даже с
load_fmu
не в цикле иногда случаются сбои - Добавление новой строки
model.reset()
передmodel.set(...)
Команда, кажется, работает нормально - Результаты отличаются при моделировании с или без
model.reset()
-> Почему?? model.instantiate()
вместоmodel.reset()
-> не работает. Использование памяти в диспетчере задач увеличивается примерно до 350 МБ, а затемFMUException: Не удалось создать экземпляр модели. Смотрите журнал для получения дополнительной информации.
Файл журнала с log_level=4:
FMIL: module = FMILIB, log level = 4: XML specifies FMI standard version 2.0
FMIL: module = FMILIB, log level = 4: Loading 'win32' binary with 'default' platform types
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiInstantiateModel completed
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiInstantiateSlave
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiInstantiateModel completed
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiInstantiateSlave
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetReal: x1 = -1.76101
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetReal: x2 = -2.53414
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetReal: x3 = 0.116583
FMIL: module = Model, log level = 4: [][FMU status:OK] fmi2SetupExperiment: startTime is set to 0
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiEnterSlaveInitializationMode...
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiEnterSlaveInitializationMode completed
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiExitSlaveInitializationMode...
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiExitSlaveInitializationMode completed
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetReal: x1 = -1.76101
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetReal: x2 = -2.53414
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetReal: x3 = 0.116583
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetReal: a = 7
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetReal: b = 0.05
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetReal: f = 1.29856
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.002
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.004
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.006
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiGetDerivatives
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.008
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.01
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.012
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.014
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.016
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.018
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.02
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
...
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.99
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.992
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.994
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.996
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 0.998
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiSetTime to 1
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiDoStep
FMIL: module = Model, log level = 1: [][FMU status:Fatal] The license file was not found. Use the environment variable "DYMOLA_RUNTIME_LICENSE" to specify your Dymola license file.
FMIL: module = Model, log level = 1: [][FMU status:Fatal] Instantiation failed
FMIL: module = Model, log level = 4: [][FMU status:OK] fmiFreeModelInstance
Использование FMU, экспортированного из JModelica:
- Работает нормально, даже если
load_fmu
находится в цикле for (но медленнее) - Этот опыт не соответствует примеру, приведенному в документации JModelica в главе 5.4.2 ( http://www.jmodelica.org/api-docs/usersguide/2.1/ch05s04.html), где
load_fmu
команда дается в цикле for - Команда
model.reset()
или жеmodel.instatiate()
требуется в течение цикла (в отличие от Димола FMU) -> Почему??
Мои вопросы:
Как правильно выполнять цикл, который многократно моделирует модель FMU с разными параметрами?
В чем разница между использованием model.reset()
, model.instatiate()
или никто из них?
прикрепление
Вот график, показывающий разницу между циклом model.reset()
и без этого.
FMU, экспортированный из JModelica (не требует лицензии), можно скачать здесь: http://www.jmodelica.org/27925
2 ответа
Правильный путь для FMU Dymola (и, вероятно, тот же для FMU от других поставщиков) будет вызывать fmi/fmi2Instantiate вне цикла for. Эти функции будут выделять память и выполнять проверку лицензии, если FMU экспортируется без двоичной лицензии на экспорт. Вызвав fmiResetSlave/fmi2Reset, вы можете сбросить FMU до установленного состояния без нового выделения памяти.
fmiInstantiateSlave / fmi2Instantiate
создает экземпляр FMU, который можно использовать для симуляции; несколько вызовов создадут несколько экземпляров, каждый из которых потребует нового выделения памяти и правильного удаления.
fmiReset
сбрасывает ваш экземпляр в состояние после создания экземпляра и перед вызовом fmiInitializeSlave/fmi2Intialize. Это быстрее, не требует нового динамического распределения памяти и должно использоваться в вашем случае.
Кроме того, проверка лицензии экспортируемого модуля Dymola FMU без двоичного экспорта может привести к утечке памяти в старых версиях Dymola при вызове fmiFreeSalveInstance/fmi2FreeInstance. В большинстве случаев это не является проблемой, так как вы обычно завершаете свою программу, когда прекращаете работу своего FMU. Создание экземпляра FMU внутри цикла for становится серьезным, и ваша память, наконец, заканчивается. Пакет исправлений должен быть доступен, если вы обратитесь в службу поддержки Dymola.
Это похоже на проблему с памятью для меня. Можете ли вы наблюдать за выделенной памятью во время выполнения в диспетчере задач Win? Кстати, ваш FMU (из кросс-поста) требует DYMOLA_RUNTIME_LICENSE, который ограничивает воспроизведение только для пользователей Dymola.