How to add (energy) constraint when using NDSolve to Equation of Motion
From the docs,
solConstraint2[x0_, p0_, m_, ω_, time_] :=
NDSolve[{x'[t] == p[t]/m, p'[t] == -m ω^2 x[t], x[0] == x0, p[0] == p0},
{x, p}, {t, 0, time},
Method -> {"TimeIntegration" -> {"Projection", "Invariants" -> energy[x[t], p[t], m, ω]}}]
This keeps the energy to within about 0.12 of its starting value. Not great, but it does not drift.
Note: Using the option WorkingPrecision -> 50
on the original sol
also reigns in the drift and keeps it around 6 * 10^-10
.
I do not know offhand what is a good way to recast as a DAE. One way to enforce the algebraic constraint, without getting an overdetermined (albeit consistent) system, is to use the projection method. I cribbed some of the submethod settings from advanced documentation in tutorial/NDSolveProjection.
sol2[x0_, p0_, m_, ω_, time_] :=
NDSolve[{x'[t] == p[t]/m, p'[t] == -m ω^2 x[t], x[0] == x0,
p[0] == p0}, {x[t], p[t]}, {t, 0, time}, MaxSteps -> ∞,
Method -> {"Projection",
Method -> {"SymplecticPartitionedRungeKutta",
"DifferenceOrder" -> 4, "PositionVariables" -> {x[t]}},
"Invariants" -> energy[x[t], p[t], m, ω]}, PrecisionGoal -> 12]
This seems to remove that drift off the constraint manifold and also to keep fluctiations to around 10^(-9). Could perhaps do better with more tuning of the various options and suboptions.