Skip to content

Commit de15bfe

Browse files
committed
Modify IntegratorBase
1 parent f3c36f7 commit de15bfe

File tree

1 file changed

+82
-5
lines changed

1 file changed

+82
-5
lines changed

systems/analysis/integrator_base.h

+82-5
Original file line numberDiff line numberDiff line change
@@ -1082,6 +1082,57 @@ class IntegratorBase {
10821082
return true;
10831083
}
10841084

1085+
/**
1086+
Stepping function for integrators operating outside of Simulator that
1087+
advances the continuous state of the `context` *using a single step* to
1088+
`t_target`. This method is designed for integrator users that do not wish to
1089+
consider publishing or discontinuous, mid-interval updates. One such
1090+
example application is that of direct transcription for trajectory
1091+
optimization, for which the integration process should be _consistent_: it
1092+
should execute the same sequence of arithmetic operations for all values
1093+
of the nonlinear programming variables. In keeping with the naming
1094+
semantics of this function, error controlled integration is not supported
1095+
(though error estimates will be computed for integrators that support that
1096+
feature), which is a minimal requirement for "consistency".
1097+
@param context The context to perform integration on.
1098+
@param t_target The current or future time to integrate to.
1099+
@throws std::exception If the integrator has not been initialized or
1100+
`t_target` is in the past or context is nullptr.
1101+
@returns `true` if the integrator was able to take a single fixed step to
1102+
`t_target`.
1103+
@warning Not thread safe. The integrator holds mutable member variables to
1104+
avoid allocation inside the integration steps.
1105+
*/
1106+
[[nodiscard]] bool IntegrateWithSingleFixedStepToTime(
1107+
Context<T>* context, const T& t_target) const {
1108+
DRAKE_THROW_UNLESS(context != nullptr);
1109+
using std::abs;
1110+
using std::max;
1111+
1112+
const T h = t_target - context->get_time();
1113+
if (scalar_predicate<T>::is_bool && h < 0) {
1114+
throw std::logic_error(
1115+
"IntegrateWithSingleFixedStepToTime() called with "
1116+
"a negative step size.");
1117+
}
1118+
1119+
if (!DoStepConst(context, h)) return false;
1120+
1121+
if constexpr (scalar_predicate<T>::is_bool) {
1122+
// Correct any round-off error that has occurred. Formula below requires
1123+
// that time be non-negative.
1124+
DRAKE_DEMAND(context->get_time() >= 0);
1125+
const double tol =
1126+
10 * std::numeric_limits<double>::epsilon() *
1127+
ExtractDoubleOrThrow(max(1.0, max(t_target, context_->get_time())));
1128+
DRAKE_DEMAND(abs(context->get_time() - t_target) < tol);
1129+
}
1130+
1131+
context->SetTime(t_target);
1132+
1133+
return true;
1134+
}
1135+
10851136
/**
10861137
@name Integrator statistics methods
10871138
@{
@@ -1318,7 +1369,8 @@ class IntegratorBase {
13181369
Subclasses should call this function rather than calling
13191370
system.EvalTimeDerivatives() directly.
13201371
*/
1321-
const ContinuousState<T>& EvalTimeDerivatives(const Context<T>& context) {
1372+
const ContinuousState<T>& EvalTimeDerivatives(
1373+
const Context<T>& context) const {
13221374
return EvalTimeDerivatives(get_system(), context); // See below.
13231375
}
13241376

@@ -1330,8 +1382,8 @@ class IntegratorBase {
13301382
function evaluations.
13311383
*/
13321384
template <typename U>
1333-
const ContinuousState<U>& EvalTimeDerivatives(const System<U>& system,
1334-
const Context<U>& context) {
1385+
const ContinuousState<U>& EvalTimeDerivatives(
1386+
const System<U>& system, const Context<U>& context) const {
13351387
const CacheEntry& entry = system.get_time_derivatives_cache_entry();
13361388
const CacheEntryValue& value = entry.get_cache_entry_value(context);
13371389
const int64_t serial_number_before = value.serial_number();
@@ -1447,7 +1499,6 @@ class IntegratorBase {
14471499
method is called during the integration process (via
14481500
StepOnceErrorControlledAtMost(), IntegrateNoFurtherThanTime(), and
14491501
IntegrateWithSingleFixedStepToTime()).
1450-
@param h The integration step to take.
14511502
@returns `true` if successful, `false` if the integrator was unable to take
14521503
a single step of size @p h (due to, e.g., an integrator
14531504
convergence failure).
@@ -1462,6 +1513,32 @@ class IntegratorBase {
14621513
*/
14631514
virtual bool DoStep(const T& h) = 0;
14641515

1516+
/**
1517+
Derived classes must implement this method to (1) integrate the continuous
1518+
portion of this system forward by a single step of size @p h and
1519+
(2) set the error estimate (via get_mutable_error_estimate()). This
1520+
method is called during the integration process (via
1521+
StepOnceErrorControlledAtMost(), IntegrateNoFurtherThanTime(), and
1522+
IntegrateWithSingleFixedStepToTime()).
1523+
@returns `true` if successful, `false` if the integrator was unable to take
1524+
a single step of size @p h (due to, e.g., an integrator
1525+
convergence failure).
1526+
@post If the time on entry is denoted `t`, the time and state will be
1527+
advanced to `t+h` if the method returns `true`; otherwise, the
1528+
time and state should be reset to those at `t`.
1529+
@warning It is expected that DoStep() will return `true` for some, albeit
1530+
possibly very small, positive value of @p h. The derived
1531+
integrator's stepping algorithm can make this guarantee, for
1532+
example, by switching to an algorithm not subject to convergence
1533+
failures (e.g., explicit Euler) for very small step sizes.
1534+
*/
1535+
virtual bool DoStepConst(Context<T>* context, const T& h) const {
1536+
unused(context);
1537+
unused(h);
1538+
throw std::logic_error(
1539+
"This integrator does not (yet) implement the const DoStep() variant.");
1540+
}
1541+
14651542
// TODO(russt): Allow subclasses to override the interpolation scheme used, as
14661543
// the 'optimal' dense output scheme is only known by the specific integration
14671544
// scheme being implemented.
@@ -1628,7 +1705,7 @@ class IntegratorBase {
16281705
T smallest_adapted_step_size_taken_{nan()};
16291706
T largest_step_size_taken_{nan()};
16301707
int64_t num_steps_taken_{0};
1631-
int64_t num_ode_evals_{0};
1708+
mutable int64_t num_ode_evals_{0};
16321709
int64_t num_shrinkages_from_error_control_{0};
16331710
int64_t num_shrinkages_from_substep_failures_{0};
16341711
int64_t num_substep_failures_{0};

0 commit comments

Comments
 (0)