Creating a ligament via C++

Provide easy-to-use, extensible software for modeling, simulating, controlling, and analyzing the neuromusculoskeletal system.
POST REPLY
User avatar
Hojin Song
Posts: 75
Joined: Wed Jul 08, 2020 9:46 am

Creating a ligament via C++

Post by Hojin Song » Wed Jul 31, 2024 2:51 am

Hi OpenSim experts!

I was trying to create an OpenSim model with using c++. I've tried the code below to add a new ligament element to an existing model but the output model is missing its geometry path. The C++ code is as follows:

Code: Select all

	// Create a new Ligament
	Ligament* newLigament = new Ligament();
	newLigament->setName("new_ligament");
	newLigament->set_pcsa_force(0.01); // Example value for PCSA (cross-sectional area)
	newLigament->set_resting_length(0.5); // Example value for resting length

	Constant* lig_flCurve = new Constant();
	lig_flCurve->setValue(500);
	newLigament->setForceLengthCurve(*lig_flCurve);

	// Define the Geometry Path
	GeometryPath geopath = newLigament->upd_GeometryPath();
	geopath.appendNewPathPoint("P1", model.getBodySet().get("pelvis"), Vec3(0));
	geopath.appendNewPathPoint("P2", model.getBodySet().get("femur_r"), Vec3(0));

	model.addForce(newLigament);
	model.print("ligGenTest.osim");
This has created a ligament, but with an empty GeometryPath. The created ligament in the output .osim file is as follows:

Code: Select all

<Ligament name="new_ligament">
	<!--the set of points defining the path of the ligament-->
	<GeometryPath name="geometrypath">
		<!--Default appearance attributes for this GeometryPath-->
		<Appearance>
			<!--The color, (red, green, blue), [0, 1], used to display the geometry. -->
			<color>0 1 0</color>
		</Appearance>
	</GeometryPath>
	<!--resting length of the ligament-->
	<resting_length>0.5</resting_length>
	<!--force magnitude that scales the force-length curve-->
	<pcsa_force>0.01</pcsa_force>
	<!--Function representing the force-length behavior of the ligament-->
	<Constant name="force_length_curve">
		<value>500</value>
	</Constant>
</Ligament>

May I ask if someone point me out what I have done wrong in here? Thank you.


Best,
Hojin

P.S. I'm using OpenSim 4.4. :)

User avatar
Thomas Uchida
Posts: 1793
Joined: Wed May 16, 2012 11:40 am

Re: Creating a ligament via C++

Post by Thomas Uchida » Wed Jul 31, 2024 7:49 am

I think the line

Code: Select all

GeometryPath geopath = newLigament->upd_GeometryPath();
Is creating a copy. Perhaps use the Ligament::updGeometryPath() method instead, which returns a reference (see https://simtk.org/api_docs/opensim/api_ ... 806d234bfb).

User avatar
Hojin Song
Posts: 75
Joined: Wed Jul 08, 2020 9:46 am

Re: Creating a ligament via C++

Post by Hojin Song » Sun Aug 04, 2024 11:54 pm

Hi Thomas,

Thank you for your suggestion. I have tried as you suggested (if I didn't misunderstood your suggestion) as follows:

Code: Select all

	// Create a new Ligament
	Ligament* newLigament = new Ligament();
	newLigament->setName("new_ligament");
	newLigament->set_pcsa_force(0.01); // Example value for PCSA (cross-sectional area)
	newLigament->set_resting_length(0.5); // Example value for resting length

	// Set Force-Length Curve
	Constant* lig_flCurve = new Constant();
	lig_flCurve->setValue(500);
	newLigament->setForceLengthCurve(*lig_flCurve);
	
	// Set Geometry Paths
	newLigament->updGeometryPath().appendNewPathPoint("P1", model.getBodySet().get("pelvis"), Vec3(0));
	newLigament->updGeometryPath().appendNewPathPoint("P2", model.getBodySet().get("femur_r"), Vec3(0));
	model.addForce(newLigament);
	model.print("ligGenTest.osim");
Unfortunately, it returns an error when compiling it. On the other hand, I have tried a different approach to define the geometry paths as below:

Code: Select all

	// Set Geometry Paths
	GeometryPath* geopath = new GeometryPath();
	geopath->appendNewPathPoint("P1", model.getBodySet().get("pelvis"), Vec3(0));
	geopath->appendNewPathPoint("P2", model.getBodySet().get("femur_r"), Vec3(0));
	newLigament->set_GeometryPath(*geopath);

	model.addForce(newLigament);
	model.print("ligGenTest.osim");
With the second approach, I was able to make the path points be appeared on the model file. However, the pathpoints are missing their "socket_parent_frame" which I believe it was defined with the second variable in "appendNewPathPoint" ("model.getBodySet().get("body_name")). The resulted new ligament in the output model file is as follows:

Code: Select all

<Ligament name="new_ligament">
	<!--the set of points defining the path of the ligament-->
	<GeometryPath name="geometrypath">
		<!--The set of points defining the path-->
		<PathPointSet>
			<objects>
				<PathPoint name="P1">
					<!--The fixed location of the path point expressed in its parent frame.-->
					<location>0 0 0</location>
				</PathPoint>
				<PathPoint name="P2">
					<!--The fixed location of the path point expressed in its parent frame.-->
					<location>0 0 0</location>
				</PathPoint>
			</objects>
			<groups />
		</PathPointSet>
		<!--Default appearance attributes for this GeometryPath-->
		<Appearance>
			<!--The color, (red, green, blue), [0, 1], used to display the geometry. -->
			<color>0 1 0</color>
		</Appearance>
	</GeometryPath>
	<!--resting length of the ligament-->
	<resting_length>0.5</resting_length>
	<!--force magnitude that scales the force-length curve-->
	<pcsa_force>0.01</pcsa_force>
	<!--Function representing the force-length behavior of the ligament-->
	<Constant name="force_length_curve">
		<value>500</value>
	</Constant>
</Ligament>
Could you possibly help me to find any mistake that I made? Thank you.

Best,
Hojin



++ I have tried different approach (the code below) to create the paths, but still getting the same issues with the second approach, "socket_parent_frame" is missing.

Code: Select all

	const PhysicalFrame& pelvis = model.getBodySet().get("pelvis");

	PathPoint* pt1 = new PathPoint();
	pt1->setName("p1");
	pt1->setParentFrame(pelvis);
	pt1->setLocation(Vec3(0));

	newLigament->updGeometryPath().updPathPointSet().cloneAndAppend(*pt1);

	model.addForce(newLigament);
	model.print("ligGenTest.osim");

User avatar
Thomas Uchida
Posts: 1793
Joined: Wed May 16, 2012 11:40 am

Re: Creating a ligament via C++

Post by Thomas Uchida » Mon Aug 05, 2024 9:29 am

I think model.finalizeConnections(); (or model.initSystem();) may need to be called before model.print(...); to resolve the Sockets. Some information about OpenSim's architecture can be found in the API Guide in the doxygen documentation (https://simtk.org/api_docs/opensim/api_ ... Guide.html).

POST REPLY