375 * #ifndef AUXILIARY_FUNCTIONS
376 * #define AUXILIARY_FUNCTIONS
386 * Comparison of
numbers with a given tolerance.
389 *
template <
typename T>
390 *
bool isapprox(
const T &a,
const T &b,
const double tol = 1e-10)
397 * Fill the std::vector with the values from the range [interval_begin, interval_end].
400 *
template <
typename T>
401 *
void linspace(T interval_begin, T interval_end, std::vector<T> &arr)
403 *
const size_t SIZE = arr.size();
404 *
const T step = (interval_end - interval_begin) /
static_cast<T
>(SIZE - 1);
405 *
for (
size_t i = 0; i < SIZE; ++i)
407 * arr[i] = interval_begin + i * step;
413 * Check the file existence.
416 *
inline bool file_exists(
const std::string &filename)
418 * std::ifstream f(filename.c_str());
426<a name=
"ann-IntegrateSystem.h"></a>
427<h1>Annotated version of IntegrateSystem.h</h1>
443 * #ifndef INTEGRATE_SYSTEM
444 * #define INTEGRATE_SYSTEM
446 * #include <
boost/numeric/odeint.hpp>
448 * #include <iostream>
452 *
template <
typename state_T,
typename time_T>
453 *
void SaveSolutionIntoFile(
const std::vector<state_T>& x_vec,
const std::vector<time_T>& t_vec, std::string filename=
"output_ode_sol.txt")
455 *
if (!x_vec.empty() && !t_vec.empty())
457 * std::ofstream output(filename);
458 * output << std::setprecision(16);
460 *
size_t dim = x_vec[0].size();
461 *
for (
size_t i = 0; i < t_vec.size(); ++i)
463 * output << std::fixed << t_vec[i];
464 *
for (
size_t j = 0; j < dim; ++j)
466 * output << std::scientific <<
" " << x_vec[i][j];
474 * std::cout <<
"Solution is not saved into file.\n";
480 * type of RK integrator
483 *
enum class Integrator_Type
495 *
template <
typename state_type>
496 *
class Push_back_state_time
499 * std::vector<state_type>& m_states;
500 * std::vector<double>& m_times;
502 * Push_back_state_time(std::vector<state_type>& states, std::vector<double>& times)
503 * : m_states(states), m_times(times)
506 *
void operator() (
const state_type& x,
double t)
508 * m_states.push_back(x);
509 * m_times.push_back(t);
516 * Integrate system at specified points.
519 *
template <
typename ODE_obj_T,
typename state_type,
typename Iterable_type>
520 *
void IntegrateSystemAtTimePoints(
521 * std::vector<state_type>& x_vec, std::vector<double>& t_vec,
const Iterable_type& iterable_time_span,
522 *
const ODE_obj_T& ode_system_obj,
523 * state_type& x,
const double dt,
524 * Integrator_Type integrator_type=Integrator_Type::dopri5,
bool save_to_file_flag=
false,
525 *
const double abs_er_tol=1.0e-15,
const double rel_er_tol=1.0e-15
528 *
using namespace boost::numeric::odeint;
530 *
if (integrator_type == Integrator_Type::dopri5)
532 *
typedef runge_kutta_dopri5< state_type > error_stepper_type;
533 * integrate_times( make_controlled< error_stepper_type >(abs_er_tol, rel_er_tol),
534 * ode_system_obj, x, iterable_time_span.begin(), iterable_time_span.end(), dt, Push_back_state_time< state_type >(x_vec, t_vec) );
536 *
else if (integrator_type == Integrator_Type::cash_karp54)
538 *
typedef runge_kutta_cash_karp54< state_type > error_stepper_type;
539 * integrate_times( make_controlled< error_stepper_type >(abs_er_tol, rel_er_tol),
540 * ode_system_obj, x, iterable_time_span.begin(), iterable_time_span.end(), dt, Push_back_state_time< state_type >(x_vec, t_vec) );
544 *
typedef runge_kutta_fehlberg78< state_type > error_stepper_type;
545 * integrate_times( make_controlled< error_stepper_type >(abs_er_tol, rel_er_tol),
546 * ode_system_obj, x, iterable_time_span.begin(), iterable_time_span.end(), dt, Push_back_state_time< state_type >(x_vec, t_vec) );
549 *
if (save_to_file_flag)
551 * SaveSolutionIntoFile(x_vec, t_vec);
560<a name=
"ann-LimitSolution.cc"></a>
561<h1>Annotated version of LimitSolution.cc</h1>
577 * #include
"LimitSolution.h"
579 *
namespace TravelingWave
582 * LimitSolution::LimitSolution(
const Parameters ¶meters,
const double ilambda_0,
const double iu_0,
const double iT_0,
const double iroot_sign)
583 * : params(parameters)
584 * , problem(params.problem)
585 * , wave_speed(problem.wave_speed_init)
586 * , lambda_0(ilambda_0)
589 * , root_sign(iroot_sign)
591 * calculate_constants_A_B();
594 *
double LimitSolution::omega_func(
const double lambda,
const double T)
const
596 *
return problem.k * (1. -
lambda) *
std::exp(-problem.theta / T);
599 *
void LimitSolution::operator() (
const state_type &x , state_type &dxdt ,
const double )
601 * dxdt[0] = -1. / wave_speed * omega_func(x[0], T_func(x[0]));
604 *
double LimitSolution::u_func(
const double lambda)
const
606 *
double coef = 2 * (wave_speed - 1) / problem.epsilon - 1;
607 *
return (coef + root_sign *
std::sqrt(coef * coef - 4 * (problem.q * lambda + B - 2 * A / problem.epsilon))) / 2;
610 *
double LimitSolution::T_func(
const double lambda)
const
612 *
return u_func(lambda) + problem.q *
lambda + B;
615 *
void LimitSolution::calculate_constants_A_B()
618 * A = u_0 * (1 - wave_speed) + problem.epsilon * (u_0 * u_0 + T_0) / 2;
621 *
void LimitSolution::set_wave_speed(
double iwave_speed)
623 * wave_speed = iwave_speed;
624 * calculate_constants_A_B();
627 *
void LimitSolution::calculate_u_T_omega()
629 *
if (!t_vec.empty() && !lambda_vec.empty())
631 * u_vec.resize(lambda_vec.size());
632 * T_vec.resize(lambda_vec.size());
633 * omega_vec.resize(lambda_vec.size());
634 *
for (
unsigned int i = 0; i < lambda_vec.size(); ++i)
636 * u_vec[i].resize(1);
637 * T_vec[i].resize(1);
638 * omega_vec[i].resize(1);
640 * u_vec[i][0] = u_func(lambda_vec[i][0]);
641 * T_vec[i][0] = T_func(lambda_vec[i][0]);
642 * omega_vec[i][0] = omega_func(lambda_vec[i][0], T_vec[i][0]);
647 * std::cout <<
"t_vec or lambda_vec vector is empty!" << std::endl;
655<a name=
"ann-LimitSolution.h"></a>
656<h1>Annotated version of LimitSolution.h</h1>
672 * #ifndef LIMIT_SOLUTION
673 * #define LIMIT_SOLUTION
675 * #include
"Parameters.h"
676 * #include <iostream>
679 *
namespace TravelingWave
681 *
typedef std::vector< double > state_type;
683 *
class LimitSolution
686 * LimitSolution(
const Parameters ¶meters,
const double ilambda_0,
const double iu_0,
const double iT_0,
const double root_sign = 1.);
688 *
void operator() (
const state_type &x , state_type &dxdt ,
const double );
689 *
void calculate_u_T_omega();
690 *
void set_wave_speed(
double iwave_speed);
692 * std::vector<double> t_vec;
693 * std::vector<state_type> omega_vec;
694 * std::vector<state_type> lambda_vec;
695 * std::vector<state_type> u_vec;
696 * std::vector<state_type> T_vec;
699 *
double omega_func(
const double lambda,
const double T)
const;
700 *
double u_func(
const double lambda)
const;
701 *
double T_func(
const double lambda)
const;
703 *
void calculate_constants_A_B();
705 *
const Parameters ¶ms;
706 *
const Problem &problem;
709 *
const double lambda_0, u_0, T_0;
712 *
const double root_sign;
722<a name=
"ann-LinearInterpolator.h"></a>
723<h1>Annotated version of LinearInterpolator.h</h1>
739 * #ifndef LINEAR_INTERPOLATOR
740 * #define LINEAR_INTERPOLATOR
743 * #include <algorithm>
748 * Linear interpolation
class
751 *
template <
typename Number_Type>
752 *
class LinearInterpolator
755 * LinearInterpolator(
const std::vector<Number_Type> &ix_points,
const std::vector<Number_Type> &iy_points);
756 * Number_Type
value(
const Number_Type x)
const;
759 *
const std::vector<Number_Type> x_points;
760 *
const std::vector<Number_Type> y_points;
763 *
template <
typename Number_Type>
764 * LinearInterpolator<Number_Type>::LinearInterpolator(
const std::vector<Number_Type> &ix_points,
const std::vector<Number_Type> &iy_points)
765 * : x_points(ix_points)
766 * , y_points(iy_points)
769 *
template <
typename Number_Type>
770 * Number_Type LinearInterpolator<Number_Type>::value(
const Number_Type x)
const
772 * Number_Type res = 0.;
774 *
auto lower = std::lower_bound(x_points.begin(), x_points.end(), x);
775 *
unsigned int right_index = 0;
776 *
unsigned int left_index = 0;
777 *
if (lower == x_points.begin())
781 *
else if (lower == x_points.end())
783 * res = y_points[x_points.size()-1];
787 * right_index = lower - x_points.begin();
788 * left_index = right_index - 1;
790 * Number_Type y_2 = y_points[right_index];
791 * Number_Type y_1 = y_points[left_index];
792 * Number_Type x_2 = x_points[right_index];
793 * Number_Type x_1 = x_points[left_index];
795 * res = (y_2 - y_1) / (x_2 - x_1) * (x - x_1) + y_1;
805<a name=
"ann-Parameters.cc"></a>
806<h1>Annotated version of Parameters.cc</h1>
822 * #include
"Parameters.h"
824 *
namespace TravelingWave
831 * add_parameter(
"delta", delta = 0.01);
832 * add_parameter(
"epsilon", epsilon = 0.1);
833 * add_parameter(
"Prandtl number", Pr = 0.75);
834 * add_parameter(
"Lewis number", Le = 1.0);
835 * add_parameter(
"Constant of reaction rate", k = 1.0);
836 * add_parameter(
"Activation energy", theta = 1.65);
837 * add_parameter(
"Heat release", q = 1.7);
838 * add_parameter(
"Ignition Temperature", T_ign = 1.0);
839 * add_parameter(
"Type of the wave (deflagration / detonation)", wave_type = 1);
841 * add_parameter(
"Type of boundary condition for the temperature at the right boundary", T_r_bc_type = 1);
843 * add_parameter(
"T_left", T_left = 5.3);
844 * add_parameter(
"T_right", T_right = 0.9);
845 * add_parameter(
"u_left", u_left = -0.2);
846 * add_parameter(
"u_right", u_right = 0.);
848 * add_parameter(
"Initial guess for the wave speed", wave_speed_init = 1.2);
851 * FiniteElements::FiniteElements()
854 * add_parameter(
"Polynomial degree", poly_degree = 1);
855 * add_parameter(
"Number of quadrature points", quadrature_points_number = 3);
861 * add_parameter(
"Interval left boundary", interval_left = -50.0);
862 * add_parameter(
"Interval right boundary", interval_right = 20.0);
863 * add_parameter<unsigned int>(
"Refinements number", refinements_number = 10);
864 * add_parameter(
"Adaptive mesh refinement", adaptive = 1);
870 * add_parameter(
"Tolerance", tol = 1e-10);
877<a name=
"ann-Parameters.h"></a>
878<h1>Annotated version of Parameters.h</h1>
897 * #include <deal.II/base/parameter_acceptor.h>
899 *
namespace TravelingWave
909 *
double k, theta, q;
913 *
double T_left, T_right;
914 *
double u_left, u_right;
916 *
double wave_speed_init;
923 *
unsigned int poly_degree;
924 *
unsigned int quadrature_points_number;
931 *
double interval_left;
932 *
double interval_right;
933 *
unsigned int refinements_number;
958<a name=
"ann-Solution.cc"></a>
959<h1>Annotated version of Solution.cc</h1>
975 * #include
"Solution.h"
977 *
namespace TravelingWave
982 * SolutionStruct::SolutionStruct() {}
983 * SolutionStruct::SolutionStruct(
const std::vector<double> &ix,
const std::vector<double> &iu,
984 *
const std::vector<double> &iT,
const std::vector<double> &ilambda,
double iwave_speed)
989 * , wave_speed(iwave_speed)
991 * SolutionStruct::SolutionStruct(
const std::vector<double> &ix,
const std::vector<double> &iu,
992 *
const std::vector<double> &iT,
const std::vector<double> &ilambda)
993 * : SolutionStruct(ix, iu, iT, ilambda, 0.)
996 *
void SolutionStruct::reinit(
const unsigned int number_of_elements)
1004 * x.resize(number_of_elements);
1005 * u.resize(number_of_elements);
1006 * T.resize(number_of_elements);
1007 *
lambda.resize(number_of_elements);
1010 *
void SolutionStruct::save_to_file(std::string filename =
"sol") const
1012 *
const std::string file_for_solution = filename +
".txt";
1013 * std::ofstream output(file_for_solution);
1015 * output << std::scientific << std::setprecision(16);
1016 *
for (
unsigned int i = 0; i < x.size(); ++i)
1018 * output << std::fixed << x[i];
1019 * output << std::scientific <<
" " << u[i] <<
" " << T[i] <<
" " <<
lambda[i] <<
"\n";
1023 * std::ofstream file_for_wave_speed_output(
"wave_speed-" + file_for_solution);
1024 * file_for_wave_speed_output << std::scientific << std::setprecision(16);
1025 * file_for_wave_speed_output << wave_speed << std::endl;
1026 * file_for_wave_speed_output.close();
1030 * Interpolant::Interpolant(
const std::vector<double> &ix_points,
const std::vector<double> &iy_points)
1031 * : interpolant(ix_points, iy_points)
1034 *
double Interpolant::value(
const Point<1> &p,
const unsigned int component)
const
1037 *
double res = interpolant.value(x);
1043 *
template <
typename InterpolantType>
1044 * SolutionVectorFunction<InterpolantType>::SolutionVectorFunction(InterpolantType iu_interpolant, InterpolantType iT_interpolant, InterpolantType ilambda_interpolant)
1046 * , u_interpolant(iu_interpolant)
1047 * , T_interpolant(iT_interpolant)
1048 * , lambda_interpolant(ilambda_interpolant)
1051 *
template <
typename InterpolantType>
1052 *
double SolutionVectorFunction<InterpolantType>::value(
const Point<1> &p,
const unsigned int component)
const
1055 *
if (component == 0) { res = u_interpolant.
value(p); }
1056 *
else if (component == 1) { res = T_interpolant.value(p); }
1057 *
else if (component == 2) { res = lambda_interpolant.value(p); }
1062 *
template class SolutionVectorFunction<Interpolant>;
1068<a name=
"ann-Solution.h"></a>
1069<h1>Annotated version of Solution.h</h1>
1088 * #include <deal.II/base/function.h>
1090 * #include
"LinearInterpolator.h"
1094 * #include <fstream>
1095 * #include <iostream>
1096 * #include <iomanip>
1099 *
namespace TravelingWave
1101 *
using namespace dealii;
1105 * 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$.
1108 *
struct SolutionStruct
1111 * SolutionStruct(
const std::vector<double> &ix,
const std::vector<double> &iu,
1112 *
const std::vector<double> &iT,
const std::vector<double> &ilambda,
const double iwave_speed);
1113 * SolutionStruct(
const std::vector<double> &ix,
const std::vector<double> &iu,
1114 *
const std::vector<double> &iT,
const std::vector<double> &ilambda);
1116 *
void reinit(
const unsigned int number_of_elements);
1118 *
void save_to_file(std::string filename)
const;
1120 * std::vector<double> x;
1121 * std::vector<double> u;
1122 * std::vector<double> T;
1123 * std::vector<double>
lambda;
1125 *
double wave_speed;
1130 * Interpolation
class
1133 *
class Interpolant :
public Function<1>
1136 * Interpolant(
const std::vector<double> &ix_points,
const std::vector<double> &iy_points);
1137 *
virtual double value(
const Point<1> &p,
const unsigned int component = 0)
const override;
1140 * LinearInterpolator<double> interpolant;
1148 *
template <
typename InterpolantType>
1149 *
class SolutionVectorFunction :
public Function<1>
1152 * SolutionVectorFunction(InterpolantType iu_interpolant, InterpolantType iT_interpolant, InterpolantType ilambda_interpolant);
1153 *
virtual double value(
const Point<1> &p,
const unsigned int component = 0)
const override;
1156 * InterpolantType u_interpolant;
1157 * InterpolantType T_interpolant;
1158 * InterpolantType lambda_interpolant;
1167<a name=
"ann-TravelingWaveSolver.cc"></a>
1168<h1>Annotated version of TravelingWaveSolver.cc</h1>
1184 * #include
"TravelingWaveSolver.h"
1186 *
namespace TravelingWave
1188 *
using namespace dealii;
1192 * Constructor of the
class that takes parameters of the problem and an
initial guess for Newton's iterations.
1195 * TravelingWaveSolver::TravelingWaveSolver(
const Parameters ¶meters,
const SolutionStruct &initial_guess_input)
1196 * : params(parameters)
1197 * , problem(params.problem)
1198 * , number_of_quadrature_points((params.fe.quadrature_points_number > 0) ? params.fe.quadrature_points_number : (params.fe.poly_degree + 1))
1199 * , triangulation_uploaded(false)
1200 * , fe(
FE_Q<1>(params.fe.poly_degree), 1,
1201 *
FE_Q<1>(params.fe.poly_degree), 1,
1202 *
FE_Q<1>(params.fe.poly_degree), 1)
1204 * , current_wave_speed(0.)
1205 * , initial_guess(initial_guess_input)
1210 *
Table with values of some parameters to be written to the standard output before calculations.
1214 * table.
add_value(
"Parameter name",
"number of quadrature points");
1215 * table.add_value(
"value", number_of_quadrature_points);
1217 * table.add_value(
"Parameter name",
"delta");
1218 * table.add_value(
"value", params.problem.delta);
1220 * table.add_value(
"Parameter name",
"epsilon");
1221 * table.add_value(
"value", params.problem.epsilon);
1223 * table.add_value(
"Parameter name",
"params.problem.wave_speed_init");
1224 * table.add_value(
"value", params.problem.wave_speed_init);
1226 * table.add_value(
"Parameter name",
"initial_guess.wave_speed");
1227 * table.add_value(
"value", initial_guess.wave_speed);
1229 * table.add_value(
"Parameter name",
"T_left");
1230 * table.add_value(
"value", params.problem.T_left);
1232 * table.set_precision(
"value", 2);
1233 * table.set_scientific(
"value",
true);
1235 * std::cout <<
"\n";
1237 * std::cout <<
"\n";
1245 *
void TravelingWaveSolver::set_triangulation(
const Triangulation<1> &itriangulation)
1249 * triangulation_uploaded =
true;
1254 * 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.
1257 *
void TravelingWaveSolver::find_boundary_and_centering_dof_numbers()
1259 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1263 * if (isapprox(cell->vertex(v_ind)[0], params.mesh.interval_left))
1265 * boundary_and_centering_dof_numbers[
"u_left"] = cell->vertex_dof_index(v_ind, 0);
1266 * boundary_and_centering_dof_numbers[
"T_left"] = cell->vertex_dof_index(v_ind, 1);
1267 * boundary_and_centering_dof_numbers[
"lambda_left"] = cell->vertex_dof_index(v_ind, 2);
1269 *
else if (isapprox(cell->vertex(v_ind)[0], params.mesh.interval_right))
1271 * boundary_and_centering_dof_numbers[
"u_right"] = cell->vertex_dof_index(v_ind, 0);
1272 * boundary_and_centering_dof_numbers[
"T_right"] = cell->vertex_dof_index(v_ind, 1);
1273 * boundary_and_centering_dof_numbers[
"lambda_right"] = cell->vertex_dof_index(v_ind, 2);
1275 *
else if (isapprox(cell->vertex(v_ind)[0], 0.))
1277 * boundary_and_centering_dof_numbers[
"T_zero"] = cell->vertex_dof_index(v_ind, 1);
1285 * Set solution values, corresponding to Dirichlet boundary conditions and the centering condition @f$T(0) = T_{\mathrm{ign}}@f$.
1288 *
void TravelingWaveSolver::set_boundary_and_centering_values()
1290 * current_solution[boundary_and_centering_dof_numbers[
"u_right"]] = problem.u_right;
1292 * current_solution[boundary_and_centering_dof_numbers[
"T_left"]] = problem.T_left;
1293 *
if (problem.T_r_bc_type == 1)
1295 * current_solution[boundary_and_centering_dof_numbers[
"T_right"]] = problem.T_right;
1297 * current_solution[boundary_and_centering_dof_numbers[
"T_zero"]] = problem.T_ign;
1299 * current_solution[boundary_and_centering_dof_numbers[
"lambda_right"]] = 0.;
1303 *
void TravelingWaveSolver::setup_system(
const bool initial_step)
1307 * dof_handler.distribute_dofs(fe);
1309 * std::cout <<
"Number of dofs : " << dof_handler.n_dofs() << std::endl;
1311 * extended_solution_dim = dof_handler.n_dofs() + 1;
1313 * find_boundary_and_centering_dof_numbers();
1317 * Boundary condition constraints
for @f$du@f$, @f$dT@f$ and @f$d\lambda@f$.
1320 * zero_boundary_constraints.clear();
1324 * Dirichlet homogeneous boundary condition
for @f$du@f$ at the right boundary.
1327 * zero_boundary_constraints.add_line(boundary_and_centering_dof_numbers[
"u_right"]);
1331 * Dirichlet homogeneous boundary condition
for @f$dT@f$ at the left boundary.
1334 * zero_boundary_constraints.add_line(boundary_and_centering_dof_numbers[
"T_left"]);
1337 * For the temperature at the left boundary there are two possibilities:
1340 *
if (problem.T_r_bc_type == 1)
1342 * std::cout <<
"Dirichlet condition for the temperature at the right boundary." << std::endl;
1343 * zero_boundary_constraints.add_line(boundary_and_centering_dof_numbers[
"T_right"]);
1347 * std::cout <<
"Neumann condition for the temperature at the right boundary." << std::endl;
1352 * 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$.)
1355 * zero_boundary_constraints.add_line(boundary_and_centering_dof_numbers[
"lambda_right"]);
1357 * zero_boundary_constraints.close();
1361 * We create extended
dynamic sparsity pattern with an additional row and an additional column.
1366 * std::vector<types::global_dof_index> dofs_on_this_cell;
1367 * dofs_on_this_cell.reserve(dof_handler.get_fe_collection().max_dofs_per_cell());
1369 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1371 * const unsigned
int dofs_per_cell = cell->get_fe().n_dofs_per_cell();
1372 * dofs_on_this_cell.resize(dofs_per_cell);
1373 * cell->get_dof_indices(dofs_on_this_cell);
1375 * zero_boundary_constraints.add_entries_local_to_global(dofs_on_this_cell,
1382 * Adding elements to the last column.
1385 *
for (
unsigned int i = 0; i < extended_solution_dim; ++i)
1387 * dsp.add(i, extended_solution_dim - 1);
1391 * Adding one element to the last row, corresponding to the T(0).
1394 * dsp.add(extended_solution_dim - 1, boundary_and_centering_dof_numbers[
"T_zero"]);
1402 * sparsity_pattern_extended.copy_from(dsp);
1403 * jacobian_matrix_extended.reinit(sparsity_pattern_extended);
1404 * jacobian_matrix_extended_factorization.reset();
1406 * current_solution_extended.reinit(extended_solution_dim);
1410 * current_solution.reinit(dof_handler.n_dofs());
1416 *
void TravelingWaveSolver::set_initial_guess()
1418 * current_wave_speed = initial_guess.wave_speed;
1422 * 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.
1425 * Interpolant u_interpolant(initial_guess.x, initial_guess.u);
1426 * Interpolant T_interpolant(initial_guess.x, initial_guess.T);
1427 * Interpolant lambda_interpolant(initial_guess.x, initial_guess.lambda);
1429 * SolutionVectorFunction init_guess_func(u_interpolant, T_interpolant, lambda_interpolant);
1433 * set_boundary_and_centering_values();
1435 *
for (
unsigned int i = 0; i < extended_solution_dim - 1; ++i)
1437 * current_solution_extended(i) = current_solution(i);
1439 * current_solution_extended(extended_solution_dim - 1) = current_wave_speed;
1444 * Heaviside function.
1447 *
double TravelingWaveSolver::Heaviside_func(
double x)
const
1460 *
void TravelingWaveSolver::compute_and_factorize_jacobian(
const Vector<double> &evaluation_point_extended)
1466 *
for (
unsigned int i = 0; i < dof_handler.n_dofs(); ++i)
1468 * evaluation_point(i) = evaluation_point_extended(i);
1471 *
const double wave_speed = evaluation_point_extended(extended_solution_dim - 1);
1473 * std::cout <<
"Computing Jacobian matrix ... " << std::endl;
1475 *
const QGauss<1> quadrature_formula(number_of_quadrature_points);
1477 * jacobian_matrix_extended = 0;
1480 * quadrature_formula,
1484 *
const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
1485 *
const unsigned int n_q_points = quadrature_formula.size();
1490 * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1496 * std::vector<double> current_velocity_values(n_q_points);
1497 * std::vector<double> current_temperature_values(n_q_points);
1498 * std::vector<double> current_lambda_values(n_q_points);
1500 * std::vector<Tensor<1, 1>> current_velocity_gradients(n_q_points);
1501 * std::vector<Tensor<1, 1>> current_temperature_gradients(n_q_points);
1502 * std::vector<Tensor<1, 1>> current_lambda_gradients(n_q_points);
1504 * std::vector<double> phi_u(dofs_per_cell);
1505 * std::vector<Tensor<1, 1>> grad_phi_u(dofs_per_cell);
1506 * std::vector<double> phi_T(dofs_per_cell);
1507 * std::vector<Tensor<1, 1>> grad_phi_T(dofs_per_cell);
1508 * std::vector<double> phi_lambda(dofs_per_cell);
1509 * std::vector<Tensor<1, 1>> grad_phi_lambda(dofs_per_cell);
1511 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1514 * row_last_element_vector = 0;
1516 * fe_values.reinit(cell);
1518 * fe_values[velocity].get_function_values(evaluation_point, current_velocity_values);
1519 * fe_values[temperature].get_function_values(evaluation_point, current_temperature_values);
1520 * fe_values[
lambda].get_function_values(evaluation_point, current_lambda_values);
1522 * fe_values[velocity].get_function_gradients(evaluation_point, current_velocity_gradients);
1523 * fe_values[temperature].get_function_gradients(evaluation_point, current_temperature_gradients);
1524 * fe_values[
lambda].get_function_gradients(evaluation_point, current_lambda_gradients);
1526 *
auto kappa_1 = [=](
double T,
double lambda){
1527 *
return problem.k * (1 -
lambda) *
std::exp(-problem.theta / T) * (
1528 * problem.theta / (T * T) * Heaviside_func(T - problem.T_ign)
1532 *
auto kappa_2 = [=](
double T,
double lambda){
1533 *
return -problem.k *
std::exp(-problem.theta / T) * Heaviside_func(T - problem.T_ign);
1536 *
for (
unsigned int q = 0; q < n_q_points; ++q)
1538 *
for (
unsigned int k = 0; k < dofs_per_cell; ++k)
1540 * phi_u[k] = fe_values[velocity].value(k, q);
1541 * grad_phi_u[k] = fe_values[velocity].gradient(k, q);
1542 * phi_T[k] = fe_values[temperature].value(k, q);
1543 * grad_phi_T[k] = fe_values[temperature].gradient(k, q);
1544 * phi_lambda[k] = fe_values[
lambda].value(k, q);
1545 * grad_phi_lambda[k] = fe_values[
lambda].gradient(k, q);
1548 *
const double del_Pr_eps = (problem.Pr * 4 * problem.delta / (3 * problem.epsilon));
1549 *
const double del_Le = (problem.delta / problem.Le);
1551 *
for (
unsigned int i = 0; i < dofs_per_cell; ++i)
1553 *
for (
unsigned int j = 0; j < dofs_per_cell; ++j)
1557 * del_Pr_eps * (-grad_phi_u[i] * grad_phi_u[j])
1559 * - (1 - wave_speed + problem.epsilon * current_velocity_values[q]) * grad_phi_u[j][0]
1560 * - problem.epsilon * current_velocity_gradients[q][0] * phi_u[j]
1561 * - problem.epsilon / 2. * grad_phi_T[j][0]
1564 * + problem.delta * (-grad_phi_T[i] * grad_phi_T[j])
1566 * - wave_speed * grad_phi_u[j][0]
1567 * + wave_speed * grad_phi_T[j][0]
1568 * + problem.q * kappa_1(current_temperature_values[q], current_lambda_values[q]) * phi_T[j]
1569 * + problem.q * kappa_2(current_temperature_values[q], current_lambda_values[q]) * phi_lambda[j]
1572 * + del_Le * (-grad_phi_lambda[i] * grad_phi_lambda[j])
1573 * + phi_lambda[i] * (
1574 * kappa_1(current_temperature_values[q], current_lambda_values[q]) * phi_T[j]
1575 * + wave_speed * grad_phi_lambda[j][0]
1576 * + kappa_2(current_temperature_values[q], current_lambda_values[q]) * phi_lambda[j]
1579 * ) * fe_values.JxW(q);
1583 * row_last_element_vector(i) += (
1584 * (phi_u[i] * current_velocity_gradients[q][0])
1585 * + (phi_T[i] * current_temperature_gradients[q][0])
1586 * - (phi_T[i] * current_velocity_gradients[q][0])
1587 * + (phi_lambda[i] * current_lambda_gradients[q][0])
1588 * ) * fe_values.JxW(q);
1593 * cell->get_dof_indices(local_dof_indices);
1595 *
for (
const unsigned int i : fe_values.dof_indices())
1597 * for (const unsigned
int j : fe_values.dof_indices())
1599 * jacobian_matrix_extended.add(local_dof_indices[i],
1600 * local_dof_indices[j],
1606 * Adding elements to the last column.
1609 * jacobian_matrix_extended.add(local_dof_indices[i],
1610 * extended_solution_dim - 1,
1611 * row_last_element_vector(i));
1618 * Global dof indices of dofs
for @f$dT@f$ and @f$d\lambda@f$, associated with vertex @f$\xi = 0@f$.
1625 * Approximating the derivative of @f$T@f$ at @f$\xi = 0@f$ as done in @ref step_14
"step-14".
1628 *
double T_point_derivative(0.);
1629 *
double T_at_zero_point(0.);
1630 *
double lambda_at_zero_point(0.);
1632 *
double derivative_evaluation_point = 0.;
1636 * quadrature_formula,
1642 *
const unsigned int n_q_points = quadrature_formula.size();
1643 * std::vector<double> current_temperature_values(n_q_points);
1644 * std::vector<Tensor<1, 1>> current_temperature_gradients(n_q_points);
1645 * std::vector<double> current_lambda_values(n_q_points);
1647 *
unsigned int derivative_evaluation_point_hits = 0;
1649 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1653 * if (isapprox(cell->vertex(vertex)[0], derivative_evaluation_point))
1655 * T_zero_point_dof_ind = cell->vertex_dof_index(vertex, 1);
1656 * lambda_zero_point_dof_ind = cell->vertex_dof_index(vertex, 2);
1658 * fe_values.reinit(cell);
1659 * fe_values[temperature].get_function_values(current_solution, current_temperature_values);
1660 * fe_values[temperature].get_function_gradients(current_solution, current_temperature_gradients);
1661 * fe_values[
lambda].get_function_values(current_solution, current_lambda_values);
1663 *
unsigned int q_point = 0;
1664 *
for (; q_point < n_q_points; ++q_point)
1666 *
if (isapprox(fe_values.quadrature_point(q_point)[0], derivative_evaluation_point))
1672 * T_at_zero_point = current_temperature_values[q_point];
1673 * lambda_at_zero_point = current_lambda_values[q_point];
1675 * T_point_derivative += current_temperature_gradients[q_point][0];
1676 * ++derivative_evaluation_point_hits;
1682 * T_point_derivative /=
static_cast<double>(derivative_evaluation_point_hits);
1687 * 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).
1690 *
double term_with_delta_func(0.);
1691 * term_with_delta_func = problem.k *
std::exp(-problem.theta / T_at_zero_point) * (1 - lambda_at_zero_point) /
std::abs(T_point_derivative);
1692 * jacobian_matrix_extended.add(T_zero_point_dof_ind, T_zero_point_dof_ind, problem.q * term_with_delta_func);
1693 * jacobian_matrix_extended.add(lambda_zero_point_dof_ind, T_zero_point_dof_ind, term_with_delta_func);
1697 * Add 1 to the position <code> T_zero_point_dof_ind </code> of the last row of the
matrix.
1700 * jacobian_matrix_extended.add(extended_solution_dim - 1, T_zero_point_dof_ind, 1.);
1702 * zero_boundary_constraints.condense(jacobian_matrix_extended);
1708 * std::cout <<
"Factorizing Jacobian matrix" << std::endl;
1710 * jacobian_matrix_extended_factorization = std::make_unique<SparseDirectUMFPACK>();
1711 * jacobian_matrix_extended_factorization->factorize(jacobian_matrix_extended);
1721 * std::cout <<
"Computing residual vector ... " << std::endl;
1726 *
for (
unsigned int i = 0; i < dof_handler.n_dofs(); ++i)
1728 * evaluation_point(i) = evaluation_point_extended(i);
1731 *
const double wave_speed = evaluation_point_extended(extended_solution_dim - 1);
1733 *
const QGauss<1> quadrature_formula(number_of_quadrature_points);
1735 * quadrature_formula,
1739 *
const unsigned int dofs_per_cell = fe.n_dofs_per_cell();
1740 *
const unsigned int n_q_points = quadrature_formula.size();
1743 * std::vector<types::global_dof_index> local_dof_indices(dofs_per_cell);
1749 * std::vector<double> current_velocity_values(n_q_points);
1750 * std::vector<Tensor<1, 1>> current_velocity_gradients(n_q_points);
1751 * std::vector<double> current_temperature_values(n_q_points);
1752 * std::vector<Tensor<1, 1>> current_temperature_gradients(n_q_points);
1753 * std::vector<double> current_lambda_values(n_q_points);
1754 * std::vector<Tensor<1, 1>> current_lambda_gradients(n_q_points);
1756 * std::vector<double> phi_u(dofs_per_cell);
1757 * std::vector<Tensor<1, 1>> grad_phi_u(dofs_per_cell);
1758 * std::vector<double> phi_T(dofs_per_cell);
1759 * std::vector<Tensor<1, 1>> grad_phi_T(dofs_per_cell);
1760 * std::vector<double> phi_lambda(dofs_per_cell);
1761 * std::vector<Tensor<1, 1>> grad_phi_lambda(dofs_per_cell);
1763 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1767 * fe_values.reinit(cell);
1769 * fe_values[velocity].get_function_values(evaluation_point, current_velocity_values);
1770 * fe_values[velocity].get_function_gradients(evaluation_point, current_velocity_gradients);
1771 * fe_values[temperature].get_function_values(evaluation_point, current_temperature_values);
1772 * fe_values[temperature].get_function_gradients(evaluation_point, current_temperature_gradients);
1773 * fe_values[
lambda].get_function_values(evaluation_point, current_lambda_values);
1774 * fe_values[
lambda].get_function_gradients(evaluation_point, current_lambda_gradients);
1776 *
auto omega = [=](
double T,
double lambda){
1777 *
return problem.k * (1 -
lambda) *
std::exp(-problem.theta / T) * Heaviside_func(T - problem.T_ign);
1780 *
for (
unsigned int q = 0; q < n_q_points; ++q)
1782 *
for (
unsigned int k = 0; k < dofs_per_cell; ++k)
1784 * phi_u[k] = fe_values[velocity].value(k, q);
1785 * grad_phi_u[k] = fe_values[velocity].gradient(k, q);
1786 * phi_T[k] = fe_values[temperature].value(k, q);
1787 * grad_phi_T[k] = fe_values[temperature].gradient(k, q);
1788 * phi_lambda[k] = fe_values[
lambda].value(k, q);
1789 * grad_phi_lambda[k] = fe_values[
lambda].gradient(k, q);
1792 *
double del_Pr_eps = (problem.Pr * 4 * problem.delta / (3 * problem.epsilon));
1793 *
double del_Le = (problem.delta / problem.Le);
1795 *
for (
unsigned int i = 0; i < dofs_per_cell; ++i)
1799 * del_Pr_eps * (-grad_phi_u[i] * current_velocity_gradients[q])
1801 * - current_velocity_gradients[q][0] * (1 - wave_speed + problem.epsilon * current_velocity_values[q])
1802 * - problem.epsilon / 2. * current_temperature_gradients[q][0]
1805 * + problem.delta * (-grad_phi_T[i] * current_temperature_gradients[q])
1807 * wave_speed * (current_temperature_gradients[q][0] - current_velocity_gradients[q][0])
1808 * + problem.q * omega(current_temperature_values[q], current_lambda_values[q])
1811 * + del_Le * (-grad_phi_lambda[i] * current_lambda_gradients[q])
1812 * + phi_lambda[i] * (
1813 * wave_speed * current_lambda_gradients[q][0] + omega(current_temperature_values[q], current_lambda_values[q])
1816 * ) * fe_values.JxW(q);
1821 * cell->get_dof_indices(local_dof_indices);
1823 *
for (
const unsigned int i : fe_values.dof_indices())
1829 * residual(extended_solution_dim - 1) = 0.;
1831 * zero_boundary_constraints.condense(residual);
1833 *
double residual_norm = residual.l2_norm();
1835 * std::cout << std::defaultfloat;
1836 * std::cout <<
"norm of residual = " << residual_norm << std::endl;
1838 *
return residual_norm;
1843 * 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.
1846 *
void TravelingWaveSolver::split_extended_solution_vector()
1848 *
for (
unsigned int i = 0; i < extended_solution_dim - 1; ++i)
1850 * current_solution(i) = current_solution_extended(i);
1853 * current_wave_speed = current_solution_extended(extended_solution_dim - 1);
1861 * std::cout <<
"Solving linear system ... " << std::endl;
1863 * jacobian_matrix_extended_factorization->vmult(solution_extended, rhs);
1865 * zero_boundary_constraints.distribute(solution_extended);
1875 *
void TravelingWaveSolver::refine_mesh()
1886 * estimated_error_per_cell,
1887 * fe.component_mask(lambda)
1891 * estimated_error_per_cell,
1898 * solution_transfer.prepare_for_coarsening_and_refinement(current_solution);
1902 * setup_system(
false);
1905 * solution_transfer.interpolate(current_solution, tmp);
1906 * current_solution = std::move(tmp);
1908 * set_boundary_and_centering_values();
1910 *
for (
unsigned int i = 0; i < extended_solution_dim - 1; ++i)
1912 * current_solution_extended(i) = current_solution(i);
1914 * current_solution_extended(extended_solution_dim - 1) = current_wave_speed;
1919 *
double TravelingWaveSolver::run_newton_iterations(
const double target_tolerance)
1922 *
double residual_norm = 0.;
1925 * additional_data.function_tolerance = target_tolerance;
1930 * x.reinit(extended_solution_dim);
1934 * residual_norm = compute_residual(evaluation_point, residual);
1940 * compute_and_factorize_jacobian(evaluation_point);
1946 * this->solve(rhs, solution, tolerance);
1951 * nonlinear_solver.solve(current_solution_extended);
1954 *
return residual_norm;
1960 * 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.
1963 *
void TravelingWaveSolver::output_with_double_precision(
const Vector<double> &solution,
const double wave_speed,
const std::string filename)
1967 *
const std::string file_for_solution = filename +
".txt";
1968 * std::ofstream output(file_for_solution);
1970 *
for (
const auto &cell : dof_handler.active_cell_iterators())
1974 * double u = solution(cell->vertex_dof_index(v_ind, 0));
1975 *
double T = solution(cell->vertex_dof_index(v_ind, 1));
1976 *
double lambda = solution(cell->vertex_dof_index(v_ind, 2));
1978 * output << std::scientific << std::setprecision(16);
1979 * output << cell->vertex(v_ind)[0];
1981 * output << std::scientific << std::setprecision(16);
1982 * output << std::scientific <<
" " << u <<
" " << T <<
" " <<
lambda <<
"\n";
1989 * std::ofstream file_for_wave_speed_output(
"wave_speed-" + file_for_solution);
1990 * file_for_wave_speed_output << std::scientific << std::setprecision(16);
1991 * file_for_wave_speed_output << wave_speed << std::endl;
1992 * file_for_wave_speed_output.close();
1997 * Copy the solution into the <code> SolutionStruct </code> object, that stores the solution in an ordered manner.
2000 *
void TravelingWaveSolver::get_solution(SolutionStruct &solution)
const
2004 * 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.
2007 *
auto comp = [](
const std::vector<double> &a,
const std::vector<double> &
b) {
2008 *
return a[0] <
b[0];
2010 * std::set<std::vector<double>,
decltype(comp)> solution_set(comp);
2011 *
for (
const auto &cell : dof_handler.active_cell_iterators())
2015 * double x = cell->vertex(v_ind)[0];
2016 *
double u = current_solution(cell->vertex_dof_index(v_ind, 0));
2017 *
double T = current_solution(cell->vertex_dof_index(v_ind, 1));
2018 *
double lambda = current_solution(cell->vertex_dof_index(v_ind, 2));
2019 * solution_set.insert({x, u, T,
lambda});
2023 * solution.x.clear();
2024 * solution.u.clear();
2025 * solution.T.clear();
2026 * solution.lambda.clear();
2028 * solution.x.reserve(solution_set.size());
2029 * solution.u.reserve(solution_set.size());
2030 * solution.T.reserve(solution_set.size());
2031 * solution.lambda.reserve(solution_set.size());
2033 *
for (
auto it = solution_set.begin(); it != solution_set.end(); ++it)
2035 * solution.x.push_back((*it)[0]);
2036 * solution.u.push_back((*it)[1]);
2037 * solution.T.push_back((*it)[2]);
2038 * solution.lambda.push_back((*it)[3]);
2041 * solution.wave_speed = current_wave_speed;
2046 *
void TravelingWaveSolver::get_triangulation(
Triangulation<1> &otriangulation)
const
2048 * otriangulation.clear();
2053 *
void TravelingWaveSolver::run(
const std::string filename,
const bool save_solution_to_file)
2055 *
const int mesh_refinement_type = params.mesh.adaptive;
2056 *
const unsigned int n_refinements = params.mesh.refinements_number;
2057 *
const double tol = params.solver.tol;
2059 *
if (triangulation_uploaded ==
false)
2063 * 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.
2068 * triangulation_left,
2069 *
static_cast<unsigned int>(
std::abs( 0. - params.mesh.interval_left )),
2070 * params.mesh.interval_left, 0.
2075 * triangulation_right,
2076 *
static_cast<unsigned int>(
std::abs( params.mesh.interval_right - 0. )),
2077 * 0., params.mesh.interval_right
2084 *
if (triangulation_uploaded ==
false)
2086 *
if (mesh_refinement_type == 1)
2090 *
else if (mesh_refinement_type == 0)
2096 * setup_system(
true);
2097 * set_initial_guess();
2099 *
if (save_solution_to_file)
2101 * output_with_double_precision(current_solution, current_wave_speed,
"solution_initial_data");
2104 *
if (mesh_refinement_type == 1)
2106 *
double residual_norm = 0.;
2109 * residual_norm = compute_residual(current_solution_extended, tmp_residual);
2112 *
unsigned int refinement_cycle = 0;
2113 *
while ((residual_norm > tol) && (refinement_cycle < n_refinements))
2115 * computing_timer.reset();
2116 * std::cout <<
"Mesh refinement step " << refinement_cycle << std::endl;
2118 *
if (refinement_cycle != 0) { refine_mesh(); }
2120 *
const double target_tolerance = 0.1 *
std::pow(0.1, refinement_cycle);
2121 * std::cout <<
" Target_tolerance: " << target_tolerance << std::endl;
2123 * residual_norm = run_newton_iterations(target_tolerance);
2124 * split_extended_solution_vector();
2127 * std::cout << std::scientific << std::setprecision(16);
2128 * std::cout <<
"current_wave_speed = " << current_wave_speed << std::endl;
2129 * std::cout << std::defaultfloat;
2132 * computing_timer.print_summary();
2134 * ++refinement_cycle;
2136 *
if (save_solution_to_file)
2138 * output_with_double_precision(current_solution, current_wave_speed, filename);
2142 *
else if (mesh_refinement_type == 0)
2144 * run_newton_iterations(tol);
2145 * split_extended_solution_vector();
2147 *
if (save_solution_to_file)
2149 * output_with_double_precision(current_solution, current_wave_speed, filename);
2153 * std::cout << std::scientific << std::setprecision(16);
2154 * std::cout <<
"current_wave_speed = " << current_wave_speed << std::endl;
2155 * std::cout << std::defaultfloat;
2158 * computing_timer.print_summary();
2169<a name=
"ann-TravelingWaveSolver.h"></a>
2170<h1>Annotated version of TravelingWaveSolver.h</h1>
2186 * #ifndef TRAVELING_WAVE_SOLVER
2187 * #define TRAVELING_WAVE_SOLVER
2189 * #include <deal.II/base/timer.h>
2190 * #include <deal.II/base/function.h>
2191 * #include <deal.II/base/table_handler.h>
2192 * #include <deal.II/grid/tria.h>
2193 * #include <deal.II/grid/grid_generator.h>
2194 * #include <deal.II/grid/grid_refinement.h>
2195 * #include <deal.II/grid/grid_out.h>
2196 * #include <deal.II/dofs/dof_handler.h>
2197 * #include <deal.II/dofs/dof_tools.h>
2198 * #include <deal.II/fe/fe_q.h>
2199 * #include <deal.II/fe/fe_system.h>
2200 * #include <deal.II/fe/fe_values.h>
2201 * #include <deal.II/lac/vector.h>
2202 * #include <deal.II/lac/full_matrix.h>
2203 * #include <deal.II/lac/sparse_matrix.h>
2204 * #include <deal.II/lac/sparse_direct.h>
2205 * #include <deal.II/lac/dynamic_sparsity_pattern.h>
2206 * #include <deal.II/numerics/vector_tools.h>
2207 * #include <deal.II/numerics/error_estimator.h>
2208 * #include <deal.II/numerics/solution_transfer.h>
2209 * #include <deal.II/numerics/data_out.h>
2210 * #include <deal.II/sundials/kinsol.h>
2212 * #include
"Parameters.h"
2213 * #include
"Solution.h"
2214 * #include
"AuxiliaryFunctions.h"
2217 * #include <algorithm>
2219 * #include <fstream>
2220 * #include <iostream>
2221 * #include <iomanip>
2226 * Namespace of the program
2229 *
namespace TravelingWave
2231 *
using namespace dealii;
2235 * The main
class for construction of the traveling wave solutions.
2238 *
class TravelingWaveSolver
2241 * TravelingWaveSolver(
const Parameters ¶meters,
const SolutionStruct &initial_guess_input);
2245 *
void run(
const std::string filename=
"solution",
const bool save_solution_to_file=
true);
2246 *
void get_solution(SolutionStruct &solution)
const;
2250 *
void setup_system(
const bool initial_step);
2251 *
void find_boundary_and_centering_dof_numbers();
2252 *
void set_boundary_and_centering_values();
2254 *
void set_initial_guess();
2256 *
double Heaviside_func(
double x)
const;
2258 *
void compute_and_factorize_jacobian(
const Vector<double> &evaluation_point_extended);
2260 *
void split_extended_solution_vector();
2263 *
void refine_mesh();
2264 *
double run_newton_iterations(
const double target_tolerance=1e-5);
2266 *
void output_with_double_precision(
const Vector<double> &solution,
const double wave_speed,
const std::string filename=
"solution");
2270 * The dimension of the finite element solution increased by one to account
for the
value corresponding to the wave speed.
2273 *
unsigned int extended_solution_dim;
2274 * std::map<std::string, unsigned int> boundary_and_centering_dof_numbers;
2278 * Parameters of the problem, taken from a .prm file.
2281 *
const Parameters ¶ms;
2282 *
const Problem &problem;
2284 *
unsigned int number_of_quadrature_points;
2289 * The flag indicating whether the
triangulation was uploaded externally or created within the <code>
run </code> member function.
2292 *
bool triangulation_uploaded;
2298 * Constraints
for Dirichlet boundary conditions.
2305 * std::unique_ptr<SparseDirectUMFPACK> jacobian_matrix_extended_factorization;
2309 * Finite element solution of the problem.
2316 * Value of the wave speed @f$c@f$.
2319 *
double current_wave_speed;
2323 * Solution with an additional term, corresponding to the variable wave_speed.
2330 * Initial guess
for Newton
's iterations.
2333 * SolutionStruct initial_guess;
2335 * TimerOutput computing_timer;
2338 * } // namespace TravelingWave
2344<a name="ann-calculate_profile.cc"></a>
2345<h1>Annotated version of calculate_profile.cc</h1>
2351 * /* -----------------------------------------------------------------------------
2353 * * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
2354 * * Copyright (C) 2024 by Shamil Magomedov
2356 * * This file is part of the deal.II code gallery.
2358 * * -----------------------------------------------------------------------------
2361 * #include "TravelingWaveSolver.h"
2362 * #include "calculate_profile.h"
2364 * namespace TravelingWave
2366 * using namespace dealii;
2370 * 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.
2373 * void compute_limit_sol_left_part(const Parameters ¶meters,
2374 * const double wave_speed,
2377 * const double lambda_0,
2378 * SolutionStruct &LimitSol,
2379 * const double root_sign)
2381 * LimitSolution limit_sol(parameters, lambda_0, u_0, T_0, root_sign);
2382 * limit_sol.set_wave_speed(wave_speed);
2387 * We take more integration points to better resolve the transition layer.
2390 * std::vector<double> t_span(static_cast<unsigned int>(std::abs( 0. - parameters.mesh.interval_left )));
2391 * double finer_mesh_starting_value = -9.1;
2392 * linspace(parameters.mesh.interval_left, finer_mesh_starting_value, t_span);
2393 * std::vector<double> fine_grid(10000);
2394 * linspace(finer_mesh_starting_value + 1e-4, 0., fine_grid);
2395 * t_span.insert(t_span.end(), fine_grid.begin(), fine_grid.end());
2399 * Reverse the order of the elements (because we need to perform back in time integration).
2402 * std::reverse(t_span.begin(), t_span.end());
2404 * state_type lambda_val(1);
2405 * lambda_val[0] = lambda_0; // initial value
2406 * IntegrateSystemAtTimePoints(limit_sol.lambda_vec, limit_sol.t_vec, t_span,
2409 * -1e-2, Integrator_Type::dopri5);
2412 * limit_sol.calculate_u_T_omega();
2416 * Reverse the order of elements
2419 * std::reverse(limit_sol.t_vec.begin(), limit_sol.t_vec.end());
2420 * std::reverse(limit_sol.lambda_vec.begin(), limit_sol.lambda_vec.end());
2421 * std::reverse(limit_sol.u_vec.begin(), limit_sol.u_vec.end());
2422 * std::reverse(limit_sol.T_vec.begin(), limit_sol.T_vec.end());
2423 * std::reverse(limit_sol.omega_vec.begin(), limit_sol.omega_vec.end());
2425 * SaveSolutionIntoFile(limit_sol.lambda_vec, limit_sol.t_vec, "solution_lambda_limit.txt");
2426 * SaveSolutionIntoFile(limit_sol.u_vec, limit_sol.t_vec, "solution_u_limit.txt");
2427 * SaveSolutionIntoFile(limit_sol.T_vec, limit_sol.t_vec, "solution_T_limit.txt");
2428 * SaveSolutionIntoFile(limit_sol.omega_vec, limit_sol.t_vec, "solution_omega_limit.txt");
2430 * LimitSol.reinit(limit_sol.t_vec.size());
2431 * LimitSol.wave_speed = wave_speed;
2432 * for (unsigned int i=0; i < limit_sol.t_vec.size(); ++i)
2434 * LimitSol.x[i] = limit_sol.t_vec[i];
2435 * LimitSol.u[i] = limit_sol.u_vec[i][0];
2436 * LimitSol.T[i] = limit_sol.T_vec[i][0];
2437 * LimitSol.lambda[i] = limit_sol.lambda_vec[i][0];
2444 * Construction of an initial guess for detonation wave solution. The ODE is solved for the ideal system with @f$\delta = 0@f$.
2447 * void compute_initial_guess_detonation(const Parameters ¶ms, SolutionStruct &initial_guess, const double root_sign)
2449 * const Problem &problem = params.problem;
2450 * double current_wave_speed(problem.wave_speed_init);
2452 * { // 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.
2453 * double DeltaT = problem.T_left - problem.T_right;
2454 * double qDT = problem.q - DeltaT;
2455 * current_wave_speed = 1. + problem.epsilon * (problem.u_right - (qDT * qDT + DeltaT) / (2 * qDT));
2458 * double u_0 = problem.u_right;
2459 * double T_0 = problem.T_right;
2460 * double lambda_0 = 0.;
2462 * compute_limit_sol_left_part(params, current_wave_speed, u_0, T_0, lambda_0, initial_guess, root_sign);
2464 * initial_guess.wave_speed = current_wave_speed;
2466 * for (int i = initial_guess.x.size() - 1; i > - 1; --i)
2468 * if (isapprox(initial_guess.x[i], 0.))
2470 * initial_guess.u[i] = problem.u_right;
2471 * initial_guess.T[i] = problem.T_ign;
2472 * initial_guess.lambda[i] = 0.;
2479 * Adding the points to the right part of the interval (w.r.t. @f$\xi = 0@f$).
2482 * unsigned int number_of_additional_points = 5;
2483 * for (unsigned int i = 0; i < number_of_additional_points; ++i)
2485 * initial_guess.x.push_back(params.mesh.interval_right / (std::pow(2., number_of_additional_points - 1 - i)));
2486 * initial_guess.u.push_back(problem.u_right);
2487 * initial_guess.T.push_back(problem.T_right);
2488 * initial_guess.lambda.push_back(0.);
2496 * Construction of a piecewise constant initial guess for deflagration wave solution.
2499 * void compute_initial_guess_deflagration(const Parameters ¶ms, SolutionStruct &initial_guess)
2501 * const Problem &problem = params.problem;
2502 * double current_wave_speed(problem.wave_speed_init);
2504 * double del_Pr_eps = (problem.Pr * 4 * problem.delta / (3 * problem.epsilon));
2505 * double del_Le = (problem.delta / problem.Le);
2507 * auto u_init_guess_func = [&](double x) {
2510 * return problem.u_left;
2514 * return problem.u_right;
2518 * auto T_init_guess_func = [&](double x) {
2521 * return problem.T_left;
2523 * else if (isapprox(x, 0.))
2525 * return problem.T_ign;
2529 * return problem.T_right;
2533 * auto lambda_init_guess_func = [=](double x) {
2536 * return -std::exp(x * std::abs(1 - current_wave_speed) / del_Pr_eps) + 1;
2544 * unsigned int multiplier_for_number_of_points = 7;
2545 * 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 )));
2546 * std::vector<double> x_span(number_of_points);
2547 * linspace(params.mesh.interval_left, params.mesh.interval_right, x_span);
2549 * std::vector<double> u_init_arr(number_of_points);
2550 * std::vector<double> T_init_arr(number_of_points);
2551 * std::vector<double> lambda_init_arr(number_of_points);
2553 * for (unsigned int i = 0; i < number_of_points; ++i)
2555 * u_init_arr[i] = u_init_guess_func(x_span[i]);
2556 * T_init_arr[i] = T_init_guess_func(x_span[i]);
2557 * lambda_init_arr[i] = lambda_init_guess_func(x_span[i]);
2560 * initial_guess.x = x_span;
2561 * initial_guess.u = u_init_arr;
2562 * initial_guess.T = T_init_arr;
2563 * initial_guess.lambda = lambda_init_arr;
2564 * initial_guess.wave_speed = current_wave_speed;
2571 * 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>.
2574 * void calculate_profile(Parameters& parameters,
2575 * const bool continuation_for_delta /* Compute with the continuation. */,
2576 * const double delta_start /* The starting value of delta for the continuation method. */,
2577 * const unsigned int number_of_continuation_points)
2579 * SolutionStruct sol;
2581 * if (parameters.problem.wave_type == 1) // detonation wave
2583 * compute_initial_guess_detonation(parameters, sol);
2585 * else if (parameters.problem.wave_type == 0) // deflagration wave
2587 * compute_initial_guess_deflagration(parameters, sol);
2590 * if (continuation_for_delta == false)
2592 * TravelingWaveSolver wave(parameters, sol);
2593 * std::string filename = "solution_delta-" + Utilities::to_string(parameters.problem.delta) + "_eps-"
2594 * + Utilities::to_string(parameters.problem.epsilon);
2595 * wave.run(filename);
2596 * wave.get_solution(sol);
2598 * else // Run with continuation_for_delta.
2600 * double delta_target = parameters.problem.delta;
2601 * parameters.problem.delta = delta_start;
2603 * std::vector<double> delta_span(number_of_continuation_points);
2607 * Generate a sequence of delta values being uniformly distributed in log10 scale.
2611 * double delta_start_log10 = std::log10(delta_start);
2612 * double delta_target_log10 = std::log10(delta_target);
2614 * std::vector<double> delta_log_span(delta_span.size());
2615 * linspace(delta_start_log10, delta_target_log10, delta_log_span);
2617 * for (unsigned int i = 0; i < delta_span.size(); ++i)
2619 * delta_span[i] = std::pow(10, delta_log_span[i]);
2623 * Triangulation<1> refined_triangulation;
2624 * bool first_iter_flag = true;
2626 * for (double delta : delta_span)
2628 * parameters.problem.delta = delta;
2629 * std::string filename = "solution_delta-" + Utilities::to_string(parameters.problem.delta) + "_eps-"
2630 * + Utilities::to_string(parameters.problem.epsilon);
2632 * TravelingWaveSolver wave(parameters, sol);
2634 * if (first_iter_flag)
2636 * first_iter_flag = false;
2640 * wave.set_triangulation(refined_triangulation);
2643 * wave.run(filename);
2644 * wave.get_solution(sol);
2645 * wave.get_triangulation(refined_triangulation);
2656 * unsigned int sol_length = sol.x.size();
2657 * double u_r = sol.u[sol_length-1]; // Dirichlet boundary condition
2658 * double T_r = sol.T[sol_length-1]; // Dirichlet condition only for detonation case
2659 * double u_l = sol.u[0];
2660 * double T_l = sol.T[0]; // Dirichlet boundary condition
2661 * double wave_speed = sol.wave_speed;
2663 * std::cout << "Error estimates:" << std::endl;
2664 * double DeltaT = T_l - T_r;
2665 * double qDT = parameters.problem.q - DeltaT;
2667 * double wave_speed_formula = 1. + parameters.problem.epsilon * (u_r - (qDT * qDT + DeltaT) / (2 * qDT));
2668 * std::cout << std::setw(18) << std::left << "For wave speed" << " : " << std::setw(5) << wave_speed - wave_speed_formula << std::endl;
2670 * double u_l_formula = DeltaT + u_r - parameters.problem.q;
2671 * std::cout << std::setw(18) << std::left << "For u_l" << " : " << std::setw(5) << u_l - u_l_formula << std::endl;
2676 * } // namespace TravelingWave
2680<a name="ann-calculate_profile.h"></a>
2681<h1>Annotated version of calculate_profile.h</h1>
2687 * /* -----------------------------------------------------------------------------
2689 * * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
2690 * * Copyright (C) 2024 by Shamil Magomedov
2692 * * This file is part of the deal.II code gallery.
2694 * * -----------------------------------------------------------------------------
2697 * #ifndef CALCULATE_PROFILE
2698 * #define CALCULATE_PROFILE
2700 * #include "Parameters.h"
2701 * #include "Solution.h"
2702 * #include "LimitSolution.h"
2703 * #include "IntegrateSystem.h"
2704 * #include "AuxiliaryFunctions.h"
2706 * namespace TravelingWave
2708 * void compute_limit_sol_left_part(const Parameters ¶meters,
2709 * const double wave_speed,
2712 * const double lambda_0,
2713 * SolutionStruct &LimitSol,
2714 * const double root_sign = 1.);
2716 * void compute_initial_guess_detonation(const Parameters ¶ms, SolutionStruct &initial_guess, const double root_sign = 1.);
2717 * void compute_initial_guess_deflagration(const Parameters ¶ms, SolutionStruct &initial_guess);
2719 * void calculate_profile(Parameters& parameters,
2720 * const bool continuation_for_delta=false /* Compute with the continuation. */,
2721 * const double delta_start=0.01 /* The starting value of delta for the continuation method. */,
2722 * const unsigned int number_of_continuation_points=10);
2724 * } // namespace TravelingWave
2730<a name="ann-main.cc"></a>
2731<h1>Annotated version of main.cc</h1>
2737 * /* -----------------------------------------------------------------------------
2739 * * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
2740 * * Copyright (C) 2024 by Shamil Magomedov
2742 * * This file is part of the deal.II code gallery.
2744 * * -----------------------------------------------------------------------------
2747 * #include "calculate_profile.h"
2749 * int main(int argc, char *argv[])
2754 * using namespace TravelingWave;
2756 * Parameters parameters;
2758 * std::string prm_filename = "ParametersList.prm";
2763 * Check if file argv[1] exists.
2766 * if (file_exists(argv[1]))
2768 * prm_filename = argv[1];
2772 * std::string errorMessage = "File \"" + std::string(argv[1]) + "\" is not found.";
2773 * throw std::runtime_error(errorMessage);
2780 * Check if the file "ParametersList.prm" exists in the current or in the parent directory.
2783 * if (!(file_exists(prm_filename) || file_exists("../" + prm_filename)))
2785 * std::string errorMessage = "File \"" + prm_filename + "\" is not found.";
2786 * throw std::runtime_error(errorMessage);
2790 * if (!file_exists(prm_filename))
2792 * prm_filename = "../" + prm_filename;
2797 * std::cout << "Reading parameters... " << std::flush;
2798 * ParameterAcceptor::initialize(prm_filename);
2799 * std::cout << "done" << std::endl;
2801 * calculate_profile(parameters, /* With continuation_for_delta */ false, 0.1, 3);
2804 * catch (std::exception &exc)
2806 * std::cerr << std::endl
2808 * << "----------------------------------------------------"
2810 * std::cerr << "Exception on processing: " << std::endl
2811 * << exc.what() << std::endl
2812 * << "Aborting!" << std::endl
2813 * << "----------------------------------------------------"
2819 * std::cerr << std::endl
2821 * << "----------------------------------------------------"
2823 * std::cerr << "Unknown exception!" << std::endl
2824 * << "Aborting!" << std::endl
2825 * << "----------------------------------------------------"
2835<a name="ann-plot.py"></a>
2836<h1>Annotated version of plot.py</h1>
2838## -----------------------------------------------------------------------------
2840## SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
2841## Copyright (C) 2024 by Shamil Magomedov
2843## This file is part of the deal.II code gallery.
2845## -----------------------------------------------------------------------------
2849import matplotlib.pyplot as plt
2855 # 'lines.marker
' : 'x
',
2857 'lines.markersize
' : 4,
2858 'lines.linewidth
' : 1,
2859 'axes.labelsize
': 16,
2860 # 'textfontsize
': 12,
2862 'legend.fontsize
': 16,
2863 'xtick.labelsize
': 14,
2864 'ytick.labelsize
': 14,
2865 'text.usetex
': True,
2866 'figure.figsize
': [9,6],
2870plt.rcParams.update(plot_params)
2873if len(sys.argv) > 1:
2875 filename = sys.argv[1]
2877 if os.path.exists(filename):
2878 data = np.loadtxt(filename, np.float64)
2879 data_unique = np.unique(data, axis=0)
2880 data_unique = np.array(sorted(data_unique, key=lambda x : x[0]))
2881 x = data_unique[:, 0]
2882 u_sol = data_unique[:, 1]
2883 T_sol = data_unique[:, 2]
2884 lambda_sol = data_unique[:, 3]
2886 fig, ax = plt.subplots(nrows=1, ncols=1)
2888 ax.scatter(x, u_sol, label=r"@f$u@f$", color='blue
')
2889 ax.scatter(x, T_sol, label=r"@f$T@f$", color='red
')
2890 ax.scatter(x, lambda_sol, label=r"@f$\lambda@f$", color='green
')
2893 # Plot of limit solutions for the detonation case. Uncomment, if needed.
2894 #===============================================================#
2897 path_to_solution_files = os.path.split(filename)[0]
2898 u_limit_path = os.path.join(path_to_solution_files,
'solution_u_limit.txt')
2899 T_limit_path = os.path.join(path_to_solution_files,
'solution_T_limit.txt')
2900 lambda_limit_path = os.path.join(path_to_solution_files,
'solution_lambda_limit.txt')
2902 if os.path.exists(u_limit_path):
2903 u_limit = np.loadtxt(u_limit_path, np.float64)
2904 ax.plot(u_limit[:, 0], u_limit[:, 1], label=r
"@f$u_{\mathrm{lim}}@f$", color=
'blue')
2905 ax.plot([0, x[-1]], [u_sol[-1], u_sol[-1]], color=
'blue')
2907 print(
"No such file:", u_limit_path)
2909 if os.path.exists(T_limit_path):
2910 T_limit = np.loadtxt(T_limit_path, np.float64)
2911 ax.plot(T_limit[:, 0], T_limit[:, 1], label=r
"@f$T_{\mathrm{lim}}@f$", color=
'red')
2912 ax.plot([0, x[-1]], [T_sol[-1], T_sol[-1]], color=
'red')
2914 print(
"No such file:", T_limit_path)
2916 if os.path.exists(lambda_limit_path):
2917 lambda_limit = np.loadtxt(lambda_limit_path, np.float64)
2918 ax.plot(lambda_limit[:, 0], lambda_limit[:, 1], label=r
"@f$\lambda_{\mathrm{lim}}@f$", color=
'green')
2919 ax.plot([0, x[-1]], [lambda_sol[-1], lambda_sol[-1]], color=
'green')
2921 print(
"No such file:", lambda_limit_path)
2925 #===============================================================#
2928 ax.set_xlabel(r"@f$\xi@f$")
2929 ax.set_ylabel(r"@f$u, T, \lambda@f$")
2932 # plt.savefig("fast_deflagration_delta_0.01.png", bbox_inches='tight
', dpi=500)
2933 # plt.savefig('slow_deflagration_delta_0.01.png
', bbox_inches='tight
', dpi=500)
2934 # plt.savefig('detonation_delta_0.01.png
', bbox_inches='tight
', dpi=500)
2938 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)
unsigned int n_active_cells() const
void refine_global(const unsigned int times=1)
virtual void execute_coarsening_and_refinement() override
virtual void copy_triangulation(const ::Triangulation< dim, spacedim > &other_tria) override
virtual bool prepare_coarsening_and_refinement() override
virtual void clear() override
__global__ void set(Number *val, const Number s, const size_type N)
@ 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