Rigid Body Solvers

Introduction

The equations of motion for a free rigid body whose center of mass is at the origin are given by the following Euler equations (see [MR99]).

Two quadratic first integrals of the system are:

The first constraint effectively confines the motion from (ℝ^3) to a sphere. The second constraint represents the kinetic energy of the system and, in conjunction with the first invariant, effectively confines the motion to ellipsoids on the sphere.

Numerical experiments for various methods are given in [HLW02] and a variety of (RefLink[NDSolve, paclet:ref/NDSolve]) methods will now be compared.

Manifold Generation and Utility Functions

Load some useful packages:

Needs["DifferentialEquations`NDSolveProblems`"];
Needs["DifferentialEquations`NDSolveUtilities`"];

Define Euler's equations for rigid body motion together with the invariants of the system:

system = GetNDSolveProblem["RigidBody"];
eqs = system["System"];
vars = system["DependentVariables"];
time = system["TimeData"];
invariants = system["Invariants"];

The equations of motion evolve as closed curves on the unit sphere. This generates a three-dimensional graphics object to represent the unit sphere:

UnitSphere = Graphics3D[{EdgeForm[],Sphere[]},Boxed->False];

This function superimposes a solution from (RefLink[NDSolve, paclet:ref/NDSolve]) on a given manifold:

PlotSolutionOnManifold[sol_,vars_, time_,manifold_,opts___?OptionQ]:=
Module[{solplot},
solplot = ParametricPlot3D[Evaluate[vars /. sol],time,opts,Boxed->False,Axes->False];
Show[solplot, manifold,opts]
]

This function plots the various solution components:

PlotSolutionComponents[sols_,vars_, time_,opts___?OptionQ]:=
Module[{ifuns, plotopts},
ifuns =vars /. First[sols];
Table[plotopts = Sequence[PlotLabel->StringForm["`1` vs time",Part[vars,i]],Frame->True,Axes->False];
Plot[Evaluate[Part[ifuns, i]],time,opts,Evaluate[plotopts]],{i, Length[vars]}]
];

Method Comparison

Various integration methods can be used to solve Euler's equations and they each have different associated costs and different dynamical properties.

Adams Multistep Method

Here an Adams method is used to solve the equations of motion:

AdamsSolution = NDSolve[system, Method->"Adams"];

This shows the solution trajectory by superimposing it on the unit sphere:

PlotSolutionOnManifold[AdamsSolution,vars, time, UnitSphere,PlotRange->All]

The solution appears visually to give a closed curve on the sphere. However, a plot of the error reveals that neither constraint is conserved particularly well:

InvariantErrorPlot[invariants,vars,T, AdamsSolution,PlotStyle->{Red,Blue}]

Euler and Implicit Midpoint Methods

This solves the equations of motion using Euler's method with a specified fixed step size:

EulerSolution = NDSolve[system,Method->{"FixedStep",Method->"ExplicitEuler"}, StartingStepSize -> 1/20];

This solves the equations of motion using the implicit midpoint method with a specified fixed step size:

ImplicitMidpoint = {"FixedStep",Method->{"ImplicitRungeKutta", "Coefficients"->"ImplicitRungeKuttaGaussCoefficients", DifferenceOrder->2,"ImplicitSolver"->{FixedPoint,"AccuracyGoal"->MachinePrecision,"PrecisionGoal"->MachinePrecision,"IterationSafetyFactor"->1}}};

IMPSolution = NDSolve[system,Method->ImplicitMidpoint, StartingStepSize -> 3/10];

This shows the superimposition on the unit sphere of the numerical solution of the equations of motion for Euler's method (left) and the implicit midpoint rule (right):

EulerPlotOnSphere = PlotSolutionOnManifold[EulerSolution, vars,time,UnitSphere,PlotRange->All];

IMPPlotOnSphere = PlotSolutionOnManifold[IMPSolution,vars, time,UnitSphere,PlotRange->All];

GraphicsArray[{EulerPlotOnSphere, IMPPlotOnSphere}]

This shows the components of the numerical solution using Euler's method (left) and the implicit midpoint rule (right):

EulerSolutionPlots = PlotSolutionComponents[EulerSolution, vars,time];

IMPSolutionPlots = PlotSolutionComponents[IMPSolution,vars, time];

GraphicsArray[Transpose[{EulerSolutionPlots, IMPSolutionPlots}]]

Orthogonal Projection Method

Here the "OrthogonalProjection" method is used to solve the equations:

OPSolution = NDSolve[system,Method->{"OrthogonalProjection",Dimensions->{3,1},Method->"ExplicitEuler"},StartingStepSize -> 1/20];

Only the orthogonal constraint is conserved so the curve is not closed:

PlotSolutionOnManifold[OPSolution,vars, time, UnitSphere,PlotRange->All]

Plotting the error in the invariants against time, it can be seen that the orthogonal projection method conserves only one of the two invariants:

InvariantErrorPlot[invariants,vars,T, OPSolution,PlotStyle->{Red,Blue}]

Projection Method

The method "Projection" takes a set of constraints and projects the solution onto a manifold at the end of each integration step.

Generally all the invariants of the problem should be used in the projection; otherwise the numerical solution may actually be qualitatively worse than the unprojected solution.

The following specifies the integration method and defers determination of the constraints until the invocation of (RefLink[NDSolve, paclet:ref/NDSolve]):

ProjectionMethod = {Projection,Method->{"FixedStep",Method->"ExplicitEuler"},"Invariants":>invts};

Projecting One Constraint

This projects the first constraint onto the manifold:

invts = First[invariants];

projsol1 = NDSolve[system,Method->ProjectionMethod, StartingStepSize -> 1/20];

PlotSolutionOnManifold[projsol1,vars, time,UnitSphere,PlotRange->All]

Only the first invariant is conserved:

InvariantErrorPlot[invariants,vars,T, projsol1,PlotStyle->{Red,Blue}]

This projects the second constraint onto the manifold:

invts =Last[invariants];

projsol2 = NDSolve[system,Method->ProjectionMethod, StartingStepSize -> 1/20];

PlotSolutionOnManifold[projsol2,vars, time,UnitSphere,PlotRange->All]

Only the second invariant is conserved:

InvariantErrorPlot[invariants,vars,T, projsol2,PlotStyle->{Red,Blue}]

Projecting Multiple Constraints

This projects both constraints onto the manifold:

invts = invariants;

projsol = NDSolve[system,Method->ProjectionMethod, StartingStepSize -> 1/20];

PlotSolutionOnManifold[projsol, vars,time,UnitSphere,PlotRange->All]

Now both invariants are conserved:

InvariantErrorPlot[invariants,vars,T, projsol,PlotStyle->{Red,Blue}]

"Splitting" Method

A splitting that yields an efficient explicit integration method was derived independently by McLachlan [M93] and Reich [R93].

Write the flow of an ODE (OverDot[y])==Y as y(t)==exp(t Y)(y(0).

The differential system is split into three components, YH1, YH2, and YH3, each of which is Hamiltonian and can be solved exactly.

The Hamiltonian systems are solved and recombined at each integration step as:

This defines an appropriate splitting into Hamiltonian vector fields:

Grad[H_,x_?VectorQ]:= Map[D[H,#]&,x];
isub = {(Subscript[I, 1])-> 2,(Subscript[I, 2])-> 1,(Subscript[I, 3])-> 2/3};
H1=(Subscript[Y, 1])[T]^2/(2 (Subscript[I, 1])) /. isub;
H2=(Subscript[Y, 2])[T]^2/(2 (Subscript[I, 2])) /. isub;
H3=(Subscript[Y, 3])[T]^2/(2 (Subscript[I, 3])) /. isub;
JX = {{0,-(Subscript[Y, 3])[T],(Subscript[Y, 2])[T]},{(Subscript[Y, 3])[T],0,-(Subscript[Y, 1])[T]},{-(Subscript[Y, 2])[T],(Subscript[Y, 1])[T],0}};
YH1 = Thread[D[vars,T]==JX.Grad[H1,vars]];
YH2= Thread[D[vars,T]==JX.Grad[H2,vars]];
YH3= Thread[D[vars,T]==JX.Grad[H3,vars]];

Here is the differential system for Euler's equations:

eqs

Here are the three split vector fields:

YH1

YH2

YH3

Solution

This defines a symmetric second-order splitting method. The coefficients are automatically determined from the structure of the equations and are an extension of the Strang splitting:

SplittingMethod = 
{"Splitting",
"DifferenceOrder"->2,
"Equations"->{YH1,YH2,YH3,YH2,YH1},
"Method"->{"LocallyExact"}};

This solves the system and graphically displays the solution:

splitsol = NDSolve[system,Method->SplittingMethod,StartingStepSize -> 1/20];

PlotSolutionOnManifold[splitsol, vars,time,UnitSphere,PlotRange->All]

One of the invariants is preserved up to roundoff while the error in the second invariant remains bounded:

InvariantErrorPlot[invariants,vars,T, splitsol,PlotStyle->{Red,Blue}]