1 #ifndef SimTK_SIMMATH_GEODESIC_INTEGRATOR_H_
2 #define SimTK_SIMMATH_GEODESIC_INTEGRATOR_H_
142 : m_eqn(eqn), m_accuracy(accuracy), m_consTol(constraintTol),
143 m_hInit(
NaN), m_hLast(
NaN), m_hNext(
Real(0.1)), m_nInitialize(0)
144 { reinitializeCounters(); }
152 reinitializeCounters();
153 m_hInit = m_hLast =
NaN;
156 if (!m_eqn.projectIfNeeded(m_consTol, m_t, m_y)) {
158 m_eqn.calcConstraintErrors(m_t, m_y, cerr);
161 "GeodesicIntegrator::initialize()",
162 "Couldn't project constraints to tol=%g;"
163 " largest error was %g.", m_consTol, consErr);
165 m_eqn.calcDerivs(m_t, m_y, m_ydot);
173 m_eqn.calcDerivs(m_t, m_y, m_ydot);
175 m_eqn.calcConstraintErrors(m_t, m_y, cerr);
177 if (consErr > m_consTol)
179 "GeodesicIntegrator::setTimeAndState()",
180 "Supplied state failed to satisfy constraints to tol=%g;"
181 " largest error was %g.", m_consTol, consErr);
246 for (
int i=0; i < Z; ++i) {
248 if (aval > norm) norm = aval;
257 for (
int i=0; i< Z; ++i)
259 return std::sqrt(norm/Z);
280 void reinitializeCounters() {
281 m_nStepsTaken=m_nStepsAttempted=0;
282 m_nErrtestFailures=m_nProjectionFailures=0;
285 int m_nStepsAttempted;
286 int m_nErrtestFailures;
287 int m_nProjectionFailures;
290 template <
class Eqn>
void
293 const Real HysteresisLow =
Real(0.9), HysteresisHigh =
Real(1.2);
296 const Real hStretch = MaxStretch*m_hNext;
300 Real t1 = m_t + m_hNext;
303 if (t1 + hStretch > tStop)
314 h = t1 - m_t; assert(h>0);
315 takeRKMStep(h, y1, y1err);
316 errNorm = calcNormInf(y1err);
317 if (errNorm > m_accuracy) {
318 ++m_nErrtestFailures;
321 "GeodesicIntegrator::takeOneStep()",
322 "Accuracy %g worse than required %g at t=%g with step size"
323 " h=%g; can't go any smaller.", errNorm, m_accuracy, m_t, h);
326 Real hNew = Safety * h * std::sqrt(std::sqrt(m_accuracy/errNorm));
327 hNew =
clamp(MinShrink*h, hNew, HysteresisLow*h);
332 if (m_eqn.projectIfNeeded(m_consTol, t1, y1))
337 ++m_nProjectionFailures;
340 "GeodesicIntegrator::takeOneStep()",
341 "Projection failed to reach constraint tolerance %g at t=%g "
342 "with step size h=%g; can't shrink step further.",
345 const Real hNew = MinShrink*h;
353 if (m_nStepsTaken==1) m_hInit = h;
354 m_t = t1; m_y = y1; m_hLast = h;
355 m_eqn.calcDerivs(m_t, m_y, m_ydot);
362 Real hNew = errNorm == 0 ? MaxGrow*h
363 : Safety * h * std::sqrt(std::sqrt(m_accuracy/errNorm));
364 if (hNew < HysteresisHigh*h) hNew = h;
370 template <
class Eqn>
void
372 const Real h2=h/2, h3=h/3, h6=h/6, h8=h/8;
373 const Real t0=m_t, t1=m_t+h;
375 const Vec<N>& f0 = m_ydot;
376 Vec<N> f1, f2, f3, f4, ysave;
377 m_eqn.calcDerivs(t0+h3, y0 + h3* f0, f1);
378 m_eqn.calcDerivs(t0+h3, y0 + h6*(f0 + f1), f2);
379 m_eqn.calcDerivs(t0+h2, y0 + h8*(f0 + 3*f2), f3);
382 ysave = y0 + h2*(f0 - 3*f2 + 4*f3);
383 m_eqn.calcDerivs(t1, ysave, f4);
389 y1 = y0 + h6*(f0 + 4*f3 + f4);
396 for (
int i=0; i<N; ++i)
397 y1err[i] =
std::abs(y1[i]-ysave[i]) / 5;
402 #endif // SimTK_SIMMATH_GEODESIC_INTEGRATOR_H_