[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
euler_gaussian_bump.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 "euler_gaussian_bump.h"
8 
9 #include "physics/initial_conditions/initial_condition_function.h"
10 #include "physics/euler.h"
11 
12 #include "flow_solver/flow_solver_factory.h"
13 
14 
15 namespace PHiLiP {
16 namespace Tests {
17 
18 template <int dim, int nstate>
20  const Parameters::AllParameters *const parameters_input,
21  const dealii::ParameterHandler &parameter_handler_input)
22  :
23  TestsBase::TestsBase(parameters_input)
24  , parameter_handler(parameter_handler_input)
25 {}
26 
27 template<int dim, int nstate>
29 ::run_test () const
30 {
31  int convergence_order_achieved = 0;
32  double run_test_output = run_euler_gaussian_bump(); // run_euler_gaussian_bump() can return either enthalpy or the convergence order
33  if (abs(run_test_output) > 1e-15) // If run_euler_gaussian_bump() returns non zero
34  {
35  convergence_order_achieved = 1; // test failed
36  }
37  return convergence_order_achieved;
38 }
39 
40 template<int dim, int nstate>
43 {
45  using GridEnum = ManParam::GridEnum;
47 
48  Assert(dim == param.dimension, dealii::ExcDimensionMismatch(dim, param.dimension));
49  Assert(dim == 2, dealii::ExcDimensionMismatch(dim, param.dimension));
50  //Assert(param.pde_type != param.PartialDifferentialEquation::euler, dealii::ExcNotImplemented());
51  //if (param.pde_type == param.PartialDifferentialEquation::euler) return 1;
52 
53  ManParam manu_grid_conv_param = param.manufactured_convergence_study_param;
54 
55  const unsigned int p_start = manu_grid_conv_param.degree_start;
56  const unsigned int p_end = manu_grid_conv_param.degree_end;
57 
58  const unsigned int n_grids = manu_grid_conv_param.number_of_grids;
59 
60  Physics::Euler<dim,nstate,double> euler_physics_double
62  &param,
63  param.euler_param.ref_length,
64  param.euler_param.gamma_gas,
65  param.euler_param.mach_inf,
66  param.euler_param.angle_of_attack,
67  param.euler_param.side_slip_angle);
68 
69  std::string error_string;
70  bool has_residual_converged = true;
71  double artificial_dissipation_max_coeff = 0.0;
72  double last_error=10;
73  std::vector<int> fail_conv_poly;
74  std::vector<double> fail_conv_slop;
75  std::vector<dealii::ConvergenceTable> convergence_table_vector;
76 
77  for (unsigned int poly_degree = p_start; poly_degree <= p_end; ++poly_degree) {
78  // p0 tends to require a finer grid to reach asymptotic region
79 
80  std::vector<double> error(n_grids);
81  std::vector<double> grid_size(n_grids);
82 
83  dealii::ConvergenceTable convergence_table;
84 
85  const std::vector<int> n_1d_cells = get_number_1d_cells(n_grids);
86  param.flow_solver_param.number_of_subdivisions_in_x_direction = n_1d_cells[0] * 4;
87  param.flow_solver_param.number_of_subdivisions_in_y_direction = n_1d_cells[0];
88 
89  for (unsigned int igrid=0; igrid<n_grids; ++igrid) {
90 
91  const double solution_degree = poly_degree;
92  const double grid_degree = solution_degree+1;
93 
94  param.flow_solver_param.poly_degree = solution_degree;
95  param.flow_solver_param.max_poly_degree_for_adaptation = solution_degree;
96  param.flow_solver_param.grid_degree = grid_degree;
97  param.flow_solver_param.number_of_mesh_refinements = igrid;
98 
99  pcout << "\n" << "************************************" << "\n" << "POLYNOMIAL DEGREE " << solution_degree
100  << ", GRID NUMBER " << (igrid+1) << "/" << n_grids << "\n" << "************************************" << std::endl;
101 
102  pcout << "\n" << "Creating FlowSolver" << std::endl;
103 
104  std::unique_ptr<FlowSolver::FlowSolver<dim,nstate>> flow_solver = FlowSolver::FlowSolverFactory<dim,nstate>::select_flow_case(&param, parameter_handler);
105 
106  flow_solver->run();
107 
108  // Overintegrate the error to make sure there is not integration error in the error estimate
109  int overintegrate = 10;
110  dealii::QGauss<dim> quad_extra(flow_solver->dg->max_degree+1+overintegrate);
111  const dealii::Mapping<dim> &mapping = (*(flow_solver->dg->high_order_grid->mapping_fe_field));
112  dealii::FEValues<dim,dim> fe_values_extra(mapping, flow_solver->dg->fe_collection[poly_degree], quad_extra,
113  dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
114  const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
115  std::array<double,nstate> soln_at_q;
116 
117  double l2error = 0;
118 
119  std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
120 
121  // Integrate solution error and output error
122  for (auto cell = flow_solver->dg->dof_handler.begin_active(); cell!=flow_solver->dg->dof_handler.end(); ++cell) {
123 
124  if (!cell->is_locally_owned()) continue;
125  fe_values_extra.reinit (cell);
126  cell->get_dof_indices (dofs_indices);
127 
128  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
129 
130  std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
131  for (unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
132  const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
133  soln_at_q[istate] += flow_solver->dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
134  }
135 
136  double unumerical, uexact;
137  if(param.artificial_dissipation_param.use_enthalpy_error)
138  {
139  error_string = "L2_enthalpy_error";
140  const double pressure = euler_physics_double.compute_pressure(soln_at_q);
141  unumerical = euler_physics_double.compute_specific_enthalpy(soln_at_q,pressure);
142  uexact = euler_physics_double.gam*euler_physics_double.pressure_inf/euler_physics_double.density_inf*(1.0/euler_physics_double.gamm1+0.5*euler_physics_double.mach_inf_sqr);
143  }
144  else
145  {
146  error_string = "L2_entropy_error";
147  const double entropy_inf = euler_physics_double.entropy_inf;
148  unumerical = euler_physics_double.compute_entropy_measure(soln_at_q);
149  uexact = entropy_inf;
150  }
151  l2error += pow(unumerical - uexact, 2) * fe_values_extra.JxW(iquad);
152  }
153  }
154  const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error, mpi_communicator));
155  last_error = l2error_mpi_sum;
156 
157  const unsigned int n_dofs = flow_solver->dg->dof_handler.n_dofs();
158  const unsigned int n_global_active_cells = flow_solver->dg->triangulation->n_global_active_cells();
159 
160  // Convergence table
161  double dx = 1.0/pow(n_dofs,(1.0/dim));
162  grid_size[igrid] = dx;
163  error[igrid] = l2error_mpi_sum;
164 
165  convergence_table.add_value("p", poly_degree);
166  convergence_table.add_value("cells", n_global_active_cells);
167  convergence_table.add_value("DoFs", n_dofs);
168  convergence_table.add_value("dx", dx);
169  convergence_table.add_value(error_string, l2error_mpi_sum);
170  convergence_table.add_value("Residual",flow_solver->ode_solver->residual_norm);
171 
172  if(flow_solver->ode_solver->residual_norm > 1e-10)
173  {
174  has_residual_converged = false;
175  }
176 
177  artificial_dissipation_max_coeff = flow_solver->dg->max_artificial_dissipation_coeff;
178 
179  pcout << " Grid size h: " << dx
180  << " L2-error: " << l2error_mpi_sum
181  << " Residual: " << flow_solver->ode_solver->residual_norm
182  << std::endl;
183 
184  if (igrid > 0) {
185  const double slope_soln_err = log(error[igrid]/error[igrid-1])
186  / log(grid_size[igrid]/grid_size[igrid-1]);
187  pcout << "From grid " << igrid-1
188  << " to grid " << igrid
189  << " dimension: " << dim
190  << " polynomial degree p: " << poly_degree
191  << std::endl
192  <<" " << error_string << 1 << " " << error[igrid-1]
193  <<" " << error_string << 2 << " " << error[igrid]
194  << " slope " << slope_soln_err
195  << std::endl;
196  }
197 
198  //output_results (igrid);
199  if (igrid == n_grids-1)
200  {
201  if (param.mesh_adaptation_param.total_mesh_adaptation_cycles > 0)
202  {
203  dealii::Point<dim> smallest_cell_coord = flow_solver->dg->coordinates_of_highest_refined_cell();
204  pcout<<" x = "<<smallest_cell_coord[0]<<" y = "<<smallest_cell_coord[1]<<std::endl;
205  // Check if the mesh is refined near the shock i.e x \in (0.1,0.5) and y \in (0.0, 0.5).
206  if ((smallest_cell_coord[0] > 0.1) && (smallest_cell_coord[0] < 0.5) && (smallest_cell_coord[1] > 0.0) && (smallest_cell_coord[1] < 0.5))
207  {
208  pcout<<"Mesh is refined near the shock. Test passed"<<std::endl;
209  return 0; // Mesh adaptation test passed.
210  }
211  return 1; // Mesh adaptation failed.
212  }
213  }
214  }
215  pcout << " ********************************************" << std::endl
216  << " Convergence rates for p = " << poly_degree << std::endl
217  << " ********************************************" << std::endl;
218  convergence_table.evaluate_convergence_rates(error_string, "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
219  convergence_table.set_scientific("dx", true);
220  convergence_table.set_scientific(error_string, true);
221  convergence_table.set_scientific("Residual",true);
222  //convergence_table.set_scientific("L2_error", true);
223  if (pcout.is_active()) convergence_table.write_text(pcout.get_stream());
224 
225  convergence_table_vector.push_back(convergence_table);
226 
227  const double expected_slope = poly_degree+1;
228 
229  double last_slope = 0.0;
230 
231  if(n_grids>=2)
232  {
233  last_slope = log(error[n_grids-1]/error[n_grids-2]) / log(grid_size[n_grids-1]/grid_size[n_grids-2]);
234  }
235 
236  const double slope_avg = last_slope;
237  const double slope_diff = slope_avg-expected_slope;
238 
239  double slope_deficit_tolerance = -std::abs(manu_grid_conv_param.slope_deficit_tolerance);
240  if(poly_degree == 0) slope_deficit_tolerance *= 2; // Otherwise, grid sizes need to be much bigger for p=0
241 
242  if( (slope_diff < slope_deficit_tolerance) || (n_grids==1) ) {
243  pcout << std::endl
244  << "Convergence order not achieved. Average last 2 slopes of "
245  << slope_avg << " instead of expected "
246  << expected_slope << " within a tolerance of "
247  << slope_deficit_tolerance
248  << std::endl;
249  // p=0 just requires too many meshes to get into the asymptotic region.
250  if(poly_degree!=0) fail_conv_poly.push_back(poly_degree);
251  if(poly_degree!=0) fail_conv_slop.push_back(slope_avg);
252  }
253 
254  }
255  pcout << std::endl << std::endl << std::endl << std::endl;
256  pcout << " ********************************************" << std::endl;
257  pcout << " Convergence summary" << std::endl;
258  pcout << " ********************************************" << std::endl;
259  for (auto conv = convergence_table_vector.begin(); conv!=convergence_table_vector.end(); conv++) {
260  if (pcout.is_active()) conv->write_text(pcout.get_stream());
261  pcout << " ********************************************" << std::endl;
262  }
263 
264 //****************Test for artificial dissipation begins *******************************************************
265  using artificial_dissipation_test_enum = Parameters::ArtificialDissipationParam::ArtificialDissipationTestType;
266  artificial_dissipation_test_enum arti_dissipation_test_type = param.artificial_dissipation_param.artificial_dissipation_test_type;
267  if (arti_dissipation_test_type == artificial_dissipation_test_enum::residual_convergence)
268  {
269  if(has_residual_converged)
270  {
271  pcout << std::endl << "Residual has converged. Test Passed"<<std::endl;
272  return 0;
273  }
274  pcout << std::endl<<"Residual has not converged. Test failed" << std::endl;
275  return 1;
276  }
277  else if (arti_dissipation_test_type == artificial_dissipation_test_enum::discontinuity_sensor_activation)
278  {
279  if(artificial_dissipation_max_coeff < 1e-10)
280  {
281  pcout << std::endl << "Discontinuity sensor is not activated. Max dissipation coeff = " <<artificial_dissipation_max_coeff << " Test passed"<<std::endl;
282  return 0;
283  }
284  pcout << std::endl << "Discontinuity sensor has been activated. Max dissipation coeff = " <<artificial_dissipation_max_coeff << " Test failed"<<std::endl;
285  return 1;
286  }
287  else if (arti_dissipation_test_type == artificial_dissipation_test_enum::enthalpy_conservation)
288  {
289  return last_error; // Return the error
290  }
291 //****************Test for artificial dissipation ends *******************************************************
292  else
293  {
294  int n_fail_poly = fail_conv_poly.size();
295  if (n_fail_poly > 0)
296  {
297  for (int ifail=0; ifail < n_fail_poly; ++ifail)
298  {
299  const double expected_slope = fail_conv_poly[ifail]+1;
300  const double slope_deficit_tolerance = -0.1;
301  pcout << std::endl
302  << "Convergence order not achieved for polynomial p = "
303  << fail_conv_poly[ifail]
304  << ". Slope of "
305  << fail_conv_slop[ifail] << " instead of expected "
306  << expected_slope << " within a tolerance of "
307  << slope_deficit_tolerance
308  << std::endl;
309  }
310  }
311  return n_fail_poly;
312  }
313 }
314 
315 
316 #if PHILIP_DIM==2
318 #endif
319 
320 } // Tests namespace
321 } // PHiLiP namespace
322 
unsigned int degree_start
First polynomial degree to start the loop. If diffusion, must be at least 1.
Performs grid convergence for various polynomial degrees.
const double mach_inf
Farfield Mach number.
Definition: euler.h:113
const double angle_of_attack
Angle of attack.
Definition: euler.h:118
Parameters related to the manufactured convergence study.
const double gam
Constant heat capacity ratio of fluid.
Definition: euler.h:105
const MPI_Comm mpi_communicator
MPI communicator.
Definition: tests.h:39
const double density_inf
Definition: euler.h:111
ArtificialDissipationTestType
Specified choices of dissipation test types.
EulerGaussianBump()=delete
Constructor. Deleted the default constructor since it should not be used.
const double gamm1
Constant heat capacity ratio (Gamma-1.0) used often.
Definition: euler.h:106
int run_test() const
Grid convergence on Euler Gaussian Bump.
Files for the baseline physics.
Definition: ADTypes.hpp:10
const double side_slip_angle
Sideslip angle.
Definition: euler.h:122
unsigned int dimension
Number of dimensions. Note that it has to match the executable PHiLiP_xD.
Main parameter class that contains the various other sub-parameter classes.
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
const double entropy_inf
Entropy measure at infinity.
Definition: euler.h:127
double run_euler_gaussian_bump() const
Returns either the order of convergence or enthalpy, depending on the test type.
real2 compute_pressure(const std::array< real2, nstate > &conservative_soln) const
Evaluate pressure from conservative variables.
Definition: euler.cpp:369
real compute_specific_enthalpy(const std::array< real, nstate > &conservative_soln, const real pressure) const
Evaluate pressure from conservative variables.
Definition: euler.cpp:309
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
std::vector< int > get_number_1d_cells(const int ngrids) const
Evaluates the number of cells to generate the grids for 1D grid based on input file.
Definition: tests.cpp:71
const double ref_length
Reference length.
Definition: euler.h:104
const double pressure_inf
Non-dimensionalized pressure* at infinity.
Definition: euler.h:126
const double mach_inf_sqr
Definition: euler.h:114
Base class of all the tests.
Definition: tests.h:17
real compute_entropy_measure(const std::array< real, nstate > &conservative_soln) const
Evaluate entropy from conservative variables.
Definition: euler.cpp:288