Skip to content

Commit 5c1f57d

Browse files
authored
Merge pull request #3872 from opensim-org/expression_based_outputs
Add force Outputs to `ExpressionBasedCoordinateForce` and `ExpressionBasedPointToPointForce`
2 parents aa1a3ab + 6b406cf commit 5c1f57d

9 files changed

+100
-52
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ v4.6
1515
- Fixed bugs in `convertToMocoTrajectory()` and `MocoTrajectory::resampleWithFrequency()` by updating `interpolate()` to
1616
allow extrapolation using the `extrapolate` flag. Combined with the `ignoreNaNs` flag, this prevents NaNs from
1717
occurring in the output. (#3867)
18+
- Added `Output`s to `ExpressionBasedCoordinateForce`, `ExpressionBasedPointToPointForce`, and `ExpressionBasedBushingForce` for accessing force values. (#3872)
19+
1820

1921
v4.5.1
2022
======
@@ -79,6 +81,7 @@ pointer to avoid crashes in scripting due to invalid pointer ownership (#3781).
7981
- Fixed `MocoOrientationTrackingGoal::initializeOnModelImpl` to check for missing kinematic states, but allow other missing columns. (#3830)
8082
- Improved exception handling for internal errors in `MocoCasADiSolver`. Problems will now abort and print a descriptive error message (rather than fail due to an empty trajectory). (#3834)
8183

84+
8285
v4.5
8386
====
8487
- Added `AbstractGeometryPath` which is a base class for `GeometryPath` and other path types (#3388). All path-based

OpenSim/Auxiliary/auxiliaryTestFunctions.h

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -268,14 +268,18 @@ OpenSim::Object* randomize(OpenSim::Object* obj)
268268
double Ixy = 0.01*Ixx;
269269
prop = SimTK::Vec6(Ixx, Ixx, Ixx, Ixy, Ixy, Ixy);
270270
} else if (ts == "string") {
271-
string base("ABCXYZ");
272-
if (isList){
273-
stringstream val;
274-
val << base << "_" << ap.size();
275-
ap.appendValue<string>(val.str());
276-
}
277-
else{
278-
ap.updValue<string>() = base;
271+
// We cannot use an arbitrary string for ExpressionBasedBushingForce
272+
// properties since they must contain specific variable names (e.g.,
273+
// "theta_x", "delta_x", etc.).
274+
if (obj->getConcreteClassName() != "ExpressionBasedBushingForce") {
275+
string base("ABCXYZ");
276+
if (isList) {
277+
stringstream val;
278+
val << base << "_" << ap.size();
279+
ap.appendValue<string>(val.str());
280+
} else {
281+
ap.updValue<string>() = base;
282+
}
279283
}
280284
} else if (ts == "double" && isList && ap.getMaxListSize() < 20) {
281285
for (int i=0; i< ap.getMaxListSize(); ++i)

OpenSim/Simulation/Model/ExpressionBasedBushingForce.cpp

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,7 @@ void ExpressionBasedBushingForce::setFzExpression(std::string expression)
269269
set_Fz_expression(expression);
270270
FzProg = Lepton::Parser::parse(expression).optimize().createProgram();
271271
}
272+
272273
//=============================================================================
273274
// COMPUTATION
274275
//=============================================================================
@@ -309,24 +310,21 @@ SimTK::Vec6 ExpressionBasedBushingForce::
309310
return -_dampingMatrix * dqdot;
310311
}
311312

313+
SimTK::Vec6 ExpressionBasedBushingForce::calcBushingForce(
314+
const SimTK::State& s) const {
315+
return calcStiffnessForce(s) + calcDampingForce(s);
316+
}
317+
312318

313319
/* Compute the force contribution to the system and add in to appropriate
314320
* bodyForce and/or system generalizedForce. */
315321
void ExpressionBasedBushingForce::computeForce(const SimTK::State& s,
316322
SimTK::Vector_<SimTK::SpatialVec>& bodyForces,
317323
SimTK::Vector& generalizedForces) const
318324
{
319-
// stiffness force
320-
Vec6 fk = calcStiffnessForce(s);
321-
// damping force
322-
Vec6 fv = calcDampingForce(s);
323-
324-
// total bushing force in the internal basis of the deflection (dq)
325-
Vec6 f = fk + fv;
326-
327325
// convert internal forces to spatial and add then add to system
328326
// physical (body) forces
329-
addInPhysicalForcesFromInternal(s, f, bodyForces);
327+
addInPhysicalForcesFromInternal(s, calcBushingForce(s), bodyForces);
330328
}
331329

332330
//=============================================================================
@@ -367,7 +365,7 @@ OpenSim::Array<double> ExpressionBasedBushingForce::
367365
SpatialVec F_GF( Vec3(0.0),Vec3(0.0) );
368366

369367
// total bushing force in the internal basis of the deflection (dq)
370-
Vec6 f = calcStiffnessForce(s) + calcDampingForce(s);
368+
Vec6 f = calcBushingForce(s);
371369

372370
convertInternalForceToForcesOnFrames(s, f, F_GF, F_GM);
373371

@@ -426,7 +424,7 @@ void ExpressionBasedBushingForce::generateDecorations
426424
SpatialVec F_GF(Vec3(0.0), Vec3(0.0));
427425

428426
// total bushing force in the internal basis of the deflection (dq)
429-
Vec6 f = calcStiffnessForce(s) + calcDampingForce(s);
427+
Vec6 f = calcBushingForce(s);
430428

431429
convertInternalForceToForcesOnFrames(s, f, F_GF, F_GM);
432430

OpenSim/Simulation/Model/ExpressionBasedBushingForce.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedBushingForce, TwoFrameLinker);
9393
OpenSim_DECLARE_PROPERTY(translational_damping, SimTK::Vec3,
9494
"Damping parameters resisting translational deflection (delta_dot) .");
9595

96+
//==============================================================================
97+
// OUTPUTS
98+
//==============================================================================
99+
OpenSim_DECLARE_OUTPUT(bushing_force, SimTK::Vec6, calcBushingForce,
100+
SimTK::Stage::Dynamics);
101+
96102
//==============================================================================
97103
// PUBLIC METHODS
98104
//==============================================================================
@@ -226,7 +232,10 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedBushingForce, TwoFrameLinker);
226232
function of the deflection rate between the bushing frames. It is the
227233
force on frame2 from frame1 in the basis of the deflection rate (dqdot).*/
228234
SimTK::Vec6 calcDampingForce(const SimTK::State& state) const;
229-
235+
236+
/** Calculate the total bushing force. This is the sum of the stiffness and
237+
damping force contributions. */
238+
SimTK::Vec6 calcBushingForce(const SimTK::State& state) const;
230239

231240
//--------------------------------------------------------------------------
232241
// Reporting

OpenSim/Simulation/Model/ExpressionBasedCoordinateForce.cpp

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ ExpressionBasedCoordinateForce::ExpressionBasedCoordinateForce(
5353
setExpression(expression);
5454
}
5555

56-
// Set the expression for the force function and create it's lepton program
57-
void ExpressionBasedCoordinateForce::setExpression(const string& expression)
56+
// Set the expression for the force function and create its lepton program
57+
void ExpressionBasedCoordinateForce::setExpression(const string& expression)
5858
{
5959
set_expression(expression);
6060
}
@@ -68,7 +68,7 @@ void ExpressionBasedCoordinateForce::setExpression(const string& expression)
6868
*/
6969
void ExpressionBasedCoordinateForce::setNull()
7070
{
71-
setAuthors("Nabeel Allana");
71+
setAuthors("Nabeel Allana");
7272
}
7373

7474
//_____________________________________________________________________________
@@ -94,9 +94,9 @@ void ExpressionBasedCoordinateForce::extendConnectToModel(Model& aModel)
9494

9595
string& expression = upd_expression();
9696
expression.erase(
97-
remove_if(expression.begin(), expression.end(), ::isspace),
97+
remove_if(expression.begin(), expression.end(), ::isspace),
9898
expression.end() );
99-
99+
100100
_forceProg = Lepton::Parser::parse(expression).optimize().createProgram();
101101

102102
// Look up the coordinate
@@ -105,7 +105,7 @@ void ExpressionBasedCoordinateForce::extendConnectToModel(Model& aModel)
105105
throw (Exception(errorMessage.c_str()));
106106
}
107107
_coord = &_model->updCoordinateSet().get(coordName);
108-
108+
109109
if(getName() == "")
110110
setName("expressionCoordForce_"+coordName);
111111
}
@@ -124,8 +124,8 @@ void ExpressionBasedCoordinateForce::
124124
// Computing
125125
//=============================================================================
126126
// Compute and apply the force
127-
void ExpressionBasedCoordinateForce::computeForce(const SimTK::State& s,
128-
SimTK::Vector_<SimTK::SpatialVec>& bodyForces,
127+
void ExpressionBasedCoordinateForce::computeForce(const SimTK::State& s,
128+
SimTK::Vector_<SimTK::SpatialVec>& bodyForces,
129129
SimTK::Vector& generalizedForces) const
130130
{
131131
applyGeneralizedForce(s, *_coord, calcExpressionForce(s), generalizedForces);
@@ -147,16 +147,15 @@ double ExpressionBasedCoordinateForce::calcExpressionForce(const SimTK::State& s
147147

148148
// get the force magnitude that has already been computed
149149
const double& ExpressionBasedCoordinateForce::
150-
getForceMagnitude(const SimTK::State& s)
151-
{
150+
getForceMagnitude(const SimTK::State& s) const {
152151
return getCacheVariableValue(s, _forceMagnitudeCV);
153152
}
154153

155154

156155
//=============================================================================
157156
// Reporting
158157
//=============================================================================
159-
// Provide names of the quantities (column labels) of the force value(s)
158+
// Provide names of the quantities (column labels) of the force value(s)
160159
// reported.
161160
Array<std::string> ExpressionBasedCoordinateForce::getRecordLabels() const {
162161
OpenSim::Array<std::string> labels("");

OpenSim/Simulation/Model/ExpressionBasedCoordinateForce.h

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedCoordinateForce, Force);
4242
"and its time derivative (qdot). Note, expression cannot have any whitespace"
4343
"separating characters");
4444
//==============================================================================
45+
// OUTPUTS
46+
//==============================================================================
47+
OpenSim_DECLARE_OUTPUT(force_magnitude, double, getForceMagnitude,
48+
SimTK::Stage::Dynamics);
49+
//==============================================================================
4550
// PUBLIC METHODS
4651
//==============================================================================
4752
/** Default constructor. **/
@@ -58,40 +63,40 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedCoordinateForce, Force);
5863
/**
5964
* Coordinate
6065
*/
61-
void setCoordinateName(const std::string& coord)
66+
void setCoordinateName(const std::string& coord)
6267
{ set_coordinate(coord); }
6368
const std::string& getCoordinateName() const {return get_coordinate();}
6469

6570
/**
6671
* %Set the mathematical expression that defines the force magnitude of this
6772
* coordinate force in terms of the coordinate value (q) and its
6873
* time derivative (qdot). Expressions with C-mathematical operations
69-
* such as +,-,*,/ and common functions: exp, pow, sqrt, sin, cos, tan,
74+
* such as +,-,*,/ and common functions: exp, pow, sqrt, sin, cos, tan,
7075
* and so on are acceptable.
7176
* NOTE: a limitation is that the expression may not contain whitespace
7277
* @param expression string containing the mathematical expression that
73-
* defines the coordinate force
78+
* defines the coordinate force
7479
*/
7580
void setExpression(const std::string& expression);
7681

7782

78-
/**
79-
* Get the computed Force magnitude determined by evaluating the
83+
/**
84+
* Get the computed Force magnitude determined by evaluating the
8085
* expression above. Note, computeForce must be evaluated first,
8186
* and this is done automatically if the system is realized to Dynamics
8287
* @param state const state (reference) for the model
8388
* @return const double ref to the force magnitude
8489
*/
85-
const double& getForceMagnitude(const SimTK::State& state);
90+
const double& getForceMagnitude(const SimTK::State& state) const;
8691

8792

8893
//==============================================================================
8994
// COMPUTATION
9095
//==============================================================================
91-
/** Compute the coordinate force based on the user-defined expression
96+
/** Compute the coordinate force based on the user-defined expression
9297
and apply it to the model */
93-
void computeForce(const SimTK::State& state,
94-
SimTK::Vector_<SimTK::SpatialVec>& bodyForces,
98+
void computeForce(const SimTK::State& state,
99+
SimTK::Vector_<SimTK::SpatialVec>& bodyForces,
95100
SimTK::Vector& generalizedForces) const override;
96101

97102
//--------------------------------------------------------------------------
@@ -103,7 +108,7 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedCoordinateForce, Force);
103108
//==============================================================================
104109
// Reporting
105110
//==============================================================================
106-
/**
111+
/**
107112
* Provide name(s) of the quantities (column labels) of the force value(s) to be reported
108113
*/
109114
OpenSim::Array<std::string> getRecordLabels() const override;
@@ -112,7 +117,7 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedCoordinateForce, Force);
112117
*/
113118
OpenSim::Array<double> getRecordValues(const SimTK::State& state) const override;
114119

115-
120+
116121

117122
protected:
118123
//==============================================================================

OpenSim/Simulation/Model/ExpressionBasedPointToPointForce.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,7 @@ void ExpressionBasedPointToPointForce::computeForce(const SimTK::State& s,
202202

203203
// get the force magnitude that has already been computed
204204
const double& ExpressionBasedPointToPointForce::
205-
getForceMagnitude(const SimTK::State& s)
206-
{
205+
getForceMagnitude(const SimTK::State& s) const {
207206
return getCacheVariableValue(s, _forceMagnitudeCV);
208207
}
209208

OpenSim/Simulation/Model/ExpressionBasedPointToPointForce.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedPointToPointForce, Force);
7171
"the distance (d) between the points and its time derivative (ddot). "
7272
"Note, expression cannot have any whitespace separating characters.");
7373

74+
//==============================================================================
75+
// OUTPUTS
76+
//==============================================================================
77+
OpenSim_DECLARE_OUTPUT(force_magnitude, double, getForceMagnitude,
78+
SimTK::Stage::Dynamics);
7479

7580
//==============================================================================
7681
// PUBLIC METHODS
@@ -132,7 +137,7 @@ OpenSim_DECLARE_CONCRETE_OBJECT(ExpressionBasedPointToPointForce, Force);
132137
* @param state const state (reference) for the model
133138
* @return const double ref to the force magnitude
134139
*/
135-
const double& getForceMagnitude(const SimTK::State& state);
140+
const double& getForceMagnitude(const SimTK::State& state) const;
136141

137142

138143
//--------------------------------------------------------------------------

0 commit comments

Comments
 (0)