opensim-org / opensim-core

SimTK OpenSim C++ libraries and command-line applications, and Java/Python wrapping.
https://opensim.stanford.edu
Apache License 2.0
783 stars 316 forks source link

Error raised when adding `ExternalForce` with data source to model in a function #3680

Closed mrrezaie closed 8 months ago

mrrezaie commented 8 months ago

Hi, when I define a Python function to add GRF ExternalForces with data source to model, an error would be raised. But I can add it outside the function without issue. Similar to https://github.com/opensim-org/opensim-core/issues/3210 and https://github.com/opensim-org/opensim-core/issues/3204.

Here is a code to reproduce the error. The test files are located here: \Resources\Code\Python\Moco\example3DWalking

This works well:

import opensim as osim

nameModel   = 'subject_walk_armless.osim'
nameGRF     = 'grf_walk.mot'
nameExtLoad = 'grf_walk.xml'

model = osim.Model(nameModel)

GRF = osim.Storage(nameGRF)
for extForce in osim.ForceSet(nameExtLoad):
    extForce = osim.ExternalForce.safeDownCast(extForce)
    extForce.setDataSource(GRF)
    model.getForceSet().cloneAndAppend(extForce)

model.initSystem()

This raises error:

def addGRFsToModel(osimModel, GRF_fileName, GRF_XML_fileName):
    # function to add GRF to model 
    GRF = osim.Storage(GRF_fileName)
    for extForce in osim.ForceSet(GRF_XML_fileName):
        extForce = osim.ExternalForce.safeDownCast(extForce)
        extForce.setDataSource(GRF)
        osimModel.getForceSet().cloneAndAppend(extForce)

model = osim.Model(nameModel)
addGRFsToModel(model, nameGRF, nameExtLoad)
model.initSystem()

RuntimeError: std::exception in 'SimTK::State & OpenSim::Model::initSystem()': ExternalForce: Data source subject11_noload_free_trial03_ground_reaction specified by name, but was set.

Is this somehow related to memory allocation?

Windows 10; Python v.3.11; OpenSim v.4.5

Looking forward to some improvements. Thanks a lot in advance!!!

nickbianco commented 8 months ago

@mrrezaie, the function is probably leading to something going out of scope in memory. It might work if you call initSystem inside the function instead.

However, I would recommend using ModelProcessor with ModOpAddExternalLoads as a safer/more robust alternative.

mrrezaie commented 8 months ago

Hi @nickbianco, thanks for your response.

It might work if you call initSystem inside the function instead.

This works, but any later initSystem call outside the function raises similar error.

However, I would recommend using ModelProcessor with ModOpAddExternalLoads as a safer/more robust alternative.

This is indeed a very nice alternative; thank you. I was aware of this method, just wanted to report this error.

nickbianco commented 8 months ago

Thanks @mrrezaie. Closing since this isn't really a bug, but again another quirk of using Python with OpenSim. (Python passes everything by reference, but OpenSim uses C++ object memory object semantics).

mrrezaie commented 8 months ago

😃 I found another way that is similar to ModOpAddExternalLoads and requires less lines:

model.addComponent( osim.ExternalLoads(ExtLoads_fileName,True) )