Program Listing for File advance.m¶
↰ Return to documentation for file (+Indigo/@RungeKutta/advance.m
)
%> Advance using a generic integration method for a system of the form
%> \f$ \mathbf{F}(\mathbf{x}, \mathbf{x}', \mathbf{v}, t) = \mathbf{0} \f$.
%> The step is based on the following formula:
%>
%> \f[
%> \mathbf{x}_{k+1}(t_{k}+\Delta t) = \mathbf{x}_k(t_{k}) +
%> \mathcal{S}(\mathbf{x}_k(t_k), \mathbf{x}'_k(t_k), t_k, \Delta t)
%> \f]
%>
%> where \f$ \mathcal{S} \f$ is the generic advancing step of the solver.
%> In the advvancing step, the system solution is also projected on the
%> manifold \f$ \mathcal{h}(\mathbf{x}, \mathbf{v}, t) \f$. Substepping is
%> also used to ensure that the solution is accurate.
%>
%> \param x_k States value at \f$ k \f$-th time step \f$ \mathbf{x}(t_k) \f$.
%> \param t_k Time step \f$ t_k \f$.
%> \param d_t Advancing time step \f$ \Delta t\f$.
%>
%> \return The approximation of \f$ \mathbf{x_{k+1}}(t_{k}+\Delta t) \f$,
%> \f$ \mathbf{x}'_{k+1}(t_{k}+\Delta t) \f$ and the suggested time
%> step for the next advancing step \f$ \Delta t_{k+1} \f$.
%
function [x_new, d_t_star, ierr] = advance( this, x_k, t_k, d_t )
CMD = 'Indigo.RungeKutta.advance(...): ';
% Check initial conditions
num_eqns = this.m_sys.get_num_eqns();
assert(num_eqns == length(x_k), ...
[CMD, 'in %s solver, length(x_0) is %d, expected %d.'], ...
this.m_name, length(x_k), num_eqns);
% Check step size
assert(d_t > 0, ...
[CMD, 'in %s solver, d_t is %f, expected > 0.'], ...
this.m_name, d_t);
% Integrate system
[x_new, d_t_star, ierr] = this.step( x_k, t_k, d_t );
% If the advance failed, try again with substepping
if (ierr ~= 0)
x_tmp = x_k;
t_tmp = t_k;
d_t_tmp = 0.5 * d_t;
max_k = this.m_max_substeps * this.m_max_substeps;
k = 2;
while (k > 0)
% Integrate system
[x_tmp, d_t_star_tmp, ierr] = this.step(x_tmp, t_tmp, d_t_tmp);
% Calculate the next time step with substepping logic
if (ierr == 0)
% Accept the step
d_t_tmp = d_t_star_tmp;
% If substepping is enabled, double the step size
if (k > 0 && k < max_k)
k = k - 1;
% If the substepping index is even, double the step size
if (rem(k, 2) == 0)
d_t_tmp = 2.0 * d_t_tmp;
if (this.m_verbose)
warning([CMD, 'in %s solver, at t = %g, integration ', ...
'succedded disable one substepping layer.'], ...
this.m_name, t_tmp);
end
end
end
% Check the infinity norm of the solution
assert(isfinite(norm(x_tmp, inf)), ...
[CMD, 'in %s solver, at t = %g, ||x||_inf = inf, computation ', ...
'interrupted.\n'], ...
this.m_name, t_tmp);
else
% If the substepping index is too high, abort the integration
k = k + 2;
assert(k < max_k, ...
[CMD, 'in %s solver, at t = %g, integration failed ', ...
'(error code %d) with d_t = %g, aborting.'], ...
this.m_name, t_tmp, ierr, d_t);
% Otherwise, try again with a smaller step
if (this.m_verbose)
warning([CMD, 'in %s solver, at t = %g, integration failed ', ...
'(error code %d), adding substepping layer.'], ...
this.m_name, t_tmp, ierr);
end
d_t_tmp = 0.5 * d_t_tmp;
continue;
end
% Store time solution
t_tmp = t_tmp + d_t_tmp;
end
% Store output states substepping solutions
x_new = x_tmp;
d_t_star = d_t_tmp;
end
% Project intermediate solution on the invariants
if (this.m_projection)
x_new = this.project(x_new, t_k+d_t);
end
end
%