Apart from solving initial value problems, for which the integrator is a key component of a simulator, integrators can also be used to solve boundary value problems (via numerical methods like the Multiple Shooting Method) and trajectory optimization problems (via numerical methods like direct transcription).
IntegratorBase and its derivatives were developed primarily toward the former application (through IntegratorBase::IntegrateNoFurtherThanTime() and the Simulator class). However, the IntegratorBase architecture was developed to support these ancillary applications as well using the IntegratorBase::IntegrateWithMultipleStepsToTime() and IntegratorBase::IntegrateWithSingleFixedStepToTime() methods; the latter permits the caller to advance time using fixed steps in applications where variable stepping would be deleterious (e.g., direct transcription).
A natural question for a user to ask of an integrator is: Which scheme (method) should be applied to a particular problem? The answer is whichever one most quickly computes the solution to the desired accuracy! Selecting an integration scheme for a particular problem is presently an artform. As examples of some selection criteria: multistep methods (none of which are currently implemented in Drake) generally work poorly when events (that require state reinitializations) are common, symplectic methods generally work well at maintaining stability for large integration steps, and stiff integrators are often best for computationally stiff systems. If ignorant as to the characteristics of a particular problem, it is often best to start with an explicit, Runge-Kutta type method. Statistics collected by the integrator can help diagnose performance issues and possibly point to the use of a different integration scheme.
Some systems are known to exhibit "computational stiffness", by which it is meant that (excessively) small integration steps are necessary for purposes of stability: in other words, steps must be taken smaller than that required to achieve a desired accuracy over a particular interval. Thus, the nature of computationally stiff problems is that the solution to the ODE is smooth in the interval of stiffness (in contrast, some problems possess such high frequency dynamics that very small steps are simply necessary to capture the solution accurately). Implicit integrators are the go-to approach for solving computationally stiff problems, but careful consideration is warranted. Implicit integrators typically require much more computation than non-implicit (explicit) integrators, stiffness might be an issue on only a very small time interval, and some problems might be only "moderately stiff". Put another way, applying an implicit integrator to a potentially stiff problem might not yield faster computation. The first chapter of [Hairer, 1996] illustrates the issues broached in this paragraph using various examples.
IntegratorBase provides numerous settings and flags that can leverage problem-specific information to speed integration and/or improve integration accuracy. As an example, IntegratorBase::set_maximum_step_size() allows the user to prevent overly large integration steps (that integration error control alone might be insufficient to detect). As noted previously, IntegratorBase also collects a plethora of statistics that can be used to diagnose poor integration performance. For example, a large number of shrinkages due to error control could indicate that a system is computationally stiff. Note that you might need to alter the default settings to obtain desired performance even though we have attempted to select reasonable defaults for many problems.
See settings for integrator-accuracy, maximum step size, minimum step size, and weighting state errors for in-depth information about the various performance settings shared across integrators.
For applications that require a more dense sampling of the system continuous state than what would be available through either fixed or error-controlled step integration (for a given accuracy), dense output support is available (through IntegratorBase::StartDenseIntegration() and IntegratorBase::StopDenseIntegration() methods). The accuracy and performance of these outputs may vary with each integration scheme implementation.
Classes | |
class | BogackiShampine3Integrator< T > |
A third-order, four-stage, first-same-as-last (FSAL) Runge-Kutta integrator with a second order error estimate. More... | |
class | ExplicitEulerIntegrator< T > |
A first-order, explicit Euler integrator. More... | |
class | ImplicitEulerIntegrator< T > |
A first-order, fully implicit integrator with second order error estimation. More... | |
class | IntegratorBase< T > |
An abstract class for an integrator for ODEs and DAEs as represented by a Drake System. More... | |
class | RadauIntegrator< T, num_stages > |
A selectable order (third- or first-order), fully implicit integrator with error estimation. More... | |
class | RungeKutta2Integrator< T > |
A second-order, explicit Runge Kutta integrator. More... | |
class | RungeKutta3Integrator< T > |
A third-order Runge Kutta integrator with a third order error estimate. More... | |
class | RungeKutta5Integrator< T > |
A fifth-order, seven-stage, first-same-as-last (FSAL) Runge Kutta integrator with a fourth order error estimate. More... | |
class | SemiExplicitEulerIntegrator< T > |
A first-order, semi-explicit Euler integrator. More... | |
class | VelocityImplicitEulerIntegrator< T > |
A first-order, fully implicit integrator optimized for second-order systems, with a second-order error estimate. More... | |