Skip to content

Commit

Permalink
Add automatic bug reproduction test for #515
Browse files Browse the repository at this point in the history
  • Loading branch information
adamkewley committed Jul 29, 2024
1 parent 20e3079 commit e0188e0
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 0 deletions.
28 changes: 28 additions & 0 deletions tests/TestOpenSimCreator/MetaTests/TestOpenSimLibraryAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,34 @@ TEST(OpenSimModel, CoordinateCouplerConstraintWorksWithMultiVariatePolynomial)
model.buildSystem(); // shouldn't have any problems
}

// repro for #515 (v3)
//
// github/@modenaxe (Luca Modenese) reported (paraphrasing):
//
// > I encountered an OpenSim bug/crash when using a CoordinateCouplerConstraint that has a MultiVariatePolynomial function
//
// this test uses a `MultiVariatePolynomialFunction` with multiple variables, which is what @modenaxe reported as
// causing the crash?
TEST(OpenSimModel, CoordinateCouplerConstraintWorksWithMultiVariatePolynomialWithMultipleInputs)
{
const std::filesystem::path brokenFilePath =
std::filesystem::path{OSC_TESTING_RESOURCES_DIR} / "opensim-creator_515-3_repro.osim";

OpenSim::Model model{brokenFilePath.string()};
//ActionSetCoordinateValueAndSave(model, )
model.buildSystem(); // shouldn't have any problems

// user report: if you load a model containing a `CoordinateCouplerConstraint` and then change
// the value of the independent coordinates (tx, rx, or ry), OSC will freeze
for (auto coord : {"tx", "rx", "ry"}) {
std::string fullPath = std::string{"/jointset/freejoint/"} + coord;
auto& coord = model.updComponent<OpenSim::Coordinate>(fullPath);
coord.set_default_value(coord.get_default_value() + 1.0); // change it at the model-level
model.buildSystem(); // shouldn't have any problems
ASSERT_EQ(coord.getValue(model.getWorkingState()), coord.get_default_value());
}
}

// repro for bug found in #654
//
// `OpenSim::Coordinate` exposes its `range` as a list property but OpenSim's API doesn't
Expand Down
142 changes: 142 additions & 0 deletions tests/TestOpenSimCreator/resources/opensim-creator_515-3_repro.osim
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<?xml version="1.0" encoding="UTF-8" ?>
<OpenSimDocument Version="40000">
<Model name="model">
<!--The model's ground reference frame.-->
<Ground name="ground">
<!--The geometry used to display the axes of this Frame.-->
<FrameGeometry name="frame_geometry">
<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
<socket_frame>..</socket_frame>
<!--Scale factors in X, Y, Z directions respectively.-->
<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
</FrameGeometry>
</Ground>
<!--List of bodies that make up this model.-->
<BodySet name="bodyset">
<objects>
<Body name="b1">
<!--The geometry used to display the axes of this Frame.-->
<FrameGeometry name="frame_geometry">
<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
<socket_frame>..</socket_frame>
<!--Scale factors in X, Y, Z directions respectively.-->
<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
</FrameGeometry>
<!--The mass of the body (kg)-->
<mass>1</mass>
<!--The location (Vec3) of the mass center in the body frame.-->
<mass_center>0 0 0</mass_center>
<!--The elements of the inertia tensor (Vec6) as [Ixx Iyy Izz Ixy Ixz Iyz] measured about the mass_center and not the body origin.-->
<inertia>1 1 1 0 0 0</inertia>
</Body>
</objects>
<groups />
</BodySet>
<!--List of joints that connect the bodies.-->
<JointSet name="jointset">
<objects>
<FreeJoint name="freejoint">
<!--Path to a Component that satisfies the Socket 'parent_frame' of type PhysicalFrame (description: The parent frame for the joint.).-->
<socket_parent_frame>ground_offset</socket_parent_frame>
<!--Path to a Component that satisfies the Socket 'child_frame' of type PhysicalFrame (description: The child frame for the joint.).-->
<socket_child_frame>b1_offset</socket_child_frame>
<!--List containing the generalized coordinates (q's) that parameterize this joint.-->
<coordinates>
<Coordinate name="rx">
<!--The value of this coordinate before any value has been set. Rotational coordinate value is in radians and Translational in meters.-->
<default_value>0</default_value>
</Coordinate>
<Coordinate name="ry">
<!--The value of this coordinate before any value has been set. Rotational coordinate value is in radians and Translational in meters.-->
<default_value>0</default_value>
</Coordinate>
<Coordinate name="rz">
<!--The value of this coordinate before any value has been set. Rotational coordinate value is in radians and Translational in meters.-->
<default_value>0</default_value>
</Coordinate>
<Coordinate name="tx">
<!--The value of this coordinate before any value has been set. Rotational coordinate value is in radians and Translational in meters.-->
<default_value>0</default_value>
</Coordinate>
<Coordinate name="ty">
<!--The value of this coordinate before any value has been set. Rotational coordinate value is in radians and Translational in meters.-->
<default_value>1</default_value>
</Coordinate>
<Coordinate name="tz">
<!--The value of this coordinate before any value has been set. Rotational coordinate value is in radians and Translational in meters.-->
<default_value>0</default_value>
</Coordinate>
</coordinates>
<!--Physical offset frames owned by the Joint that are typically used to satisfy the owning Joint's parent and child frame connections (sockets). PhysicalOffsetFrames are often used to describe the fixed transformation from a Body's origin to another location of interest on the Body (e.g., the joint center). When the joint is deleted, so are the PhysicalOffsetFrame components in this list.-->
<frames>
<PhysicalOffsetFrame name="ground_offset">
<!--The geometry used to display the axes of this Frame.-->
<FrameGeometry name="frame_geometry">
<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
<socket_frame>..</socket_frame>
<!--Scale factors in X, Y, Z directions respectively.-->
<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
</FrameGeometry>
<!--Path to a Component that satisfies the Socket 'parent' of type C (description: The parent frame to this frame.).-->
<socket_parent>/ground</socket_parent>
</PhysicalOffsetFrame>
<PhysicalOffsetFrame name="b1_offset">
<!--The geometry used to display the axes of this Frame.-->
<FrameGeometry name="frame_geometry">
<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
<socket_frame>..</socket_frame>
<!--Scale factors in X, Y, Z directions respectively.-->
<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
</FrameGeometry>
<!--Path to a Component that satisfies the Socket 'parent' of type C (description: The parent frame to this frame.).-->
<socket_parent>/bodyset/b1</socket_parent>
</PhysicalOffsetFrame>
</frames>
</FreeJoint>
</objects>
<groups />
</JointSet>
<!--Controllers that provide the control inputs for Actuators.-->
<ControllerSet name="controllerset">
<objects />
<groups />
</ControllerSet>
<!--Constraints in the model.-->
<ConstraintSet name="constraintset">
<objects>
<!-- as stated in https://github.com/ComputationalBiomechanicsLab/opensim-creator/issues/515#issuecomment-1699102942 -->
<CoordinateCouplerConstraint name="CoordinateCouplerConstraint">
<!--Constraint function of generalized coordinates (to be specified) used to evaluate the constraint errors and their derivatives, and must valid to at least 2nd order. Constraint function must evaluate to zero when coordinates satisfy the constraint.-->
<coupled_coordinates_function>
<MultivariatePolynomialFunction>
<!--Coefficients of a multivariate polynomial function in order of ascending powers starting from the last dependent component.-->
<coefficients>1 1 1 1</coefficients>
<!--Number of input dimensions (i.e., dependent components).-->
<dimension>3</dimension>
<!--The largest sum of exponents in a single term.-->
<order>1</order>
</MultivariatePolynomialFunction>
</coupled_coordinates_function>
<!--List of names of the right hand side (independent) coordinates. Note the constraint function above, must be able to handle multiple coordinate values if more than one coordinate name is provided.-->
<independent_coordinate_names>tx rx ry</independent_coordinate_names>
<!--Name of the left-hand side (dependent) coordinate of the constraint coupling function.-->
<dependent_coordinate_name>ty</dependent_coordinate_name>
</CoordinateCouplerConstraint>
</objects>
<groups />
</ConstraintSet>
<!--Forces in the model (includes Actuators).-->
<ForceSet name="forceset">
<objects />
<groups />
</ForceSet>
<!--Visual preferences for this model.-->
<ModelVisualPreferences name="modelvisualpreferences">
<!--Model display preferences-->
<ModelDisplayHints>
<!--Flag to indicate whether or not to show frames, default to false.-->
<show_frames>true</show_frames>
</ModelDisplayHints>
</ModelVisualPreferences>
</Model>
</OpenSimDocument>

0 comments on commit e0188e0

Please sign in to comment.