1 #include "root_finding_rrk_ode_solver.h" 2 #include "physics/euler.h" 3 #include "physics/physics_factory.h" 8 template <
int dim,
typename real,
typename MeshType>
15 template <
int dim,
typename real,
typename MeshType>
18 const std::vector<dealii::LinearAlgebra::distributed::Vector<double>> &rk_stage,
19 const dealii::LinearAlgebra::distributed::Vector<double> &solution_update
23 const bool do_output = (dg->all_parameters->ode_solver_param.rrk_root_solver_output == Parameters::OutputEnum::verbose);
27 dealii::LinearAlgebra::distributed::Vector<double> step_direction;
28 step_direction.reinit(rk_stage[0]);
36 if (do_output) this->
pcout <<
"Entropy change estimate: " << std::setprecision(16) << entropy_change_est << std::endl;
39 const dealii::LinearAlgebra::distributed::Vector<double> u_n = solution_update;
44 const bool use_secant =
true;
45 bool secant_failed =
false;
49 const double conv_tol = dg->all_parameters->ode_solver_param.relaxation_runge_kutta_root_tolerance;
51 const int iter_limit = 100;
56 double residual = 1.0;
57 double gamma_k = initial_guess_1;
58 double gamma_km1 = initial_guess_0;
59 double r_gamma_k =
compute_root_function(gamma_k, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
60 double r_gamma_km1 =
compute_root_function(gamma_km1, u_n, step_direction, num_entropy_n,entropy_change_est,dg);
62 while ((residual > conv_tol) && (iter_counter < iter_limit)){
63 if (r_gamma_km1 == r_gamma_k){
64 if (do_output) this->
pcout <<
" Roots are identical. Multiplying gamma_k by 1.001 and recomputing..." << std::endl;
66 r_gamma_km1 =
compute_root_function(gamma_km1, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
67 r_gamma_k =
compute_root_function(gamma_k, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
69 if ((gamma_k < 0.5) || (gamma_k > 1.5)) {
70 if (do_output) this->
pcout <<
" Gamma is far from 1. Setting gamma_k = 1 and contining iterations." << std::endl;
72 r_gamma_k =
compute_root_function(gamma_k, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
76 gamma_kp1 = gamma_k - r_gamma_k * (gamma_k - gamma_km1)/(r_gamma_k-r_gamma_km1);
77 residual = abs(gamma_kp1 - gamma_k);
83 r_gamma_km1 = r_gamma_k;
84 r_gamma_k =
compute_root_function(gamma_k, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
88 this->
pcout <<
"Iter: " << iter_counter
89 <<
" gamma_k: " << gamma_k
90 <<
" residual: " << residual << std::endl;
93 if (isnan(gamma_k) || isnan(gamma_km1)) {
94 if (do_output) this->
pcout <<
" NaN detected. Restarting iterations from 1.0." << std::endl;
96 r_gamma_k =
compute_root_function(gamma_k, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
97 gamma_km1 = 1.0 + 1E-5;
98 r_gamma_km1 =
compute_root_function(gamma_km1, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
104 if (iter_limit == iter_counter) {
105 this->
pcout <<
"Secant method failed to find a root within the iteration limit. Restarting with bisection method." << std::endl;
106 secant_failed =
true;
109 if (!use_secant || secant_failed) {
116 double root_l_limit =
compute_root_function(l_limit, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
117 double root_u_limit =
compute_root_function(u_limit, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
119 double residual = 1.0;
121 while ((residual > conv_tol) && (iter_counter < iter_limit)){
122 if (root_l_limit * root_u_limit > 0){
123 this->
pcout <<
"Bisection solver: No root in the interval. Increasing interval size..." << std::endl;
128 gamma_kp1 = 0.5 * (l_limit + u_limit);
129 if (do_output) this->
pcout <<
"Iter: " << iter_counter;
130 if (do_output) this->
pcout <<
" Gamma by bisection is " << gamma_kp1;
131 double root_at_gamma =
compute_root_function(gamma_kp1, u_n, step_direction, num_entropy_n, entropy_change_est,dg);
132 if (root_at_gamma < 0) {
134 root_l_limit = root_at_gamma;
137 root_u_limit = root_at_gamma;
139 residual = u_limit-l_limit;
140 if (do_output) this->
pcout <<
" With residual " << residual << std::endl;
145 if (iter_limit == iter_counter) {
146 this->
pcout <<
"Error: Iteration limit reached and root finding was not successful." << std::endl;
147 secant_failed =
true;
154 const double FR_entropy_contribution = gamma_kp1 *(
160 dealii::LinearAlgebra::distributed::Vector<double> temp = u_n;
161 temp.add(gamma_kp1, step_direction);
163 const double FR_entropy_this_tstep = num_entropy_npgamma - num_entropy_n + FR_entropy_contribution;
166 this->
pcout <<
"Convergence reached!" << std::endl;
167 this->
pcout <<
" Entropy at prev timestep (DG) : " << num_entropy_n << std::endl
168 <<
" Entropy at current timestep (DG) : " << num_entropy_npgamma << std::endl;
169 this->
pcout <<
" Estimate entropy change (M norm): " << entropy_change_est << std::endl
170 <<
" Actual entropy change (DG): " << num_entropy_npgamma - num_entropy_n << std::endl
171 <<
" FR contribution: " << FR_entropy_contribution << std::endl
172 <<
" Corrected entropy change (FR): " << FR_entropy_this_tstep << std::endl
182 template <
int dim,
typename real,
typename MeshType>
185 const dealii::LinearAlgebra::distributed::Vector<double> &u_n,
186 const dealii::LinearAlgebra::distributed::Vector<double> &step_direction,
187 const double num_entropy_n,
188 const double entropy_change_est,
191 dealii::LinearAlgebra::distributed::Vector<double> temp = u_n;
192 temp.add(gamma, step_direction);
194 return num_entropy_np1 - num_entropy_n - gamma * entropy_change_est;
198 template <
int dim,
typename real,
typename MeshType>
200 const dealii::LinearAlgebra::distributed::Vector<double> &u,
210 template <
int dim,
typename real,
typename MeshType>
212 const dealii::LinearAlgebra::distributed::Vector<double> &u,
217 if (dg->get_max_fe_degree() != dg->get_min_fe_degree()) {
219 this->
pcout <<
"ERROR: compute_integrated_quantities() is untested for nonuniform p. Aborting..." << std::endl;
224 if (parameters_euler.
pde_type != Parameters::AllParameters::PartialDifferentialEquation::euler
226 parameters_euler.
pde_type != Parameters::AllParameters::PartialDifferentialEquation::navier_stokes){
227 this->
pcout <<
"ERROR: Only implemented for Euler or Navier-Stokes. Aborting..." << std::endl;
233 const int nstate = dim+2;
234 double integrated_quantity = 0.0;
236 const double poly_degree = dg->all_parameters->flow_solver_param.poly_degree;
238 const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell;
239 const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size();
240 const unsigned int n_shape_fns = n_dofs_cell / nstate;
244 dg->oneD_quadrature_collection[poly_degree]);
249 dg->oneD_quadrature_collection[poly_degree]);
253 dg->high_order_grid->oneD_grid_nodes);
255 dg->oneD_quadrature_collection[poly_degree],
256 dg->oneD_face_quadrature);
258 std::vector<dealii::types::global_dof_index> dofs_indices (n_dofs_cell);
260 const std::vector<double> &quad_weights = dg->volume_quadrature_collection[poly_degree].get_weights();
264 const bool store_vol_flux_nodes =
false;
265 const bool store_surf_flux_nodes =
false;
267 auto metric_cell = dg->high_order_grid->dof_handler_grid.begin_active();
270 for (
auto cell = dg->dof_handler.begin_active(); cell!= dg->dof_handler.end(); ++cell, ++metric_cell) {
271 if (!cell->is_locally_owned())
continue;
272 cell->get_dof_indices (dofs_indices);
275 const dealii::FESystem<dim> &fe_metric = dg->high_order_grid->fe_system;
276 const unsigned int n_metric_dofs = fe_metric.dofs_per_cell;
277 const unsigned int n_grid_nodes = n_metric_dofs / dim;
278 std::vector<dealii::types::global_dof_index> metric_dof_indices(n_metric_dofs);
279 metric_cell->get_dof_indices (metric_dof_indices);
280 std::array<std::vector<double>,dim> mapping_support_points;
281 for(
int idim=0; idim<dim; idim++){
282 mapping_support_points[idim].resize(n_grid_nodes);
286 const std::vector<unsigned int > &index_renumbering = dealii::FETools::hierarchic_to_lexicographic_numbering<dim>(dg->max_grid_degree);
287 for (
unsigned int idof = 0; idof< n_metric_dofs; ++idof) {
288 const double val = (dg->high_order_grid->volume_nodes[metric_dof_indices[idof]]);
289 const unsigned int istate = fe_metric.system_to_component_index(idof).first;
290 const unsigned int ishape = fe_metric.system_to_component_index(idof).second;
291 const unsigned int igrid_node = index_renumbering[ishape];
292 mapping_support_points[istate][igrid_node] = val;
300 n_quad_pts, n_grid_nodes,
301 mapping_support_points,
303 dg->all_parameters->use_invariant_curl_form);
310 std::array<std::vector<double>,nstate> soln_coeff;
311 for (
unsigned int idof = 0; idof < n_dofs_cell; ++idof) {
312 const unsigned int istate = dg->fe_collection[poly_degree].system_to_component_index(idof).first;
313 const unsigned int ishape = dg->fe_collection[poly_degree].system_to_component_index(idof).second;
315 soln_coeff[istate].resize(n_shape_fns);
318 soln_coeff[istate][ishape] = u(dofs_indices[idof]);
323 std::array<std::vector<double>,nstate> soln_at_q_vect;
324 for(
int istate=0; istate<nstate; istate++){
325 soln_at_q_vect[istate].resize(n_quad_pts);
332 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
334 std::array<double,nstate> soln_at_q;
336 for(
int istate=0; istate<nstate; istate++){
337 soln_at_q[istate] = soln_at_q_vect[istate][iquad];
343 const double quadrature_entropy = euler_physics->compute_numerical_entropy_function(soln_at_q);
344 integrated_quantity += quadrature_entropy * quad_weights[iquad] * metric_oper.
det_Jac_vol[iquad];
349 integrated_quantity = dealii::Utilities::MPI::sum(integrated_quantity, this->
mpi_communicator);
351 return integrated_quantity;
354 template <
int dim,
typename real,
typename MeshType>
357 const std::vector<dealii::LinearAlgebra::distributed::Vector<double>> &rk_stage,
358 const bool use_M_norm_for_entropy_change_est)
const 360 double entropy_change_estimate = 0;
362 for (
int istage = 0; istage<this->
n_rk_stages; ++istage){
366 dealii::LinearAlgebra::distributed::Vector<double> mass_matrix_times_rk_stage(dg->solution);
367 if(dg->all_parameters->use_inverse_mass_on_the_fly)
369 if (use_M_norm_for_entropy_change_est)
370 dg->apply_global_mass_matrix(rk_stage[istage], mass_matrix_times_rk_stage,
375 dg->apply_global_mass_matrix(rk_stage[istage],mass_matrix_times_rk_stage);
379 dg->global_mass_matrix.vmult( mass_matrix_times_rk_stage, rk_stage[istage]);
384 double entropy = entropy_var_hat_global * mass_matrix_times_rk_stage;
386 entropy_change_estimate += this->
butcher_tableau->get_b(istage) * entropy;
389 return dt * entropy_change_estimate;
const int n_rk_stages
Number of RK stages.
PartialDifferentialEquation pde_type
Store the PDE type to be solved.
void build_1D_volume_operator(const dealii::FESystem< 1, 1 > &finite_element, const dealii::Quadrature< 1 > &quadrature)
Assembles the one dimensional operator.
dealii::LinearAlgebra::distributed::Vector< double > compute_entropy_vars(const dealii::LinearAlgebra::distributed::Vector< double > &u, std::shared_ptr< DGBase< dim, real, MeshType >> dg) const
Return the entropy variables from a solution vector u.
real compute_root_function(const double gamma, const dealii::LinearAlgebra::distributed::Vector< double > &u_n, const dealii::LinearAlgebra::distributed::Vector< double > &d, const double eta_n, const double e, std::shared_ptr< DGBase< dim, real, MeshType >> dg) const
Compute the remainder of the root function Ranocha 2020 Eq. 2.4.
void build_1D_volume_operator(const dealii::FESystem< 1, 1 > &finite_element, const dealii::Quadrature< 1 > &quadrature)
Assembles the one dimensional operator.
RootFindingRRKODESolver(std::shared_ptr< RKTableauBase< dim, real, MeshType >> rk_tableau_input)
Default constructor that will set the constants.
real relaxation_parameter
Relaxation Runge-Kutta parameter gamma^n.
Files for the baseline physics.
real compute_integrated_numerical_entropy(const dealii::LinearAlgebra::distributed::Vector< double > &u, std::shared_ptr< DGBase< dim, real, MeshType >> dg) const
Compute numerical entropy by integrating over quadrature points.
void build_1D_shape_functions_at_grid_nodes(const dealii::FESystem< 1, 1 > &finite_element, const dealii::Quadrature< 1 > &quadrature)
Constructs the volume operator and gradient operator.
Main parameter class that contains the various other sub-parameter classes.
dealii::ConditionalOStream pcout
Parallel std::cout that only outputs on mpi_rank==0.
std::vector< real > det_Jac_vol
The determinant of the metric Jacobian at volume cubature nodes.
Base metric operators class that stores functions used in both the volume and on surface.
real FR_entropy_cumulative
Storing cumulative entropy change for output.
The mapping shape functions evaluated at the desired nodes (facet set included in volume grid nodes f...
Euler equations. Derived from PhysicsBase.
dealii::FullMatrix< double > oneD_vol_operator
Stores the one dimensional volume operator.
static std::shared_ptr< PhysicsBase< dim, nstate, real > > create_Physics(const Parameters::AllParameters *const parameters_input, std::shared_ptr< ModelBase< dim, nstate, real > > model_input=nullptr)
Factory to return the correct physics given input file.
Base class for storing the RK method.
real compute_entropy_change_estimate(const real dt, std::shared_ptr< DGBase< dim, real, MeshType >> dg, const std::vector< dealii::LinearAlgebra::distributed::Vector< double >> &rk_stage, const bool use_M_norm_for_entropy_change_est=true) const
Compute the estimated entropy change during a timestep.
void build_volume_metric_operators(const unsigned int n_quad_pts, const unsigned int n_metric_dofs, const std::array< std::vector< real >, dim > &mapping_support_points, mapping_shape_functions< dim, n_faces, real > &mapping_basis, const bool use_invariant_curl_form=false)
Builds the volume metric operators.
DGBase is independent of the number of state variables.
std::vector< dealii::LinearAlgebra::distributed::Vector< double > > rk_stage_solution
Storage for the solution at each Runge-Kutta stage.
std::shared_ptr< RKTableauBase< dim, real, MeshType > > butcher_tableau
Store pointer to RK tableau.
void build_1D_shape_functions_at_flux_nodes(const dealii::FESystem< 1, 1 > &finite_element, const dealii::Quadrature< 1 > &quadrature, const dealii::Quadrature< 0 > &face_quadrature)
Constructs the volume, gradient, surface, and surface gradient operator.
const MPI_Comm mpi_communicator
MPI communicator.
void matrix_vector_mult_1D(const std::vector< real > &input_vect, std::vector< real > &output_vect, const dealii::FullMatrix< double > &basis_x, const bool adding=false, const double factor=1.0)
Apply the matrix vector operation using the 1D operator in each direction.
Relaxation Runge-Kutta ODE solver base class.
Projection operator corresponding to basis functions onto M-norm (L2).
real compute_relaxation_parameter(const real dt, std::shared_ptr< DGBase< dim, real, MeshType >> dg, const std::vector< dealii::LinearAlgebra::distributed::Vector< double >> &rk_stage, const dealii::LinearAlgebra::distributed::Vector< double > &solution_update) override
real compute_numerical_entropy(const dealii::LinearAlgebra::distributed::Vector< double > &u, std::shared_ptr< DGBase< dim, real, MeshType >> dg) const
Compute numerical entropy.