[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
bound_preserving_limiter_tests.cpp
1 #include <stdlib.h> /* srand, rand */
2 #include <iostream>
3 
4 #include <deal.II/base/convergence_table.h>
5 #include <deal.II/fe/fe_values.h>
6 
7 #include "bound_preserving_limiter_tests.h"
8 
9 #include "physics/initial_conditions/initial_condition_function.h"
10 #include "flow_solver/flow_solver_factory.h"
11 
12 namespace PHiLiP {
13 namespace Tests {
14 
15 template <int dim, int nstate>
17  const PHiLiP::Parameters::AllParameters* const parameters_input,
18  const dealii::ParameterHandler& parameter_handler_input)
19  :
20  TestsBase::TestsBase(parameters_input)
21  , parameter_handler(parameter_handler_input)
22 {}
23 
24 template <int dim, int nstate>
25 double BoundPreservingLimiterTests<dim, nstate>::calculate_uexact(const dealii::Point<dim> qpoint, const dealii::Tensor<1, 3, double> adv_speeds, double final_time) const
26 {
28  using flow_case_enum = Parameters::FlowSolverParam::FlowCaseType;
29  flow_case_enum flow_case = all_parameters_new.flow_solver_param.flow_case_type;
30  const double pi = atan(1) * 4.0;
31 
32  double uexact = 1.0;
33  if (flow_case == Parameters::FlowSolverParam::FlowCaseType::low_density_2d && dim == 2) {
34  uexact = 1.00 + 0.99 * sin(qpoint[0] + qpoint[1] - (2.00 * final_time));
35  }
36  else {
37  for (int idim = 0; idim < dim; idim++) {
38  if (flow_case == Parameters::FlowSolverParam::FlowCaseType::burgers_limiter)
39  uexact *= cos(pi * (qpoint[idim] - final_time));//for grid 1-3
40  if (flow_case == Parameters::FlowSolverParam::FlowCaseType::advection_limiter)
41  uexact *= sin(2.0 * pi * (qpoint[idim] - adv_speeds[idim] * final_time));//for grid 1-3
42  }
43  }
44 
45  return uexact;
46 }
47 
48 template <int dim, int nstate>
50  std::shared_ptr<DGBase<dim, double>> dg,
51  const int poly_degree,
52  const double final_time) const
53 {
54  // Overintegrate the error to make sure there is not integration error in the error estimate
55  int overintegrate = 10;
56  dealii::QGauss<dim> quad_extra(poly_degree + 1 + overintegrate);
57  dealii::FEValues<dim, dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra,
58  dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
59  const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
60  std::array<double, nstate> soln_at_q;
61 
62  double l2error = 0.0;
63 
64  // Integrate every cell and compute L2
65  std::vector<dealii::types::global_dof_index> dofs_indices(fe_values_extra.dofs_per_cell);
66  const dealii::Tensor<1, 3, double> adv_speeds = Parameters::ManufacturedSolutionParam::get_default_advection_vector();
67  for (auto cell = dg->dof_handler.begin_active(); cell != dg->dof_handler.end(); ++cell) {
68  if (!cell->is_locally_owned()) continue;
69 
70  fe_values_extra.reinit(cell);
71  cell->get_dof_indices(dofs_indices);
72 
73  for (unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
74 
75  std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
76  for (unsigned int idof = 0; idof < fe_values_extra.dofs_per_cell; ++idof) {
77  const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
78  soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
79  }
80 
81  const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
82  double uexact = calculate_uexact(qpoint, adv_speeds, final_time);
83  l2error += pow(soln_at_q[0] - uexact, 2) * fe_values_extra.JxW(iquad);
84  }
85  }
86  const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error, this->mpi_communicator));
87  return l2error_mpi_sum;
88 }
89 
90 template <int dim, int nstate>
92 {
93  pcout << " Running Bound Preserving Limiter test. " << std::endl;
94  pcout << dim << " " << nstate << std::endl;
96 
97  int test_result = 1;
98 
99  if (!all_parameters_new.limiter_param.use_OOA) {
100  test_result = run_full_limiter_test();
101  }
102  else {
103  test_result = run_convergence_test();
104  }
105  return test_result; //if got to here means passed the test, otherwise would've failed earlier
106 }
107 
108 template <int dim, int nstate>
110 {
111  pcout << "\n" << "Creating FlowSolver" << std::endl;
112 
115 
116  using flow_case_enum = Parameters::FlowSolverParam::FlowCaseType;
117  flow_case_enum flow_case = all_parameters_new.flow_solver_param.flow_case_type;
118  const double pi = atan(1) * 4.0;
119  if (flow_case == Parameters::FlowSolverParam::FlowCaseType::low_density_2d) {
121  param.flow_solver_param.grid_right_bound = 2.0 * pi;
122  }
123 
124  std::unique_ptr<FlowSolver::FlowSolver<dim, nstate>> flow_solver = FlowSolver::FlowSolverFactory<dim, nstate>::select_flow_case(&param, parameter_handler);
125  flow_solver->run();
126 
127  return 0;
128 }
129 
130 template <int dim, int nstate>
132 {
135 
136  const unsigned int n_grids = manu_grid_conv_param.number_of_grids;
137  dealii::ConvergenceTable convergence_table;
138  std::vector<double> grid_size(n_grids);
139  std::vector<double> soln_error(n_grids);
140 
141  for (unsigned int igrid = 0; igrid < n_grids; igrid++) {
142 
143  pcout << "\n" << "Creating FlowSolver" << std::endl;
144 
147 
148  using flow_case_enum = Parameters::FlowSolverParam::FlowCaseType;
149  flow_case_enum flow_case = all_parameters_new.flow_solver_param.flow_case_type;
150  const double pi = atan(1) * 4.0;
151 
152  if (flow_case == Parameters::FlowSolverParam::FlowCaseType::low_density_2d) {
154  param.flow_solver_param.grid_right_bound = 2.0 * pi;
155  }
156 
157  std::unique_ptr<FlowSolver::FlowSolver<dim, nstate>> flow_solver = FlowSolver::FlowSolverFactory<dim, nstate>::select_flow_case(&param, parameter_handler);
158  const unsigned int n_global_active_cells = flow_solver->dg->triangulation->n_global_active_cells();
159  const int poly_degree = all_parameters_new.flow_solver_param.poly_degree;
160  const double final_time = all_parameters_new.flow_solver_param.final_time;
161 
162  flow_solver->run();
163 
164  // output results
165  const unsigned int n_dofs = flow_solver->dg->dof_handler.n_dofs();
166  this->pcout << "Dimension: " << dim
167  << "\t Polynomial degree p: " << poly_degree
168  << std::endl
169  << "Grid number: " << igrid + 1 << "/" << n_grids
170  << ". Number of active cells: " << n_global_active_cells
171  << ". Number of degrees of freedom: " << n_dofs
172  << std::endl;
173 
174  const double l2error_mpi_sum = calculate_l2error(flow_solver->dg, poly_degree, final_time);
175 
176  // Convergence table
177  const double dx = 1.0 / pow(n_dofs, (1.0 / dim));
178  grid_size[igrid] = dx;
179  soln_error[igrid] = l2error_mpi_sum;
180 
181  convergence_table.add_value("p", poly_degree);
182  convergence_table.add_value("cells", n_global_active_cells);
183  convergence_table.add_value("DoFs", n_dofs);
184  convergence_table.add_value("dx", dx);
185  convergence_table.add_value("soln_L2_error", l2error_mpi_sum);
186 
187  this->pcout << " Grid size h: " << dx
188  << " L2-soln_error: " << l2error_mpi_sum
189  << " Residual: " << flow_solver->ode_solver->residual_norm
190  << std::endl;
191 
192  if (igrid > 0) {
193  const double slope_soln_err = log(soln_error[igrid] / soln_error[igrid - 1])
194  / log(grid_size[igrid] / grid_size[igrid - 1]);
195  this->pcout << "From grid " << igrid - 1
196  << " to grid " << igrid
197  << " dimension: " << dim
198  << " polynomial degree p: " << poly_degree
199  << std::endl
200  << " solution_error1 " << soln_error[igrid - 1]
201  << " solution_error2 " << soln_error[igrid]
202  << " slope " << slope_soln_err
203  << std::endl;
204  }
205 
206  this->pcout << " ********************************************"
207  << std::endl
208  << " Convergence rates for p = " << poly_degree
209  << std::endl
210  << " ********************************************"
211  << std::endl;
212  convergence_table.evaluate_convergence_rates("soln_L2_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
213  convergence_table.set_scientific("dx", true);
214  convergence_table.set_scientific("soln_L2_error", true);
215  if (this->pcout.is_active()) convergence_table.write_text(this->pcout.get_stream());
216  }//end of grid loop
217  return 0;
218 }
219 
220 #if PHILIP_DIM==1
222 #elif PHILIP_DIM==2
226 #endif
227 
228 } // Tests namespace
229 } // PHiLiP namespace
FlowCaseType
Selects the flow case to be simulated.
double final_time
Final solution time.
double calculate_l2error(std::shared_ptr< DGBase< dim, double >> flow_solver_dg, const int poly_degree, const double final_time) const
Calculate and return the L2 Error.
LimiterParam limiter_param
Contains parameters for limiter.
FlowCaseType flow_case_type
Selected FlowCaseType from the input file.
static dealii::Tensor< 1, 3, double > get_default_advection_vector()
gets the default advection vector
FlowSolverParam flow_solver_param
Contains the parameters for simulation cases (flow solver test)
Parameters related to the manufactured convergence study.
Class used to run tests that verify implementation of bound preserving limiters.
const MPI_Comm mpi_communicator
MPI communicator.
Definition: tests.h:39
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.
Files for the baseline physics.
Definition: ADTypes.hpp:10
bool use_OOA
Flag to perform convergence analysis for Limiter Tests (ie. burgers_limiter, advection_limiter, low_density_2d)
int run_convergence_test() const
Runs convergence test and prints out results in console.
unsigned int poly_degree
Polynomial order (P) of the basis functions for DG.
Main parameter class that contains the various other sub-parameter classes.
BoundPreservingLimiterTests(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler &parameter_handler_input)
Constructor.
double grid_left_bound
Left bound of domain for hyper_cube mesh based cases.
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
static std::unique_ptr< FlowSolver< dim, nstate > > select_flow_case(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler &parameter_handler_input)
Factory to return the correct flow solver given input file.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: tests.h:20
int run_full_limiter_test() const
Runs full test and outputs VTK files.
int number_of_mesh_refinements
Number of refinements for naca0012 and Gaussian bump based cases.
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
double grid_right_bound
Right bound of domain for hyper_cube mesh based cases.
double calculate_uexact(const dealii::Point< dim > qpoint, const dealii::Tensor< 1, 3, double > adv_speeds, double final_time) const
Calculate and return the exact value at the point depending on the case being run.
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
Base class of all the tests.
Definition: tests.h:17