374 * #ifndef AUXILIARY_FUNCTIONS
375 * #define AUXILIARY_FUNCTIONS
385 * Comparison of
numbers with a given tolerance.
388 *
template <
typename T>
389 *
bool isapprox(
const T &a,
const T &b,
const double tol = 1e-10)
396 * Fill the std::vector with the
values from the range [interval_begin, interval_end].
399 *
template <
typename T>
400 *
void linspace(T interval_begin, T interval_end, std::vector<T> &arr)
402 *
const size_t SIZE = arr.size();
403 *
const T step = (interval_end - interval_begin) /
static_cast<T
>(SIZE - 1);
404 *
for (
size_t i = 0; i < SIZE; ++i)
406 * arr[i] = interval_begin + i * step;
412 * Check the file existence.
415 *
inline bool file_exists(
const std::string &filename)
417 * std::ifstream f(filename.c_str());
425<a name=
"ann-IntegrateSystem.h"></a>
426<h1>Annotated version of IntegrateSystem.h</h1>
442 * #ifndef INTEGRATE_SYSTEM
443 * #define INTEGRATE_SYSTEM
445 * #include <
boost/numeric/odeint.hpp>
447 * #include <iostream>
451 *
template <
typename state_T,
typename time_T>
452 *
void SaveSolutionIntoFile(
const std::vector<state_T>& x_vec,
const std::vector<time_T>& t_vec, std::string filename=
"output_ode_sol.txt")
454 *
if (!x_vec.empty() && !t_vec.empty())
456 * std::ofstream output(filename);
457 * output << std::setprecision(16);
459 *
size_t dim = x_vec[0].size();
460 *
for (
size_t i = 0; i < t_vec.size(); ++i)
462 * output << std::fixed << t_vec[i];
463 *
for (
size_t j = 0; j < dim; ++j)
465 * output << std::scientific <<
" " << x_vec[i][j];
473 * std::cout <<
"Solution is not saved into file.\n";
479 * type of RK integrator
482 *
enum class Integrator_Type
494 *
template <
typename state_type>
495 *
class Push_back_state_time
498 * std::vector<state_type>& m_states;
499 * std::vector<double>& m_times;
501 * Push_back_state_time(std::vector<state_type>& states, std::vector<double>& times)
502 * : m_states(states), m_times(times)
505 *
void operator() (
const state_type& x,
double t)
507 * m_states.push_back(x);
508 * m_times.push_back(t);
515 * Integrate system at specified points.
518 *
template <
typename ODE_obj_T,
typename state_type,
typename Iterable_type>
519 *
void IntegrateSystemAtTimePoints(
520 * std::vector<state_type>& x_vec, std::vector<double>& t_vec,
const Iterable_type& iterable_time_span,
521 *
const ODE_obj_T& ode_system_obj,
522 * state_type& x,
const double dt,
523 * Integrator_Type integrator_type=Integrator_Type::dopri5,
bool save_to_file_flag=
false,
524 *
const double abs_er_tol=1.0e-15,
const double rel_er_tol=1.0e-15
527 *
using namespace boost::numeric::odeint;
529 *
if (integrator_type == Integrator_Type::dopri5)
531 *
typedef runge_kutta_dopri5< state_type > error_stepper_type;
532 * integrate_times( make_controlled< error_stepper_type >(abs_er_tol, rel_er_tol),
533 * ode_system_obj, x, iterable_time_span.begin(), iterable_time_span.end(), dt, Push_back_state_time< state_type >(x_vec, t_vec) );
535 *
else if (integrator_type == Integrator_Type::cash_karp54)
537 *
typedef runge_kutta_cash_karp54< state_type > error_stepper_type;
538 * integrate_times( make_controlled< error_stepper_type >(abs_er_tol, rel_er_tol),
539 * ode_system_obj, x, iterable_time_span.begin(), iterable_time_span.end(), dt, Push_back_state_time< state_type >(x_vec, t_vec) );
543 *
typedef runge_kutta_fehlberg78< state_type > error_stepper_type;
544 * integrate_times( make_controlled< error_stepper_type >(abs_er_tol, rel_er_tol),
545 * ode_system_obj, x, iterable_time_span.begin(), iterable_time_span.end(), dt, Push_back_state_time< state_type >(x_vec, t_vec) );
548 *
if (save_to_file_flag)
550 * SaveSolutionIntoFile(x_vec, t_vec);
559<a name=
"ann-LimitSolution.cc"></a>
560<h1>Annotated version of LimitSolution.cc</h1>
576 * #include
"LimitSolution.h"
578 *
namespace TravelingWave
581 * LimitSolution::LimitSolution(
const Parameters ¶meters,
const double ilambda_0,
const double iu_0,
const double iT_0,
const double iroot_sign)
582 * : params(parameters)
583 * , problem(params.problem)
584 * , wave_speed(problem.wave_speed_init)
585 * , lambda_0(ilambda_0)
588 * , root_sign(iroot_sign)
590 * calculate_constants_A_B();
593 *
double LimitSolution::omega_func(
const double lambda,
const double T)
const
595 *
return problem.k * (1. -
lambda) *
std::exp(-problem.theta / T);
598 *
void LimitSolution::operator() (
const state_type &x , state_type &dxdt ,
const double )
600 * dxdt[0] = -1. / wave_speed * omega_func(x[0], T_func(x[0]));
603 *
double LimitSolution::u_func(
const double lambda)
const
605 *
double coef = 2 * (wave_speed - 1) / problem.epsilon - 1;
606 *
return (coef + root_sign *
std::sqrt(coef * coef - 4 * (problem.q * lambda + B - 2 * A / problem.epsilon))) / 2;
609 *
double LimitSolution::T_func(
const double lambda)
const
611 *
return u_func(lambda) + problem.q *
lambda + B;
614 *
void LimitSolution::calculate_constants_A_B()
617 * A = u_0 * (1 - wave_speed) + problem.epsilon * (u_0 * u_0 + T_0) / 2;
620 *
void LimitSolution::set_wave_speed(
double iwave_speed)
622 * wave_speed = iwave_speed;
623 * calculate_constants_A_B();
626 *
void LimitSolution::calculate_u_T_omega()
628 *
if (!t_vec.empty() && !lambda_vec.empty())
630 * u_vec.resize(lambda_vec.size());
631 * T_vec.resize(lambda_vec.size());
632 * omega_vec.resize(lambda_vec.size());
633 *
for (
unsigned int i = 0; i < lambda_vec.size(); ++i)
635 * u_vec[i].resize(1);
636 * T_vec[i].resize(1);
637 * omega_vec[i].resize(1);
639 * u_vec[i][0] = u_func(lambda_vec[i][0]);
640 * T_vec[i][0] = T_func(lambda_vec[i][0]);
641 * omega_vec[i][0] = omega_func(lambda_vec[i][0], T_vec[i][0]);
646 * std::cout <<
"t_vec or lambda_vec vector is empty!" << std::endl;
654<a name=
"ann-LimitSolution.h"></a>
655<h1>Annotated version of LimitSolution.h</h1>
671 * #ifndef LIMIT_SOLUTION
672 * #define LIMIT_SOLUTION
674 * #include
"Parameters.h"
675 * #include <iostream>
678 *
namespace TravelingWave
680 *
typedef std::vector< double > state_type;
682 *
class LimitSolution
685 * LimitSolution(
const Parameters ¶meters,
const double ilambda_0,
const double iu_0,
const double iT_0,
const double root_sign = 1.);
687 *
void operator() (
const state_type &x , state_type &dxdt ,
const double );
688 *
void calculate_u_T_omega();
689 *
void set_wave_speed(
double iwave_speed);
691 * std::vector<double> t_vec;
692 * std::vector<state_type> omega_vec;
693 * std::vector<state_type> lambda_vec;
694 * std::vector<state_type> u_vec;
695 * std::vector<state_type> T_vec;
698 *
double omega_func(
const double lambda,
const double T)
const;
699 *
double u_func(
const double lambda)
const;
700 *
double T_func(
const double lambda)
const;
702 *
void calculate_constants_A_B();
704 *
const Parameters ¶ms;
705 *
const Problem &problem;
708 *
const double lambda_0, u_0, T_0;
711 *
const double root_sign;
721<a name=
"ann-LinearInterpolator.h"></a>
722<h1>Annotated version of LinearInterpolator.h</h1>
738 * #ifndef LINEAR_INTERPOLATOR
739 * #define LINEAR_INTERPOLATOR
742 * #include <algorithm>
747 * Linear interpolation
class
750 *
template <
typename Number_Type>
751 *
class LinearInterpolator
754 * LinearInterpolator(
const std::vector<Number_Type> &ix_points,
const std::vector<Number_Type> &iy_points);
755 * Number_Type
value(
const Number_Type x)
const;
758 *
const std::vector<Number_Type> x_points;
759 *
const std::vector<Number_Type> y_points;
762 *
template <
typename Number_Type>
763 * LinearInterpolator<Number_Type>::LinearInterpolator(
const std::vector<Number_Type> &ix_points,
const std::vector<Number_Type> &iy_points)
764 * : x_points(ix_points)
765 * , y_points(iy_points)
768 *
template <
typename Number_Type>
769 * Number_Type LinearInterpolator<Number_Type>::value(
const Number_Type x)
const
771 * Number_Type res = 0.;
773 *
auto lower = std::lower_bound(x_points.begin(), x_points.end(), x);
774 *
unsigned int right_index = 0;
775 *
unsigned int left_index = 0;
776 *
if (lower == x_points.begin())
780 *
else if (lower == x_points.end())
782 * res = y_points[x_points.size()-1];
786 * right_index = lower - x_points.begin();
787 * left_index = right_index - 1;
789 * Number_Type y_2 = y_points[right_index];
790 * Number_Type y_1 = y_points[left_index];
791 * Number_Type x_2 = x_points[right_index];
792 * Number_Type x_1 = x_points[left_index];
794 * res = (y_2 - y_1) / (x_2 - x_1) * (x - x_1) + y_1;
804<a name=
"ann-Parameters.cc"></a>
805<h1>Annotated version of Parameters.cc</h1>
821 * #include
"Parameters.h"
823 *
namespace TravelingWave
830 * add_parameter(
"delta", delta = 0.01);
831 * add_parameter(
"epsilon", epsilon = 0.1);
832 * add_parameter(
"Prandtl number", Pr = 0.75);
833 * add_parameter(
"Lewis number", Le = 1.0);
834 * add_parameter(
"Constant of reaction rate", k = 1.0);
835 * add_parameter(
"Activation energy", theta = 1.65);
836 * add_parameter(
"Heat release", q = 1.7);
837 * add_parameter(
"Ignition Temperature", T_ign = 1.0);
838 * add_parameter(
"Type of the wave (deflagration / detonation)", wave_type = 1);
840 * add_parameter(
"Type of boundary condition for the temperature at the right boundary", T_r_bc_type = 1);
842 * add_parameter(
"T_left", T_left = 5.3);
843 * add_parameter(
"T_right", T_right = 0.9);
844 * add_parameter(
"u_left", u_left = -0.2);
845 * add_parameter(
"u_right", u_right = 0.);
847 * add_parameter(
"Initial guess for the wave speed", wave_speed_init = 1.2);
850 * FiniteElements::FiniteElements()
853 * add_parameter(
"Polynomial degree", poly_degree = 1);
854 * add_parameter(
"Number of quadrature points", quadrature_points_number = 3);
860 * add_parameter(
"Interval left boundary", interval_left = -50.0);
861 * add_parameter(
"Interval right boundary", interval_right = 20.0);
862 * add_parameter<unsigned int>(
"Refinements number", refinements_number = 10);
863 * add_parameter(
"Adaptive mesh refinement", adaptive = 1);
869 * add_parameter(
"Tolerance", tol = 1e-10);
876<a name=
"ann-Parameters.h"></a>
877<h1>Annotated version of Parameters.h</h1>
896 * #include <deal.II/base/parameter_acceptor.h>
898 *
namespace TravelingWave
908 *
double k, theta, q;
912 *
double T_left, T_right;
913 *
double u_left, u_right;
915 *
double wave_speed_init;
922 *
unsigned int poly_degree;
923 *
unsigned int quadrature_points_number;
930 *
double interval_left;
931 *
double interval_right;
932 *
unsigned int refinements_number;
957<a name=
"ann-Solution.cc"></a>
958<h1>Annotated version of Solution.cc</h1>
974 * #include
"Solution.h"
976 *
namespace TravelingWave
981 * SolutionStruct::SolutionStruct() {}
982 * SolutionStruct::SolutionStruct(
const std::vector<double> &ix,
const std::vector<double> &iu,
983 *
const std::vector<double> &iT,
const std::vector<double> &ilambda,
double iwave_speed)
988 * , wave_speed(iwave_speed)
990 * SolutionStruct::SolutionStruct(
const std::vector<double> &ix,
const std::vector<double> &iu,
991 *
const std::vector<double> &iT,
const std::vector<double> &ilambda)
992 * : SolutionStruct(ix, iu, iT, ilambda, 0.)
995 *
void SolutionStruct::reinit(
const unsigned int number_of_elements)
1003 * x.resize(number_of_elements);
1004 * u.resize(number_of_elements);
1005 * T.resize(number_of_elements);
1006 *
lambda.resize(number_of_elements);
1009 *
void SolutionStruct::save_to_file(std::string filename =
"sol") const
1011 *
const std::string file_for_solution = filename +
".txt";
1012 * std::ofstream output(file_for_solution);
1014 * output << std::scientific << std::setprecision(16);
1015 *
for (
unsigned int i = 0; i < x.size(); ++i)
1017 * output << std::fixed << x[i];
1018 * output << std::scientific <<
" " << u[i] <<
" " << T[i] <<
" " <<
lambda[i] <<
"\n";
1022 * std::ofstream file_for_wave_speed_output(
"wave_speed-" + file_for_solution);
1023 * file_for_wave_speed_output << std::scientific << std::setprecision(16);
1024 * file_for_wave_speed_output << wave_speed << std::endl;
1025 * file_for_wave_speed_output.close();
1029 * Interpolant::Interpolant(
const std::vector<double> &ix_points,
const std::vector<double> &iy_points)
1030 * : interpolant(ix_points, iy_points)
1033 *
double Interpolant::value(
const Point<1> &p,
const unsigned int component)
const
1036 *
double res = interpolant.value(x);
1042 *
template <
typename InterpolantType>
1043 * SolutionVectorFunction<InterpolantType>::SolutionVectorFunction(InterpolantType iu_interpolant, InterpolantType iT_interpolant, InterpolantType ilambda_interpolant)
1045 * , u_interpolant(iu_interpolant)
1046 * , T_interpolant(iT_interpolant)
1047 * , lambda_interpolant(ilambda_interpolant)
1050 *
template <
typename InterpolantType>
1051 *
double SolutionVectorFunction<InterpolantType>::value(
const Point<1> &p,
const unsigned int component)
const
1054 *
if (component == 0) { res = u_interpolant.
value(p); }
1055 *
else if (component == 1) { res = T_interpolant.value(p); }
1056 *
else if (component == 2) { res = lambda_interpolant.value(p); }
1061 *
template class SolutionVectorFunction<Interpolant>;
1067<a name=
"ann-Solution.h"></a>
1068<h1>Annotated version of Solution.h</h1>
1087 * #include <deal.II/base/function.h>
1089 * #include
"LinearInterpolator.h"
1093 * #include <fstream>
1094 * #include <iostream>
1095 * #include <iomanip>
1098 *
namespace TravelingWave
1100 *
using namespace dealii;
1104 * The structure
for keeping the solution: arrays of coordinates @f$\xi@f$, solution @f$u@f$, @f$T@f$, @f$\lambda@f$, and the wave speed @f$c@f$.
1107 *
struct SolutionStruct
1110 * SolutionStruct(
const std::vector<double> &ix,
const std::vector<double> &iu,
1111 *
const std::vector<double> &iT,
const std::vector<double> &ilambda,
const double iwave_speed);
1112 * SolutionStruct(
const std::vector<double> &ix,
const std::vector<double> &iu,
1113 *
const std::vector<double> &iT,
const std::vector<double> &ilambda);
1115 *
void reinit(
const unsigned int number_of_elements);
1117 *
void save_to_file(std::string filename)
const;
1119 * std::vector<double> x;
1120 * std::vector<double> u;
1121 * std::vector<double> T;
1122 * std::vector<double>
lambda;
1124 *
double wave_speed;
1129 * Interpolation
class
1132 *
class Interpolant :
public Function<1>
1135 * Interpolant(
const std::vector<double> &ix_points,
const std::vector<double> &iy_points);
1136 *
virtual double value(
const Point<1> &p,
const unsigned int component = 0)
const override;
1139 * LinearInterpolator<double> interpolant;
1147 *
template <
typename InterpolantType>
1148 *
class SolutionVectorFunction :
public Function<1>
1151 * SolutionVectorFunction(InterpolantType iu_interpolant, InterpolantType iT_interpolant, InterpolantType ilambda_interpolant);
1152 *
virtual double value(
const Point<1> &p,
const unsigned int component = 0)
const override;
1155 * InterpolantType u_interpolant;
1156 * InterpolantType T_interpolant;
1157 * InterpolantType lambda_interpolant;
1166<a name=
"ann-TravelingWaveSolver.cc"></a>
1167<h1>Annotated version of TravelingWaveSolver.cc</h1>
1183 * #include
"TravelingWaveSolver.h"
1185 *
namespace TravelingWave
1187 *
using namespace dealii;
1191 * Constructor of the
class that takes parameters of the problem and an
initial guess for Newton's iterations.
1194 * TravelingWaveSolver::TravelingWaveSolver(
const Parameters ¶meters,
const SolutionStruct &initial_guess_input)
1195 * : params(parameters)
1196 * , problem(params.problem)
1197 * , number_of_quadrature_points((params.fe.quadrature_points_number > 0) ? params.fe.quadrature_points_number : (params.fe.poly_degree + 1))
1198 * , triangulation_uploaded(false)
1199 * , fe(
FE_Q<1>(params.fe.poly_degree), 1,
1200 *
FE_Q<1>(params.fe.poly_degree), 1,
1201 *
FE_Q<1>(params.fe.poly_degree), 1)
1203 * , current_wave_speed(0.)
1204 * , initial_guess(initial_guess_input)
1209 *
Table with
values of some parameters to be written to the standard output before calculations.
1213 * table.
add_value(
"Parameter name",
"number of quadrature points");
1214 * table.add_value(
"value", number_of_quadrature_points);
1216 * table.add_value(
"Parameter name",
"delta");
1217 * table.add_value(
"value", params.problem.delta);
1219 * table.add_value(
"Parameter name",
"epsilon");
1220 * table.add_value(
"value", params.problem.epsilon);
1222 * table.add_value(
"Parameter name",
"params.problem.wave_speed_init");
1223 * table.add_value(
"value", params.problem.wave_speed_init);
1225 * table.add_value(
"Parameter name",
"initial_guess.wave_speed");
1226 * table.add_value(
"value", initial_guess.wave_speed);
1228 * table.add_value(
"Parameter name",
"T_left");
1229 * table.add_value(
"value", params.problem.T_left);
1231 * table.set_precision(
"value", 2);
1232 * table.set_scientific(
"value",
true);
1234 * std::cout <<
"\n";
1236 * std::cout <<
"\n";
1244 *
void TravelingWaveSolver::set_triangulation(
const Triangulation<1> &itriangulation)
1248 * triangulation_uploaded =
true;
1253 * Here we find the indices of the degrees of freedom, associated with the boundary vertices, and the degree of freedom, associated with the vertex with coordinate @f$\xi = 0@f$, and corresponding to temperature.
1256 *
void TravelingWaveSolver::find_boundary_and_centering_dof_numbers()
1258 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1262 * if (isapprox(cell->vertex(v_ind)[0], params.mesh.interval_left))
1264 * boundary_and_centering_dof_numbers[
"u_left"] = cell->vertex_dof_index(v_ind, 0);
1265 * boundary_and_centering_dof_numbers[
"T_left"] = cell->vertex_dof_index(v_ind, 1);
1266 * boundary_and_centering_dof_numbers[
"lambda_left"] = cell->vertex_dof_index(v_ind, 2);
1268 *
else if (isapprox(cell->vertex(v_ind)[0], params.mesh.interval_right))
1270 * boundary_and_centering_dof_numbers[
"u_right"] = cell->vertex_dof_index(v_ind, 0);
1271 * boundary_and_centering_dof_numbers[
"T_right"] = cell->vertex_dof_index(v_ind, 1);
1272 * boundary_and_centering_dof_numbers[
"lambda_right"] = cell->vertex_dof_index(v_ind, 2);
1274 *
else if (isapprox(cell->vertex(v_ind)[0], 0.))
1276 * boundary_and_centering_dof_numbers[
"T_zero"] = cell->vertex_dof_index(v_ind, 1);
1284 * Set solution
values, corresponding to Dirichlet boundary conditions and the centering condition @f$T(0) = T_{\mathrm{ign}}@f$.
1287 *
void TravelingWaveSolver::set_boundary_and_centering_values()
1289 * current_solution[boundary_and_centering_dof_numbers[
"u_right"]] = problem.u_right;
1291 * current_solution[boundary_and_centering_dof_numbers[
"T_left"]] = problem.T_left;
1292 *
if (problem.T_r_bc_type == 1)
1294 * current_solution[boundary_and_centering_dof_numbers[
"T_right"]] = problem.T_right;
1296 * current_solution[boundary_and_centering_dof_numbers[
"T_zero"]] = problem.T_ign;
1298 * current_solution[boundary_and_centering_dof_numbers[
"lambda_right"]] = 0.;
1302 *
void TravelingWaveSolver::setup_system(
const bool initial_step)
1306 * dof_handler.distribute_dofs(fe);
1308 * std::cout <<
"Number of dofs : " << dof_handler.n_dofs() << std::endl;
1310 * extended_solution_dim = dof_handler.n_dofs() + 1;
1312 * find_boundary_and_centering_dof_numbers();
1316 * Boundary condition constraints
for @f$du@f$, @f$dT@f$ and @f$d\lambda@f$.
1319 * zero_boundary_constraints.clear();
1323 * Dirichlet homogeneous boundary condition
for @f$du@f$ at the right boundary.
1326 * zero_boundary_constraints.add_line(boundary_and_centering_dof_numbers[
"u_right"]);
1330 * Dirichlet homogeneous boundary condition
for @f$dT@f$ at the left boundary.
1333 * zero_boundary_constraints.add_line(boundary_and_centering_dof_numbers[
"T_left"]);
1336 * For the temperature at the left boundary there are two possibilities:
1339 *
if (problem.T_r_bc_type == 1)
1341 * std::cout <<
"Dirichlet condition for the temperature at the right boundary." << std::endl;
1342 * zero_boundary_constraints.add_line(boundary_and_centering_dof_numbers[
"T_right"]);
1346 * std::cout <<
"Neumann condition for the temperature at the right boundary." << std::endl;
1351 * Dirichlet homogeneous boundary condition
for @f$d\lambda@f$ at the right boundary. (At the left boundary we consider the homogeneous Neumann boundary condition
for @f$d\lambda@f$.)
1354 * zero_boundary_constraints.add_line(boundary_and_centering_dof_numbers[
"lambda_right"]);
1356 * zero_boundary_constraints.close();
1360 * We create extended
dynamic sparsity pattern with an additional row and an additional column.
1365 * std::vector<types::global_dof_index> dofs_on_this_cell;
1366 * dofs_on_this_cell.reserve(dof_handler.get_fe_collection().max_dofs_per_cell());
1368 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1370 * const unsigned
int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
1371 * dofs_on_this_cell.resize(dofs_per_cell);
1372 * cell->get_dof_indices(dofs_on_this_cell);
1374 * zero_boundary_constraints.add_entries_local_to_global(dofs_on_this_cell,
1381 * Adding elements to the last column.
1384 *
for (
unsigned int i = 0; i < extended_solution_dim; ++i)
1386 * dsp.add(i, extended_solution_dim - 1);
1390 * Adding one element to the last row, corresponding to the T(0).
1393 * dsp.add(extended_solution_dim - 1, boundary_and_centering_dof_numbers[
"T_zero"]);
1401 * sparsity_pattern_extended.copy_from(dsp);
1402 * jacobian_matrix_extended.reinit(sparsity_pattern_extended);
1403 * jacobian_matrix_extended_factorization.reset();
1405 * current_solution_extended.reinit(extended_solution_dim);
1409 * current_solution.reinit(dof_handler.n_dofs());
1415 *
void TravelingWaveSolver::set_initial_guess()
1417 * current_wave_speed = initial_guess.wave_speed;
1421 * The
initial condition is a discrete set of coordinates @f$\xi@f$ and
values of
functions @f$u@f$, @f$T@f$ and @f$\lambda@f$. From the three sets we create three continuous
functions using interpolation, which then form one continuous vector function of <code> SolutionVectorFunction </code> type.
1424 * Interpolant u_interpolant(initial_guess.x, initial_guess.u);
1425 * Interpolant T_interpolant(initial_guess.x, initial_guess.T);
1426 * Interpolant lambda_interpolant(initial_guess.x, initial_guess.lambda);
1428 * SolutionVectorFunction init_guess_func(u_interpolant, T_interpolant, lambda_interpolant);
1432 * set_boundary_and_centering_values();
1434 *
for (
unsigned int i = 0; i < extended_solution_dim - 1; ++i)
1436 * current_solution_extended(i) = current_solution(i);
1438 * current_solution_extended(extended_solution_dim - 1) = current_wave_speed;
1443 * Heaviside function.
1446 *
double TravelingWaveSolver::Heaviside_func(
double x)
const
1459 *
void TravelingWaveSolver::compute_and_factorize_jacobian(
const Vector<double> &evaluation_point_extended)
1465 *
for (
unsigned int i = 0; i < dof_handler.n_dofs(); ++i)
1467 * evaluation_point(i) = evaluation_point_extended(i);
1470 *
const double wave_speed = evaluation_point_extended(extended_solution_dim - 1);
1472 * std::cout <<
"Computing Jacobian matrix ... " << std::endl;
1474 *
const QGauss<1> quadrature_formula(number_of_quadrature_points);
1476 * jacobian_matrix_extended = 0;
1479 * quadrature_formula,
1483 *
const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
1484 *
const unsigned int n_q_points = quadrature_formula.size();
1489 * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1495 * std::vector<double> current_velocity_values(n_q_points);
1496 * std::vector<double> current_temperature_values(n_q_points);
1497 * std::vector<double> current_lambda_values(n_q_points);
1499 * std::vector<Tensor<1, 1>> current_velocity_gradients(n_q_points);
1500 * std::vector<Tensor<1, 1>> current_temperature_gradients(n_q_points);
1501 * std::vector<Tensor<1, 1>> current_lambda_gradients(n_q_points);
1503 * std::vector<double> phi_u(dofs_per_cell);
1504 * std::vector<Tensor<1, 1>> grad_phi_u(dofs_per_cell);
1505 * std::vector<double> phi_T(dofs_per_cell);
1506 * std::vector<Tensor<1, 1>> grad_phi_T(dofs_per_cell);
1507 * std::vector<double> phi_lambda(dofs_per_cell);
1508 * std::vector<Tensor<1, 1>> grad_phi_lambda(dofs_per_cell);
1510 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1513 * row_last_element_vector = 0;
1515 * fe_values.reinit(cell);
1517 * fe_values[velocity].get_function_values(evaluation_point, current_velocity_values);
1518 * fe_values[temperature].get_function_values(evaluation_point, current_temperature_values);
1519 * fe_values[
lambda].get_function_values(evaluation_point, current_lambda_values);
1521 * fe_values[velocity].get_function_gradients(evaluation_point, current_velocity_gradients);
1522 * fe_values[temperature].get_function_gradients(evaluation_point, current_temperature_gradients);
1523 * fe_values[
lambda].get_function_gradients(evaluation_point, current_lambda_gradients);
1525 *
auto kappa_1 = [=](
double T,
double lambda){
1526 *
return problem.k * (1 -
lambda) *
std::exp(-problem.theta / T) * (
1527 * problem.theta / (T * T) * Heaviside_func(T - problem.T_ign)
1531 *
auto kappa_2 = [=](
double T,
double ){
1532 *
return -problem.k *
std::exp(-problem.theta / T) * Heaviside_func(T - problem.T_ign);
1535 *
for (
unsigned int q = 0; q < n_q_points; ++q)
1537 *
for (
unsigned int k = 0; k < dofs_per_cell; ++k)
1539 * phi_u[k] = fe_values[velocity].value(k, q);
1540 * grad_phi_u[k] = fe_values[velocity].gradient(k, q);
1541 * phi_T[k] = fe_values[temperature].value(k, q);
1542 * grad_phi_T[k] = fe_values[temperature].gradient(k, q);
1543 * phi_lambda[k] = fe_values[
lambda].value(k, q);
1544 * grad_phi_lambda[k] = fe_values[
lambda].gradient(k, q);
1547 *
const double del_Pr_eps = (problem.Pr * 4 * problem.delta / (3 * problem.epsilon));
1548 *
const double del_Le = (problem.delta / problem.Le);
1550 *
for (
unsigned int i = 0; i < dofs_per_cell; ++i)
1552 *
for (
unsigned int j = 0; j < dofs_per_cell; ++j)
1556 * del_Pr_eps * (-grad_phi_u[i] * grad_phi_u[j])
1558 * - (1 - wave_speed + problem.epsilon * current_velocity_values[q]) * grad_phi_u[j][0]
1559 * - problem.epsilon * current_velocity_gradients[q][0] * phi_u[j]
1560 * - problem.epsilon / 2. * grad_phi_T[j][0]
1563 * + problem.delta * (-grad_phi_T[i] * grad_phi_T[j])
1565 * - wave_speed * grad_phi_u[j][0]
1566 * + wave_speed * grad_phi_T[j][0]
1567 * + problem.q * kappa_1(current_temperature_values[q], current_lambda_values[q]) * phi_T[j]
1568 * + problem.q * kappa_2(current_temperature_values[q], current_lambda_values[q]) * phi_lambda[j]
1571 * + del_Le * (-grad_phi_lambda[i] * grad_phi_lambda[j])
1572 * + phi_lambda[i] * (
1573 * kappa_1(current_temperature_values[q], current_lambda_values[q]) * phi_T[j]
1574 * + wave_speed * grad_phi_lambda[j][0]
1575 * + kappa_2(current_temperature_values[q], current_lambda_values[q]) * phi_lambda[j]
1578 * ) * fe_values.JxW(q);
1582 * row_last_element_vector(i) += (
1583 * (phi_u[i] * current_velocity_gradients[q][0])
1584 * + (phi_T[i] * current_temperature_gradients[q][0])
1585 * - (phi_T[i] * current_velocity_gradients[q][0])
1586 * + (phi_lambda[i] * current_lambda_gradients[q][0])
1587 * ) * fe_values.JxW(q);
1592 * cell->get_dof_indices(local_dof_indices);
1594 *
for (
const unsigned int i : fe_values.dof_indices())
1596 * for (const unsigned
int j : fe_values.dof_indices())
1598 * jacobian_matrix_extended.add(local_dof_indices[i],
1599 * local_dof_indices[j],
1605 * Adding elements to the last column.
1608 * jacobian_matrix_extended.add(local_dof_indices[i],
1609 * extended_solution_dim - 1,
1610 * row_last_element_vector(i));
1617 * Global dof indices of dofs
for @f$dT@f$ and @f$d\lambda@f$, associated with vertex @f$\xi = 0@f$.
1624 * Approximating the derivative of @f$T@f$ at @f$\xi = 0@f$ as done in @ref step_14
"step-14".
1627 *
double T_point_derivative(0.);
1628 *
double T_at_zero_point(0.);
1629 *
double lambda_at_zero_point(0.);
1631 *
double derivative_evaluation_point = 0.;
1635 * quadrature_formula,
1641 *
const unsigned int n_q_points = quadrature_formula.size();
1642 * std::vector<double> current_temperature_values(n_q_points);
1643 * std::vector<Tensor<1, 1>> current_temperature_gradients(n_q_points);
1644 * std::vector<double> current_lambda_values(n_q_points);
1646 *
unsigned int derivative_evaluation_point_hits = 0;
1648 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1652 * if (isapprox(cell->vertex(vertex)[0], derivative_evaluation_point))
1654 * T_zero_point_dof_ind = cell->vertex_dof_index(vertex, 1);
1655 * lambda_zero_point_dof_ind = cell->vertex_dof_index(vertex, 2);
1657 * fe_values.reinit(cell);
1658 * fe_values[temperature].get_function_values(current_solution, current_temperature_values);
1659 * fe_values[temperature].get_function_gradients(current_solution, current_temperature_gradients);
1660 * fe_values[
lambda].get_function_values(current_solution, current_lambda_values);
1662 *
unsigned int q_point = 0;
1663 *
for (; q_point < n_q_points; ++q_point)
1665 *
if (isapprox(fe_values.quadrature_point(q_point)[0], derivative_evaluation_point))
1671 * T_at_zero_point = current_temperature_values[q_point];
1672 * lambda_at_zero_point = current_lambda_values[q_point];
1674 * T_point_derivative += current_temperature_gradients[q_point][0];
1675 * ++derivative_evaluation_point_hits;
1681 * T_point_derivative /=
static_cast<double>(derivative_evaluation_point_hits);
1686 * Here we add to the
matrix the terms that appear after integrating the terms with the Dirac delta function (which we skipped inside the loop).
1689 *
double term_with_delta_func(0.);
1690 * term_with_delta_func = problem.k *
std::exp(-problem.theta / T_at_zero_point) * (1 - lambda_at_zero_point) /
std::abs(T_point_derivative);
1691 * jacobian_matrix_extended.add(T_zero_point_dof_ind, T_zero_point_dof_ind, problem.q * term_with_delta_func);
1692 * jacobian_matrix_extended.add(lambda_zero_point_dof_ind, T_zero_point_dof_ind, term_with_delta_func);
1696 * Add 1 to the position <code> T_zero_point_dof_ind </code> of the last row of the
matrix.
1699 * jacobian_matrix_extended.add(extended_solution_dim - 1, T_zero_point_dof_ind, 1.);
1701 * zero_boundary_constraints.condense(jacobian_matrix_extended);
1707 * std::cout <<
"Factorizing Jacobian matrix" << std::endl;
1709 * jacobian_matrix_extended_factorization = std::make_unique<SparseDirectUMFPACK>();
1710 * jacobian_matrix_extended_factorization->factorize(jacobian_matrix_extended);
1720 * std::cout <<
"Computing residual vector ... " << std::endl;
1725 *
for (
unsigned int i = 0; i < dof_handler.n_dofs(); ++i)
1727 * evaluation_point(i) = evaluation_point_extended(i);
1730 *
const double wave_speed = evaluation_point_extended(extended_solution_dim - 1);
1732 *
const QGauss<1> quadrature_formula(number_of_quadrature_points);
1734 * quadrature_formula,
1738 *
const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
1739 *
const unsigned int n_q_points = quadrature_formula.size();
1742 * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1748 * std::vector<double> current_velocity_values(n_q_points);
1749 * std::vector<Tensor<1, 1>> current_velocity_gradients(n_q_points);
1750 * std::vector<double> current_temperature_values(n_q_points);
1751 * std::vector<Tensor<1, 1>> current_temperature_gradients(n_q_points);
1752 * std::vector<double> current_lambda_values(n_q_points);
1753 * std::vector<Tensor<1, 1>> current_lambda_gradients(n_q_points);
1755 * std::vector<double> phi_u(dofs_per_cell);
1756 * std::vector<Tensor<1, 1>> grad_phi_u(dofs_per_cell);
1757 * std::vector<double> phi_T(dofs_per_cell);
1758 * std::vector<Tensor<1, 1>> grad_phi_T(dofs_per_cell);
1759 * std::vector<double> phi_lambda(dofs_per_cell);
1760 * std::vector<Tensor<1, 1>> grad_phi_lambda(dofs_per_cell);
1762 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1766 * fe_values.reinit(cell);
1768 * fe_values[velocity].get_function_values(evaluation_point, current_velocity_values);
1769 * fe_values[velocity].get_function_gradients(evaluation_point, current_velocity_gradients);
1770 * fe_values[temperature].get_function_values(evaluation_point, current_temperature_values);
1771 * fe_values[temperature].get_function_gradients(evaluation_point, current_temperature_gradients);
1772 * fe_values[
lambda].get_function_values(evaluation_point, current_lambda_values);
1773 * fe_values[
lambda].get_function_gradients(evaluation_point, current_lambda_gradients);
1775 *
auto omega = [=](
double T,
double lambda){
1776 *
return problem.k * (1 -
lambda) *
std::exp(-problem.theta / T) * Heaviside_func(T - problem.T_ign);
1779 *
for (
unsigned int q = 0; q < n_q_points; ++q)
1781 *
for (
unsigned int k = 0; k < dofs_per_cell; ++k)
1783 * phi_u[k] = fe_values[velocity].value(k, q);
1784 * grad_phi_u[k] = fe_values[velocity].gradient(k, q);
1785 * phi_T[k] = fe_values[temperature].value(k, q);
1786 * grad_phi_T[k] = fe_values[temperature].gradient(k, q);
1787 * phi_lambda[k] = fe_values[
lambda].value(k, q);
1788 * grad_phi_lambda[k] = fe_values[
lambda].gradient(k, q);
1791 *
double del_Pr_eps = (problem.Pr * 4 * problem.delta / (3 * problem.epsilon));
1792 *
double del_Le = (problem.delta / problem.Le);
1794 *
for (
unsigned int i = 0; i < dofs_per_cell; ++i)
1798 * del_Pr_eps * (-grad_phi_u[i] * current_velocity_gradients[q])
1800 * - current_velocity_gradients[q][0] * (1 - wave_speed + problem.epsilon * current_velocity_values[q])
1801 * - problem.epsilon / 2. * current_temperature_gradients[q][0]
1804 * + problem.delta * (-grad_phi_T[i] * current_temperature_gradients[q])
1806 * wave_speed * (current_temperature_gradients[q][0] - current_velocity_gradients[q][0])
1807 * + problem.q * omega(current_temperature_values[q], current_lambda_values[q])
1810 * + del_Le * (-grad_phi_lambda[i] * current_lambda_gradients[q])
1811 * + phi_lambda[i] * (
1812 * wave_speed * current_lambda_gradients[q][0] + omega(current_temperature_values[q], current_lambda_values[q])
1815 * ) * fe_values.JxW(q);
1820 * cell->get_dof_indices(local_dof_indices);
1822 *
for (
const unsigned int i : fe_values.dof_indices())
1828 * residual(extended_solution_dim - 1) = 0.;
1830 * zero_boundary_constraints.condense(residual);
1832 *
double residual_norm = residual.l2_norm();
1834 * std::cout << std::defaultfloat;
1835 * std::cout <<
"norm of residual = " << residual_norm << std::endl;
1837 *
return residual_norm;
1842 * Split the solution vector into two parts: one part is the solution @f$u@f$, @f$T@f$ and @f$\lambda@f$, and another part is the wave speed.
1845 *
void TravelingWaveSolver::split_extended_solution_vector()
1847 *
for (
unsigned int i = 0; i < extended_solution_dim - 1; ++i)
1849 * current_solution(i) = current_solution_extended(i);
1852 * current_wave_speed = current_solution_extended(extended_solution_dim - 1);
1860 * std::cout <<
"Solving linear system ... " << std::endl;
1862 * jacobian_matrix_extended_factorization->vmult(solution_extended, rhs);
1864 * zero_boundary_constraints.distribute(solution_extended);
1874 *
void TravelingWaveSolver::refine_mesh()
1885 * estimated_error_per_cell,
1886 * fe.component_mask(lambda)
1890 * estimated_error_per_cell,
1897 * solution_transfer.prepare_for_coarsening_and_refinement(current_solution);
1901 * setup_system(
false);
1904 * current_solution.reinit(dof_handler.n_dofs());
1905 * solution_transfer.interpolate(current_solution);
1908 * solution_transfer.interpolate(current_solution, tmp);
1909 * current_solution = std::move(tmp);
1912 * set_boundary_and_centering_values();
1914 *
for (
unsigned int i = 0; i < extended_solution_dim - 1; ++i)
1916 * current_solution_extended(i) = current_solution(i);
1918 * current_solution_extended(extended_solution_dim - 1) = current_wave_speed;
1923 *
double TravelingWaveSolver::run_newton_iterations(
const double target_tolerance)
1926 *
double residual_norm = 0.;
1929 * additional_data.function_tolerance = target_tolerance;
1934 * x.reinit(extended_solution_dim);
1938 * residual_norm = compute_residual(evaluation_point, residual);
1944 * compute_and_factorize_jacobian(evaluation_point);
1950 * this->solve(rhs, solution, tolerance);
1955 * nonlinear_solver.solve(current_solution_extended);
1958 *
return residual_norm;
1964 * Output the solution (@f$u@f$, @f$T@f$ and @f$\lambda@f$) and the wave speed into two separate files with
double precision. The files can be read by
gnuplot.
1967 *
void TravelingWaveSolver::output_with_double_precision(
const Vector<double> &solution,
const double wave_speed,
const std::string filename)
1971 *
const std::string file_for_solution = filename +
".txt";
1972 * std::ofstream output(file_for_solution);
1974 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1978 * double u = solution(cell->vertex_dof_index(v_ind, 0));
1979 *
double T = solution(cell->vertex_dof_index(v_ind, 1));
1980 *
double lambda = solution(cell->vertex_dof_index(v_ind, 2));
1982 * output << std::scientific << std::setprecision(16);
1983 * output << cell->vertex(v_ind)[0];
1985 * output << std::scientific << std::setprecision(16);
1986 * output << std::scientific <<
" " << u <<
" " << T <<
" " <<
lambda <<
"\n";
1993 * std::ofstream file_for_wave_speed_output(
"wave_speed-" + file_for_solution);
1994 * file_for_wave_speed_output << std::scientific << std::setprecision(16);
1995 * file_for_wave_speed_output << wave_speed << std::endl;
1996 * file_for_wave_speed_output.close();
2001 * Copy the solution into the <code> SolutionStruct </code> object, that stores the solution in an ordered manner.
2004 *
void TravelingWaveSolver::get_solution(SolutionStruct &solution)
const
2008 * To obtain an ordered solution array, we
first create a set consisting of the elements <code> {x, u, T,
lambda} </code> in which the sorting is done by coordinate, and then
copy the contents of the set into the arrays of the <code> SolutionStruct </code>
object.
2011 *
auto comp = [](
const std::vector<double> &a,
const std::vector<double> &
b) {
2012 *
return a[0] <
b[0];
2014 * std::set<std::vector<double>,
decltype(comp)> solution_set(comp);
2015 *
for (
const auto &cell : dof_handler.active_cell_iterators())
2019 * double x = cell->vertex(v_ind)[0];
2020 *
double u = current_solution(cell->vertex_dof_index(v_ind, 0));
2021 *
double T = current_solution(cell->vertex_dof_index(v_ind, 1));
2022 *
double lambda = current_solution(cell->vertex_dof_index(v_ind, 2));
2023 * solution_set.insert({x, u, T,
lambda});
2027 * solution.x.clear();
2028 * solution.u.clear();
2029 * solution.T.clear();
2030 * solution.lambda.clear();
2032 * solution.x.reserve(solution_set.size());
2033 * solution.u.reserve(solution_set.size());
2034 * solution.T.reserve(solution_set.size());
2035 * solution.lambda.reserve(solution_set.size());
2037 *
for (
auto it = solution_set.begin(); it != solution_set.end(); ++it)
2039 * solution.x.push_back((*it)[0]);
2040 * solution.u.push_back((*it)[1]);
2041 * solution.T.push_back((*it)[2]);
2042 * solution.lambda.push_back((*it)[3]);
2045 * solution.wave_speed = current_wave_speed;
2050 *
void TravelingWaveSolver::get_triangulation(
Triangulation<1> &otriangulation)
const
2052 * otriangulation.clear();
2057 *
void TravelingWaveSolver::run(
const std::string filename,
const bool save_solution_to_file)
2059 *
const int mesh_refinement_type = params.mesh.adaptive;
2060 *
const unsigned int n_refinements = params.mesh.refinements_number;
2061 *
const double tol = params.solver.tol;
2063 *
if (triangulation_uploaded ==
false)
2067 * We create two triangulations: one to the left and one to the right of zero coordinate. After that we
merge them to obtain one
triangulation, which contains zero
point.
2072 * triangulation_left,
2073 *
static_cast<unsigned int>(
std::abs( 0. - params.mesh.interval_left )),
2074 * params.mesh.interval_left, 0.
2079 * triangulation_right,
2080 *
static_cast<unsigned int>(
std::abs( params.mesh.interval_right - 0. )),
2081 * 0., params.mesh.interval_right
2088 *
if (triangulation_uploaded ==
false)
2090 *
if (mesh_refinement_type == 1)
2094 *
else if (mesh_refinement_type == 0)
2100 * setup_system(
true);
2101 * set_initial_guess();
2103 *
if (save_solution_to_file)
2105 * output_with_double_precision(current_solution, current_wave_speed,
"solution_initial_data");
2108 *
if (mesh_refinement_type == 1)
2110 *
double residual_norm = 0.;
2113 * residual_norm = compute_residual(current_solution_extended, tmp_residual);
2116 *
unsigned int refinement_cycle = 0;
2117 *
while ((residual_norm > tol) && (refinement_cycle < n_refinements))
2119 * computing_timer.reset();
2120 * std::cout <<
"Mesh refinement step " << refinement_cycle << std::endl;
2122 *
if (refinement_cycle != 0) { refine_mesh(); }
2124 *
const double target_tolerance = 0.1 *
std::pow(0.1, refinement_cycle);
2125 * std::cout <<
" Target_tolerance: " << target_tolerance << std::endl;
2127 * residual_norm = run_newton_iterations(target_tolerance);
2128 * split_extended_solution_vector();
2131 * std::cout << std::scientific << std::setprecision(16);
2132 * std::cout <<
"current_wave_speed = " << current_wave_speed << std::endl;
2133 * std::cout << std::defaultfloat;
2136 * computing_timer.print_summary();
2138 * ++refinement_cycle;
2140 *
if (save_solution_to_file)
2142 * output_with_double_precision(current_solution, current_wave_speed, filename);
2146 *
else if (mesh_refinement_type == 0)
2148 * run_newton_iterations(tol);
2149 * split_extended_solution_vector();
2151 *
if (save_solution_to_file)
2153 * output_with_double_precision(current_solution, current_wave_speed, filename);
2157 * std::cout << std::scientific << std::setprecision(16);
2158 * std::cout <<
"current_wave_speed = " << current_wave_speed << std::endl;
2159 * std::cout << std::defaultfloat;
2162 * computing_timer.print_summary();
2173<a name=
"ann-TravelingWaveSolver.h"></a>
2174<h1>Annotated version of TravelingWaveSolver.h</h1>
2190 * #ifndef TRAVELING_WAVE_SOLVER
2191 * #define TRAVELING_WAVE_SOLVER
2193 * #include <deal.II/base/timer.h>
2194 * #include <deal.II/base/function.h>
2195 * #include <deal.II/base/table_handler.h>
2196 * #include <deal.II/grid/tria.h>
2197 * #include <deal.II/grid/grid_generator.h>
2198 * #include <deal.II/grid/grid_refinement.h>
2199 * #include <deal.II/grid/grid_out.h>
2200 * #include <deal.II/dofs/dof_handler.h>
2201 * #include <deal.II/dofs/dof_tools.h>
2202 * #include <deal.II/fe/fe_q.h>
2203 * #include <deal.II/fe/fe_system.h>
2204 * #include <deal.II/fe/fe_values.h>
2205 * #include <deal.II/lac/vector.h>
2206 * #include <deal.II/lac/full_matrix.h>
2207 * #include <deal.II/lac/sparse_matrix.h>
2208 * #include <deal.II/lac/sparse_direct.h>
2209 * #include <deal.II/lac/dynamic_sparsity_pattern.h>
2210 * #include <deal.II/numerics/vector_tools.h>
2211 * #include <deal.II/numerics/error_estimator.h>
2212 * #include <deal.II/numerics/solution_transfer.h>
2213 * #include <deal.II/numerics/data_out.h>
2214 * #include <deal.II/sundials/kinsol.h>
2216 * #include
"Parameters.h"
2217 * #include
"Solution.h"
2218 * #include
"AuxiliaryFunctions.h"
2221 * #include <algorithm>
2223 * #include <fstream>
2224 * #include <iostream>
2225 * #include <iomanip>
2230 * Namespace of the program
2233 *
namespace TravelingWave
2235 *
using namespace dealii;
2239 * The main
class for construction of the traveling wave solutions.
2242 *
class TravelingWaveSolver
2245 * TravelingWaveSolver(
const Parameters ¶meters,
const SolutionStruct &initial_guess_input);
2249 *
void run(
const std::string filename=
"solution",
const bool save_solution_to_file=
true);
2250 *
void get_solution(SolutionStruct &solution)
const;
2254 *
void setup_system(
const bool initial_step);
2255 *
void find_boundary_and_centering_dof_numbers();
2256 *
void set_boundary_and_centering_values();
2258 *
void set_initial_guess();
2260 *
double Heaviside_func(
double x)
const;
2262 *
void compute_and_factorize_jacobian(
const Vector<double> &evaluation_point_extended);
2264 *
void split_extended_solution_vector();
2267 *
void refine_mesh();
2268 *
double run_newton_iterations(
const double target_tolerance=1e-5);
2270 *
void output_with_double_precision(
const Vector<double> &solution,
const double wave_speed,
const std::string filename=
"solution");
2274 * The dimension of the finite element solution increased by one to account
for the
value corresponding to the wave speed.
2277 *
unsigned int extended_solution_dim;
2278 * std::map<std::string, unsigned int> boundary_and_centering_dof_numbers;
2282 * Parameters of the problem, taken from a .prm file.
2285 *
const Parameters ¶ms;
2286 *
const Problem &problem;
2288 *
unsigned int number_of_quadrature_points;
2293 * The flag indicating whether the
triangulation was uploaded externally or created within the <code>
run </code> member function.
2296 *
bool triangulation_uploaded;
2302 * Constraints
for Dirichlet boundary conditions.
2309 * std::unique_ptr<SparseDirectUMFPACK> jacobian_matrix_extended_factorization;
2313 * Finite element solution of the problem.
2320 * Value of the wave speed @f$c@f$.
2323 *
double current_wave_speed;
2327 * Solution with an additional term, corresponding to the variable wave_speed.
2334 * Initial guess
for Newton
's iterations.
2337 * SolutionStruct initial_guess;
2339 * TimerOutput computing_timer;
2342 * } // namespace TravelingWave
2348<a name="ann-calculate_profile.cc"></a>
2349<h1>Annotated version of calculate_profile.cc</h1>
2355 * /* -----------------------------------------------------------------------------
2357 * * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
2358 * * Copyright (C) 2024 by Shamil Magomedov
2360 * * This file is part of the deal.II code gallery.
2362 * * -----------------------------------------------------------------------------
2365 * #include "TravelingWaveSolver.h"
2366 * #include "calculate_profile.h"
2368 * namespace TravelingWave
2370 * using namespace dealii;
2374 * Computation of the limit case (ideal) solution, corresponding to @f$\delta = 0@f$, by solving the ODE. The output is the part of the solution to the left of zero. Here u_0, T_0, lambda_0 are the values of the medium state to the right of zero.
2377 * void compute_limit_sol_left_part(const Parameters ¶meters,
2378 * const double wave_speed,
2381 * const double lambda_0,
2382 * SolutionStruct &LimitSol,
2383 * const double root_sign)
2385 * LimitSolution limit_sol(parameters, lambda_0, u_0, T_0, root_sign);
2386 * limit_sol.set_wave_speed(wave_speed);
2391 * We take more integration points to better resolve the transition layer.
2394 * std::vector<double> t_span(static_cast<unsigned int>(std::abs( 0. - parameters.mesh.interval_left )));
2395 * double finer_mesh_starting_value = -9.1;
2396 * linspace(parameters.mesh.interval_left, finer_mesh_starting_value, t_span);
2397 * std::vector<double> fine_grid(10000);
2398 * linspace(finer_mesh_starting_value + 1e-4, 0., fine_grid);
2399 * t_span.insert(t_span.end(), fine_grid.begin(), fine_grid.end());
2403 * Reverse the order of the elements (because we need to perform back in time integration).
2406 * std::reverse(t_span.begin(), t_span.end());
2408 * state_type lambda_val(1);
2409 * lambda_val[0] = lambda_0; // initial value
2410 * IntegrateSystemAtTimePoints(limit_sol.lambda_vec, limit_sol.t_vec, t_span,
2413 * -1e-2, Integrator_Type::dopri5);
2416 * limit_sol.calculate_u_T_omega();
2420 * Reverse the order of elements
2423 * std::reverse(limit_sol.t_vec.begin(), limit_sol.t_vec.end());
2424 * std::reverse(limit_sol.lambda_vec.begin(), limit_sol.lambda_vec.end());
2425 * std::reverse(limit_sol.u_vec.begin(), limit_sol.u_vec.end());
2426 * std::reverse(limit_sol.T_vec.begin(), limit_sol.T_vec.end());
2427 * std::reverse(limit_sol.omega_vec.begin(), limit_sol.omega_vec.end());
2429 * SaveSolutionIntoFile(limit_sol.lambda_vec, limit_sol.t_vec, "solution_lambda_limit.txt");
2430 * SaveSolutionIntoFile(limit_sol.u_vec, limit_sol.t_vec, "solution_u_limit.txt");
2431 * SaveSolutionIntoFile(limit_sol.T_vec, limit_sol.t_vec, "solution_T_limit.txt");
2432 * SaveSolutionIntoFile(limit_sol.omega_vec, limit_sol.t_vec, "solution_omega_limit.txt");
2434 * LimitSol.reinit(limit_sol.t_vec.size());
2435 * LimitSol.wave_speed = wave_speed;
2436 * for (unsigned int i=0; i < limit_sol.t_vec.size(); ++i)
2438 * LimitSol.x[i] = limit_sol.t_vec[i];
2439 * LimitSol.u[i] = limit_sol.u_vec[i][0];
2440 * LimitSol.T[i] = limit_sol.T_vec[i][0];
2441 * LimitSol.lambda[i] = limit_sol.lambda_vec[i][0];
2448 * Construction of an initial guess for detonation wave solution. The ODE is solved for the ideal system with @f$\delta = 0@f$.
2451 * void compute_initial_guess_detonation(const Parameters ¶ms, SolutionStruct &initial_guess, const double root_sign)
2453 * const Problem &problem = params.problem;
2454 * double current_wave_speed(problem.wave_speed_init);
2456 * { // Here we compute the exact value of the wave speed c for the detonation case. We can do this because we have the Dirichlet boundary conditions T_l, T_r and u_r. Exact values of u_l and c are obtained using the integral relations.
2457 * double DeltaT = problem.T_left - problem.T_right;
2458 * double qDT = problem.q - DeltaT;
2459 * current_wave_speed = 1. + problem.epsilon * (problem.u_right - (qDT * qDT + DeltaT) / (2 * qDT));
2462 * double u_0 = problem.u_right;
2463 * double T_0 = problem.T_right;
2464 * double lambda_0 = 0.;
2466 * compute_limit_sol_left_part(params, current_wave_speed, u_0, T_0, lambda_0, initial_guess, root_sign);
2468 * initial_guess.wave_speed = current_wave_speed;
2470 * for (int i = initial_guess.x.size() - 1; i > - 1; --i)
2472 * if (isapprox(initial_guess.x[i], 0.))
2474 * initial_guess.u[i] = problem.u_right;
2475 * initial_guess.T[i] = problem.T_ign;
2476 * initial_guess.lambda[i] = 0.;
2483 * Adding the points to the right part of the interval (w.r.t. @f$\xi = 0@f$).
2486 * unsigned int number_of_additional_points = 5;
2487 * for (unsigned int i = 0; i < number_of_additional_points; ++i)
2489 * initial_guess.x.push_back(params.mesh.interval_right / (std::pow(2., number_of_additional_points - 1 - i)));
2490 * initial_guess.u.push_back(problem.u_right);
2491 * initial_guess.T.push_back(problem.T_right);
2492 * initial_guess.lambda.push_back(0.);
2500 * Construction of a piecewise constant initial guess for deflagration wave solution.
2503 * void compute_initial_guess_deflagration(const Parameters ¶ms, SolutionStruct &initial_guess)
2505 * const Problem &problem = params.problem;
2506 * double current_wave_speed(problem.wave_speed_init);
2508 * double del_Pr_eps = (problem.Pr * 4 * problem.delta / (3 * problem.epsilon));
2509 * double del_Le = (problem.delta / problem.Le);
2511 * auto u_init_guess_func = [&](double x) {
2514 * return problem.u_left;
2518 * return problem.u_right;
2522 * auto T_init_guess_func = [&](double x) {
2525 * return problem.T_left;
2527 * else if (isapprox(x, 0.))
2529 * return problem.T_ign;
2533 * return problem.T_right;
2537 * auto lambda_init_guess_func = [=](double x) {
2540 * return -std::exp(x * std::abs(1 - current_wave_speed) / del_Pr_eps) + 1;
2548 * unsigned int multiplier_for_number_of_points = 7;
2549 * unsigned int number_of_points = multiplier_for_number_of_points * static_cast<unsigned int>(std::trunc(std::abs( params.mesh.interval_right - params.mesh.interval_left )));
2550 * std::vector<double> x_span(number_of_points);
2551 * linspace(params.mesh.interval_left, params.mesh.interval_right, x_span);
2553 * std::vector<double> u_init_arr(number_of_points);
2554 * std::vector<double> T_init_arr(number_of_points);
2555 * std::vector<double> lambda_init_arr(number_of_points);
2557 * for (unsigned int i = 0; i < number_of_points; ++i)
2559 * u_init_arr[i] = u_init_guess_func(x_span[i]);
2560 * T_init_arr[i] = T_init_guess_func(x_span[i]);
2561 * lambda_init_arr[i] = lambda_init_guess_func(x_span[i]);
2564 * initial_guess.x = x_span;
2565 * initial_guess.u = u_init_arr;
2566 * initial_guess.T = T_init_arr;
2567 * initial_guess.lambda = lambda_init_arr;
2568 * initial_guess.wave_speed = current_wave_speed;
2575 * Compute the traveling-wave profile. The continuation method can be switched on by setting the argument <code> continuation_for_delta </code> as <code> true </code>.
2578 * void calculate_profile(Parameters& parameters,
2579 * const bool continuation_for_delta /* Compute with the continuation. */,
2580 * const double delta_start /* The starting value of delta for the continuation method. */,
2581 * const unsigned int number_of_continuation_points)
2583 * SolutionStruct sol;
2585 * if (parameters.problem.wave_type == 1) // detonation wave
2587 * compute_initial_guess_detonation(parameters, sol);
2589 * else if (parameters.problem.wave_type == 0) // deflagration wave
2591 * compute_initial_guess_deflagration(parameters, sol);
2594 * if (continuation_for_delta == false)
2596 * TravelingWaveSolver wave(parameters, sol);
2597 * std::string filename = "solution_delta-" + Utilities::to_string(parameters.problem.delta) + "_eps-"
2598 * + Utilities::to_string(parameters.problem.epsilon);
2599 * wave.run(filename);
2600 * wave.get_solution(sol);
2602 * else // Run with continuation_for_delta.
2604 * double delta_target = parameters.problem.delta;
2605 * parameters.problem.delta = delta_start;
2607 * std::vector<double> delta_span(number_of_continuation_points);
2611 * Generate a sequence of delta values being uniformly distributed in log10 scale.
2615 * double delta_start_log10 = std::log10(delta_start);
2616 * double delta_target_log10 = std::log10(delta_target);
2618 * std::vector<double> delta_log_span(delta_span.size());
2619 * linspace(delta_start_log10, delta_target_log10, delta_log_span);
2621 * for (unsigned int i = 0; i < delta_span.size(); ++i)
2623 * delta_span[i] = std::pow(10, delta_log_span[i]);
2627 * Triangulation<1> refined_triangulation;
2628 * bool first_iter_flag = true;
2630 * for (double delta : delta_span)
2632 * parameters.problem.delta = delta;
2633 * std::string filename = "solution_delta-" + Utilities::to_string(parameters.problem.delta) + "_eps-"
2634 * + Utilities::to_string(parameters.problem.epsilon);
2636 * TravelingWaveSolver wave(parameters, sol);
2638 * if (first_iter_flag)
2640 * first_iter_flag = false;
2644 * wave.set_triangulation(refined_triangulation);
2647 * wave.run(filename);
2648 * wave.get_solution(sol);
2649 * wave.get_triangulation(refined_triangulation);
2660 * unsigned int sol_length = sol.x.size();
2661 * double u_r = sol.u[sol_length-1]; // Dirichlet boundary condition
2662 * double T_r = sol.T[sol_length-1]; // Dirichlet condition only for detonation case
2663 * double u_l = sol.u[0];
2664 * double T_l = sol.T[0]; // Dirichlet boundary condition
2665 * double wave_speed = sol.wave_speed;
2667 * std::cout << "Error estimates:" << std::endl;
2668 * double DeltaT = T_l - T_r;
2669 * double qDT = parameters.problem.q - DeltaT;
2671 * double wave_speed_formula = 1. + parameters.problem.epsilon * (u_r - (qDT * qDT + DeltaT) / (2 * qDT));
2672 * std::cout << std::setw(18) << std::left << "For wave speed" << " : " << std::setw(5) << wave_speed - wave_speed_formula << std::endl;
2674 * double u_l_formula = DeltaT + u_r - parameters.problem.q;
2675 * std::cout << std::setw(18) << std::left << "For u_l" << " : " << std::setw(5) << u_l - u_l_formula << std::endl;
2680 * } // namespace TravelingWave
2684<a name="ann-calculate_profile.h"></a>
2685<h1>Annotated version of calculate_profile.h</h1>
2691 * /* -----------------------------------------------------------------------------
2693 * * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
2694 * * Copyright (C) 2024 by Shamil Magomedov
2696 * * This file is part of the deal.II code gallery.
2698 * * -----------------------------------------------------------------------------
2701 * #ifndef CALCULATE_PROFILE
2702 * #define CALCULATE_PROFILE
2704 * #include "Parameters.h"
2705 * #include "Solution.h"
2706 * #include "LimitSolution.h"
2707 * #include "IntegrateSystem.h"
2708 * #include "AuxiliaryFunctions.h"
2710 * namespace TravelingWave
2712 * void compute_limit_sol_left_part(const Parameters ¶meters,
2713 * const double wave_speed,
2716 * const double lambda_0,
2717 * SolutionStruct &LimitSol,
2718 * const double root_sign = 1.);
2720 * void compute_initial_guess_detonation(const Parameters ¶ms, SolutionStruct &initial_guess, const double root_sign = 1.);
2721 * void compute_initial_guess_deflagration(const Parameters ¶ms, SolutionStruct &initial_guess);
2723 * void calculate_profile(Parameters& parameters,
2724 * const bool continuation_for_delta=false /* Compute with the continuation. */,
2725 * const double delta_start=0.01 /* The starting value of delta for the continuation method. */,
2726 * const unsigned int number_of_continuation_points=10);
2728 * } // namespace TravelingWave
2734<a name="ann-main.cc"></a>
2735<h1>Annotated version of main.cc</h1>
2741 * /* -----------------------------------------------------------------------------
2743 * * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
2744 * * Copyright (C) 2024 by Shamil Magomedov
2746 * * This file is part of the deal.II code gallery.
2748 * * -----------------------------------------------------------------------------
2751 * #include "calculate_profile.h"
2753 * int main(int argc, char *argv[])
2758 * using namespace TravelingWave;
2760 * Parameters parameters;
2762 * std::string prm_filename = "ParametersList.prm";
2767 * Check if file argv[1] exists.
2770 * if (file_exists(argv[1]))
2772 * prm_filename = argv[1];
2776 * std::string errorMessage = "File \"" + std::string(argv[1]) + "\" is not found.";
2777 * throw std::runtime_error(errorMessage);
2784 * Check if the file "ParametersList.prm" exists in the current or in the parent directory.
2787 * if (!(file_exists(prm_filename) || file_exists("../" + prm_filename)))
2789 * std::string errorMessage = "File \"" + prm_filename + "\" is not found.";
2790 * throw std::runtime_error(errorMessage);
2794 * if (!file_exists(prm_filename))
2796 * prm_filename = "../" + prm_filename;
2801 * std::cout << "Reading parameters... " << std::flush;
2802 * ParameterAcceptor::initialize(prm_filename);
2803 * std::cout << "done" << std::endl;
2805 * calculate_profile(parameters, /* With continuation_for_delta */ false, 0.1, 3);
2808 * catch (std::exception &exc)
2810 * std::cerr << std::endl
2812 * << "----------------------------------------------------"
2814 * std::cerr << "Exception on processing: " << std::endl
2815 * << exc.what() << std::endl
2816 * << "Aborting!" << std::endl
2817 * << "----------------------------------------------------"
2823 * std::cerr << std::endl
2825 * << "----------------------------------------------------"
2827 * std::cerr << "Unknown exception!" << std::endl
2828 * << "Aborting!" << std::endl
2829 * << "----------------------------------------------------"
2839<a name="ann-plot.py"></a>
2840<h1>Annotated version of plot.py</h1>
2842## -----------------------------------------------------------------------------
2844## SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
2845## Copyright (C) 2024 by Shamil Magomedov
2847## This file is part of the deal.II code gallery.
2849## -----------------------------------------------------------------------------
2853import matplotlib.pyplot as plt
2859 # 'lines.marker
' : 'x
',
2861 'lines.markersize
' : 4,
2862 'lines.linewidth
' : 1,
2863 'axes.labelsize
': 16,
2864 # 'textfontsize
': 12,
2866 'legend.fontsize
': 16,
2867 'xtick.labelsize
': 14,
2868 'ytick.labelsize
': 14,
2869 'text.usetex
': True,
2870 'figure.figsize
': [9,6],
2874plt.rcParams.update(plot_params)
2877if len(sys.argv) > 1:
2879 filename = sys.argv[1]
2881 if os.path.exists(filename):
2882 data = np.loadtxt(filename, np.float64)
2883 data_unique = np.unique(data, axis=0)
2884 data_unique = np.array(sorted(data_unique, key=lambda x : x[0]))
2885 x = data_unique[:, 0]
2886 u_sol = data_unique[:, 1]
2887 T_sol = data_unique[:, 2]
2888 lambda_sol = data_unique[:, 3]
2890 fig, ax = plt.subplots(nrows=1, ncols=1)
2892 ax.scatter(x, u_sol, label=r"@f$u@f$", color='blue
')
2893 ax.scatter(x, T_sol, label=r"@f$T@f$", color='red
')
2894 ax.scatter(x, lambda_sol, label=r"@f$\lambda@f$", color='green
')
2897 # Plot of limit solutions for the detonation case. Uncomment, if needed.
2898 #===============================================================#
2901 path_to_solution_files = os.path.split(filename)[0]
2902 u_limit_path = os.path.join(path_to_solution_files,
'solution_u_limit.txt')
2903 T_limit_path = os.path.join(path_to_solution_files,
'solution_T_limit.txt')
2904 lambda_limit_path = os.path.join(path_to_solution_files,
'solution_lambda_limit.txt')
2906 if os.path.exists(u_limit_path):
2907 u_limit = np.loadtxt(u_limit_path, np.float64)
2908 ax.plot(u_limit[:, 0], u_limit[:, 1], label=r
"@f$u_{\mathrm{lim}}@f$", color=
'blue')
2909 ax.plot([0, x[-1]], [u_sol[-1], u_sol[-1]], color=
'blue')
2911 print(
"No such file:", u_limit_path)
2913 if os.path.exists(T_limit_path):
2914 T_limit = np.loadtxt(T_limit_path, np.float64)
2915 ax.plot(T_limit[:, 0], T_limit[:, 1], label=r
"@f$T_{\mathrm{lim}}@f$", color=
'red')
2916 ax.plot([0, x[-1]], [T_sol[-1], T_sol[-1]], color=
'red')
2918 print(
"No such file:", T_limit_path)
2920 if os.path.exists(lambda_limit_path):
2921 lambda_limit = np.loadtxt(lambda_limit_path, np.float64)
2922 ax.plot(lambda_limit[:, 0], lambda_limit[:, 1], label=r
"@f$\lambda_{\mathrm{lim}}@f$", color=
'green')
2923 ax.plot([0, x[-1]], [lambda_sol[-1], lambda_sol[-1]], color=
'green')
2925 print(
"No such file:", lambda_limit_path)
2929 #===============================================================#
2932 ax.set_xlabel(r"@f$\xi@f$")
2933 ax.set_ylabel(r"@f$u, T, \lambda@f$")
2936 # plt.savefig("fast_deflagration_delta_0.01.png", bbox_inches='tight
', dpi=500)
2937 # plt.savefig('slow_deflagration_delta_0.01.png
', bbox_inches='tight
', dpi=500)
2938 # plt.savefig('detonation_delta_0.01.png
', bbox_inches='tight
', dpi=500)
2942 print("No such file:", filename)
virtual RangeNumberType value(const Point< dim > &p, const unsigned int component=0) const
static void estimate(const Mapping< dim, spacedim > &mapping, const DoFHandler< dim, spacedim > &dof, const Quadrature< dim - 1 > &quadrature, const std::map< types::boundary_id, const Function< spacedim, Number > * > &neumann_bc, const ReadVector< Number > &solution, Vector< float > &error, const ComponentMask &component_mask={}, const Function< spacedim > *coefficients=nullptr, const unsigned int n_threads=numbers::invalid_unsigned_int, const types::subdomain_id subdomain_id=numbers::invalid_subdomain_id, const types::material_id material_id=numbers::invalid_material_id, const Strategy strategy=cell_diameter_over_24)
void add_value(const std::string &key, const T value)
#define DEAL_II_VERSION_GTE(major, minor, subminor)
@ update_values
Shape function values.
@ update_JxW_values
Transformed quadrature weights.
@ update_gradients
Shape function gradients.
@ update_quadrature_points
Transformed quadrature points.
void subdivided_hyper_cube(Triangulation< dim, spacedim > &tria, const unsigned int repetitions, const double left=0., const double right=1., const bool colorize=false)
void merge_triangulations(const Triangulation< dim, spacedim > &triangulation_1, const Triangulation< dim, spacedim > &triangulation_2, Triangulation< dim, spacedim > &result, const double duplicated_vertex_tolerance=1.0e-12, const bool copy_manifold_ids=false, const bool copy_boundary_ids=false)
void refine_and_coarsen_fixed_number(Triangulation< dim, spacedim > &triangulation, const Vector< Number > &criteria, const double top_fraction_of_cells, const double bottom_fraction_of_cells, const unsigned int max_n_cells=std::numeric_limits< unsigned int >::max())
@ matrix
Contents is actually a matrix.
void cell_matrix(FullMatrix< double > &M, const FEValuesBase< dim > &fe, const FEValuesBase< dim > &fetest, const ArrayView< const std::vector< double > > &velocity, const double factor=1.)
void cell_residual(Vector< double > &result, const FEValuesBase< dim > &fe, const std::vector< Tensor< 1, dim > > &input, const ArrayView< const std::vector< double > > &velocity, double factor=1.)
Point< spacedim > point(const gp_Pnt &p, const double tolerance=1e-10)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
SymmetricTensor< 2, dim, Number > epsilon(const Tensor< 2, dim, Number > &Grad_u)
T scatter(const MPI_Comm comm, const std::vector< T > &objects_to_send, const unsigned int root_process=0)
void run(const Iterator &begin, const std_cxx20::type_identity_t< Iterator > &end, Worker worker, Copier copier, const ScratchData &sample_scratch_data, const CopyData &sample_copy_data, const unsigned int queue_length, const unsigned int chunk_size)
DEAL_II_HOST constexpr TableIndices< 2 > merge(const TableIndices< 2 > &previous_indices, const unsigned int new_index, const unsigned int position)
void copy(const T *begin, const T *end, U *dest)
int(&) functions(const void *v1, const void *v2)
void reinit(MatrixBlock< MatrixType > &v, const BlockSparsityPattern &p)
::VectorizedArray< Number, width > exp(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
::VectorizedArray< Number, width > pow(const ::VectorizedArray< Number, width > &, const Number p)
::VectorizedArray< Number, width > abs(const ::VectorizedArray< Number, width > &)
const ::parallel::distributed::Triangulation< dim, spacedim > * triangulation