00001 #ifndef SimTK_SIMBODY_NUMERICAL_METHODS_H_
00002 #define SimTK_SIMBODY_NUMERICAL_METHODS_H_
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include "simbody/internal/common.h"
00036 #include "SimTKcpodes.h"
00037
00038 #include <cassert>
00039
00040 namespace SimTK {
00041
00146 class MechanicalDAEIntegrator {
00147 public:
00148 explicit MechanicalDAEIntegrator(const MultibodySystem& mb, State& s)
00149 : mbs(mb), state(s) {
00150 initializeUserStuff();
00151 zeroStats();
00152 }
00153 virtual ~MechanicalDAEIntegrator() { }
00154
00155 const MultibodySystem& getMultibodySystem() const {return mbs;}
00156 const State& getState() const {return state;}
00157 State& updState() {return state;}
00158
00159 virtual MechanicalDAEIntegrator* clone() const = 0;
00160
00161 virtual bool initialize() = 0;
00162 virtual bool step(const Real& tout) = 0;
00163
00164 virtual Real getConstraintTolerance() const = 0;
00165
00166 void setStopTime(const Real& tstop) {
00167 assert(tstop == -1. || (0. <= tstop));
00168 userStopTime = tstop;
00169 }
00170
00171 void setInitialStepSize(const Real& z) {
00172 assert(z == -1. || z > 0.);
00173 assert(userMinStepSize==-1. || z >= userMinStepSize);
00174 assert(userMaxStepSize==-1. || z <= userMaxStepSize);
00175 userInitStepSize = z;
00176 }
00177 void setMinimumStepSize(const Real& z) {
00178 assert(z == -1. || z > 0.);
00179 assert(userInitStepSize==-1. || z <= userInitStepSize);
00180 assert(userMaxStepSize ==-1. || z <= userMaxStepSize);
00181 userMinStepSize = z;
00182 }
00183 void setMaximumStepSize(const Real& z) {
00184 assert(z == -1. || z > 0.);
00185 assert(userInitStepSize==-1. || z >= userInitStepSize);
00186 assert(userMinStepSize ==-1. || z >= userMinStepSize);
00187 userMaxStepSize = z;
00188 }
00189 void setAccuracy(const Real& accuracy) {
00190 assert(accuracy == -1. || (0. < accuracy && accuracy < 1.));
00191 userAccuracy = accuracy;
00192 }
00193 void setRelativeTolerance(const Real& relTol) {
00194 assert(relTol == -1. || (0. < relTol && relTol <= 1.));
00195 userRelTol=relTol;
00196 }
00197 void setAbsoluteTolerance(const Real& absTol) {
00198 assert(absTol == -1. || (0. < absTol && absTol <= 1.));
00199 userAbsTol=absTol;
00200 }
00201 void setConstraintTolerance(const Real& consTol) {
00202 assert(consTol == -1. || (0. < consTol && consTol <= 1.));
00203 userConsTol=consTol;
00204 }
00205 void setVelocityConstraintRescale(const Real& rescale) {
00206 assert(rescale == -1 || (0. <= rescale));
00207 userVConsRescale = rescale;
00208 }
00209 void setProjectEveryStep(bool forceProject) {
00210 userProjectEveryStep = forceProject ? 1 : 0;
00211 }
00212
00213 long getStepsAttempted() const {return statsStepsAttempted;}
00214 long getStepsTaken() const {return statsStepsTaken;}
00215 long getErrorTestFailures() const {return statsErrorTestFailures;}
00216 long getRealizeFailures() const {return statsRealizationFailures;}
00217 long getProjectionFailures() const {return statsProjectionFailures;}
00218 long getStepSizeChanges() const {return statsStepSizeChanges;}
00219
00220 protected:
00221 const MultibodySystem& mbs;
00222 State& state;
00223
00224
00225 Real userInitStepSize, userMinStepSize, userMaxStepSize;
00226 Real userAccuracy;
00227 Real userRelTol, userAbsTol, userConsTol, userVConsRescale;
00228 Real userStopTime;
00229 long userMaxNumSteps;
00230 int userProjectEveryStep;
00231
00232
00233 void initializeUserStuff() {
00234 userInitStepSize = userMinStepSize = userMaxStepSize = -1.;
00235 userAccuracy = userRelTol = userAbsTol = userConsTol = userVConsRescale = -1.;
00236 userStopTime = -1.;
00237 userMaxNumSteps = -1;
00238 userProjectEveryStep= -1;
00239 }
00240
00241
00242 long statsStepsAttempted;
00243 long statsStepsTaken;
00244 long statsErrorTestFailures;
00245 long statsRealizationFailures;
00246 long statsProjectionFailures;
00247 long statsStepSizeChanges;
00248
00249 void zeroStats() {
00250 statsStepsAttempted = statsStepsTaken = statsErrorTestFailures
00251 = statsRealizationFailures = statsProjectionFailures = statsStepSizeChanges = 0;
00252 }
00253
00254 };
00255
00256
00257
00258 class CPodesMultibodySystem : public CPodesSystem {
00259 public:
00260 CPodesMultibodySystem(MechanicalDAEIntegrator* p) : mdae(p)
00261 {
00262 }
00263
00264
00265
00266
00267
00268
00269
00270 int explicitODE(Real t, const Vector& y, Vector& ydot) const {
00271 mdae->updState().updY() = y;
00272 mdae->updState().updTime() = t;
00273
00274 try {
00275 mdae->getMultibodySystem().realize(mdae->getState(), Stage::Acceleration);
00276 }
00277 catch(...) { return CPodes::RecoverableError; }
00278 ydot = mdae->getState().getYDot();
00279 return CPodes::Success;
00280 }
00281
00282
00283 int constraint(Real t, const Vector& y, Vector& yerr) const {
00284 mdae->updState().updY() = y;
00285 mdae->updState().updTime() = t;
00286
00287 try {
00288 mdae->getMultibodySystem().realize(mdae->getState(), Stage::Velocity);
00289 }
00290 catch(...) { return CPodes::RecoverableError; }
00291 yerr = mdae->getState().getYErr();
00292 return CPodes::Success;
00293 }
00294
00295
00296
00297
00298
00299 int project(Real t, const Vector& y, Vector& ycorr, Real epsProj,
00300 Vector& err) const
00301 {
00302 State& s = mdae->updState();
00303 s.updY() = y;
00304 s.updTime() = t;
00305
00306 const MultibodySystem& mbs = mdae->getMultibodySystem();
00307
00308 try {
00309 const Real tol = mdae->getConstraintTolerance();
00310 Vector yUnitWeights, unitTolerances;
00311 mbs.realize(s, Stage::Position);
00312 mbs.calcYUnitWeights(s, yUnitWeights);
00313 mbs.calcYErrUnitTolerances(s, unitTolerances);
00314
00315 mbs.project(s, tol, yUnitWeights, unitTolerances, err);
00316 }
00317 catch (...) { return CPodes::RecoverableError; }
00318
00319 ycorr = s.getY()-y;
00320 return CPodes::Success;
00321 }
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 MechanicalDAEIntegrator *mdae;
00334 };
00335
00336 class OLDCPodesIntegrator : public MechanicalDAEIntegrator {
00337 public:
00338 OLDCPodesIntegrator(const MultibodySystem& mb, State& s)
00339 : MechanicalDAEIntegrator(mb,s), cpodes(0), sys(0)
00340 {
00341 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Topology,
00342 "CPodesIntegrator::CPodesIntegrator()");
00343 reconstructForNewModel();
00344 }
00345
00346
00347 ~OLDCPodesIntegrator() {
00348 delete cpodes;
00349 delete sys;
00350 }
00351 OLDCPodesIntegrator* clone() const {assert(false); return 0;}
00352
00353 const CPodes& getCPodes() const {assert(cpodes); return *cpodes;}
00354
00355 bool initialize() {
00356 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Topology,
00357 "CPodesIntegrator::initialize()");
00358 if (state.getSystemStage() < Stage::Model)
00359 reconstructForNewModel();
00360 initializeIntegrationParameters();
00361
00362 initialized = true;
00363
00364 mbs.realize(state, Stage::Velocity);
00365
00366 const int ny = state.getY().size();
00367 const int nc = state.getYErr().size();
00368
00369 Vector ycorr(ny);
00370 Vector err(ny, Real(0));
00371 if (sys->project(state.getTime(), state.getY(), ycorr, 0., err)
00372 != CPodes::Success)
00373 return false;
00374 state.updY() = state.getY() + ycorr;
00375
00376 mbs.realize(state, Stage::Velocity);
00377
00378 Vector ydot(ny);
00379 if (sys->explicitODE(state.getTime(), state.getY(), ydot)
00380 != CPodes::Success)
00381 return false;
00382
00383 int retval;
00384 if ((retval=cpodes->init(*sys, state.getTime(), state.getY(), ydot,
00385 CPodes::ScalarScalar, relTol, &absTol)) != CPodes::Success)
00386 {
00387 printf("init returned %d\n", retval);
00388 return false;
00389 }
00390 cpodes->lapackDense(ny);
00391 cpodes->setNonlinConvCoef(0.01);
00392 cpodes->setMaxNumSteps(50000);
00393 cpodes->projDefine();
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410 return true;
00411 }
00412
00413 bool step(const Real& tout) {
00414
00415 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Instance,
00416 "CPodesIntegrator::step()");
00417 assert(initialized);
00418
00419 Real tret;
00420 Vector ypout(state.getY().size());
00421
00422
00423 int res = cpodes->step(tout, &tret, state.updY(), ypout, CPodes::Normal);
00424 return res >= 0;
00425 }
00426
00427 Real getConstraintTolerance() const {
00428 assert(initialized);
00429 return consTol;
00430 }
00431
00432 Real getPredictedNextStep() const {
00433 assert(initialized);
00434 Real hnext;
00435 (void)cpodes->getCurrentStep(&hnext);
00436 return hnext;
00437 }
00438 private:
00439 void initializeIntegrationParameters() {
00440 mbs.realize(state, Stage::Instance);
00441
00442 initializeStepSizes();
00443 initializeTolerances();
00444
00445 if (userStopTime != -1.)
00446 cpodes->setStopTime(userStopTime);
00447 if (userMaxNumSteps != -1)
00448 cpodes->setMaxNumSteps(userMaxNumSteps);
00449 if (userProjectEveryStep != -1)
00450 if (userProjectEveryStep==1)
00451 cpodes->setProjFrequency(1);
00452 }
00453
00454 void initializeStepSizes() {
00455 if (userInitStepSize != -1)
00456 cpodes->setInitStep(userInitStepSize);
00457 if (userMinStepSize != -1)
00458 cpodes->setMinStep(userMinStepSize);
00459 if (userMaxStepSize != -1)
00460 cpodes->setMaxStep(userMaxStepSize);
00461 }
00462
00463 void initializeTolerances() {
00464 accuracy = (userAccuracy != -1. ? userAccuracy : 1e-3);
00465 relTol = (userRelTol != -1. ? userRelTol : accuracy);
00466 absTol = (userAbsTol != -1. ? userAbsTol : accuracy);
00467 consTol = (userConsTol != -1. ? userConsTol : accuracy);
00468 vconsRescale = (userVConsRescale != -1. ? userVConsRescale : 1.);
00469 }
00470 private:
00471 void reconstructForNewModel() {
00472 initialized = false;
00473 delete cpodes;
00474 delete sys;
00475 mbs.realize(state, Stage::Model);
00476 accuracy=relTol=absTol=consTol=vconsRescale
00477 = CNT<Real>::getNaN();
00478
00479 cpodes = new CPodes(CPodes::ExplicitODE, CPodes::BDF, CPodes::Newton);
00480
00481 sys = new CPodesMultibodySystem(this);
00482 }
00483
00484 CPodes* cpodes;
00485 CPodesMultibodySystem* sys;
00486 Real accuracy, relTol, absTol, consTol, vconsRescale;
00487 bool initialized;
00488 };
00489
00490 class OLDExplicitEuler : public MechanicalDAEIntegrator {
00491 public:
00492 OLDExplicitEuler(const MultibodySystem& mb, State& s)
00493 : MechanicalDAEIntegrator(mb,s)
00494 {
00495 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Topology,
00496 "ExplicitEuler::ExplicitEuler()");
00497 reconstructForNewModel();
00498 }
00499
00500 OLDExplicitEuler* clone() const {return new OLDExplicitEuler(*this);}
00501
00502 Real getConstraintTolerance() const {
00503 assert(initialized);
00504 return consTol;
00505 }
00506
00507 Real getPredictedNextStep() const {
00508 assert(initialized);
00509 return maxStepSize;
00510 }
00511
00512 bool initialize() {
00513 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Topology,
00514 "OLDExplicitEuler::initialize()");
00515 if (state.getSystemStage() < Stage::Model)
00516 reconstructForNewModel();
00517 initializeIntegrationParameters();
00518
00519 try {
00520 Vector yUnitWeights, unitTolerances;
00521 mbs.realize(state, Stage::Position);
00522 mbs.calcYUnitWeights(state, yUnitWeights);
00523 mbs.calcYErrUnitTolerances(state, unitTolerances);
00524 Vector dummyErrest;
00525 mbs.project(state, consTol, yUnitWeights, unitTolerances,
00526 dummyErrest);
00527 }
00528 catch (...) { ++statsProjectionFailures; return false; }
00529
00530 try { mbs.realize(state, Stage::Acceleration); }
00531 catch (...) { ++statsRealizationFailures; return false; }
00532
00533 initialized = true;
00534 return true;
00535 }
00536
00537 bool step(const Real& tOut) {
00538
00539 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Instance,
00540 "OLDExplicitEuler::step()");
00541
00542 assert(initialized && tOut >= state.getTime());
00543 const Real tMax = std::min(tOut, stopTime);
00544
00545 bool wasLastStep;
00546 long stepsTaken = 0;
00547 do {
00548 if (maxNumSteps && stepsTaken >= maxNumSteps)
00549 return false;
00550
00551 mbs.realize(state, Stage::Acceleration);
00552 t0 = state.getTime();
00553 ydot0 = state.getYDot();
00554
00555
00556 Real hTry = std::min(maxStepSize, tMax-t0);
00557 for (;;) {
00558 ++statsStepsAttempted;
00559 wasLastStep = false;
00560 Real nextT = t0+hTry;
00561 if (tMax-nextT < minStepSize)
00562 nextT = tMax, hTry = tMax-t0, wasLastStep=true;
00563
00564 state.updTime() = nextT;
00565 state.updY() = state.getY() + hTry*ydot0;
00566
00567 bool projectOK = false, realizeOK = false;
00568 try {
00569 projectOK = true;
00570 Vector yUnitWeights, unitTolerances;
00571 mbs.realize(state, Stage::Position);
00572 mbs.calcYUnitWeights(state, yUnitWeights);
00573 mbs.calcYErrUnitTolerances(state, unitTolerances);
00574 bool needProjection = true;
00575 if (!projectEveryStep) {
00576 mbs.realize(state, Stage::Velocity);
00577 const Real err =
00578 mbs.calcWeightedRMSNorm(state.getYErr(), unitTolerances);
00579 if (err < 0.9*consTol)
00580 needProjection = false;
00581 }
00582 if (needProjection) {
00583 Vector dummyErrest;
00584 mbs.project(state, consTol, yUnitWeights, unitTolerances,
00585 dummyErrest);
00586 }
00587 }
00588 catch (...) { projectOK=false; }
00589
00590 if (projectOK) {
00591 try {
00592 realizeOK = true;
00593 mbs.realize(state, Stage::Acceleration);
00594 } catch (...) { realizeOK = false; }
00595 if (!realizeOK) ++statsRealizationFailures;
00596 } else ++statsProjectionFailures;
00597
00598 if (projectOK && realizeOK)
00599 break;
00600
00601
00602
00603 if (hTry <= minStepSize)
00604 return false;
00605
00606 hTry = std::max(minStepSize, hTry/2);
00607 }
00608
00609
00610 ++stepsTaken;
00611 ++statsStepsTaken;
00612 } while (!wasLastStep);
00613
00614
00615 return true;
00616 }
00617 private:
00618
00619
00620 void initializeIntegrationParameters() {
00621 mbs.realize(state, Stage::Instance);
00622
00623 initializeStepSizes();
00624 initializeTolerances();
00625 if (userStopTime != -1.) stopTime = userStopTime;
00626 else stopTime = CNT<Real>::getInfinity();
00627 if (userMaxNumSteps != -1)
00628 maxNumSteps = userMaxNumSteps;
00629 else maxNumSteps = 0;
00630 if (userProjectEveryStep != -1)
00631 projectEveryStep = (userProjectEveryStep==1);
00632 }
00633
00634 void initializeTolerances() {
00635 accuracy = (userAccuracy != -1. ? userAccuracy : 1e-3);
00636 relTol = (userRelTol != -1. ? userRelTol : accuracy);
00637 absTol = (userAbsTol != -1. ? userAbsTol : accuracy);
00638 consTol = (userConsTol != -1. ? userConsTol : accuracy);
00639 vconsRescale = (userVConsRescale != -1. ? userVConsRescale : 1.);
00640 }
00641
00642 void initializeStepSizes() {
00643 if (userMaxStepSize != -1.) {
00644 maxStepSize = userMaxStepSize;
00645 if (userInitStepSize != -1.) {
00646 initStepSize = userInitStepSize;
00647 if (userMinStepSize != -1.)
00648 minStepSize = userMinStepSize;
00649 else minStepSize = std::min(maxStepSize/3, initStepSize);
00650 } else {
00651 initStepSize = maxStepSize;
00652 if (userMinStepSize != -1.)
00653 minStepSize = userMinStepSize;
00654 else minStepSize = maxStepSize/3;
00655 }
00656 } else {
00657 if (userInitStepSize != -1.) {
00658 initStepSize = userInitStepSize;
00659 maxStepSize = initStepSize;
00660 minStepSize = (userMinStepSize != -1. ? userMinStepSize : maxStepSize/3);
00661 } else {
00662 if (userMinStepSize != -1.) {
00663 minStepSize = userMinStepSize;
00664 maxStepSize = std::max(mbs.calcTimescale(state)/10., minStepSize);
00665 initStepSize = maxStepSize;
00666 } else {
00667 maxStepSize = initStepSize = mbs.calcTimescale(state)/10.;
00668 minStepSize = maxStepSize/3;
00669 }
00670 }
00671 }
00672 }
00673
00674 void reconstructForNewModel() {
00675 mbs.realize(state, Stage::Model);
00676 initStepSize=minStepSize=maxStepSize
00677 =accuracy=relTol=absTol=consTol=vconsRescale
00678 =stopTime=CNT<Real>::getNaN();
00679 maxNumSteps = -1;
00680 projectEveryStep = false;
00681 ydot0.resize(state.getY().size());
00682 initialized = false;
00683 }
00684
00685 Real initStepSize, minStepSize, maxStepSize;
00686 Real accuracy, relTol, absTol, consTol, vconsRescale;
00687 Real stopTime;
00688 long maxNumSteps;
00689 bool projectEveryStep;
00690 Real t0;
00691 Vector ydot0;
00692
00693 bool initialized;
00694 };
00695
00696
00697 class OLDRungeKuttaMerson : public MechanicalDAEIntegrator {
00698 public:
00699 OLDRungeKuttaMerson(const MultibodySystem& mb, State& s, bool noProject=false)
00700 : MechanicalDAEIntegrator(mb,s)
00701 {
00702 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Topology,
00703 "OLDRungeKuttaMerson::OLDRungeKuttaMerson()");
00704 reconstructForNewModel();
00705 if (noProject) suppressProject = true;
00706 }
00707
00708 OLDRungeKuttaMerson* clone() const {return new OLDRungeKuttaMerson(*this);}
00709
00710 Real getConstraintTolerance() const {
00711 assert(initialized);
00712 return consTol;
00713 }
00714 Real getPredictedNextStep() const {
00715 assert(initialized);
00716 return predictedNextStep;
00717 }
00718
00719 bool initialize() {
00720 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Topology,
00721 "OLDRungeKuttaMerson::initialize()");
00722 if (state.getSystemStage() < Stage::Model)
00723 reconstructForNewModel();
00724
00725 initializeIntegrationParameters();
00726
00727 if (!evaluateAndProject(true))
00728 return false;
00729
00730 initialized = true;
00731 return true;
00732 }
00733
00735
00737 bool step(const Real& tOut) {
00738
00739 SimTK_STAGECHECK_GE_ALWAYS(state.getSystemStage(), Stage::Instance,
00740 "OLDRungeKuttaMerson::step()");
00741
00742 assert(initialized && tOut >= state.getTime());
00743 const Real tMax = std::min(tOut, stopTime);
00744
00745
00746 if (tMax-state.getTime() < minStepSize) {
00747 ++statsStepsAttempted;
00748 state.updTime() = tMax;
00749
00750 if (!evaluateAndProject())
00751 return false;
00752
00753 ++statsStepsTaken;
00754 return true;
00755 }
00756
00757 bool wasLastStep;
00758 long stepsTaken = 0;
00759
00760
00761
00762 Real hWanted = std::min(predictedNextStep, maxStepSize);
00763 do {
00764 if (maxNumSteps && stepsTaken >= maxNumSteps)
00765 return false;
00766
00767
00768
00769
00770 bool trialHWasLimitedByTOut = false;
00771
00772 wasLastStep = false;
00773
00774 t0 = state.getTime();
00775 y0 = state.getY();
00776
00777
00778
00779
00780 Real trialH = hWanted;
00781 if (t0 + 1.05*trialH > tMax) {
00782 const Real hAdj = tMax - t0;
00783 trialHWasLimitedByTOut = hAdj < 0.9*trialH;
00784 trialH = hAdj;
00785 wasLastStep = true;
00786 }
00787
00788 mbs.realize(state, Stage::Acceleration);
00789 ydot0 = state.getYDot();
00790
00791
00792
00793
00794 Real scalarError;
00795 bool RKstepOK;
00796 for (;;) {
00797 ++statsStepsAttempted;
00798
00799 RKstepOK =
00800 takeAnRK4MStep(t0, y0, ydot0, trialH,
00801 ytmp[0], ytmp[1], ytmp[2],
00802 ynew, errEst);
00803
00804 if (!RKstepOK) ++statsRealizationFailures;
00805
00806 if (RKstepOK) {
00807 Vector wts;
00808 mbs.calcYUnitWeights(state, wts);
00809 scalarError = mbs.calcWeightedRMSNorm(errEst, wts) / accuracy;
00810
00811
00812 if (scalarError <= 1.) {
00813
00814 state.updTime() = t0+trialH;
00815 state.updY() = ynew;
00816
00817 if (evaluateAndProject()) {
00818
00819 t0 = state.getTime(); y0 = state.getY();
00820
00821
00822
00823
00824
00825
00826
00827
00828
00829
00830 Real optimalStepScale =
00831 scalarError > 0 ? 0.9/pow(scalarError, 0.25) : 5.;
00832 optimalStepScale =
00833 std::min(std::max(optimalStepScale, 0.1), 5.);
00834
00835
00836
00837 if (0.9 < optimalStepScale && optimalStepScale < 1.2)
00838 optimalStepScale = 1.;
00839
00840
00841
00842 if (!(trialHWasLimitedByTOut && optimalStepScale >= 1)) {
00843 hWanted = optimalStepScale * trialH;
00844 hWanted = std::min(std::max(hWanted, minStepSize), maxStepSize);
00845 if (hWanted != trialH)
00846 ++statsStepSizeChanges;
00847 }
00848 predictedNextStep = hWanted;
00849 break;
00850 }
00851 ++statsRealizationFailures;
00852 ++statsProjectionFailures;
00853 } else
00854 ++statsErrorTestFailures;
00855 }
00856
00857
00858 if (trialH <= minStepSize )
00859 return false;
00860
00861 Real optimalStepScale;
00862 if (RKstepOK) {
00863 optimalStepScale = scalarError > 1. ? 0.9/pow(scalarError, 0.25) : 1.;
00864 optimalStepScale =
00865 std::max(optimalStepScale, 0.1);
00866 } else
00867 optimalStepScale = 0.5;
00868
00869 hWanted = optimalStepScale * trialH;
00870 hWanted = std::min(std::max(hWanted, minStepSize), maxStepSize);
00871 if (hWanted != trialH)
00872 ++statsStepSizeChanges;
00873
00874 trialH = hWanted;
00875 trialHWasLimitedByTOut = false;
00876 wasLastStep = false;
00877 }
00878
00879 ++stepsTaken;
00880 ++statsStepsTaken;
00881 } while (!wasLastStep);
00882
00883 return true;
00884 }
00885
00886 private:
00887 bool f(const Real& t, const Vector& y, Vector& yd) const {
00888 state.updY() = y;
00889 state.updTime() = t;
00890
00891 try { mbs.realize(state, Stage::Acceleration); }
00892 catch(...) { return false; }
00893 yd = state.getYDot();
00894 return true;
00895 }
00896
00897 bool takeAnRK4MStep(const Real& t0, const Vector& y0, const Vector& yd0,
00898 const Real& h,
00899 Vector& ytmp, Vector& yd1, Vector& yd2,
00900 Vector& y, Vector& errEst)
00901 {
00902 ytmp = y0 + (h/3)*yd0;
00903 if (!f(t0+h/3, ytmp, yd1)) return false;
00904
00905 ytmp = y0 + (h/6)*(yd0+yd1);
00906 if (!f(t0+h/3, ytmp, yd1)) return false;
00907
00908 ytmp = y0 + (h/8)*(yd0 + 3.*yd1);
00909 if (!f(t0+h/2, ytmp, yd2)) return false;
00910
00911 ytmp = y0 + (h/2)*(yd0 - 3.*yd1 + 4.*yd2);
00912 if (!f(t0+h, ytmp, yd1)) return false;
00913
00914
00915 y = y0 + (h/6)*(yd0 + 4.*yd2 + yd1);
00916
00917 for (int i=0; i<y.size(); ++i)
00918 errEst[i] = 0.2*std::fabs(y[i]-ytmp[i]);
00919
00920 return true;
00921 }
00922
00923
00924
00925 bool evaluateAndProject(bool forceProject=false) {
00926 bool projectOK = false, realizeOK = false;
00927 try {
00928 projectOK = true;
00929 Vector yUnitWeights, unitTolerances;
00930 mbs.realize(state, Stage::Position);
00931 mbs.calcYUnitWeights(state, yUnitWeights);
00932 mbs.calcYErrUnitTolerances(state, unitTolerances);
00933 bool needProjection = true;
00934 if (!projectEveryStep) {
00935 mbs.realize(state, Stage::Velocity);
00936 const Real err =
00937 mbs.calcWeightedRMSNorm(state.getYErr(), unitTolerances);
00938 if (err < 0.9*consTol)
00939 needProjection = false;
00940 }
00941 if ((needProjection && !suppressProject) || forceProject) {
00942 Vector dummyErrest;
00943 mbs.project(state, consTol, yUnitWeights, unitTolerances,
00944 dummyErrest);
00945 }
00946 }
00947 catch (...) { projectOK=false; }
00948
00949 if (projectOK) {
00950 try {
00951 realizeOK = true;
00952 mbs.realize(state, Stage::Acceleration);
00953 } catch (...) { realizeOK = false; }
00954 if (!realizeOK) ++statsRealizationFailures;
00955 } else ++statsProjectionFailures;
00956
00957 return projectOK && realizeOK;
00958 }
00959
00960 private:
00961 void initializeIntegrationParameters() {
00962 mbs.realize(state, Stage::Instance);
00963
00964 initializeStepSizes();
00965 predictedNextStep = initStepSize;
00966 initializeTolerances();
00967 if (userStopTime != -1.) stopTime = userStopTime;
00968 else stopTime = CNT<Real>::getInfinity();
00969 if (userMaxNumSteps != -1)
00970 maxNumSteps = userMaxNumSteps;
00971 else maxNumSteps = 0;
00972 if (userProjectEveryStep != -1)
00973 projectEveryStep = (userProjectEveryStep==1);
00974 }
00975
00976 void initializeTolerances() {
00977 accuracy = (userAccuracy != -1. ? userAccuracy : 1e-3);
00978 relTol = (userRelTol != -1. ? userRelTol : accuracy);
00979 absTol = (userAbsTol != -1. ? userAbsTol : accuracy);
00980 consTol = (userConsTol != -1. ? userConsTol : accuracy);
00981 vconsRescale = (userVConsRescale != -1. ? userVConsRescale : 1.);
00982 }
00983
00984 void initializeStepSizes() {
00985 const Real MinStep = std::pow(Eps, Real(0.75));
00986 if (userMaxStepSize != -1.) {
00987 maxStepSize = userMaxStepSize;
00988 if (userInitStepSize != -1.) {
00989 initStepSize = userInitStepSize;
00990 if (userMinStepSize != -1.)
00991 minStepSize = userMinStepSize;
00992 else minStepSize = std::min(MinStep, initStepSize);
00993 } else {
00994 if (userMinStepSize != -1.) {
00995 minStepSize = userMinStepSize;
00996 initStepSize = std::max(minStepSize, mbs.calcTimescale(state)/10.);
00997 } else {
00998
00999 initStepSize = std::min(mbs.calcTimescale(state)/10., maxStepSize);
01000 minStepSize = std::min(MinStep, initStepSize);
01001 }
01002 }
01003 } else {
01004 maxStepSize = CNT<Real>::getInfinity();
01005 if (userInitStepSize != -1.) {
01006 initStepSize = userInitStepSize;
01007 if (userMinStepSize != -1.) minStepSize = userMinStepSize;
01008 else minStepSize = std::min(MinStep, initStepSize);
01009 } else {
01010 if (userMinStepSize != -1.) {
01011 minStepSize = userMinStepSize;
01012 initStepSize = std::max(mbs.calcTimescale(state)/10., minStepSize);
01013 } else {
01014 initStepSize = mbs.calcTimescale(state)/10.;
01015 minStepSize = std::min(MinStep, initStepSize);
01016 }
01017 }
01018 }
01019 }
01020
01021 static const int NTemps = 4;
01022
01023 void reconstructForNewModel() {
01024 mbs.realize(state, Stage::Model);
01025 initStepSize=minStepSize=maxStepSize
01026 =accuracy=relTol=absTol=consTol=vconsRescale
01027 =stopTime=predictedNextStep=CNT<Real>::getNaN();
01028 maxNumSteps = -1;
01029 projectEveryStep = false;
01030 suppressProject = false;
01031 y0.resize(state.getY().size());
01032 ydot0.resize(state.getY().size());
01033 errEst.resize(state.getY().size());
01034 ynew.resize(state.getY().size());
01035 for (int i=0; i<NTemps; ++i)
01036 ytmp[i].resize(state.getY().size());
01037 initialized = false;
01038 }
01039
01040 Real initStepSize, minStepSize, maxStepSize;
01041 Real accuracy, relTol, absTol, consTol, vconsRescale;
01042 Real stopTime;
01043 long maxNumSteps;
01044 bool projectEveryStep;
01045 bool suppressProject;
01046 Real t0;
01047 Vector y0, ydot0, errEst, ynew;
01048 Vector ytmp[NTemps];
01049 Real predictedNextStep;
01050
01051 bool initialized;
01052 };
01053
01054 }
01055
01056 #endif // SimTK_SIMBODY_NUMERICAL_METHODS_H_