OpenModelica / OMSimulator

The OpenModelica FMI & SSP-based co-simulation environment.
Other
67 stars 49 forks source link

Unable to change parameter values using replaceSubModel in OMSimulator Python #1262

Open njsaisashank opened 9 months ago

njsaisashank commented 9 months ago

@arun3688 I have opened an issue in the OMSimulator repository like you mentioned and also I am sharing the ssp file, the python script and also the fmu file that needs to be replaced for your reference. Please look into it. replaceSubModel.zip

arun3688 commented 9 months ago

@njsaisashank the API is working as expected, you cannot see the new replaced values because of the <parameterBindings> values defined in ssd for the VFController.fmu has more priority compared to the new start values defined in the modeldescription.xml in the replacing fmu VFController2.fmu, these are the parameterBindings defined in ssd

<ssd:ParameterBindings>
  <ssd:ParameterBinding>
    <ssd:ParameterValues>
      <ssv:ParameterSet
        version="1.0"
        name="parameters">
          <ssv:Parameter
            name="trapezoid.width">
            <ssv:Real
              value="20"
              unit="s" />
          </ssv:Parameter>
          <ssv:Parameter
            name="trapezoid.rising">
            <ssv:Real
              value="10"
              unit="s" />
          </ssv:Parameter>
          <ssv:Parameter
            name="trapezoid.amplitude">
            <ssv:Real
              value="60" />
          </ssv:Parameter>
        </ssv:Parameters>
      </ssv:ParameterSet>
    </ssd:ParameterValues>
  </ssd:ParameterBinding>
</ssd:ParameterBindings>

And this is the reason the new values are not updated, I hope you set this values using oms_setReal API when creating the ssp.

I made a minimal example where you can see the new start values gets updated in the replaced fmus, I just extracted your ssp and made this example

from OMSimulator import OMSimulator

oms = OMSimulator()

oms.setTempDirectory("./replacesubmodel_py/")

oms.newModel("sim1")

oms.addSystem("sim1.Root", oms.system_wc)
oms.addSubModel("sim1.Root.VfController", "sim1/resources/0005_VfController.fmu")

print("info:    Original VfController_Model_inside ssp")
print("info:     sim1.Root.VfController.trapezoid.width      : " , oms.getReal("sim1.Root.VfController.trapezoid.width")[0])
print("info:     sim1.Root.VfController.trapezoid.amplitude  : " , oms.getReal("sim1.Root.VfController.trapezoid.amplitude")[0])
print("info:     sim1.Root.VfController.trapezoid.rising     : " , oms.getReal("sim1.Root.VfController.trapezoid.rising")[0])

oms.replaceSubModel("sim1.Root.VfController", "VfController2.fmu", False)

print("info:    After Replacing VfController_Model")
print("info:     sim1.Root.VfController.trapezoid.width      : " , oms.getReal("sim1.Root.VfController.trapezoid.width")[0])
print("info:     sim1.Root.VfController.trapezoid.amplitude  : " , oms.getReal("sim1.Root.VfController.trapezoid.amplitude")[0])
print("info:     sim1.Root.VfController.trapezoid.rising     : " , oms.getReal("sim1.Root.VfController.trapezoid.rising")[0])

Output

# ../../install/bin/OMSimulatorPython3 oms.py
info:    Original VfController_Model_inside ssp
info:     sim1.Root.VfController.trapezoid.width      :  20.0
info:     sim1.Root.VfController.trapezoid.amplitude  :  60.0
info:     sim1.Root.VfController.trapezoid.rising     :  10.0
info:    After Replacing VfController_Model
info:     sim1.Root.VfController.trapezoid.width      :  40.0
info:     sim1.Root.VfController.trapezoid.amplitude  :  30.0
info:     sim1.Root.VfController.trapezoid.rising     :  20.0

Example for priority values in parameterBindings over modeldescription.xml in the new replaced fmu , so that new start values are not replaced

from OMSimulator import OMSimulator
oms = OMSimulator()

oms.setTempDirectory("./replacesubmodel_py/")
oms.newModel("sim1")
oms.addSystem("sim1.Root", oms.system_wc)
oms.addSubModel("sim1.Root.VfController", "sim1/resources/0005_VfController.fmu")

## set new value for trapezoid.width
oms.setReal("sim1.Root.VfController.trapezoid.width", -100)

oms.export("sim1", "replaceSubmodelError.ssp")
oms.terminate("sim1")
oms.delete("sim1")

oms.importFile("replaceSubmodelError.ssp")

print("info:    After setting new value VfController")
print("info:     sim1.Root.VfController.trapezoid.width      : " , oms.getReal("sim1.Root.VfController.trapezoid.width")[0])
print("info:     sim1.Root.VfController.trapezoid.amplitude  : " , oms.getReal("sim1.Root.VfController.trapezoid.amplitude")[0])
print("info:     sim1.Root.VfController.trapezoid.rising     : " , oms.getReal("sim1.Root.VfController.trapezoid.rising")[0])

oms.replaceSubModel("sim1.Root.VfController", "VfController2.fmu", False)

print("info:    After Replacing VfController_Model")
print("info:     sim1.Root.VfController.trapezoid.width      : " , oms.getReal("sim1.Root.VfController.trapezoid.width")[0])
print("info:     sim1.Root.VfController.trapezoid.amplitude  : " , oms.getReal("sim1.Root.VfController.trapezoid.amplitude")[0])
print("info:     sim1.Root.VfController.trapezoid.rising     : " , oms.getReal("sim1.Root.VfController.trapezoid.rising")[0])

Output

info:    After setting new value VfController
info:     sim1.Root.VfController.trapezoid.width      :  -100.0
info:     sim1.Root.VfController.trapezoid.amplitude  :  60.0
info:     sim1.Root.VfController.trapezoid.rising     :  10.0

info:    After Replacing VfController_Model
info:     sim1.Root.VfController.trapezoid.width      :  -100 ## here you can see the value is not updated based on priority over values set by user
info:     sim1.Root.VfController.trapezoid.amplitude  :  30.0
info:     sim1.Root.VfController.trapezoid.rising     :  20.0
arun3688 commented 9 months ago

@njsaisashank the meaning for dry is

    if (dryRun==true)
      showwarnings, reimport the snapshot and replacing is not done
    else
      show warnings and replace is done

But i also found that there is a bug if we directly replace the submodel from memory without exporting to the ssp. The priority set by user is not taken into account see below

from OMSimulator import OMSimulator
oms = OMSimulator()
oms.setTempDirectory("./replacesubmodel_py/")

oms.newModel("sim1")
oms.addSystem("sim1.Root", oms.system_wc)
oms.addSubModel("sim1.Root.VfController", "sim1/resources/0005_VfController.fmu")

## set new value for trapezoid.width
oms.setReal("sim1.Root.VfController.trapezoid.width", -100)

print("info:    Original VfController_Model_inside ssp")
print("info:     sim1.Root.VfController.trapezoid.width      : " , oms.getReal("sim1.Root.VfController.trapezoid.width")[0])
print("info:     sim1.Root.VfController.trapezoid.amplitude  : " , oms.getReal("sim1.Root.VfController.trapezoid.amplitude")[0])
print("info:     sim1.Root.VfController.trapezoid.rising     : " , oms.getReal("sim1.Root.VfController.trapezoid.rising")[0])

oms.replaceSubModel("sim1.Root.VfController", "VfController2.fmu", False)

print("info:    After Replacing VfController_Model")
print("info:     sim1.Root.VfController.trapezoid.width      : " , oms.getReal("sim1.Root.VfController.trapezoid.width")[0])
print("info:     sim1.Root.VfController.trapezoid.amplitude  : " , oms.getReal("sim1.Root.VfController.trapezoid.amplitude")[0])
print("info:     sim1.Root.VfController.trapezoid.rising     : " , oms.getReal("sim1.Root.VfController.trapezoid.rising")[0])

# ../../install/bin/OMSimulatorPython3 oms.py
info:    Original VfController_Model_inside ssp
info:     sim1.Root.VfController.trapezoid.width      :  -100.0
info:     sim1.Root.VfController.trapezoid.amplitude  :  60.0
info:     sim1.Root.VfController.trapezoid.rising     :  10.0

info:    After Replacing VfController_Model
info:     sim1.Root.VfController.trapezoid.width      :  40.0  ## bug here it should -100
info:     sim1.Root.VfController.trapezoid.amplitude  :  30.0
info:     sim1.Root.VfController.trapezoid.rising     :  20.0
njsaisashank commented 9 months ago

@arun3688 I have actually created the ssp using the OMEdit. Does it mean that OMEdit uses the set_real API by default? If so, are there any settings I could change so that it doesn't do it?

arun3688 commented 9 months ago

@njsaisashank no OMEdit internally calls OMSimulator API to make the ssp, setReal is called during different modes, during initialization, instantantion and simulation, but before instantiation if you use setReal it means you are setting a new value for the variable and it will be used for the simulation. e.g

from OMSimulator import OMSimulator
oms = OMSimulator()
oms.setTempDirectory("./replacesubmodel_py/")
oms.newModel("sim1")
oms.addSystem("sim1.Root", oms.system_wc)
oms.addSubModel("sim1.Root.VfController", "sim1/resources/0005_VfController.fmu")
## set new value by user for trapezoid.width 
oms.setReal("sim1.Root.VfController.trapezoid.width", -100)

oms.instantiate("sim1")
oms.initialize("sim1")
oms.simulate("sim1")

So this is how it works, and by default if nothing is set by the user or value is not modified, then the default values does not come in parameterBindings in SystemStructure.ssd , I have not used OMEDit to test this so i am not sure, but you can use OMSimulator from command Line as well

arun3688 commented 9 months ago

@njsaisashank I tested the example with OMEdit and i found that if you just opened the parameter dialogue of an fmu and even if you don't change any values it gets updated in the ssd file which should not be the case and that is why there is a difference from the command line and OMEdit, this need to be fixed in OMEdit

njsaisashank commented 9 months ago

Yes, I think that is the case. I think it would work only if the fmus are added and connections are given and saved without modifying anything else.

njsaisashank commented 9 months ago

Anyway, thanks a lot for the help.

arun3688 commented 9 months ago

@njsaisashank this commit https://github.com/OpenModelica/OMSimulator/pull/1264 will fix the replaceSubModel() API when replacing submodel directly from memory without exporting to a ssp file see example https://github.com/OpenModelica/OMSimulator/blob/master/testsuite/simulation/replaceSubmodel14.py and https://github.com/OpenModelica/OMSimulator/blob/master/testsuite/simulation/replaceSubmodel13.py

However still the OMEdit issue exists and we will try to fix it