[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
grid_study.cpp
1 #include <stdlib.h> /* srand, rand */
2 #include <iostream>
3 
4 //#include <deal.II/base/convergence_table.h> //<-- included in header file
5 
6 #include <deal.II/dofs/dof_tools.h>
7 
8 #include <deal.II/distributed/tria.h>
9 #include <deal.II/grid/tria.h>
10 
11 #include <deal.II/grid/grid_generator.h>
12 #include <deal.II/grid/grid_refinement.h>
13 #include <deal.II/grid/grid_tools.h>
14 #include <deal.II/grid/grid_out.h>
15 #include <deal.II/grid/grid_in.h>
16 
17 #include <deal.II/numerics/vector_tools.h>
18 
19 #include <deal.II/fe/fe_values.h>
20 
21 #include <Sacado.hpp>
22 
23 #include "tests.h"
24 #include "mesh/grids/curved_periodic_grid.hpp"
25 
26 #include "grid_study.h"
27 
28 #include "physics/physics_factory.h"
29 #include "physics/model_factory.h"
30 #include "physics/manufactured_solution.h"
31 #include "dg/dg_factory.hpp"
32 #include "ode_solver/ode_solver_factory.h"
33 
34 #include "grid_refinement/grid_refinement.h"
35 #include "grid_refinement/gmsh_out.h"
36 #include "grid_refinement/size_field.h"
37 
38 namespace PHiLiP {
39 namespace Tests {
40 
41 template <int dim, int nstate>
43  :
44  TestsBase::TestsBase(parameters_input)
45 {}
46 
47 template <int dim, int nstate>
50 {
51  dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
52  solution_no_ghost.reinit(dg.locally_owned_dofs, MPI_COMM_WORLD);
53  const auto mapping = (*(dg.high_order_grid->mapping_fe_field));
54  dealii::VectorTools::interpolate(mapping, dg.dof_handler, *physics.manufactured_solution_function, solution_no_ghost);
55  // solution_no_ghost *= 1.0+1e-3;
56  // solution_no_ghost = 0.0;
57  // int i = 0;
58  // for (auto sol = solution_no_ghost.begin(); sol != solution_no_ghost.end(); ++sol) {
59  // *sol = (++i) * 0.01;
60  // }
61  dg.solution = solution_no_ghost;
62 }
63 template <int dim, int nstate>
66 {
67  pcout << "Evaluating solution integral..." << std::endl;
68  double solution_integral = 0.0;
69 
70  // Overintegrate the error to make sure there is not integration error in the error estimate
71  //int overintegrate = 5;
72  //dealii::QGauss<dim> quad_extra(dg.fe_system.tensor_degree()+overintegrate);
73  //dealii::FEValues<dim,dim> fe_values_extra(dg.mapping, dg.fe_system, quad_extra,
74  // dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
75  int overintegrate = 10;
76  dealii::QGauss<dim> quad_extra(dg.max_degree+1+overintegrate);
77  //dealii::MappingQ<dim,dim> mappingq_temp(dg.max_degree+1);
78  dealii::FEValues<dim,dim> fe_values_extra(*(dg.high_order_grid->mapping_fe_field), dg.fe_collection[dg.max_degree], quad_extra,
79  dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
80  const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
81  std::array<double,nstate> soln_at_q;
82 
83  const bool linear_output = true;
84  int exponent;
85  if (linear_output) exponent = 1;
86  else exponent = 2;
87 
88  // Integrate solution error and output error
89  std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
90  for (auto cell : dg.dof_handler.active_cell_iterators()) {
91 
92  if (!cell->is_locally_owned()) continue;
93 
94  fe_values_extra.reinit (cell);
95  cell->get_dof_indices (dofs_indices);
96 
97  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
98 
99  // Interpolate solution to quadrature points
100  std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
101  for (unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
102  const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
103  soln_at_q[istate] += dg.solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
104  }
105  // Integrate solution
106  for (int s=0; s<nstate; s++) {
107  solution_integral += pow(soln_at_q[s], exponent) * fe_values_extra.JxW(iquad);
108  }
109  }
110 
111  }
112  const double solution_integral_mpi_sum = dealii::Utilities::MPI::sum(solution_integral, mpi_communicator);
113  return solution_integral_mpi_sum;
114 }
115 
116 template<int dim, int nstate>
117 std::string GridStudy<dim,nstate>::
119 {
120  // initial base name
121  std::string error_filename_baseline = "convergence_table";
122 
123  std::string pde_string = this->get_pde_string(param);
124  std::string conv_num_flux_string = this->get_conv_num_flux_string(param);
125  std::string diss_num_flux_string = this->get_diss_num_flux_string(param);
126  std::string manufactured_solution_string = this->get_manufactured_solution_string(param);
127 
128  error_filename_baseline += std::string("_") + std::to_string(dim) + std::string("d");
129  error_filename_baseline += std::string("_") + pde_string;
130  error_filename_baseline += std::string("_") + conv_num_flux_string;
131  error_filename_baseline += std::string("_") + diss_num_flux_string;
132  error_filename_baseline += std::string("_") + manufactured_solution_string;
133  return error_filename_baseline;
134 }
135 
136 template<int dim, int nstate>
139  const std::string error_filename_baseline,
140  const dealii::ConvergenceTable convergence_table,
141  const unsigned int poly_degree) const
142 {
143  std::string error_filename = error_filename_baseline;
144  std::string error_fileType = std::string("txt");
145  error_filename += std::string("_") + std::string("p") + std::to_string(poly_degree);
146  std::ofstream error_table_file(error_filename + std::string(".") + error_fileType);
147  convergence_table.write_text(error_table_file);
148 }
149 
150 
151 template<int dim, int nstate>
153 ::run_test () const
154 {
155  int test_fail = 0;
157  using GridEnum = ManParam::GridEnum;
159 
160  Assert(dim == param.dimension, dealii::ExcDimensionMismatch(dim, param.dimension));
161  //Assert(param.pde_type != param.PartialDifferentialEquation::euler, dealii::ExcNotImplemented());
162  //if (param.pde_type == param.PartialDifferentialEquation::euler) return 1;
163 
164  ManParam manu_grid_conv_param = param.manufactured_convergence_study_param;
165 
166  const unsigned int p_start = manu_grid_conv_param.degree_start;
167  const unsigned int p_end = manu_grid_conv_param.degree_end;
168 
169  const unsigned int n_grids_input = manu_grid_conv_param.number_of_grids;
170 
171  std::shared_ptr< Physics::ModelBase<dim,nstate,double> > model_double = Physics::ModelFactory<dim,nstate,double>::create_Model(&param);
172  std::shared_ptr <Physics::PhysicsBase<dim,nstate,double>> physics_double = Physics::PhysicsFactory<dim, nstate, double>::create_Physics(&param,model_double);
173 
174  // Evaluate solution integral on really fine mesh
175  double exact_solution_integral;
176  pcout << "Evaluating EXACT solution integral..." << std::endl;
177  // Limit the scope of grid_super_fine and dg_super_fine
178 #if PHILIP_DIM==1
179  using Triangulation = dealii::Triangulation<dim>;
180 #else
181  using Triangulation = dealii::parallel::distributed::Triangulation<dim>;
182 #endif
183  {
184  const std::vector<int> n_1d_cells = get_number_1d_cells(n_grids_input);
185  std::shared_ptr<Triangulation> grid_super_fine = std::make_shared<Triangulation>(
186 #if PHILIP_DIM!=1
187  MPI_COMM_WORLD,
188 #endif
189  typename dealii::Triangulation<dim>::MeshSmoothing(
190  dealii::Triangulation<dim>::smoothing_on_refinement |
191  dealii::Triangulation<dim>::smoothing_on_coarsening));
192 
193  dealii::GridGenerator::subdivided_hyper_cube(*grid_super_fine, n_1d_cells[n_grids_input-1]);
194  //dealii::Point<dim> p1, p2;
195  //const double DX = 3;
196  //for (int d=0;d<dim;++d) {
197  // p1[d] = 0.0-DX;
198  // p2[d] = 1.0+DX;
199  //}
200  //const std::vector<unsigned int> repetitions(dim,n_1d_cells[n_grids_input-1]);
201  //dealii::GridGenerator::subdivided_hyper_rectangle<dim,dim>(*grid_super_fine, repetitions, p1, p2);
202 
203  //grid_super_fine->clear();
204  //const std::vector<unsigned int> n_subdivisions(dim,n_1d_cells[n_grids_input-1]);
205  //PHiLiP::Grids::curved_periodic_sine_grid<dim,Triangulation>(*grid_super_fine, n_subdivisions);
206  for (auto cell = grid_super_fine->begin_active(); cell != grid_super_fine->end(); ++cell) {
207  for (unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
208  if (cell->face(face)->at_boundary()) cell->face(face)->set_boundary_id (1000);
209  }
210  }
211 
212  std::shared_ptr < DGBase<dim, double> > dg_super_fine = DGFactory<dim,double>::create_discontinuous_galerkin(&param, p_end, grid_super_fine);
213  dg_super_fine->allocate_system ();
214 
215  initialize_perturbed_solution(*dg_super_fine, *physics_double);
216  if (manu_grid_conv_param.output_solution) {
217  dg_super_fine->output_results_vtk(9999);
218  }
219  exact_solution_integral = integrate_solution_over_domain(*dg_super_fine);
220  pcout << "Exact solution integral is " << exact_solution_integral << std::endl;
221  }
222 
223  int n_flow_convergence_error = 0;
224  std::vector<int> fail_conv_poly;
225  std::vector<double> fail_conv_slop;
226  std::vector<dealii::ConvergenceTable> convergence_table_vector;
227 
228  std::string error_filename_baseline;
229  if (manu_grid_conv_param.output_convergence_tables) {
230  error_filename_baseline = get_convergence_tables_baseline_filename(&param);
231  }
232 
233  for (unsigned int poly_degree = p_start; poly_degree <= p_end; ++poly_degree) {
234 
235  // p0 tends to require a finer grid to reach asymptotic region
236  unsigned int n_grids = n_grids_input;
237  if (poly_degree <= 1) n_grids = n_grids_input + 1;
238 
239  std::vector<double> soln_error(n_grids);
240  std::vector<double> output_error(n_grids);
241  std::vector<double> grid_size(n_grids);
242 
243  const std::vector<int> n_1d_cells = get_number_1d_cells(n_grids);
244 
245  dealii::ConvergenceTable convergence_table;
246 
247  // Note that Triangulation must be declared before DG
248  // DG will be destructed before Triangulation
249  // thus removing any dependence of Triangulation and allowing Triangulation to be destructed
250  // Otherwise, a Subscriptor error will occur
251  std::shared_ptr<Triangulation> grid = std::make_shared<Triangulation>(
252 #if PHILIP_DIM!=1
253  MPI_COMM_WORLD,
254 #endif
255  typename dealii::Triangulation<dim>::MeshSmoothing(
256  dealii::Triangulation<dim>::smoothing_on_refinement |
257  dealii::Triangulation<dim>::smoothing_on_coarsening));
258 
259  dealii::Vector<float> estimated_error_per_cell;
260  dealii::Vector<double> estimated_error_per_cell_double;
261 
262  for (unsigned int igrid=0; igrid<n_grids; ++igrid) {
263  grid->clear();
264  dealii::GridGenerator::subdivided_hyper_cube(*grid, n_1d_cells[igrid]);
265  //dealii::Point<dim> p1, p2;
266  //const double DX = 3;
267  //for (int d=0;d<dim;++d) {
268  // p1[d] = 0.0-DX;
269  // p2[d] = 1.0+DX;
270  //}
271  //const std::vector<unsigned int> repetitions(dim,n_1d_cells[igrid]);
272  //dealii::GridGenerator::subdivided_hyper_rectangle<dim,dim>(*grid, repetitions, p1, p2);
273 
274  for (auto cell = grid->begin_active(); cell != grid->end(); ++cell) {
275  // Set a dummy boundary ID
276  cell->set_material_id(9002);
277  for (unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
278  if (cell->face(face)->at_boundary()) cell->face(face)->set_boundary_id (1000);
279  }
280  }
281  //dealii::GridTools::transform (&warp, *grid);
282  // Warp grid if requested in input file
283  if (manu_grid_conv_param.grid_type == GridEnum::sinehypercube) dealii::GridTools::transform (&warp, *grid);
284 
285 
286  //grid->clear();
287  //const std::vector<unsigned int> n_subdivisions(dim,n_1d_cells[igrid]);
288  //PHiLiP::Grids::curved_periodic_sine_grid<dim,Triangulation>(*grid, n_subdivisions);
289  //for (auto cell = grid->begin_active(); cell != grid->end(); ++cell) {
290  // for (unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
291  // if (cell->face(face)->at_boundary()) cell->face(face)->set_boundary_id (1000);
292  // }
293  //}
294 
295  // // Generate hypercube
296  // if ( igrid==0 && (manu_grid_conv_param.grid_type == GridEnum::hypercube || manu_grid_conv_param.grid_type == GridEnum::sinehypercube ) ) {
297 
298  // grid->clear();
299  // dealii::GridGenerator::subdivided_hyper_cube(*, n_1d_cells[igrid]);
300  // for (auto cell = grid->begin_active(); cell != grid->end(); ++cell) {
301  // // Set a dummy boundary ID
302  // cell->set_material_id(9002);
303  // for (unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
304  // if (cell->face(face)->at_boundary()) cell->face(face)->set_boundary_id (1000);
305  // }
306  // }
307  // // Warp grid if requested in input file
308  // if (manu_grid_conv_param.grid_type == GridEnum::sinehypercube) dealii::GridTools::transform (&warp, *grid);
309  // } else {
310  // dealii::GridRefinement::refine_and_coarsen_fixed_number(*grid,
311  // estimated_error_per_cell,
312  // 0.3,
313  // 0.03);
314  // grid->execute_coarsening_and_refinement();
315  // }
316 
317  //for (int i=0; i<5;i++) {
318  // int icell = 0;
319  // for (auto cell = grid->begin_active(grid->n_levels()-1); cell!=grid->end(); ++cell) {
320  // if (!cell->is_locally_owned()) continue;
321  // icell++;
322  // if (icell < 2) {
323  // cell->set_refine_flag();
324  // }
325  // //else if (icell%2 == 0) {
326  // // cell->set_refine_flag();
327  // //} else if (icell%3 == 0) {
328  // // //cell->set_coarsen_flag();
329  // //}
330  // }
331  // grid->execute_coarsening_and_refinement();
332  //}
333 
334  // Distort grid by random amount if requested
335  const double random_factor = manu_grid_conv_param.random_distortion;
336  const bool keep_boundary = true;
337  if (random_factor > 0.0) dealii::GridTools::distort_random (random_factor, *grid, keep_boundary);
338 
339  // Read grid if requested
340  if (manu_grid_conv_param.grid_type == GridEnum::read_grid) {
341  //std::string write_mshname = "grid-"+std::to_string(igrid)+".msh";
342  std::string read_mshname = manu_grid_conv_param.input_grids+std::to_string(igrid)+".msh";
343  pcout<<"Reading grid: " << read_mshname << std::endl;
344  std::ifstream inmesh(read_mshname);
345  dealii::GridIn<dim,dim> grid_in;
346  grid->clear();
347  grid_in.attach_triangulation(*grid);
348  grid_in.read_msh(inmesh);
349  }
350  // Output grid if requested
351  if (manu_grid_conv_param.output_meshes) {
352  std::string write_mshname = "grid-"+std::to_string(igrid)+".msh";
353  std::ofstream outmesh(write_mshname);
354  dealii::GridOutFlags::Msh msh_flags(true, true);
355  dealii::GridOut grid_out;
356  grid_out.set_flags(msh_flags);
357  grid_out.write_msh(*grid, outmesh);
358  }
359 
360  // Show mesh if in 2D
361  //std::string gridname = "grid-"+std::to_string(igrid)+".eps";
362  //if (dim == 2) print_mesh_info (*grid, gridname);
363 
364  using FadType = Sacado::Fad::DFad<double>;
365 
366  // Create DG object using the factory
367  std::shared_ptr < DGBase<dim, double> > dg = DGFactory<dim,double>::create_discontinuous_galerkin(&param, poly_degree, grid);
368  dg->allocate_system ();
369  //dg->evaluate_inverse_mass_matrices();
370  //
371  // PhysicsBase required for exact solution and output error
372 
373  initialize_perturbed_solution(*(dg), *(physics_double));
374 
375  // Create ODE solver using the factory and providing the DG object
376  std::shared_ptr<ODE::ODESolverBase<dim, double>> ode_solver = ODE::ODESolverFactory<dim, double>::create_ODESolver(dg);
377 
378  const unsigned int n_global_active_cells = grid->n_global_active_cells();
379  const unsigned int n_dofs = dg->dof_handler.n_dofs();
380  pcout << "Dimension: " << dim
381  << "\t Polynomial degree p: " << poly_degree
382  << std::endl
383  << "Grid number: " << igrid+1 << "/" << n_grids
384  << ". Number of active cells: " << n_global_active_cells
385  << ". Number of degrees of freedom: " << n_dofs
386  << std::endl;
387 
388  // Solve the steady state problem
389  //ode_solver->initialize_steady_polynomial_ramping (poly_degree);
390  const int flow_convergence_error = ode_solver->steady_state();
391  if (flow_convergence_error) n_flow_convergence_error += 1;
392 
393  // Overintegrate the error to make sure there is not integration error in the error estimate
394  int overintegrate = 10;
395  dealii::QGauss<dim> quad_extra(dg->max_degree+overintegrate);
396  //dealii::MappingQ<dim,dim> mappingq(dg->max_degree+1);
397  dealii::FEValues<dim,dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra,
398  dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
399  const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
400  std::array<double,nstate> soln_at_q;
401 
402  // l2error for each state
403  std::array<double,nstate> cell_l2error_state;
404  std::array<double,nstate> l2error_state;
405  for (int istate=0; istate<nstate; ++istate) {
406  l2error_state[istate] = 0.0;
407  }
408 
409  double l2error = 0;
410 
411  // Integrate solution error and output error
412 
413  std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
414  estimated_error_per_cell.reinit(grid->n_active_cells());
415  estimated_error_per_cell_double.reinit(grid->n_active_cells());
416  for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
417 
418  if (!cell->is_locally_owned()) continue;
419 
420  fe_values_extra.reinit (cell);
421  cell->get_dof_indices (dofs_indices);
422 
423  double cell_l2error = 0;
424 
425  for (int istate=0; istate<nstate; ++istate) {
426  cell_l2error_state[istate] = 0.0;
427  }
428 
429  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
430 
431  std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
432  for (unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
433  const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
434  soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
435  }
436 
437  const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
438 
439  for (int istate=0; istate<nstate; ++istate) {
440  const double uexact = physics_double->manufactured_solution_function->value(qpoint, istate);
441  //l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_extra.JxW(iquad);
442 
443  cell_l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_extra.JxW(iquad);
444 
445  cell_l2error_state[istate] += pow(soln_at_q[istate] - uexact, 2) * fe_values_extra.JxW(iquad); // TESTING
446  }
447  }
448  estimated_error_per_cell[cell->active_cell_index()] = cell_l2error;
449  estimated_error_per_cell_double[cell->active_cell_index()] = cell_l2error;
450  l2error += cell_l2error;
451 
452  for (int istate=0; istate<nstate; ++istate) {
453  l2error_state[istate] += cell_l2error_state[istate];
454  }
455  }
456  const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error, mpi_communicator));
457 
458  std::array<double,nstate> l2error_mpi_sum_state;
459  for (int istate=0; istate<nstate; ++istate) {
460  l2error_mpi_sum_state[istate] = std::sqrt(dealii::Utilities::MPI::sum(l2error_state[istate], mpi_communicator));
461  }
462 
463  double solution_integral = integrate_solution_over_domain(*dg);
464 
465  if (manu_grid_conv_param.output_solution) {
466  /*
467  dg->output_results_vtk(igrid);
468 
469  std::string write_posname = "error-"+std::to_string(igrid)+".pos";
470  std::ofstream outpos(write_posname);
471  GridRefinement::GmshOut<dim,double>::write_pos(grid,estimated_error_per_cell_double,outpos);
472 
473  std::shared_ptr< GridRefinement::GridRefinementBase<dim,nstate,double> > gr
474  = GridRefinement::GridRefinementFactory<dim,nstate,double>::create_GridRefinement(param.grid_refinement_study_param.grid_refinement_param_vector[0],dg,physics_double);
475 
476  gr->refine_grid();
477 
478  // dg->output_results_vtk(igrid);
479  */
480 
481  // Use gr->output_results_vtk(), which includes L2error per cell, instead of dg->output_results_vtk() as done above
482  std::shared_ptr< GridRefinement::GridRefinementBase<dim,nstate,double> > gr
484  gr->output_results_vtk(igrid);
485  }
486 
487 
488  // Convergence table
489  const double dx = 1.0/pow(n_dofs,(1.0/dim));
490  grid_size[igrid] = dx;
491  soln_error[igrid] = l2error_mpi_sum;
492  output_error[igrid] = std::abs(solution_integral - exact_solution_integral);
493 
494  convergence_table.add_value("p", poly_degree);
495  convergence_table.add_value("cells", n_global_active_cells);
496  convergence_table.add_value("DoFs", n_dofs);
497  convergence_table.add_value("dx", dx);
498  convergence_table.add_value("residual", dg->get_residual_l2norm ());
499  convergence_table.add_value("soln_L2_error", l2error_mpi_sum);
500  convergence_table.add_value("output_error", output_error[igrid]);
501 
502  // add l2error for each state to the convergence table
503  if (manu_grid_conv_param.add_statewise_solution_error_to_convergence_tables) {
504  std::array<std::string,nstate> soln_L2_error_state_str;
505  for (int istate=0; istate<nstate; ++istate) {
506  soln_L2_error_state_str[istate] = std::string("soln_L2_error_state") + std::string("_") + std::to_string(istate);
507  convergence_table.add_value(soln_L2_error_state_str[istate], l2error_mpi_sum_state[istate]);
508  }
509  }
510 
511  pcout << " Grid size h: " << dx
512  << " L2-soln_error: " << l2error_mpi_sum
513  << " Residual: " << ode_solver->residual_norm
514  << std::endl;
515 
516  pcout << " output_exact: " << exact_solution_integral
517  << " output_discrete: " << solution_integral
518  << " output_error: " << output_error[igrid]
519  << std::endl;
520 
521  if (igrid > 0) {
522  const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1])
523  / log(grid_size[igrid]/grid_size[igrid-1]);
524  const double slope_output_err = log(output_error[igrid]/output_error[igrid-1])
525  / log(grid_size[igrid]/grid_size[igrid-1]);
526  pcout << "From grid " << igrid-1
527  << " to grid " << igrid
528  << " dimension: " << dim
529  << " polynomial degree p: " << poly_degree
530  << std::endl
531  << " solution_error1 " << soln_error[igrid-1]
532  << " solution_error2 " << soln_error[igrid]
533  << " slope " << slope_soln_err
534  << std::endl
535  << " solution_integral_error1 " << output_error[igrid-1]
536  << " solution_integral_error2 " << output_error[igrid]
537  << " slope " << slope_output_err
538  << std::endl;
539  }
540 
541  // update the table with additional grid
542  convergence_table.evaluate_convergence_rates("soln_L2_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
543  convergence_table.evaluate_convergence_rates("output_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
544  convergence_table.set_scientific("dx", true);
545  convergence_table.set_scientific("residual", true);
546  convergence_table.set_scientific("soln_L2_error", true);
547  convergence_table.set_scientific("output_error", true);
548  if (manu_grid_conv_param.add_statewise_solution_error_to_convergence_tables) {
549  std::string test_str;
550  for (int istate=0; istate<nstate; ++istate) {
551  test_str = std::string("soln_L2_error_state") + std::string("_") + std::to_string(istate);
552  convergence_table.set_scientific(test_str,true);
553  }
554  }
555 
556  if (manu_grid_conv_param.output_convergence_tables) {
558  error_filename_baseline,
559  convergence_table,
560  poly_degree);
561  }
562  }
563  pcout << " ********************************************"
564  << std::endl
565  << " Convergence rates for p = " << poly_degree
566  << std::endl
567  << " ********************************************"
568  << std::endl;
569 
570  if (pcout.is_active()) convergence_table.write_text(pcout.get_stream());
571 
572  convergence_table_vector.push_back(convergence_table);
573 
574  const double expected_slope = poly_degree+1;
575 
576  double last_slope = 0.0;
577  if ( n_grids > 1 ) {
578  last_slope = log(soln_error[n_grids-1]/soln_error[n_grids-2])
579  / log(grid_size[n_grids-1]/grid_size[n_grids-2]);
580  }
581  double before_last_slope = last_slope;
582  if ( n_grids > 2 ) {
583  before_last_slope = log(soln_error[n_grids-2]/soln_error[n_grids-3])
584  / log(grid_size[n_grids-2]/grid_size[n_grids-3]);
585  }
586  const double slope_avg = 0.5*(before_last_slope+last_slope);
587  const double slope_diff = slope_avg-expected_slope;
588 
589  double slope_deficit_tolerance = -std::abs(manu_grid_conv_param.slope_deficit_tolerance);
590  if(poly_degree == 0) slope_deficit_tolerance *= 2; // Otherwise, grid sizes need to be much bigger for p=0
591 
592  if (slope_diff < slope_deficit_tolerance) {
593  pcout << std::endl
594  << "Convergence order not achieved. Average last 2 slopes of "
595  << slope_avg << " instead of expected "
596  << expected_slope << " within a tolerance of "
597  << slope_deficit_tolerance
598  << std::endl;
599  // p=0 just requires too many meshes to get into the asymptotic region.
600  if(poly_degree!=0) fail_conv_poly.push_back(poly_degree);
601  if(poly_degree!=0) fail_conv_slop.push_back(slope_avg);
602  }
603 
604  }
605  pcout << std::endl << std::endl << std::endl << std::endl;
606  pcout << " ********************************************" << std::endl;
607  pcout << " Convergence summary" << std::endl;
608  pcout << " ********************************************" << std::endl;
609  for (auto conv = convergence_table_vector.begin(); conv!=convergence_table_vector.end(); conv++) {
610  if (pcout.is_active()) conv->write_text(pcout.get_stream());
611  pcout << " ********************************************" << std::endl;
612  }
613  int n_fail_poly = fail_conv_poly.size();
614  if (n_fail_poly > 0) {
615  for (int ifail=0; ifail < n_fail_poly; ++ifail) {
616  const double expected_slope = fail_conv_poly[ifail]+1;
617  const double slope_deficit_tolerance = -std::abs(manu_grid_conv_param.slope_deficit_tolerance);
618  pcout << std::endl
619  << "Convergence order not achieved for polynomial p = "
620  << fail_conv_poly[ifail]
621  << ". Slope of "
622  << fail_conv_slop[ifail] << " instead of expected "
623  << expected_slope << " within a tolerance of "
624  << slope_deficit_tolerance
625  << std::endl;
626  }
627  }
628  if (n_fail_poly) test_fail += 1;
629  test_fail += n_flow_convergence_error;
630  if (n_flow_convergence_error) {
631  pcout << std::endl
632  << "Flow did not converge some some cases. Please check the residuals achieved versus the residual tolerance."
633  << std::endl;
634  }
635  return test_fail;
636 }
637 
638 template <int dim, int nstate>
639 dealii::Point<dim> GridStudy<dim,nstate>
640 ::warp (const dealii::Point<dim> &p)
641 {
642  dealii::Point<dim> q = p;
643  q[dim-1] *= 1.5;
644  if (dim >= 2) q[0] += 1*std::sin(q[dim-1]);
645  if (dim >= 3) q[1] += 1*std::cos(q[dim-1]);
646  return q;
647 }
648 
649 template <int dim, int nstate>
651 ::print_mesh_info(const dealii::Triangulation<dim> &triangulation, const std::string &filename) const
652 {
653  pcout << "Mesh info:" << std::endl
654  << " dimension: " << dim << std::endl
655  << " no. of cells: " << triangulation.n_global_active_cells() << std::endl;
656  std::map<dealii::types::boundary_id, unsigned int> boundary_count;
657  for (auto cell : triangulation.active_cell_iterators()) {
658  for (unsigned int face=0; face < dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
659  if (cell->face(face)->at_boundary()) boundary_count[cell->face(face)->boundary_id()]++;
660  }
661  }
662  pcout << " boundary indicators: ";
663  for (const std::pair<const dealii::types::boundary_id, unsigned int> &pair : boundary_count) {
664  pcout << pair.first << "(" << pair.second << " times) ";
665  }
666  pcout << std::endl;
667  if (dim == 2) {
668  std::ofstream out (filename);
669  dealii::GridOut grid_out;
670  grid_out.write_eps (triangulation, out);
671  pcout << " written to " << filename << std::endl << std::endl;
672  }
673 }
674 
675 template class GridStudy <PHILIP_DIM,1>;
676 template class GridStudy <PHILIP_DIM,2>;
677 template class GridStudy <PHILIP_DIM,3>;
678 template class GridStudy <PHILIP_DIM,4>;
679 template class GridStudy <PHILIP_DIM,5>;
680 //template struct Instantiator<GridStudy,3,5>;
681 
682 
683 
684 } // Tests namespace
685 } // PHiLiP namespace
unsigned int degree_start
First polynomial degree to start the loop. If diffusion, must be at least 1.
std::string get_convergence_tables_baseline_filename(const Parameters::AllParameters *const parameters_input) const
Returns the baseline filename for outputted convergence tables.
Definition: grid_study.cpp:118
double integrate_solution_over_domain(DGBase< dim, double > &dg) const
L2-Integral of the solution over the entire domain.
Definition: grid_study.cpp:65
Performs grid convergence for various polynomial degrees.
Definition: grid_study.h:16
Sacado::Fad::DFad< double > FadType
Sacado AD type for first derivatives.
Definition: ADTypes.hpp:11
int run_test() const
Manufactured grid convergence.
Definition: grid_study.cpp:153
Parameters related to the manufactured convergence study.
const MPI_Comm mpi_communicator
MPI communicator.
Definition: tests.h:39
Files for the baseline physics.
Definition: ADTypes.hpp:10
GridRefinementStudyParam grid_refinement_study_param
Contains the parameters for grid refinement study.
std::array< GridRefinementParam, MAX_REFINEMENTS > grid_refinement_param_vector
Array of grid refinement parameters to be run as part of grid refinement study.
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.
dealii::LinearAlgebra::distributed::Vector< double > solution
Current modal coefficients of the solution.
Definition: dg_base.hpp:409
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
dealii::IndexSet locally_owned_dofs
Locally own degrees of freedom.
Definition: dg_base.hpp:398
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: tests.h:20
static std::shared_ptr< DGBase< dim, real, MeshType > > create_discontinuous_galerkin(const Parameters::AllParameters *const parameters_input, const unsigned int degree, const unsigned int max_degree_input, const unsigned int grid_degree_input, const std::shared_ptr< Triangulation > triangulation_input)
Creates a derived object DG, but returns it as DGBase.
Definition: dg_factory.cpp:10
const unsigned int max_degree
Maximum degree used for p-refi1nement.
Definition: dg_base.hpp:104
std::string get_conv_num_flux_string(const Parameters::AllParameters *const param) const
Returns a string describing which convective numerical flux is being used.
Definition: tests.cpp:132
static std::shared_ptr< ModelBase< dim, nstate, real > > create_Model(const Parameters::AllParameters *const parameters_input)
Factory to return the correct model given input parameters.
std::shared_ptr< HighOrderGrid< dim, real, MeshType > > high_order_grid
High order grid that will provide the MappingFEField.
Definition: dg_base.hpp:655
void write_convergence_table_to_output_file(const std::string error_filename_baseline, const dealii::ConvergenceTable convergence_table, const unsigned int poly_degree) const
Writes the convergence table output file.
Definition: grid_study.cpp:138
GridStudy()=delete
Constructor. Deleted the default constructor since it should not be used.
std::string get_pde_string(const Parameters::AllParameters *const param) const
Returns a string describing which PDE is being used.
Definition: tests.cpp:82
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.
std::string get_diss_num_flux_string(const Parameters::AllParameters *const param) const
Returns a string describing which dissipative numerical flux is being used.
Definition: tests.cpp:153
dealii::DoFHandler< dim > dof_handler
Finite Element Collection to represent the high-order grid.
Definition: dg_base.hpp:652
static std::shared_ptr< GridRefinementBase< dim, nstate, real, MeshType > > create_GridRefinement(PHiLiP::Parameters::GridRefinementParam gr_param, std::shared_ptr< PHiLiP::Adjoint< dim, nstate, real, MeshType > > adj, std::shared_ptr< PHiLiP::Physics::PhysicsBase< dim, nstate, real > > physics_input)
Construct grid refinement class based on adjoint and physics.
void print_mesh_info(const dealii::Triangulation< dim > &triangulation, const std::string &filename) const
Prints our mesh info and generates eps file if 2D grid.
Definition: grid_study.cpp:651
std::string get_manufactured_solution_string(const Parameters::AllParameters *const param) const
Returns a string describing which manufactured solution is being used.
Definition: tests.cpp:163
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
void initialize_perturbed_solution(DGBase< dim, double > &dg, const Physics::PhysicsBase< dim, nstate, double > &physics) const
Initialize the solution with the exact solution.
Definition: grid_study.cpp:49
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
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
std::shared_ptr< ManufacturedSolutionFunction< dim, real > > manufactured_solution_function
Manufactured solution function.
Definition: physics.h:71
static std::shared_ptr< ODESolverBase< dim, real, MeshType > > create_ODESolver(std::shared_ptr< DGBase< dim, real, MeshType > > dg_input)
Creates either implicit or explicit ODE solver based on parameter value(no POD basis given) ...
const dealii::hp::FECollection< dim > fe_collection
Finite Element Collection for p-finite-element to represent the solution.
Definition: dg_base.hpp:597
Base class of all the tests.
Definition: tests.h:17
static dealii::Point< dim > warp(const dealii::Point< dim > &p)
Warps mesh into sinusoidal.
Definition: grid_study.cpp:640