Opened 4 years ago

Last modified 3 years ago

#6080 new defect

Changing parameters of a model via Python

Reported by: bode@… Owned by: Lennart Ochel
Priority: high Milestone:
Component: FMI Version: v1.16.0-dev
Keywords: Cc:

Description

I created a minimal example (DC-Voltage, Load) in OpenModelica. Afterwards, I created an FMU and used it via Python.

Problem summary: By using just a Resistor as a load, i can´t change the parameters via python. After adding an Inductor to the model, I can change some parameters and the simulation reacts to this changes.

In this simple model, there is nothing which could cause troubles from the electrical engineering part, the problem must be somewhere else.

Model Set-up

Problematical Model:

https://i.stack.imgur.com/MFQz5.png

 model testbench
  parameter Real v_DC (start = 100);
  Modelica.Blocks.Sources.RealExpression realExpression(y = v_DC)  annotation(
    Placement(visible = true, transformation(origin = {-70, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Electrical.Analog.Sources.SignalVoltage signalVoltage annotation(
    Placement(visible = true, transformation(origin = {-30, 46}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Electrical.Analog.Basic.Resistor resistor(R = 10)  annotation(
    Placement(visible = true, transformation(origin = {-30, 14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Electrical.Analog.Basic.Ground ground annotation(
    Placement(visible = true, transformation(origin = {28, 28}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
equation
  connect(realExpression.y, signalVoltage.v) annotation(
    Line(points = {{-58, 70}, {-30, 70}, {-30, 58}, {-30, 58}}, color = {0, 0, 127}));
  connect(signalVoltage.n, resistor.n) annotation(
    Line(points = {{-20, 46}, {-6, 46}, {-6, 14}, {-20, 14}, {-20, 14}}, color = {0, 0, 255}));
  connect(signalVoltage.n, ground.p) annotation(
    Line(points = {{-20, 46}, {28, 46}, {28, 38}, {28, 38}}, color = {0, 0, 255}));
  connect(resistor.p, signalVoltage.p) annotation(
    Line(points = {{-40, 14}, {-40, 14}, {-40, 46}, {-40, 46}}, color = {0, 0, 255}));
  annotation(
    uses(Modelica(version = "3.2.3")));
end testbench;

Partly working model:
https://i.stack.imgur.com/w4ncq.png

model testbench
  parameter Real v_DC (start = 100);
  Modelica.Blocks.Sources.RealExpression realExpression(y = v_DC)  annotation(
    Placement(visible = true, transformation(origin = {-70, 70}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Electrical.Analog.Sources.SignalVoltage signalVoltage annotation(
    Placement(visible = true, transformation(origin = {-30, 46}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Electrical.Analog.Basic.Resistor resistor(R = 10)  annotation(
    Placement(visible = true, transformation(origin = {-30, 14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Electrical.Analog.Basic.Ground ground annotation(
    Placement(visible = true, transformation(origin = {28, 28}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
  Modelica.Electrical.Analog.Basic.Inductor inductor annotation(
    Placement(visible = true, transformation(origin = {-60, 14}, extent = {{-10, -10}, {10, 10}}, rotation = 0)));
equation
  connect(realExpression.y, signalVoltage.v) annotation(
    Line(points = {{-58, 70}, {-30, 70}, {-30, 58}, {-30, 58}}, color = {0, 0, 127}));
  connect(signalVoltage.n, resistor.n) annotation(
    Line(points = {{-20, 46}, {-6, 46}, {-6, 14}, {-20, 14}, {-20, 14}}, color = {0, 0, 255}));
  connect(signalVoltage.n, ground.p) annotation(
    Line(points = {{-20, 46}, {28, 46}, {28, 38}, {28, 38}}, color = {0, 0, 255}));
  connect(inductor.n, resistor.p) annotation(
    Line(points = {{-50, 14}, {-40, 14}, {-40, 14}, {-40, 14}}, color = {0, 0, 255}));
  connect(signalVoltage.p, inductor.p) annotation(
    Line(points = {{-40, 46}, {-74, 46}, {-74, 14}, {-70, 14}, {-70, 14}}, color = {0, 0, 255}));
  annotation(
    uses(Modelica(version = "3.2.3")));
end testbench;

Used Software

Windows 10
OpenModelica 1.16.0
PyFMI 2.5
Spyder 3.3.6

FMU Creation

Created the FMU with a .mos file with the following settings:

OpenModelica.Scripting.loadFile("testbench.mo"); getErrorString();
setCommandLineOptions("-d=newInst"); getErrorString();
setCommandLineOptions("-d=initialization"); getErrorString();
setCommandLineOptions("--simCodeTarget=Cpp"); getErrorString();
setCommandLineOptions("-d=-disableDirectionalDerivatives"); getErrorString();
OpenModelica.Scripting.translateModelFMU(testbench, version="2.0", fmuType = "me"); getErrorString();

Python code for testing

import pylab as P
import numpy as N

from pyfmi import load_fmu

def run_demo(with_plots=True):

    model = load_fmu('testbench.fmu') 
    Tstart = 0.0 #
    Tend   = 0.1     
    dt = 0.0001 
  
    model.setup_experiment(start_time = Tstart) 
    model.enter_initialization_mode()
    model.exit_initialization_mode()
    time = Tstart
    
    model.enter_continuous_time_mode()
    x = model.continuous_states
    model.set('resistor.R', 1000)
    model.set('v_DC', 5700)

    vref  = [model.get_variable_valueref('resistor.i')]    
    vref2  = [model.get_variable_valueref('resistor.R')]  
    t_sol = [Tstart]
    sol = [model.get_real(vref)]  
    sol2 = [model.get_real(vref2)]     
    
    while time < Tend:

        dx = model.get_derivatives()
             
        time = time + dt
        model.time = time
        x = x + dt*dx
        model.continuous_states = x
        t_sol += [time]
        sol += [model.get_real(vref)]
        sol2 += [model.get_real(vref2)]
        
    if with_plots:
        P.figure(1)
        P.plot(t_sol,N.array(sol)[:,0])
        P.title(model.get_name())
        P.ylabel('Current at Resistor1 (A)')
        P.xlabel('Time (s)')
        P.figure(2)
        P.plot(t_sol,N.array(sol2)[:,0])
        P.title(model.get_name())
        P.ylabel('Resistor1 (Ohm)')
        P.xlabel('Time (s)')


if __name__ == "__main__":
    run_demo()


Bugs

In the second model (with the inductor), a change of the DC voltage (model.set('v_DC', 5700)) leads to a proportional change of the current at resistor1. This works as it should.

A change of the value of the resistor (model.set('resistor.R', 10000)) does not affect the current in the resistor in any way. The printing the value shows the one which was actually set (see second plotted figure), but for the calculation of the current, the default value which was selected in OpenModelica is used.

In the first model (without inductor), neither a change in the DC voltage nor a change in the Resistor affect the current in the resistor, though should.

Within other models, changing the value of the resistor works with the demanded result, and we had difficulties setting the voltage of the source.

Is there a mistake in the way of setting the parameters, a bug in OpenModelica, in PyFMI, or what is going on here?

Change History (9)

comment:1 by Francesco Casella, 4 years ago

Milestone: 1.16.01.17.0

comment:2 by trista.arinomo@…, 4 years ago

Just curious, have you try to add a parameter for resistor in the highest model?

e.g.

parameter Real R_param(unit="Ohm", start=10);
Modelica.Electrical.Analog.Basic.Resistor resistor(R = R_param);

if I understand correctly, you can only set parameter on the highest model layer on FMU but not sub-model. CMIIW

comment:3 by trista.arinomo@…, 4 years ago

ignore my comment, did not read the ticket properly. sorry

in reply to:  3 comment:4 by anonymous, 4 years ago

Replying to trista.arinomo@…:

ignore my comment, did not read the ticket properly. sorry

No problem, still thank you for your interest :-)

In Our main toolbox, it is with our actual model possible to change the resistors (4. Level), but not the v_DC (first level).

But yes, the Level seems to be in the settings important, since it is (as far as I know) only possible to hand ove inputs to the first level, and not to the ones behind it.

comment:5 by trista.arinomo@…, 4 years ago

i was testing you model a little bit and able to change the parameters of resistor.R and inductor.L and got a right result (at least almost the same results from simulation in OM) when i set the model parametes in the initialization mode

    model.setup_experiment(start_time = Tstart) 
    model.enter_initialization_mode()
    model.set('resistor.R', 100)
    model.set('inductor.L',10)
    model.exit_initialization_mode()
    time = Tstart
    
    model.enter_continuous_time_mode()
    x = model.continuous_states
    model.set('v_DC', 5700)

so i assume you have to set parameter of sub-models in initializaiton mode, and the top model could be changed in continous time mode.

hope it helps, and if its incorrect than maybe dev will tell us the preferable approch for manipulating parameter in FMU


comment:6 by bode@…, 4 years ago

This helps a little, thank you!

But this is not the whole truth, especially since it seems to be possible for some parameters to be changed in the cont. time mode.

And this feature is important for us. We wrote an open source toolbox for machine learning in inverter tuning in electrical grids. One important feature is a loadstep, meaning a change of the resistor (and inductor...) after a certain simulation time. So changing them in the cont. mode in between some simulation steps is really important for us. It seems to work sometimes, but not reliable.

The developer (modelon) does not seem to be to motivated in answering questions, especially since the main developer of this project left the company, at least as far as I know.

comment:7 by bode@…, 4 years ago

Somehow, it seems to be an FMU issue.

writing the model.set(...) in between enter- and exit_initialization_mode() works for most models fine. Even during simulations, so that a parameterchange within the middle of a simulation works.

But in some models, absolutely nothing happens. I can not even chance the value of a resistor. The FMU is generated with the same .mos file, it is a similar type of simulation, but not even the value of the resistor gets changed.

From this package:

https://github.com/upb-lea/openmodelica-microgrid-gym/blob/measurment/fmu/grid.mo

I am using the model grid.testbench_SC2

It consists of 3 inputs, a 3-phase inverter which transforms the input with the gain v_DC to a voltage, and a LC filter. The phases behind the filter are shortcutted.

Generate the FMU via

OpenModelica.Scripting.loadFile("grid.mo"); getErrorString();
setCommandLineOptions("-d=newInst"); getErrorString();
setCommandLineOptions("-d=initialization"); getErrorString();
setCommandLineOptions("--simCodeTarget=Cpp"); getErrorString();
setCommandLineOptions("-d=-disableDirectionalDerivatives"); getErrorString();
OpenModelica.Scripting.translateModelFMU(grid.testbench_SC2, version="2.0", fmuType = "me"); getErrorString();

Here, the first strange thing happens: I only get warnings for fixed startvalues of 2 of the 3 state-variables of the model, the inductor currents.
The third inductorcurrent (inductor1) is not mentioned.

Testing the FMU with following code showed that there were big issues which could not be solved/explained with the previously gained insights.

import pylab as P
import numpy as N

from pyfmi import load_fmu


def run_demo(with_plots=True):
    model = load_fmu('grid.testbench_SC2.fmu')
    Tstart = 0.0  #
    Tend = 0.1
    dt = 0.0001

    n = 0
    model.setup_experiment(start_time=Tstart)
    model.enter_initialization_mode()
    model.set('inverter1.v_DC', 570) # This parameterchange works
    model.set('rl.resistor1.R', 10) # This parameterchange does not work
    model.exit_initialization_mode()
    time = Tstart

    model.enter_continuous_time_mode()
    x = model.continuous_states

    vref = [model.get_variable_valueref('rl.resistor1.i')]
    vref2 = [model.get_variable_valueref('rl.resistor1.R')]
    vref3 = [model.get_variable_valueref('rl.resistor2.R')]
    t_sol = [Tstart]
    sol = [model.get_real(vref)]
    sol2 = [model.get_real(vref2)]
    sol3 = [model.get_real(vref2)]

    model.set('rl.resistor2.R', 10)

    while time < Tend:
        model.set('i1p1', 0)
        model.set('i1p2', 1)
        model.set('i1p3', 0)
        model.enter_initialization_mode()
        model.set('rl.resistor2.R', 100)
        model.exit_initialization_mode()
        dx = model.get_derivatives()
        n = n + 1
        if n == 200:
            model.enter_initialization_mode()
            model.set('inverter1.v_DC', 5700) # this change works again
            model.set('rl.resistor1.R', 100) # This does not work
            model.exit_initialization_mode()
            print(n) # check if the if-condition was fulfilled
        time = time + dt
        model.time = time
        x = x + dt * dx
        model.continuous_states = x
        t_sol += [time]
        sol += [model.get_real(vref)]
        sol2 += [model.get_real(vref2)]
        sol3 += [model.get_real(vref3)]
    if with_plots:
        P.figure(1)
        P.plot(t_sol, N.array(sol)[:, 0])
        P.title(model.get_name())
        P.ylabel('Current at Resistor1 (A)')
        P.xlabel('Time (s)')
        P.figure(2)
        P.plot(t_sol, N.array(sol2)[:, 0])
        P.title(model.get_name())
        P.ylabel('Resistor1 (Ohm)')
        P.xlabel('Time (s)')
        P.figure(3)
        P.plot(t_sol, N.array(sol3)[:, 0])
        P.title(model.get_name())
        P.ylabel('Resistor2 (Ohm)')
        P.xlabel('Time (s)')
        P.show()

if __name__ == "__main__":
    run_demo()

In theory, i should have been able to change the resistor while being in the initialization_mode, isn´t it?

So has anyone any clue, why this is not possible?

comment:8 by Francesco Casella, 4 years ago

Milestone: 1.17.01.18.0

Retargeted to 1.18.0 because of 1.17.0 timed release.

comment:9 by Francesco Casella, 3 years ago

Milestone: 1.18.0

Ticket retargeted after milestone closed

Note: See TracTickets for help on using tickets.