Skip to content

Commit 7703592

Browse files
authored
Merge pull request #3600 from ComputationalBiomechanicsLab/FixQuinticDomainBug
Fixes bug introduced by #3596 when handling NaNs.
2 parents d0e1228 + fd9a1b4 commit 7703592

File tree

2 files changed

+73
-41
lines changed

2 files changed

+73
-41
lines changed

OpenSim/Common/SmoothSegmentedFunction.cpp

Lines changed: 36 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -584,50 +584,52 @@ ________________________________________________________________________
584584

585585
double SmoothSegmentedFunction::calcDerivative(double x, int order) const
586586
{
587-
{
587+
const double x0 = _smoothData->_x0;
588+
const double x1 = _smoothData->_x1;
589+
590+
if (x < x0) {
588591
const double y0 = _smoothData->_y0;
589-
const double x0 = _smoothData->_x0;
590592
const double dydx0 = _smoothData->_dydx0;
591-
if (x < x0) {
592-
switch (order) {
593-
case 0: return y0 + dydx0*(x-x0);
594-
case 1: return dydx0;
595-
default: return 0.;
596-
}
593+
switch (order) {
594+
case 0: return y0 + dydx0*(x-x0);
595+
case 1: return dydx0;
596+
default: return 0.;
597597
}
598598
}
599599

600-
{
601-
const double x1 = _smoothData->_x1;
600+
if (x <= x1) {
601+
const SimTK::Array_<SimTK::Vec6>& ctrlPtsX = _smoothData->_ctrlPtsX;
602+
const int idx = SegmentedQuinticBezierToolkit::calcIndex(x,ctrlPtsX);
603+
604+
const SimTK::Array_<SimTK::Spline>& arraySplineUX =
605+
_smoothData->_arraySplineUX;
606+
const double u = SegmentedQuinticBezierToolkit::calcU(
607+
x,
608+
ctrlPtsX[idx],
609+
arraySplineUX[idx],
610+
UTOL,
611+
MAXITER);
612+
613+
const SimTK::Array_<SimTK::Vec6>& ctrlPtsY = _smoothData->_ctrlPtsY;
614+
return SegmentedQuinticBezierToolkit::calcQuinticBezierCurveDerivDYDX(
615+
u,
616+
ctrlPtsX[idx],
617+
ctrlPtsY[idx],
618+
order);
619+
}
620+
621+
if (x > x1) {
602622
const double y1 = _smoothData->_y1;
603623
const double dydx1 = _smoothData->_dydx1;
604-
if (x > x1) {
605-
switch (order) {
606-
case 0: return y1 + dydx1*(x-x1);
607-
case 1: return dydx1;
608-
default: return 0.;
609-
}
624+
switch (order) {
625+
case 0: return y1 + dydx1*(x-x1);
626+
case 1: return dydx1;
627+
default: return 0.;
610628
}
611629
}
612630

613-
const SimTK::Array_<SimTK::Vec6>& ctrlPtsX = _smoothData->_ctrlPtsX;
614-
const int idx = SegmentedQuinticBezierToolkit::calcIndex(x,ctrlPtsX);
615-
616-
const SimTK::Array_<SimTK::Spline>& arraySplineUX =
617-
_smoothData->_arraySplineUX;
618-
const double u = SegmentedQuinticBezierToolkit::calcU(
619-
x,
620-
ctrlPtsX[idx],
621-
arraySplineUX[idx],
622-
UTOL,
623-
MAXITER);
624-
625-
const SimTK::Array_<SimTK::Vec6>& ctrlPtsY = _smoothData->_ctrlPtsY;
626-
return SegmentedQuinticBezierToolkit::calcQuinticBezierCurveDerivDYDX(
627-
u,
628-
ctrlPtsX[idx],
629-
ctrlPtsY[idx],
630-
order);
631+
// In case of NaN return NaN.
632+
return SimTK::NaN;
631633
}
632634

633635
double SmoothSegmentedFunction::

OpenSim/Common/Test/testSmoothSegmentedFunctionFactory.cpp

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,22 @@ void testMonotonicity(SimTK::Matrix mcfSample)
11221122
cout << endl;
11231123
}
11241124

1125+
/*
1126+
5. Tests the output when NaN is the input.
1127+
*/
1128+
template<typename F>
1129+
void testMuscleCurveNaNBehavior(const F& curve)
1130+
{
1131+
cout << " TEST: NaN behavior. " << endl;
1132+
1133+
// Curve value at NaN gives NaN.
1134+
SimTK_TEST(std::isnan(curve.calcValue(SimTK::NaN)));
1135+
SimTK_TEST(std::isnan(curve.calcDerivative(SimTK::NaN, 1)));
1136+
SimTK_TEST(std::isnan(curve.calcDerivative(SimTK::NaN, 2)));
1137+
1138+
cout << " passed testing NaN behavior." << endl;
1139+
}
1140+
11251141
//______________________________________________________________________________
11261142
/**
11271143
* Create a muscle bench marking system. The bench mark consists of a single muscle
@@ -1209,8 +1225,10 @@ int main(int argc, char* argv[])
12091225
testMuscleCurveC2Continuity(tendonCurve,tendonCurveSample);
12101226
//4. Test for monotonicity where appropriate
12111227
testMonotonicity(tendonCurveSample);
1228+
//5. Test NaN behavior.
1229+
testMuscleCurveNaNBehavior(tendonCurve);
12121230

1213-
//5. Testing Exceptions
1231+
//6. Testing Exceptions
12141232
cout << endl;
12151233
cout << " Exception Testing" << endl;
12161234
SimTK_TEST_MUST_THROW(/*SmoothSegmentedFunction* tendonCurveEX
@@ -1279,8 +1297,10 @@ int main(int argc, char* argv[])
12791297
//4. Test for monotonicity where appropriate
12801298

12811299
testMonotonicity(fiberFLCurveSample);
1300+
//5. Test NaN behavior.
1301+
testMuscleCurveNaNBehavior(fiberFLCurve);
12821302

1283-
//5. Testing Exceptions
1303+
//6. Testing Exceptions
12841304
cout << endl;
12851305
cout << " Exception Testing" << endl;
12861306
SimTK_TEST_MUST_THROW(/*SmoothSegmentedFunction* fiberFLCurveEX
@@ -1348,7 +1368,9 @@ int main(int argc, char* argv[])
13481368
//4. Test for monotonicity where appropriate
13491369

13501370
testMonotonicity(fiberCECurveSample);
1351-
//5. Testing Exceptions
1371+
//5. Test NaN behavior.
1372+
testMuscleCurveNaNBehavior(fiberCECurve);
1373+
//6. Testing Exceptions
13521374
cout << endl;
13531375
cout << " Exception Testing" << endl;
13541376
SimTK_TEST_MUST_THROW(/*SmoothSegmentedFunction* fiberCECurveEX
@@ -1412,7 +1434,9 @@ int main(int argc, char* argv[])
14121434
testMuscleCurveC2Continuity(fiberCEPhiCurve,fiberCEPhiCurveSample);
14131435
//4. Test for monotonicity where appropriate
14141436
testMonotonicity(fiberCEPhiCurveSample);
1415-
//5. Testing Exceptions
1437+
//5. Test NaN behavior.
1438+
testMuscleCurveNaNBehavior(fiberCEPhiCurve);
1439+
//6. Testing Exceptions
14161440
cout << endl;
14171441
cout << " Exception Testing" << endl;
14181442
SimTK_TEST_MUST_THROW(/*SmoothSegmentedFunction* fiberCEPhiCurveEX
@@ -1485,7 +1509,9 @@ int main(int argc, char* argv[])
14851509
//4. Test for monotonicity where appropriate
14861510

14871511
testMonotonicity(fiberCECosPhiCurveSample);
1488-
//5. Test exceptions
1512+
//5. Test NaN behavior.
1513+
testMuscleCurveNaNBehavior(fiberCECosPhiCurve);
1514+
//6. Test exceptions
14891515
cout << endl;
14901516
cout << " Exception Testing" << endl;
14911517
SimTK_TEST_MUST_THROW(/*SmoothSegmentedFunction* fiberCECosPhiCurveEX
@@ -1575,7 +1601,9 @@ int main(int argc, char* argv[])
15751601
//4. Test for monotonicity where appropriate
15761602

15771603
testMonotonicity(fiberFVCurveSample);
1578-
//5. Exception testing
1604+
//5. Test NaN behavior.
1605+
testMuscleCurveNaNBehavior(fiberFVCurve);
1606+
//6. Exception testing
15791607
cout << endl;
15801608
cout << " Exception Testing" << endl;
15811609

@@ -1686,8 +1714,10 @@ int main(int argc, char* argv[])
16861714
//4. Test for monotonicity where appropriate
16871715

16881716
testMonotonicity(fiberFVInvCurveSample);
1717+
//5. Test NaN behavior.
1718+
testMuscleCurveNaNBehavior(fiberFVInvCurve);
16891719

1690-
//5. Testing the exceptions
1720+
//6. Testing the exceptions
16911721

16921722
//5. Exception testing
16931723
cout << endl;

0 commit comments

Comments
 (0)