Skip to content

Output violates force balance of a connection set in ME FMU simulation #405

@cbu-hw

Description

@cbu-hw

We have an ME FMU (related to #403, same original problem model, different MWE) that we're simulating with pyfmi (CVode), and we find that the outputs are not consistent -- the forces in a connection between one mass and an array of two MSL ElastoGaps do not sum to (approximately) zero when computed from the csv output results (postproc_sum)
Tracking the same sum in the Modelica model works as expected (internal_sum).

If elastoGap is not a 2-element array but a single object, the problem disappears, and postproc_sum becomes zero.

We simulated with pyfmi (mismatch O(1e0)), fmpy (mismatch O(1e-14)) and OMSimulator (mismatch O(1e-10)) to exclude the FMU as the source of the problem.

Expected result: postproc_sum built from pyfmi simulation outputs remains very small throughout the simulation time.

model SumMismatchMWE
  Modelica.Mechanics.Translational.Components.ElastoGap[2] elastoGap(each s_rel(start = -0.1), each c = 100, each d = 0)  annotation(
    Placement(transformation(origin = {36, 14}, extent = {{-10, -10}, {10, 10}})));
  Modelica.Mechanics.Translational.Sources.Position position annotation(
    Placement(transformation(origin = {-40, 14}, extent = {{-10, -10}, {10, 10}})));
  Modelica.Blocks.Sources.Sine sine(f = 1, continuous = true)  annotation(
    Placement(transformation(origin = {-70, 14}, extent = {{-10, -10}, {10, 10}})));
  Modelica.Mechanics.Translational.Components.Mass[2] mass(each m = 1)  annotation(
    Placement(transformation(origin = {68, 14}, extent = {{-10, -10}, {10, 10}})));
  Modelica.Mechanics.Translational.Components.Mass UL(m = 1)  annotation(
    Placement(transformation(origin = {-14, 14}, extent = {{-10, -10}, {10, 10}})));
  Real internal_sum = UL.flange_b.f + elastoGap[1].flange_a.f + elastoGap[2].flange_a.f; // expected to be 0
equation
  for i in 1:2 loop
    connect(UL.flange_b, elastoGap[i].flange_a) annotation(
    Line(points = {{-4, 14}, {26, 14}}, color = {0, 127, 0}));
    connect(elastoGap[i].flange_b, mass[i].flange_a) annotation(
    Line(points = {{46, 14}, {58, 14}}, color = {0, 127, 0}));;
  end for;
  connect(sine.y, position.s_ref) annotation(
    Line(points = {{-59, 14}, {-52, 14}}, color = {0, 0, 127}));
  connect(position.flange, UL.flange_a) annotation(
    Line(points = {{-30, 14}, {-24, 14}}, color = {0, 127, 0}));
  annotation(
    uses(Modelica(version = "4.1.0")),
  experiment(StartTime = 0, StopTime = 1, Tolerance = 1e-06, Interval = 0.002));
end SumMismatchMWE;
Image Image Image Image
Python script producing the plots (for OMSimulator you have to set up a minimal SSP model)
"""Reproduce pyfmi force sum mismatch"""
from pathlib import Path

import fmpy
import matplotlib.pyplot as plt
import pandas as pd
import pyfmi
import assimulo

STOP_TIME = 0.25

def simulate_pyfmi(fmu_name):
    print(f'{pyfmi.__version__=}') # 2.21.0
    print(f'{assimulo.__version__=}') # 3.7.3
    model = pyfmi.load_fmu(fmu_name, kind='ME')

    opts = model.simulate_options()
    opts["logging"] = True
    opts["result_handling"] = "csv"
    print(opts)

    model.simulate(final_time=STOP_TIME, options=opts)
    print("Finished pyfmi simulation")

def simulate_fmpy(fmu_name):
    print(f'{fmpy.__version__=}')
    fmpy.dump(fmu_name)
    outputs = [
        'UL.flange_b.f',
        'elastoGap[1].flange_a.f',
        'elastoGap[2].flange_a.f',
        'internal_sum',
    ]
    result = fmpy.simulate_fmu(fmu_name, stop_time=STOP_TIME, fmi_type='ModelExchange', solver='CVode', output=outputs)
    fmpy.write_csv(Path(fmu_name).stem + '_result_fmpy.csv', result)

def postproc(resultfile, prefix='eHydroCOMHDRingValveSystem.SV.', fig_title = ''):
    df = pd.read_csv(resultfile, index_col='time')
    df['postproc_sum'] = df[prefix + 'UL.flange_b.f'] + df[prefix + 'elastoGap[1].flange_a.f'] + df[prefix + 'elastoGap[2].flange_a.f']
    df['abs_node_sum'] = abs(df['postproc_sum'])
    fig, axes = plt.subplots(nrows=3, ncols=1, sharex=True)
    fig.suptitle(fig_title)
    axes[0] = df.plot.line(y=[prefix + 'UL.flange_b.f', 
                              prefix + 'elastoGap[1].flange_a.f', 
                              prefix + 'elastoGap[2].flange_a.f'],
                           ax=axes[0],
                           )
    axes[1] = df.plot.line(y=['postproc_sum', prefix + 'internal_sum'], ax=axes[1])
    axes[2] = df.plot.line(y='abs_node_sum', logy=True, ax=axes[2])
    return fig


if __name__ == '__main__':
    simulate_pyfmi('SumMismatchMWE.fmu')
    postproc('SumMismatchMWE_result.csv', prefix='', fig_title='pyfmi')
    simulate_fmpy('SumMismatchMWE.fmu') 
    postproc('SumMismatchMWE_result_fmpy.csv', prefix='', fig_title='fmpy')
    #postproc('mismatch_res.csv', prefix='mismatch.Root.SumMismatchMWE.', fig_title='OMSimulator') # OMSimulator
    plt.show()

Versions:
pyfmi='2.21.0'
assimulo='3.7.3'
OpenModelica v1.27.0-dev-330-g5f16e75445
Windows 11

Metadata

Metadata

Labels

bugIssue or PR covers a bug.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions