首页 文章

使用PyFMI - FMU在for循环中的灵敏度分析

提问于
浏览
3

Main goal

区域供热网络的灵敏度分析 .

Approach

  • Modelica模型的系统(在Dymola中)使用AixLib和BuildingSystem库

  • 将模型导出为FMU协同仿真

  • 使用SALib(灵敏度分析python库)定义样本(参数扫描)

  • 使用PyFMI在Python的for循环中为所有单个样本运行模型(并且可以使用JobLib并行化多个处理器上的仿真来并行化for循环)

  • SALib执行基于方差的灵敏度分析(http://salib.readthedocs.io/en/latest/basics.html#an-example

First step

Ishigami函数的简单modelica模型(不依赖于时间) . 此功能通常用于测试灵敏度分析方法(https://www.sfu.ca/~ssurjano/ishigami.html) .

python代码(包括用PyFMI加载FMU和参数扫描)工作正常 .

The problem

经过一定程度的模拟后,我们得到一个错误 . 错误输出看起来并不总是相同 . 有时我们得到

FMUException:加载二进制文件时出错 . 无法加载DLL:Eine DLL-Initialisierungsroutine ist fehlgeschlagen .

翻译:DLL-Initilisation例程失败 .

有时我们得到:

FMUException:加载二进制文件时出错 . 无法加载DLL:FürdiesenBefehl istnichtgenügendSpeicherverfügbar .

翻译:此命令有 not enough memory 可用 .

发生错误 after around 650 simulation runs . 这不依赖于是否在较小的循环块中执行模拟,这些循环块一个接一个地重新运行,或者如果一个单个循环遍历所有模拟 . 通过重新启动python控制台/进程,可以再次运行新的模拟 .

Working environment:

使用pip(不是JModelica)安装Windows 10,Python 2.7,PyFMI,在Jupyther笔记本上安装Python(在Mozilla Firefox上)

我们只有python和PyFMI的基本知识,并且真的在努力解决这个错误!

Attachment

你可以在下面找到

  • Modelica模型用于从Dymola导出协同仿真FMU(使用CVode)

  • Python代码为py文件

  • python代码的输出散点图 .

我还在JModelica论坛上发了帖子,你可以直接下载文件(FMU,Jupyter笔记本等):http://www.jmodelica.org/27925

Modelica model

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 code

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)

Output plot from python script
enter image description here

更新

我做了一些测试,这就是我发现的:

根据FMU是从Dymola还是从JModelica导出,行为是不同的:

Using an FMU exported from Dymola:

  • 从for循环中取出 load_fmu 行似乎有效

  • 即使 load_fmu 不在for循环中,有时也会崩溃

  • model.set(...) 命令之前添加新行 model.reset() 似乎工作正常

  • 使用或不使用 model.reset() -> Why?? 进行模拟时结果不同

  • model.instantiate() 而不是 model.reset() - >不起作用 . 任务管理器中的内存使用量最多可达350 MB左右

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

Using an FMU exported from JModelica:

  • 即使 load_fmu 在for循环内(但速度较慢)也能正常工作

  • 此体验与第5.4.2节(http://www.jmodelica.org/api-docs/usersguide/2.1/ch05s04.html#d0e1854)中JModelica文档中给出的示例不一致,其中在for循环中给出了 load_fmu 命令

  • for循环中需要 model.reset()model.instatiate() 命令(与Dymola FMU相反) -> Why??

My questions:

执行循环的原因是什么,它使用不同的参数多次模拟FMU模型?

使用 model.reset()model.instatiate() 或者没有一个有什么区别?

Attachment

这是一个图表,显示了for循环与 model.reset() 之间的差异,没有它 .
enter image description here

从JModelica导出的FMU(不需要任何许可证)可以在这里下载:http://www.jmodelica.org/27925#comment-6668

2 回答

  • 1

    Dymola FMU的正确方式(可能与其他供应商的FMU相同)将在for循环外调用fmi / fmi2Instantiate . 如果在没有二进制导出许可证的情况下导出FMU,这些功能将分配内存并执行许可证检查 . 通过调用fmiResetSlave / fmi2Reset,您可以将FMU重置为实例化状态,而无需新的内存分配 .

    • fmiInstantiateSlave / fmi2Instantiate

    创建一个可用于模拟的FMU实例,多个调用将创建多个实例,每个实例都需要新的内存分配和正确的删除 .

    • fmiReset

    重置你的实例化之后和调用fmiInitializeSlave / fmi2Intialize之前的实例 . 这更快,不需要新的动态内存分配,应该在您的情况下使用 .

    此外,在调用fmiFreeSalveInstance / fmi2FreeInstance时,在没有二进制导出的情况下导出的Dymola FMU的许可检查可能会泄漏旧Dymola版本中的内存 . 这在大多数情况下不是问题,因为您通常在终止FMU时终止程序 . 通过在for循环中实例化你的FMU,这变得严重,你的记忆将最终结束 . 如果您联系Dymola支持,应该可以使用修订包 .

  • 4

    这看起来像是一个记忆问题 . 您可以在Win任务管理器中运行期间观察分配的内存吗?顺便说一句,你的FMU(来自你的邮件)需要一个DYMOLA_RUNTIME_LICENSE,它仅限于Dymola用户的复制 .

相关问题