Page 1 of 1

making custom goal in python

Posted: Tue Feb 13, 2024 12:21 am
by hojin95
Hi Moco developers,

I was wondering if there's any guideline to create a custom goal in python. I've created and have been using one in c++ as below:

Code: Select all

class MocoBalanceGoal : public MocoGoal {
	OpenSim_DECLARE_CONCRETE_OBJECT(MocoBalanceGoal, MocoGoal);

public:
	MocoBalanceGoal() {}
	MocoBalanceGoal(string name) : MocoGoal(move(name)) {}
	MocoBalanceGoal(string name, double weight) : MocoGoal(move(name), weight) {}

protected:
	Mode getDefaultModeImpl() const override { return Mode::Cost; }
	bool getSupportsEndpointConstraintImpl() const override { return true; }
	void initializeOnModelImpl(const Model&) const override {
		setRequirements(1, 1);
	}
	void calcIntegrandImpl(
		const IntegrandInput& input, double& integrand) const override {
		getModel().realizeAcceleration(input.state);

		const auto& COM = getModel().calcMassCenterPosition(input.state);
		const auto& torso_mc = getModel().getBodySet().get("torso").getMassCenter();
		const auto& torso_pos = getModel().getBodySet().get("torso").findStationLocationInGround(input.state, torso_mc);
		const auto& calcn_r_mc = getModel().getBodySet().get("calcn_r").getMassCenter();
		const auto& calcn_r_pos = getModel().getBodySet().get("calcn_r").findStationLocationInGround(input.state, calcn_r_mc);

		integrand = (COM[0] - calcn_r_pos[0]) * (COM[0] - calcn_r_pos[0]);
	}

	void calcGoalImpl(
		const GoalInput& input, SimTK::Vector& cost) const override {
		cost[0] = input.integral;
	}
};
I've tried to migrate to python and the code below is the one.

Code: Select all

class MocoBalanceGoal(MocoControlGoal):
    def __init__(self, name="", weight=1.0):
        super().__init__(name)
        self.setWeight(weight)

    def initializeOnModelImpl(self, model):
        self.setRequirements(1, 1)

    def calcIntegrandImpl(self, input, integrand):
        model = self.getModel()
        model.realizeAcceleration(input.state)

        COM = model.calcMassCenterPosition(input.state)
        torso_mc = model.getBodySet().get("torso").getMassCenter()
        torso_pos = model.getBodySet().get("torso").findStationLocationInGround(input.state, torso_mc)
        calcn_r_mc = model.getBodySet().get("calcn_r").getMassCenter()
        calcn_r_pos = model.getBodySet().get("calcn_r").findStationLocationInGround(input.state, calcn_r_mc)

        integrand[0] = (COM[0] - calcn_r_pos[0]) ** 2

    def calcGoalImpl(self, input, cost):
        cost[0] = input.integral
My concern is when creating this custom goal, I can only overwrite either "MocoControlGoal" or "MocoOutputGoal", and when I chose a MocoControlGoal, I'm getting the following messages for costs configuration:

Code: Select all

Costs: (total: 1)
  balance. MocoControlGoal, enabled: true, mode: cost, weight: 10.0
        control: /forceset/hip_actu_r, weight: 1.0
        control: /forceset/knee_actu_r, weight: 1.0
        control: /forceset/ankle_actu_r, weight: 1.0
        control: /forceset/lumbar_actu, weight: 1.0
The solution also tells that it did not applied as I intended to. Can someone help me to create a custom goal properly in a python environment?

Thank you :)

Re: making custom goal in python

Posted: Tue Feb 13, 2024 5:44 pm
by nbianco
Hi Hojin,

Unfortunately, there is currently no way to create a custom MocoGoal directly in Python as you've sketched out in your example. The only way to write it directly in C++.

I see that you are already able to write your class in C++. Is there a specific reason (other than convenience) that you're looking to do this directly in Python? If you're having trouble loading a MocoStudy with your custom class via XML or the scripting API, I can help resolve those issues.

Best,
Nick

Re: making custom goal in python

Posted: Wed Feb 14, 2024 7:20 pm
by hojin95
Hi Nicholas,

Thank you for your response. I was trying to running my Moco code on a cluster but the opensim-moco package that I found on anaconda (https://anaconda.org/opensim-org/opensim-moco/files) only supports python scripting, so I was trying to migrate my C++ code to python.

When I create my custom class, I was unable (due to lack of experience, sadly :cry: ) to put it in a separate C++ file and make it work as a sort of library file just like the other Moco goals do, so I just put it together in the Moco main script. This is why I was trying to create a custom goal class directly in python script.

May I ask if you could help me how to get my custom goal class written in C++ to work in python?

Best wishes,
Hojin

Re: making custom goal in python

Posted: Thu Feb 15, 2024 3:44 pm
by nbianco
Hi Hojin,

Is it not possible to upload a custom C++ build to your cluster (or build directly on the cluster) and use that? I could show you how to extend the Python bindings to use your custom class, but that would still require uploading/building a custom installation on the cluster.

You could take a look at the SWIG bindings code to see how we create our Python interface to the OpenSim API.

Best,
Nick

Re: making custom goal in python

Posted: Sun Feb 18, 2024 9:14 pm
by hojin95
Hi Nick,

I was not able to build it directly on the cluster due to a permission issue so I was trying to use already existing anaconda environment (which only supports python), but I'll have a look at the SWIG bindings for now. I tried pybind11 but wasn't successful :(.

best,
Hojin

Re: making custom goal in python

Posted: Tue Feb 20, 2024 4:54 pm
by nbianco
Hi Hojin,

Sounds good! The SWIG bindings code for OpenSim live here: https://github.com/opensim-org/opensim- ... ngs/Python.

As an alternative, you could build your custom goal as a plugin run a MocoStudy from an XML using that. Here's an example for building a plugin for a custom MocoGoal: https://github.com/opensim-org/opensim- ... EffortGoal.

Best,
Nick