37 static constexpr unsigned int cORDER = Order;
52 mMaxAdjustmentAttempts = aMaxAdjustmentAttempts;
66 switch (aErrorCriterion)
69 retval =
"L_infinity";
85 if (aErrorCriterion ==
"L_infinity")
89 else if (aErrorCriterion ==
"L_2")
99 std::string command = aInput.GetCommand();
100 if (command ==
"tolerance")
102 aInput.ReadValue(mTolerance);
103 aInput.ValueGreater(mTolerance, 0.0);
105 else if (command ==
"max_adjustment_attempts")
107 aInput.ReadValue(mMaxAdjustmentAttempts);
108 aInput.ValueGreater(mMaxAdjustmentAttempts, 0u);
110 else if (command ==
"max_step_size")
112 aInput.ReadValue(mMaxStepSize);
113 aInput.ValueGreater(mMaxStepSize, 0.0);
114 if (mMaxStepSize < mMinStepSize)
116 throw UtInput::BadValue{aInput,
"max_step_size must be larger than min_step_size."};
119 else if (command ==
"min_step_size")
121 aInput.ReadValue(mMinStepSize);
122 aInput.ValueGreaterOrEqual(mMinStepSize, 0.0);
123 if (mMinStepSize > mMaxStepSize)
125 throw UtInput::BadValue{aInput,
"min_step_size must be smaller than max_step_size."};
128 else if (command ==
"error_criterion")
130 std::string criterion;
131 aInput.ReadValue(criterion);
135 throw UtInput::BadValue(aInput,
"Unknown error criterion.");
138 else if (command ==
"initial_step_size")
140 aInput.ReadValue(mInitialStepSize);
141 aInput.ValueGreater(mInitialStepSize, 0.0);
151 const UtCalendar& aFinalTime,
152 const ut::OrbitalState& aInitialState)
override
154 ut::OrbitalState retval{aInitialState};
158 mStepSize = mInitialStepSize;
161 double finalTime = aFinalTime.GetTimeSince(retval.GetEpoch());
162 double currentTime{0.0};
163 bool acceptStep{
false};
164 unsigned int attempts{0};
167 if ((finalTime < 0.0 && mStepSize > 0.0) || (finalTime > 0.0 && mStepSize < 0.0))
169 mStepSize = -mStepSize;
172 while (fabs(currentTime) < fabs(finalTime))
174 if (fabs(mStepSize + currentTime) > fabs(finalTime))
176 mStepSize = finalTime - currentTime;
179 TakeStep(aDynamics, retval);
180 double error = ComputeError(retval.GetOrbitalStateVector());
181 if (error < mTolerance)
191 if (attempts > mMaxAdjustmentAttempts)
195 auto warn = ut::log::warning() <<
"Unable to find acceptable step size.";
196 warn.AddNote() <<
"Integration will proceed, but error will be outside tolerance.";
197 warn.AddNote() <<
"Attempts made: " << attempts;
198 warn.AddNote() <<
"Integrator type: " << Integrator::cTYPE;
206 AdvanceState(retval);
208 currentTime += mStepSize;
211 AdjustTimeStep(error);
218 static double L_InfinityNorm(
const UtVec3d& aVector)
220 return std::max(fabs(aVector[0]), std::max(fabs(aVector[1]), fabs(aVector[2])));
223 double ComputeError(
const ut::OrbitalStateVector& aInitialOSV)
const
226 switch (mErrorCriterion)
229 retval = std::max(L_InfinityNorm(mPosDiff), L_InfinityNorm(mVelDiff));
233 UtVec3d stepPosDiff = mPredictedPosition - aInitialOSV.GetLocation();
234 double posMag2 = stepPosDiff.MagnitudeSquared();
235 double posError = mPosDiff.MagnitudeSquared();
240 posError = sqrt(posError);
242 UtVec3d stepVelDiff = mPredictedVelocity - aInitialOSV.GetVelocity();
243 double velMag2 = stepVelDiff.MagnitudeSquared();
244 double velError = mVelDiff.MagnitudeSquared();
249 velError = sqrt(velError);
251 retval = std::max(posError, velError);
255 throw std::runtime_error{
"Invalid value for error criterion."};
265 void TakeStep(
const WsfOrbitalDynamics& aDynamics,
const ut::OrbitalState& aCurrentState)
270 auto& osv = aCurrentState.GetOrbitalStateVector();
271 mRHS_Position[0] = osv.GetVelocity();
272 mRHS_Velocity[0] = aCurrentState.GetAccelerationInertial();
274 for (
unsigned int i = 1; i < Integrator::cSTEPCOUNT; ++i)
277 mY_Position = osv.GetLocation();
278 mY_Velocity = osv.GetVelocity();
279 for (
unsigned int j = 0; j < i; ++j)
281 double factor = mStepSize * Integrator::cAVALUES[i][j];
283 mY_Position[0] += mRHS_Position[j][0] * factor;
284 mY_Position[1] += mRHS_Position[j][1] * factor;
285 mY_Position[2] += mRHS_Position[j][2] * factor;
286 mY_Velocity[0] += mRHS_Velocity[j][0] * factor;
287 mY_Velocity[1] += mRHS_Velocity[j][1] * factor;
288 mY_Velocity[2] += mRHS_Velocity[j][2] * factor;
292 UtCalendar predTime{aCurrentState.GetEpoch()};
293 predTime.AdvanceTimeBy(Integrator::cCVALUES[i] * mStepSize);
296 mRHS_Position[i] = mY_Velocity;
302 mPredictedPosition = osv.GetLocation();
303 mPredictedVelocity = osv.GetVelocity();
307 for (
unsigned int i = 0; i < Integrator::cSTEPCOUNT; ++i)
309 double bFactor = mStepSize * Integrator::cBVALUES[i];
310 double bErrorFactor = mStepSize * Integrator::cERRORVALUES[i];
312 mPredictedPosition[0] += mRHS_Position[i][0] * bFactor;
313 mPredictedPosition[1] += mRHS_Position[i][1] * bFactor;
314 mPredictedPosition[2] += mRHS_Position[i][2] * bFactor;
315 mPredictedVelocity[0] += mRHS_Velocity[i][0] * bFactor;
316 mPredictedVelocity[1] += mRHS_Velocity[i][1] * bFactor;
317 mPredictedVelocity[2] += mRHS_Velocity[i][2] * bFactor;
318 mPosDiff[0] += mRHS_Position[i][0] * bErrorFactor;
319 mPosDiff[1] += mRHS_Position[i][1] * bErrorFactor;
320 mPosDiff[2] += mRHS_Position[i][2] * bErrorFactor;
321 mVelDiff[0] += mRHS_Velocity[i][0] * bErrorFactor;
322 mVelDiff[1] += mRHS_Velocity[i][1] * bErrorFactor;
323 mVelDiff[2] += mRHS_Velocity[i][2] * bErrorFactor;
327 void AdjustTimeStep(
double aError)
329 if (aError > mTolerance)
331 mStepSize *= 0.9 * pow(mTolerance / aError, 1.0 / (Integrator::cORDER - 1.0));
335 mStepSize *= 0.9 * pow(mTolerance / aError, 1.0 / Integrator::cORDER);
337 if (fabs(mStepSize) > mMaxStepSize)
341 mStepSize = mMaxStepSize;
345 mStepSize = -mMaxStepSize;
348 if (fabs(mStepSize) < mMinStepSize)
352 auto warn = ut::log::warning() <<
"Timestep limited by minimum step size.";
353 warn.AddNote() <<
"Integration will proceed, but will be outside error tolerance";
354 warn.AddNote() <<
"Adjusted timestep: " << mStepSize;
355 warn.AddNote() <<
"Minimum timestep: " << mMinStepSize;
356 warn.AddNote() <<
"Integrator: " << Integrator::cTYPE;
361 mStepSize = mMinStepSize;
365 mStepSize = -mMinStepSize;
370 void AdvanceState(ut::OrbitalState& aCurrentState)
372 auto epoch = aCurrentState.GetEpoch();
373 epoch.AdvanceTimeBy(mStepSize);
374 aCurrentState.Set(epoch, ut::OrbitalStateVector{mPredictedPosition, mPredictedVelocity});
375 aCurrentState.SetAccelerationInertial(mRHS_Velocity[Integrator::cSTEPCOUNT - 1]);
378 double mStepSize{-1.0};
379 double mTolerance{1.0e-10};
380 double mMaxStepSize{std::numeric_limits<double>::max()};
381 double mMinStepSize{0.0};
382 double mInitialStepSize{0.1};
383 unsigned int mMaxAdjustmentAttempts{50};
385 std::array<UtVec3d, StepCount> mRHS_Position{};
386 std::array<UtVec3d, StepCount> mRHS_Velocity{};
387 UtVec3d mY_Position{};
388 UtVec3d mY_Velocity{};
389 UtVec3d mPredictedPosition{};
390 UtVec3d mPredictedVelocity{};