Parameter tuning issue with MocoTrack

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
Oliver Demuth
Posts: 11
Joined: Mon Nov 27, 2023 8:10 am

Parameter tuning issue with MocoTrack

Post by Oliver Demuth » Thu Jul 25, 2024 8:01 am

Hi everyone,

I tried parameter tuning in OpenSim Moco using MocoTrack. I can run MocoTrack without any issues with a MocoControlGoal and a MocoContactTrackingGoal. However, as soon as I add a MocoParameter to the problem it fails.

My problem is set up as follows:

Code: Select all

        % initialise Moco Study
        study = track.initialize();
        problem = study.updProblem();
        
        disp('Appending problems...');
        
        % ==== Get excitation effort from the problem ==== %
        
        % Get a reference to the MocoControlGoal that is added to every MocoTrack
        % problem by default and change the weight
        excitationEffort = MocoControlGoal.safeDownCast(problem.updGoal('control_effort'));
        excitationEffort.setWeight(effortWeights(ef)); 
        
        % ==== Add a MocoContactTrackingGoal to the problem ==== %
        
        contactTracking = MocoContactTrackingGoal('contact');
        contactTracking.setExternalLoadsFile(GRFPath);
        contactTracking.setWeight(trackingWeights(tr));
        
        % define contact groups
        contactGroupR = MocoContactTrackingGoalGroup(forceNamesRight, 'Right_pes_GRF',StdVectorString(ContactBodies));
        contactGroupL = MocoContactTrackingGoalGroup(forceNamesRight, 'Left_pes_GRF',StdVectorString(ContactBodies));
        
        % append contact groups to problem
        contactTracking.addContactGroup(contactGroupR);
        contactTracking.addContactGroup(contactGroupL);
        
        % append goal to problem
        problem.addGoal(contactTracking);
        
        % ==== configure the solver and solve the problem ==== %
        
        solver = MocoCasADiSolver.safeDownCast(study.updSolver()); % get solver
        solver.resetProblem(problem); % reset problem
        
        % update the solver tolerances
        solver.set_optim_convergence_tolerance(1e-3);
        solver.set_optim_constraint_tolerance(1e-4);
        solver.set_optim_max_iterations(1000);

        % ==== solve problem ==== %
        
        disp(append('Solving problem ',num2str(loopCount),' of ', num2str(length(effortWeights)*length(trackingWeights)), '...'));
        
        solution = study.solve(); 

However, when I add a single MocoParameter to the problem (before the solver configuration), for example as in the the following lines of code:

Code: Select all

        stiffnessParam = MocoParameter('contactStiffness',StdVectorString(HalfSpaceForces),'stiffness',MocoBounds(1e-5,1e6));
        problem.addParameter(stiffnessParam); % append contact stiffnes to problem
I get the following error message:
Java exception occurred:
java.lang.RuntimeException: casVector should be 1-dimensional, but has size 0 x 0.
Thrown at MocoCasOCProblem.h:108 in convertToSimTKVector().
at org.opensim.modeling.opensimMocoJNI.MocoStudy_solve(Native Method)
at org.opensim.modeling.MocoStudy.solve(MocoStudy.java:282)
The same problem setup works absolutely fine in MocoInverse. Is it not possible to do parameter optimisation (e.g., for muscle parameters like lm opt or TSL) with MocoTrack and only with MocoInverse?

My workflow currently is now going back an forth between MocoInverse and MocoTrack:
1. MocoInverse for contact parameter optimisation -> Receive GRF profiles and improved contact model
2. MocoTrack for dynamic consistency and residual reduction -> Receive new and improved kinematics
3. MocoInverse with new kinematics to calculate muscle activations -> Receive tuned muscle parameters and muscle activations to calculate cost of transport

Is there a way around it? Many thanks for your help!

Cheers,
Oliver

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

Re: Parameter tuning issue with MocoTrack

Post by Nicholas Bianco » Fri Jul 26, 2024 9:58 am

Hi Oliver,

Yes, it is possible include parameter optimization in any problem. That error message usually occurs when there is an issue with the initial guess, which can sometimes happen when using the default initial guess (i.e., the midpoint between the variable bounds). Have you check what the initial guess for the parameters would be if using the midpoint? Make sure it is a "valid" parameter value, something will not cause the model to produce very large or NaN values.
1. MocoInverse for contact parameter optimisation -> Receive GRF profiles and improved contact model
How are you "receiving" GRF profiles from MocoInverse?

Best,
Nick

User avatar
Oliver Demuth
Posts: 11
Joined: Mon Nov 27, 2023 8:10 am

Re: Parameter tuning issue with MocoTrack

Post by Oliver Demuth » Thu Aug 01, 2024 7:10 am

Hi Nick,

Good to know. I tried a few other things and I keep running into the same issue. I tried to optimise the trunk segments COM (i.e., called 'Body' in my model).

Code: Select all

        % optimise body COM position

        COMxPos = Bodies.get('Body').getMassCenter().get(0);
        COMyPos = Bodies.get('Body').getMassCenter().get(1);
        COMzPos = Bodies.get('Body').getMassCenter().get(2);

        COMx = MocoParameter('COMx',StdVectorString(BodyPath),'mass_center',MocoBounds(COMxPos-0.05,COMxPos+0.05),0); % can move 5 cm in either direction from original position
        problem.addParameter(COMx); % append COM X-position to problem

        COMy = MocoParameter('COMy',StdVectorString(BodyPath),'mass_center',MocoBounds(-0.01,0.01),1); % constrain to between -1 and 1 cm
        problem.addParameter(COMy); % append COM Y-position to problem

        COMz = MocoParameter('COMz',StdVectorString(BodyPath),'mass_center',MocoBounds(COMzPos-0.025,COMzPos+0.025),2); % can move 2.5 cm in either direction from original position
        problem.addParameter(COMz); % append COM Z-position to problem
The bounds midpoints are now:
-0.056741, -0, -0.024239
Compared to the original position:
-0.056741,-0.0045681, -0.024239
Without the above added MocoParameters, MocoTrack runs fine. However, as soon as I add them I receive the previous error of a 0 x 0 size for the casVector (which I assume is a CasADi error?).

Similarly, when I set the multibody dynamics mode to implicit I also receive the above mentioned error.

Code: Select all

 % ==== configure the solver and solve the problem ==== %
        
        solver = MocoCasADiSolver.safeDownCast(study.updSolver()); % get solver
        solver.resetProblem(problem); % reset problem

        solver.set_multibody_dynamics_mode('implicit');
Any ideas where the issue could come from? The marker data is read in from a TRC file and the GRF data is read from an xml and associated mot file (which workes fine in MocoInverse).

Regarding your question about the GRF profiles: In MocoInverse I calibrate the contact model by tracking an external GRF which is an initial guess/approximation based on external data. In a second step I then recalculate the GRF profiles based on the optimised contact parameters in Matlab (based on the individual body segment velocities and their positions) and export the profiles for the left and right feet as a .mot file.

Many thanks for your help!

Cheers,
Oliver

User avatar
Ross Miller
Posts: 375
Joined: Tue Sep 22, 2009 2:02 pm

Re: Parameter tuning issue with MocoTrack

Post by Ross Miller » Mon Aug 05, 2024 4:51 am

Hi Oliver,

I've done parameter optimization with MocoTrack before (adjusting prosthesis stiffness, for example).

I think Nick mentioned this already but in your initial guess for MocoTrack, is the parameter included in the guess? If I'm starting from a solution that didn't have parameter optimization, I do this by auto-generating a guess then copying over the states and controls from the previous solution:

Code: Select all

% Insert previous solution from a less complex problem
guess = solver.createGuess();
prevSolution = MocoTrajectory('my_previous_solution.sto');
prevStatesTable = prevSolution.exportToStatesTable();
prevControlsTable = prevSolution.exportToControlsTable();
guess.insertStatesTrajectory(prevStatesTable, true);
guess.insertControlsTrajectory(prevControlsTable, true);
solver.setGuess(guess);
You may also need to adjust this setting in the solver:

Code: Select all

solver.set_parameters_require_initsystem(false);
Ross

POST REPLY