Анализ чувствительности с использованием PyFMI - FMU в цикле for

Основная цель

Анализ чувствительности сети централизованного теплоснабжения.

Подход

  1. Модель Modelica системы (в Dymola) с использованием библиотек AixLib и BuildingSystem

  2. Экспорт модели в качестве симулятора FMU

  3. Используйте SALib (библиотека Python для анализа чувствительности), чтобы определить образцы (параметр развертки)

  4. Используйте PyFMI для запуска модели в цикле for в Python для всех отдельных выборок (и распараллеливание цикла for, возможно, с использованием JobLib для выполнения моделирования на нескольких процессорах)

  5. 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.

Другие вопросы по тегам