// The first task as usual is to include the functionality of these well-known
// deal.II library files and some C++ header files.
+#include <deal.II/base/discrete_time.h>
#include <deal.II/base/function.h>
#include <deal.II/base/quadrature_lib.h>
// constraints are respected; of course, with the mesh we use here,
// hanging node constraints are not in fact an issue). It then calls
// <code>evolve_one_time_step</code> which performs one time step.
+ // Time is stored and incremented through a DiscreteTime object.
//
// For explicit methods, <code>evolve_one_time_step</code> needs to
// evaluate $M^{-1}(f(t,y))$, i.e, it needs
{
const double time_step =
(final_time - initial_time) / static_cast<double>(n_time_steps);
- double time = initial_time;
solution = 0.;
constraint_matrix.distribute(solution);
TimeStepping::ExplicitRungeKutta<Vector<double>> explicit_runge_kutta(
method);
- output_results(time, 0, method);
- for (unsigned int i = 0; i < n_time_steps; ++i)
+ output_results(initial_time, 0, method);
+ DiscreteTime time(initial_time, final_time, time_step);
+ while (time.is_at_end() == false)
{
- time = explicit_runge_kutta.evolve_one_time_step(
+ explicit_runge_kutta.evolve_one_time_step(
[this](const double time, const Vector<double> &y) {
return this->evaluate_diffusion(time, y);
},
- time,
- time_step,
+ time.get_current_time(),
+ time.get_next_step_size(),
solution);
+ time.advance_time();
constraint_matrix.distribute(solution);
- if ((i + 1) % 10 == 0)
- output_results(time, i + 1, method);
+ if (time.get_step_number() % 10 == 0)
+ output_results(time.get_current_time(),
+ time.get_step_number(),
+ method);
}
}
{
const double time_step =
(final_time - initial_time) / static_cast<double>(n_time_steps);
- double time = initial_time;
solution = 0.;
constraint_matrix.distribute(solution);
TimeStepping::ImplicitRungeKutta<Vector<double>> implicit_runge_kutta(
method);
- output_results(time, 0, method);
- for (unsigned int i = 0; i < n_time_steps; ++i)
+ output_results(initial_time, 0, method);
+ DiscreteTime time(initial_time, final_time, time_step);
+ while (time.is_at_end() == false)
{
- time = implicit_runge_kutta.evolve_one_time_step(
+ implicit_runge_kutta.evolve_one_time_step(
[this](const double time, const Vector<double> &y) {
return this->evaluate_diffusion(time, y);
},
[this](const double time, const double tau, const Vector<double> &y) {
return this->id_minus_tau_J_inverse(time, tau, y);
},
- time,
- time_step,
+ time.get_current_time(),
+ time.get_next_step_size(),
solution);
+ time.advance_time();
constraint_matrix.distribute(solution);
- if ((i + 1) % 10 == 0)
- output_results(time, i + 1, method);
+ if (time.get_step_number() % 10 == 0)
+ output_results(time.get_current_time(),
+ time.get_step_number(),
+ method);
}
}
// - max_delta: largest time step acceptable.
// - refine_tol: threshold above which the time step is refined.
// - coarsen_tol: threshold below which the time step is coarsen.
+ //
// Embedded methods use a guessed time step. If the error using this time step
// is too large, the time step will be reduced. If the error is below the
// threshold, a larger time step will be tried for the next time step.
// <code>delta_t_guess</code> is the guessed time step produced by the
- // embedded method.
+ // embedded method. In summary, time step size is potentially modified in
+ // three ways:
+ // - Reducing or increasing time step size within
+ // TimeStepping::EmbeddedExplicitRungeKutta::evolve_one_time_step().
+ // - Using the calculated <code>delta_t_guess</code>.
+ // - Automatically adjusting the step size of the last time step to ensure
+ // simulation ends precisely at <code>final_time</code>. This adjustment
+ // is handled inside the DiscreteTime instance.
unsigned int Diffusion::embedded_explicit_method(
const TimeStepping::runge_kutta_method method,
const unsigned int n_time_steps,
const double initial_time,
const double final_time)
{
- double time_step =
+ const double time_step =
(final_time - initial_time) / static_cast<double>(n_time_steps);
- double time = initial_time;
const double coarsen_param = 1.2;
const double refine_param = 0.8;
const double min_delta = 1e-8;
max_delta,
refine_tol,
coarsen_tol);
- output_results(time, 0, method);
-
- // Now for the time loop. The last time step is chosen such that the final
- // time is exactly reached.
- unsigned int n_steps = 0;
- while (time < final_time)
+ output_results(initial_time, 0, method);
+ DiscreteTime time(initial_time, final_time, time_step);
+ while (time.is_at_end() == false)
{
- if (time + time_step > final_time)
- time_step = final_time - time;
-
- time = embedded_explicit_runge_kutta.evolve_one_time_step(
- [this](const double time, const Vector<double> &y) {
- return this->evaluate_diffusion(time, y);
- },
- time,
- time_step,
- solution);
+ const double new_time =
+ embedded_explicit_runge_kutta.evolve_one_time_step(
+ [this](const double time, const Vector<double> &y) {
+ return this->evaluate_diffusion(time, y);
+ },
+ time.get_current_time(),
+ time.get_next_step_size(),
+ solution);
+ time.set_next_step_size(new_time - time.get_current_time());
+ time.advance_time();
constraint_matrix.distribute(solution);
- if ((n_steps + 1) % 10 == 0)
- output_results(time, n_steps + 1, method);
+ if (time.get_step_number() % 10 == 0)
+ output_results(time.get_current_time(),
+ time.get_step_number(),
+ method);
- time_step = embedded_explicit_runge_kutta.get_status().delta_t_guess;
- ++n_steps;
+ time.set_desired_next_step_size(
+ embedded_explicit_runge_kutta.get_status().delta_t_guess);
}
- return n_steps;
+ return time.get_step_number();
}
final_time);
std::cout << " Heun-Euler: error=" << solution.l2_norm()
<< std::endl;
- std::cout << " steps performed=" << n_steps << std::endl;
+ std::cout << " steps performed=" << n_steps << std::endl;
n_steps = embedded_explicit_method(TimeStepping::BOGACKI_SHAMPINE,
n_time_steps,
final_time);
std::cout << " Bogacki-Shampine: error=" << solution.l2_norm()
<< std::endl;
- std::cout << " steps performed=" << n_steps << std::endl;
+ std::cout << " steps performed=" << n_steps << std::endl;
n_steps = embedded_explicit_method(TimeStepping::DOPRI,
n_time_steps,
final_time);
std::cout << " Dopri: error=" << solution.l2_norm()
<< std::endl;
- std::cout << " steps performed=" << n_steps << std::endl;
+ std::cout << " steps performed=" << n_steps << std::endl;
n_steps = embedded_explicit_method(TimeStepping::FEHLBERG,
n_time_steps,
final_time);
std::cout << " Fehlberg: error=" << solution.l2_norm()
<< std::endl;
- std::cout << " steps performed=" << n_steps << std::endl;
+ std::cout << " steps performed=" << n_steps << std::endl;
n_steps = embedded_explicit_method(TimeStepping::CASH_KARP,
n_time_steps,
final_time);
std::cout << " Cash-Karp: error=" << solution.l2_norm()
<< std::endl;
- std::cout << " steps performed=" << n_steps << std::endl;
+ std::cout << " steps performed=" << n_steps << std::endl;
}
} // namespace Step52