Kin/pot energy & joint reactions from MocoTrajectory in Matlab

OpenSim Moco is a software toolkit to solve optimal control problems with musculoskeletal models defined in OpenSim using the direct collocation method.
POST REPLY
User avatar
Pasha van Bijlert
Posts: 235
Joined: Sun May 10, 2020 3:15 am

Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Pasha van Bijlert » Wed Feb 24, 2021 3:52 pm

Hello all!

I'm working on a post processing script in Matlab that takes all the (subjectively) relevant model outputs computed from a MocoTrajectory (from a prediction solution). Think: states, controls, all fiber lengths, tendon lengths, active/passive fiber forces, tendon forces, etc. The reason for this is that I'm running simulations while sequentially increasing the desired speed of a locomotion task, and I'd like to batch-process the simulation results later. The script stores all of the outputs of a simulation in structured arrays within a single matlab 'struct', with all the column names as cell arrays as well, and saves it as a .mat file. This makes batch processing in Matlab efficient, without having to type lengthy column names (since those are all stored in array tables as well). Once the script is finished I'd be happy to post it on here, if people are interested.

It all works the way it should, except for two issues that I've run into.

1): I can't seem to extract the outputs of the model itself (CoM pos, vel, E_kin, E_pot).

Code: Select all

outputPaths_model = StdVectorString();
outputPaths_model.add('.*com_acceleration');
outputPaths_model.add('.*com_position');
outputPaths_model.add('.*com_velocity');
outputPaths_model.add('.*kinetic_energy');
outputPaths_model.add('.*potential_energy');

model_outputs_table=study.analyze(gaitPredictionSolution, outputPaths_model);
 
model_outputs=osimTableToStruct(model_outputs_table);
The above code only succeeds in acquiring the potential energy from the muscles in the model, while I was expecting it to provide me with the potential and kinetic energy of the model itself (I'd like to have this to see if/at what speed the model transitions from walking to running). I'm wondering if I'm perhaps overlooking some type of 'realizetovelocity' step or something similar, but I'm not sure how I would implement that.

2): I'd like to store the joint reaction forces/moments from a mocoTrajectory, so that I can get all the simulation data in a single data struct. The reason for this is that once I can access these, I'd like to work towards implementing a stress-constraint as a custom goal, similar to Sellers et al 2017. They showed that maximal running speed of T. rex was limited by stress on the limb bones. They compute limb stress using the following equations:
sellers et al 2017 equations.PNG
sellers et al 2017 equations.PNG (48.1 KiB) Viewed 2441 times
(taken from their paper, I think they define Z as up instead of Y as up).

They compute the stress on the hindlimbs using Euler-Bernoulli beam equations, so stress is the sum of the bending moments & compressive stresses on the limbs. To easily implement this, I'll be adding weldjoints at the mid point of each hindlimb segment. Before adding these, however, I'd like to be able to access the jointreactions from a MocoTrajectory in Matlab, but I'm not sure how to best approach this. The examples that I found on the Opensim forum relate to running an analysis in the standalone Opensim program, which is not what I'm trying to achieve.

As an aside: I'd like to work towards running optimizations with different stress levels set as inequality constraints (i.e. 100 MPa, 200MPa, etc). Is this possible using a custom goal in Moco? I was confused by the wording of "endpoint constraint' in the documentation, but my thinking was that I could set an endpoint constraint to lie between 0 - 200, if I wanted it to work as an inequality constraint? Or would the correct route be a regular weighted cost? I also expect that I can approximate the effect of the stress constraint by adding the weldjoints, and then defining M_z and M_x and F_y as standard joint reaction costs, although I suspect that this route would require a lot of tuning of their relative weights.

Any suggestions are welcome!
Pasha

User avatar
Pasha van Bijlert
Posts: 235
Joined: Sun May 10, 2020 3:15 am

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Pasha van Bijlert » Tue Mar 09, 2021 10:58 am

I've figured out the answer to my first question, and thought I would post it here just in case someone finds this thread in the future, and was having the same issues as me.

Code: Select all

statesTraj= mocoTrajectory.exportToStatesTrajectory(model); %get a StatesTrajectory from a mocoTrajectory

for i = 1:statesTraj.getSize  %loop through each timepoint/state in the statesTrajectory
    
    model.realizeDynamics(statesTraj.get(i-1)) %realize model stage, with current state as input
    E_kin(i,1)= model.calcKineticEnergy(statesTraj.get(i-1));
    E_pot(i,1)= model.calcPotentialEnergy(statesTraj.get(i-1));
    
    CoM_pos(i,1)= model.calcMassCenterPosition(statesTraj.get(i-1)).get(0);%CoM_x
    CoM_pos(i,2)= model.calcMassCenterPosition(statesTraj.get(i-1)).get(1);%CoM_y
    CoM_pos(i,3)= model.calcMassCenterPosition(statesTraj.get(i-1)).get(2);%CoM_z
    
    
    
end

mass=model.getTotalMass(statesTraj.get(0)); %get the mass of your model
E_pot_com=mass*9.81*CoM_pos(:,2);  %E_pot of the CoM
I realized after some quick napkin math that "calcPotentialEnergy" includes both E_pot of the CoM (m*g*CoM_y), and the potential energy from the outputs of each muscle. That's why I added the last two lines, since I was after E_pot of the center of mass.

User avatar
Nicholas Bianco
Posts: 1082
Joined: Thu Oct 04, 2012 8:09 pm

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Nicholas Bianco » Wed Mar 10, 2021 3:01 am

Hi Pasha,

Glad you figured out the potential energy issue. I actually didn't realize that model.calcPotentialEnergy() would include muscle potential energy, good to know!
Before adding these, however, I'd like to be able to access the jointreactions from a MocoTrajectory in Matlab, but I'm not sure how to best approach this.
In Matlab, you can use analyzeSpatialVec() to compute the Outputs "reaction_on_child" and "reaction_on_parent" of the Joint class. No need to run a JointReaction analysis.
Is this possible using a custom goal in Moco? I was confused by the wording of "endpoint constraint' in the documentation, but my thinking was that I could set an endpoint constraint to lie between 0 - 200, if I wanted it to work as an inequality constraint?
It is possible to do this, but it would developing a new MocoGoal that could add arbitrary model Outputs to an endpoint constraint. But I think you want a path constraint, meaning that you want to keep stress levels below 200MPa throughout the whole trajectory (this would also require a new MocoPathConstraint).
Or would the correct route be a regular weighted cost? I also expect that I can approximate the effect of the stress constraint by adding the weldjoints, and then defining M_z and M_x and F_y as standard joint reaction costs, although I suspect that this route would require a lot of tuning of their relative weights.
This actually might be the quickest way to go for now, as you can use the MocoJointReactionGoal as-is. You will have approximate the actual bending moment with cost weights as you say, but no new components or MocoGoals are needed.

-Nick

User avatar
Pasha van Bijlert
Posts: 235
Joined: Sun May 10, 2020 3:15 am

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Pasha van Bijlert » Wed Mar 10, 2021 1:04 pm

Hi Nick,
In Matlab, you can use analyzeSpatialVec() to compute the Outputs "reaction_on_child" and "reaction_on_parent" of the Joint class. No need to run a JointReaction analysis.
That sounds exactly like what I need! Do you know where I can find the correct call to analyzeSpatialVec in Matlab? I had tried the following two versions after you mentioned it in the other thread with Ross Miller:

Code: Select all

 JR_paths=StdVectorString();
 JR_paths.add('.*reaction_on_parent');
 JR_paths.add('.*reaction_on_child');
 
JR_outputs_table=study.analyzeSpatialVec(gaitPredictionSolution, JR_paths);
This throws the error: "Check for missing argument or incorrect argument data type in call to function 'analyzeSpatialVec'." I'm not sure where to find the correct call to analyzeSpatialVec in matlab (it's also not listed as a method for a mocoStudy). I tried searching for analyzeSpatialVec on Doxygen to see what the inputs are, but I couldn't find it there. On github, I found the following way to call on the function (translated to Matlab):

Code: Select all

statesTST= mocoTrajectory.exportToStatesTable;
controlsTST= mocoTrajectory.exportToControlsTable;

JR_outputs_table = analyzeSpatialVec(model,statesTST, controlsTST, JR_paths);
That throws the same error, but I'm not sure where I can find the correct inputs (I double checked that my TimeSeriesTables are indeed TimeSeriesTables, and I tried searching the opensim forum as well but to no avail).

Thanks for your help!
Pasha

User avatar
Nicholas Bianco
Posts: 1082
Joined: Thu Oct 04, 2012 8:09 pm

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Nicholas Bianco » Wed Mar 10, 2021 1:12 pm

Hi Pasha,

Are you using Moco 0.4?

User avatar
Pasha van Bijlert
Posts: 235
Joined: Sun May 10, 2020 3:15 am

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Pasha van Bijlert » Wed Mar 10, 2021 1:31 pm

Hey Nick,

Yes, I think I am. To be precise, org.opensim.modeling.opensimMoco.GetMocoVersionAndDate() outputs:

version 0.4.0, build date 23:46:16 Apr 7 2020

User avatar
Nicholas Bianco
Posts: 1082
Joined: Thu Oct 04, 2012 8:09 pm

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Nicholas Bianco » Wed Mar 10, 2021 2:04 pm

Try this:

Code: Select all

JR_outputs_table = analyzeSpatialVec(model, gaitPredictionSolution, JR_paths);
MocoStudy's analyze() function only support scalar (double) Outputs. You were right to try the base utility, but just a little off with the syntax. If you're looking on GitHub, the opensim-moco repo is where you need to look for Moco 0.4.0. The Moco stuff on opensim-core has yet to be put out on an official release (although that's coming soon).

Best,
-Nick

User avatar
Pasha van Bijlert
Posts: 235
Joined: Sun May 10, 2020 3:15 am

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Pasha van Bijlert » Wed Mar 10, 2021 2:31 pm

Hi Nick,

I get the same error when I try that (Check for missing argument or incorrect argument data type in call to function 'analyzeSpatialVec'.).

model, gaitPredictionSolution & JR_paths exist in the workspace and can be used in other functions, so I think the issue might still be the syntax?

Just to be sure, this is the correct repo, right? I'll keep it bookmarked.

User avatar
Nicholas Bianco
Posts: 1082
Joined: Thu Oct 04, 2012 8:09 pm

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Nicholas Bianco » Wed Mar 17, 2021 11:46 am

Hi Pasha,

That is the correct repo. It seems like the 'analyzeSpatialVec' function exists in your build, you just might not be calling it correctly. Could you post the code of how you're calling 'analyzeSpatialVec'? You might be missing a key argument somewhere.

-Nick

User avatar
Pasha van Bijlert
Posts: 235
Joined: Sun May 10, 2020 3:15 am

Re: Kin/pot energy & joint reactions from MocoTrajectory in Matlab

Post by Pasha van Bijlert » Wed Mar 17, 2021 2:50 pm

Hi Nick,

I only have access to my laptop right now, but I reran the script (unchanged from last week):

Code: Select all

JR_paths=StdVectorString();
 JR_paths.add('.*reaction_on_parent');
 JR_paths.add('.*reaction_on_child');
 
statesTST= gaitPredictionSolution.exportToStatesTable;
controlsTST= gaitPredictionSolution.exportToControlsTable;

JR_outputs_table = analyzeSpatialVec(model, gaitPredictionSolution, JR_paths);
But on my laptop, I got a different error message: "Undefined function 'analyzeSpatialVec' for input arguments of type 'org.opensim.modeling.Model'.". This got me wondering if there was maybe a conflict going on between OpenSim scripts & Moco specific scripts. I tried prefacing the call to analyzeSpatialVec with opensimMoco, so: " JR_outputs_table = opensimMoco.analyzeSpatialVec(etc..)"

This works! At the start of my Matlab script, I have the following statement: "import org.opensim.modeling.*;". I now suspect that this does not load all of the Moco-specific scripts.

Thanks for debugging this with me! Is there an example script available anywhere for accessing data from a "TimeSeriesTableSpatialVec"? I tried following the method in the script "osimTableToStruct", so something like:

JR_outputs_table.getDependentColumnAtIndex(0)

which outputs a "SWIGTYPE_p_SimTK__VectorView_T_SimTK__VecT_2_SimTK__Vec3_1_t_t". It is my understanding that a SpatialVec in this context is a collection of two 3D vectors, containing the torques and then forces in the joint. So when I call "getDependentColumntAtIndex(ind), I'm getting a time series of these two vectors, packed into a single variable. I tried following this up with "get(row_index).get(0)", but that outputs "Error using get. Second argument must be character vector or cell array."

Not sure how to proceed (is this a question that's better asked in the OpenSim forum or is this still Moco-specific? I couldn't find any info on the type "TimeSeriesTableSpatialVec" in Doxygen.).

Thanks! Looks like I'm almost there now.

Pasha

POST REPLY