使用PyFMI进行灵敏度分析 - FMU for for-loop

时间:2017-11-17 19:24:37

标签: python modelica fmi jmodelica

主要目标

区域供热网络的敏感性分析。

方法

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

  2. 将模型导出为FMU协同模拟

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

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

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

  6. 第一步

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

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

    问题

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

      

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

    翻译:DLL-Initilisation例程失败。

    有时我们得到:

      

    FMUException:加载二进制文件时出错。无法加载DLL:Für   Diesen Befehl istnichtgenügendSpeicherverfügbar。

    翻译:此命令有内存不足

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

    工作环境:

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

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

    附件

    下面你可以找到

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

    • Python代码为py文件

    • python代码的输出散点图。

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

    Modelica模型

    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脚本的输出图 enter image description here

    更新

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

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

    使用从Dymola导出的FMU:

    • 从{for循环中取出load_fmu行似乎正常工作
    • 即使{for}循环中没有load_fmu,有时候也是如此 崩溃
    • model.reset()命令之前添加新行model.set(...) 似乎工作正常
    • 使用或不使用模拟时的结果会有所不同 model.reset() - >为什么??
    • 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
    

    使用从JModelica导出的FMU:

    • 即使load_fmu在for循环中(但速度较慢)
    • ,也能正常工作
    • 此体验与第5.4.2节(http://www.jmodelica.org/api-docs/usersguide/2.1/ch05s04.html#d0e1854)中JModelica文档中给出的示例不一致,其中在for循环中给出了load_fmu命令
    • 其中需要model.reset()model.instatiate()命令 for-loop(与Dymola FMU相反) - >为什么??

    我的问题:

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

    使用model.reset()model.instatiate()或其中之一有什么区别?

    附件

    这是一个图表,显示了for循环与model.reset()之间的区别。 enter image description here

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

2 个答案:

答案 0 :(得分:4)

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支持,则应提供修订包。

答案 1 :(得分:1)

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