[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_adjoint.cpp
1 #include <stdlib.h> /* srand, rand */
2 #include <iostream>
3 
4 #include <deal.II/base/convergence_table.h>
5 
6 #include <deal.II/distributed/tria.h>
7 #include <deal.II/distributed/grid_refinement.h>
8 
9 #include <deal.II/distributed/solution_transfer.h>
10 #include <deal.II/dofs/dof_tools.h>
11 
12 #include <deal.II/differentiation/ad/sacado_math.h>
13 #include <deal.II/differentiation/ad/sacado_number_types.h>
14 #include <deal.II/differentiation/ad/sacado_product_types.h>
15 
16 #include <deal.II/grid/grid_generator.h>
17 #include <deal.II/grid/grid_refinement.h>
18 #include <deal.II/grid/grid_tools.h>
19 #include <deal.II/grid/grid_out.h>
20 #include <deal.II/grid/grid_in.h>
21 
22 #include <deal.II/numerics/vector_tools.h>
23 #include <deal.II/numerics/data_out.h>
24 
25 #include <deal.II/fe/fe_values.h>
26 
27 #include <deal.II/fe/mapping_q.h>
28 
29 #include "euler_gaussian_bump_adjoint.h"
30 
31 #include "physics/euler.h"
32 #include "physics/manufactured_solution.h"
33 #include "dg/dg_base.hpp"
34 #include "ode_solver/ode_solver_factory.h"
35 
36 #include "functional/functional.h"
37 #include "functional/adjoint.h"
38 
39 #include <deal.II/distributed/solution_transfer.h>
40 
41 
42 #include "linear_solver/linear_solver.h"
43 //#include "template_instantiator.h"
44 #include "post_processor/physics_post_processor.h"
45 
46 namespace PHiLiP {
47 namespace Tests {
48 
49 // template <int dim, int nstate, typename real>
50 // class L2_Norm_Functional : public Functional<dim, nstate, real>
51 // {
52 // public:
53 // template <typename real2>
54 // real2 evaluate_cell_volume(
55 // const Physics::PhysicsBase<dim,nstate,real> &physics,
56 // const dealii::FEValues<dim,dim> &fe_values_volume,
57 // std::vector<real2> local_solution)
58 // {
59 // unsigned int n_quad_pts = fe_values_volume.n_quadrature_points;
60 
61 // std::array<real2,nstate> soln_at_q;
62 
63 // real2 l2error = 0;
64 
65 // // looping over the quadrature points
66 // for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
67 // std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
68 // for (unsigned int idof=0; idof<fe_values_volume.dofs_per_cell; ++idof) {
69 // const unsigned int istate = fe_values_volume.get_fe().system_to_component_index(idof).first;
70 // soln_at_q[istate] += local_solution[idof] * fe_values_volume.shape_value_component(idof, iquad, istate);
71 // }
72 
73 // const dealii::Point<dim> qpoint = (fe_values_volume.quadrature_point(iquad));
74 
75 // for (int istate=0; istate<nstate; ++istate) {
76 // const double uexact = physics.manufactured_solution_function.value(qpoint, istate);
77 // l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_volume.JxW(iquad);
78 // }
79 // }
80 
81 // return l2error;
82 // }
83 
84 // // non-template functions to override the template classes
85 // real evaluate_cell_volume(
86 // const Physics::PhysicsBase<dim,nstate,real> &physics,
87 // const dealii::FEValues<dim,dim> &fe_values_volume,
88 // std::vector<real> local_solution) override
89 // {
90 // return evaluate_cell_volume<>(physics, fe_values_volume, local_solution);
91 // }
92 // Sacado::Fad::DFad<real> evaluate_cell_volume(
93 // const Physics::PhysicsBase<dim,nstate,real> &physics,
94 // const dealii::FEValues<dim,dim> &fe_values_volume,
95 // std::vector<Sacado::Fad::DFad<real>> local_solution) override
96 // {
97 // return evaluate_cell_volume<>(physics, fe_values_volume, local_solution);
98 // }
99 // };
100 
104 template <int dim, int nstate, typename real>
105 class BoundaryIntegral : public PHiLiP::Functional<dim, nstate, real>
106 {
107  public:
109  template <typename real2>
112  const unsigned int boundary_id,
113  const dealii::FEFaceValues<dim,dim> &fe_values_boundary,
114  std::vector<real2> local_solution){
115 
116  real2 l2error = 0.0;
117 
118  if(boundary_id == 1002){
119  // casting it to a physics euler as it is needed for the pressure computation
120  const Physics::Euler<dim,nstate,real2>& euler_physics = dynamic_cast<const Physics::Euler<dim,nstate,real2>&>(physics);
121 
122  unsigned int n_quad_pts = fe_values_boundary.n_quadrature_points;
123 
124  // looping over quadrature points one at a time and assembling the state vector
125  std::array<real2,nstate> soln_at_q;
126  for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
127  std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
128  for(unsigned int idof=0; idof<fe_values_boundary.dofs_per_cell; idof++){
129  const unsigned int istate = fe_values_boundary.get_fe().system_to_component_index(idof).first;
130  soln_at_q[istate] += local_solution[idof] * fe_values_boundary.shape_value_component(idof, iquad, istate);
131  }
132 
133  // converting the state vector to the point pressure
134  real2 pressure = euler_physics.compute_pressure(soln_at_q);
135 
136  // integrating (with quadrature weights)
137  l2error += pressure * fe_values_boundary.JxW(iquad);
138  }
139  }
140  // std::cout << boundary_id << " == 10002? " << (boundary_id == 1002) << std::endl;
141  // if(boundary_id == 1002){
142  // for(unsigned int idof=0; idof<fe_values_boundary.dofs_per_cell; idof++){
143  // l2error += local_solution[idof];
144  // }
145  // }
146 
147  // unsigned int n_quad_pts = fe_values_boundary.n_quadrature_points;
148 
149  // std::array<real2,nstate> soln_at_q;
150 
151  // trying with the functional from the test case but only on the boundaray
152  // // seeing if evaluating anything seems to work
153  // for(unsigned int iquad=0; iquad<n_quad_pts; iquad++){
154  // for(unsigned int idof=0; idof<fe_values_boundary.dofs_per_cell; idof++){
155  // const unsigned int istate = fe_values_boundary.get_fe().system_to_component_index(idof).first;
156  // soln_at_q[istate] += local_solution[idof] * fe_values_boundary.shape_value_component(idof, iquad, istate);
157  // }
158  // const dealii::Point<dim> qpoint = (fe_values_boundary.quadrature_point(iquad));
159  // for (int istate=0; istate<nstate; ++istate) {
160  // const double uexact = physics.manufactured_solution_function.value(qpoint, istate);
161  // l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_boundary.JxW(iquad);
162  // }
163 
164  // }
165 
166 
167  // // only for the outflow conditions
168  // if(boundary_id == 1002){
169  // const std::vector<real> &JxW = fe_values_boundary.get_JxW_values();
170  // const unsigned int n_dofs_cell = fe_values_boundary.dofs_per_cell;
171  // const unsigned int n_face_quad_pts = fe_values_boundary.n_quadrature_points;
172 
173  // for(unsigned int itest=0; itest<n_dofs_cell; itest++){
174  // const unsigned int istate = fe_values_boundary.get_fe().system_to_component_index(itest).first;
175 
176  // for(unsigned int iquad=0; iquad<n_face_quad_pts; iquad++){
177  // local_sum += std::pow(fe_values_boundary.shape_value_component(itest,iquad,istate) * local_solution[itest], 2.0) * JxW[iquad];
178  // }
179  // }
180  // }
181  return l2error;
182  }
183 
187  const unsigned int boundary_id,
188  const dealii::FEFaceValues<dim,dim> &fe_values_boundary,
189  std::vector<real> local_solution) override {return evaluate_cell_boundary<>(physics, boundary_id, fe_values_boundary, local_solution);}
190 
192  Sacado::Fad::DFad<real> evaluate_cell_boundary(
193  const PHiLiP::Physics::PhysicsBase<dim,nstate,Sacado::Fad::DFad<real>> &physics,
194  const unsigned int boundary_id,
195  const dealii::FEFaceValues<dim,dim> &fe_values_boundary,
196  std::vector<Sacado::Fad::DFad<real>> local_solution) override {return evaluate_cell_boundary<>(physics, boundary_id, fe_values_boundary, local_solution);}
197 };
198 
200 template <int dim, int nstate>
201 class FreeStreamInitialConditionsAdjoint : public dealii::Function<dim>
202 {
203 public:
205  std::array<double,nstate> far_field_conservative;
206 
209  : dealii::Function<dim,double>(nstate)
210  {
211  const double density_bc = 2.33333*euler_physics.density_inf;
212  const double pressure_bc = 1.0/(euler_physics.gam*euler_physics.mach_inf_sqr);
213  std::array<double,nstate> primitive_boundary_values;
214  primitive_boundary_values[0] = density_bc;
215  for (int d=0;d<dim;d++) { primitive_boundary_values[1+d] = euler_physics.velocities_inf[d]; }
216  primitive_boundary_values[nstate-1] = pressure_bc;
217  farfield_conservative = euler_physics.convert_primitive_to_conservative(primitive_boundary_values);
218  }
219 
221  double value (const dealii::Point<dim> &/*point*/, const unsigned int istate) const override
222  {
223  return farfield_conservative[istate];
224  }
225 };
227 
228 template <int dim, int nstate>
230  :
231  TestsBase::TestsBase(parameters_input)
232 {}
233 
234 const double y_height = 0.8;
235 const double bump_height = 0.0625; // High-Order Prediction Workshop
236 const double coeff_expx = -25; // High-Order Prediction Workshop
237 const double coeff_expy = -30;
238 template <int dim, int nstate>
239 dealii::Point<dim> EulerGaussianBumpAdjoint<dim,nstate>
240 ::warp (const dealii::Point<dim> &p)
241 {
242  const double x_ref = p[0];
243  const double coeff = 1.0;
244  const double y_ref = (exp(coeff*std::pow(p[1],1.25))-1.0)/(exp(coeff)-1.0);
245  dealii::Point<dim> q = p;
246  q[0] = x_ref;
247  q[1] = 0.8*y_ref + bump_height*exp(coeff_expy*y_ref*y_ref)*exp(coeff_expx*q[0]*q[0]) * (1.0+0.7*q[0]);
248  return q;
249 }
250 
251 
252 dealii::Point<2> BumpManifoldAdjoint::pull_back(const dealii::Point<2> &space_point) const {
253  double x_phys = space_point[0];
254  double y_phys = space_point[1];
255  double x_ref = x_phys;
256 
257  double y_ref = y_phys;
258 
259  for (int i=0; i<200; i++) {
260  const double function = y_height*y_ref + bump_height*exp(coeff_expy*y_ref*y_ref)*exp(coeff_expx*x_phys*x_phys) * (1.0+0.7*x_phys) - y_phys;
261  const double derivative = y_height + bump_height*coeff_expy*2*y_ref*exp(coeff_expy*y_ref*y_ref)*exp(coeff_expx*x_phys*x_phys) * (1.0+0.7*x_phys);
262  //const double function = y_height*y_ref + bump_height*exp(coeff_expy*y_ref*y_ref)*exp(coeff_expx*x_phys*x_phys) - y_phys;
263  //const double derivative = y_height + bump_height*coeff_expy*2*y_ref*exp(coeff_expy*y_ref*y_ref)*exp(coeff_expx*x_phys*x_phys);
264  y_ref = y_ref - function/derivative;
265  if(std::abs(function) < 1e-15) break;
266  }
267  const double function = y_height*y_ref + bump_height*exp(coeff_expy*y_ref*y_ref)*exp(coeff_expx*x_phys*x_phys) * (1.0+0.7*x_phys);
268  const double error = std::abs(function - y_phys);
269  if (error > 1e-13) {
270  std::cout << "Large error " << error << std::endl;
271  std::cout << "xref " << x_ref << "yref " << y_ref << "y_phys " << y_phys << " " << function << " " << error << std::endl;
272  }
273 
274  dealii::Point<2> p(x_ref, y_ref);
275  return p;
276 }
277 
278 dealii::Point<2> BumpManifoldAdjoint::push_forward(const dealii::Point<2> &chart_point) const
279 {
280  double x_ref = chart_point[0];
281  double y_ref = chart_point[1];
282  double x_phys = x_ref;//-1.5+x_ref*3.0;
283  double y_phys = y_height*y_ref + exp(coeff_expy*y_ref*y_ref)*bump_height*exp(coeff_expx*x_phys*x_phys) * (1.0+0.7*x_phys);
284  return dealii::Point<2> ( x_phys, y_phys); // Trigonometric
285 }
286 
287 dealii::DerivativeForm<1,2,2> BumpManifoldAdjoint::push_forward_gradient(const dealii::Point<2> &chart_point) const
288 {
289  dealii::DerivativeForm<1, 2, 2> dphys_dref;
290  double x_ref = chart_point[0];
291  double y_ref = chart_point[1];
292  double x_phys = x_ref;
293  //double y_phys = y_height*y_ref + exp(coeff_expy*y_ref*y_ref)*bump_height*exp(coeff_expx*x_phys*x_phys);
294  dphys_dref[0][0] = 1;
295  dphys_dref[0][1] = 0;
296  dphys_dref[1][0] = exp(coeff_expy*y_ref*y_ref)*bump_height*exp(coeff_expx*x_phys*x_phys) * coeff_expx*2*x_phys*dphys_dref[0][0] * (1.0+0.7*x_phys);
297  dphys_dref[1][0] += exp(coeff_expy*y_ref*y_ref)*bump_height*exp(coeff_expx*x_phys*x_phys) * 0.7*dphys_dref[0][0];
298  dphys_dref[1][1] = y_height + coeff_expy * 2*y_ref * exp(coeff_expy*y_ref*y_ref)*bump_height*exp(coeff_expx*x_phys*x_phys) * (1.0+0.7*x_phys);
299  return dphys_dref;
300 }
301 
302 std::unique_ptr<dealii::Manifold<2,2> > BumpManifoldAdjoint::clone() const
303 {
304  return std::make_unique<BumpManifoldAdjoint>();
305 }
306 
307 
308 template<int dim, int nstate>
310 ::run_test () const
311 {
313  using GridEnum = ManParam::GridEnum;
315 
316  Assert(dim == param.dimension, dealii::ExcDimensionMismatch(dim, param.dimension));
317  //Assert(param.pde_type != param.PartialDifferentialEquation::euler, dealii::ExcNotImplemented());
318  //if (param.pde_type == param.PartialDifferentialEquation::euler) return 1;
319 
320  ManParam manu_grid_conv_param = param.manufactured_convergence_study_param;
321 
322  const unsigned int p_start = manu_grid_conv_param.degree_start;
323  const unsigned int p_end = manu_grid_conv_param.degree_end;
324 
325  const unsigned int n_grids_input = manu_grid_conv_param.number_of_grids;
326 
327  // const unsigned int poly_max = p_end+1;
328 
329  Physics::Euler<dim,nstate,double> euler_physics_double
331  param.euler_param.ref_length,
332  param.euler_param.gamma_gas,
333  param.euler_param.mach_inf,
336 
339  param.euler_param.ref_length,
340  param.euler_param.gamma_gas,
341  param.euler_param.mach_inf,
344 
345  FreeStreamInitialConditionsAdjoint<dim,nstate> initial_conditions(euler_physics_double);
346  pcout << "Farfield conditions: "<< std::endl;
347  for (int s=0;s<nstate;s++) {
348  pcout << initial_conditions.farfield_conservative[s] << std::endl;
349  }
350 
351  std::vector<int> fail_conv_poly;
352  std::vector<double> fail_conv_slop;
353  std::vector<dealii::ConvergenceTable> convergence_table_vector;
354 
355  for (unsigned int poly_degree = p_start; poly_degree <= p_end; ++poly_degree) {
356 
357  // p0 tends to require a finer grid to reach asymptotic region
358  unsigned int n_grids = n_grids_input;
359  if (poly_degree <= 1) n_grids = n_grids_input;
360 
361  std::vector<double> entropy_error(n_grids);
362  std::vector<double> grid_size(n_grids);
363 
364  const std::vector<int> n_1d_cells = get_number_1d_cells(n_grids);
365 
366  dealii::ConvergenceTable convergence_table;
367 
368  std::vector<unsigned int> n_subdivisions(dim);
369  //n_subdivisions[1] = n_1d_cells[0]; // y-direction
370  //n_subdivisions[0] = 4*n_subdivisions[1]; // x-direction
371  n_subdivisions[1] = n_1d_cells[0]; // y-direction
372  n_subdivisions[0] = 9*n_subdivisions[1]; // x-direction
373  dealii::Point<2> p1(-1.5,0.0), p2(1.5,y_height);
374  const bool colorize = true;
375  dealii::parallel::distributed::Triangulation<dim> grid(this->mpi_communicator);
376  // typename dealii::Triangulation<dim>::MeshSmoothing(
377  // dealii::Triangulation<dim>::smoothing_on_refinement |
378  // dealii::Triangulation<dim>::smoothing_on_coarsening));
379  dealii::GridGenerator::subdivided_hyper_rectangle (grid, n_subdivisions, p1, p2, colorize);
380 
381  for (typename dealii::parallel::distributed::Triangulation<dim>::active_cell_iterator cell = grid.begin_active(); cell != grid.end(); ++cell) {
382  for (unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
383  if (cell->face(face)->at_boundary()) {
384  unsigned int current_id = cell->face(face)->boundary_id();
385  if (current_id == 2 || current_id == 3) cell->face(face)->set_boundary_id (1001); // Bottom and top wall
386  if (current_id == 1) cell->face(face)->set_boundary_id (1002); // Outflow with supersonic or back_pressure
387  if (current_id == 0) cell->face(face)->set_boundary_id (1003); // Inflow
388  }
389  }
390  }
391 
392  // Warp grid to be a gaussian bump
393  dealii::GridTools::transform (&warp, grid);
394 
395 
396  // Assign a manifold to have curved geometry
397  const BumpManifoldAdjoint bump_manifold;
398  unsigned int manifold_id=0; // top face, see GridGenerator::hyper_rectangle, colorize=true
399  grid.reset_all_manifolds();
400  grid.set_all_manifold_ids(manifold_id);
401  grid.set_manifold ( manifold_id, bump_manifold );
402 
403  // Create DG object
404  // std::shared_ptr < DGBase<dim, double> > dg = DGFactory<dim,double>::create_discontinuous_galerkin(&param, poly_degree, &grid);
405  // std::shared_ptr < DGBase<dim, double> > dg = DGFactory<dim,double>::create_discontinuous_galerkin(&param, poly_max/*poly_degree*/, &grid);
406  std::shared_ptr < DGBase<dim, double> > dg = DGFactory<dim,double>::create_discontinuous_galerkin(&param, poly_degree, poly_degree+1, &grid);
407 
408  // Initialize coarse grid solution with free-stream
409  dg->allocate_system ();
410  dealii::VectorTools::interpolate(dg->dof_handler, initial_conditions, dg->solution);
411 
412  // Create ODE solver and ramp up the solution from p0
413  std::shared_ptr<ODE::ODESolverBase<dim, double>> ode_solver = ODE::ODESolverFactory<dim, double>::create_ODESolver(dg);
414  ode_solver->initialize_steady_polynomial_ramping (poly_degree);
415 
416  // setting up the target functional (error reduction)
417  BoundaryIntegral<dim, nstate, double> BoundaryIntegralFunctional;
418 
419  // initializing an adjoint for this case
420  Adjoint<dim, nstate, double> adjoint(*dg, BoundaryIntegralFunctional, euler_physics_adtype);
421 
422  dealii::Vector<float> estimated_error_per_cell(grid.n_active_cells());
423  for (unsigned int igrid=0; igrid<n_grids; ++igrid) {
424 
425 
426  if (igrid!=0) {
427  dealii::LinearAlgebra::distributed::Vector<double> old_solution(dg->solution);
428  dealii::parallel::distributed::SolutionTransfer<dim, dealii::LinearAlgebra::distributed::Vector<double>, dealii::DoFHandler<dim>> solution_transfer(dg->dof_handler);
429  solution_transfer.prepare_for_coarsening_and_refinement(old_solution);
430  dg->high_order_grid.prepare_for_coarsening_and_refinement();
431  // grid.refine_global (1);
432 
433  dealii::parallel::distributed::GridRefinement::refine_and_coarsen_fixed_number(grid,
434  // dealii::GridRefinement::refine_and_coarsen_fixed_number(grid,
435  estimated_error_per_cell,
436  0.3,
437  0.03);
438 
439  grid.execute_coarsening_and_refinement();
440  dg->high_order_grid.execute_coarsening_and_refinement();
441  dg->allocate_system ();
442  dg->solution.zero_out_ghosts();
443  solution_transfer.interpolate(dg->solution);
444  dg->solution.update_ghost_values();
445 
446  estimated_error_per_cell.reinit(grid.n_active_cells());
447  }
448 
449  const unsigned int n_global_active_cells = grid.n_global_active_cells();
450  const unsigned int n_dofs = dg->dof_handler.n_dofs();
451  pcout << "Dimension: " << dim << "\t Polynomial degree p: " << poly_degree << std::endl
452  << "Grid number: " << igrid+1 << "/" << n_grids
453  << ". Number of active cells: " << n_global_active_cells
454  << ". Number of degrees of freedom: " << n_dofs
455  << std::endl;
456 
457  // Solve the steady state problem
458  ode_solver->steady_state();
459  //ode_solver->initialize_steady_polynomial_ramping(poly_degree);
460 
461  // Overintegrate the error to make sure there is not integration error in the error estimate
462  int overintegrate = 10;
463  dealii::QGauss<dim> quad_extra(dg->max_degree+1+overintegrate);
464  dealii::MappingQ<dim> mappingq(dg->max_degree+overintegrate);
465  dealii::FEValues<dim,dim> fe_values_extra(mappingq, dg->fe_collection[poly_degree], quad_extra,
466  dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
467  const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
468  std::array<double,nstate> soln_at_q;
469 
470  double l2error = 0;
471 
472  std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
473 
474  const double entropy_inf = euler_physics_double.entropy_inf;
475 
476  // Integrate solution error and output error
477  for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
478 
479  if (!cell->is_locally_owned()) continue;
480  fe_values_extra.reinit (cell);
481  cell->get_dof_indices (dofs_indices);
482 
483  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
484 
485  std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
486  for (unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
487  const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
488  soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
489  }
490  const double entropy = euler_physics_double.compute_entropy_measure(soln_at_q);
491 
492  const double uexact = entropy_inf;
493  l2error += pow(entropy - uexact, 2) * fe_values_extra.JxW(iquad);
494  }
495  }
496  const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error, mpi_communicator));
497 
498  // computing using Functional for comparison
499  const double l2error_functional = BoundaryIntegralFunctional.evaluate_function(*dg, euler_physics_double);
500  pcout << "Error computed by original loop: " << l2error_mpi_sum << std::endl << "Error computed by the functional: " << std::sqrt(l2error_functional) << std::endl;
501 
502  // reinitializing the adjoint with the current values (from references)
503  adjoint.reinit();
504 
505  // evaluating the derivatives and the adjoint on the fine grid
506  adjoint.convert_to_state(PHiLiP::Adjoint<dim,nstate,double>::AdjointStateEnum::fine); // will do this automatically, but I prefer to repeat explicitly
507  adjoint.fine_grid_adjoint();
508  estimated_error_per_cell = adjoint.dual_weighted_residual(); // performing the error indicator computation
509 
510  // and outputing the fine properties
511  adjoint.output_results_vtk(igrid);
512 
514  adjoint.coarse_grid_adjoint();
515  adjoint.output_results_vtk(igrid);
516 
517  // Convergence table
518  double dx = 1.0/pow(n_dofs,(1.0/dim));
519  //dx = dealii::GridTools::maximal_cell_diameter(grid);
520  grid_size[igrid] = dx;
521  entropy_error[igrid] = l2error_mpi_sum;
522 
523  convergence_table.add_value("p", poly_degree);
524  convergence_table.add_value("cells", n_global_active_cells);
525  convergence_table.add_value("DoFs", n_dofs);
526  convergence_table.add_value("dx", dx);
527  convergence_table.add_value("L2_entropy_error", l2error_mpi_sum);
528 
529 
530  pcout << " Grid size h: " << dx
531  << " L2-entropy_error: " << l2error_mpi_sum
532  << " Residual: " << ode_solver->residual_norm
533  << std::endl;
534 
535  if (igrid > 0) {
536  const double slope_soln_err = log(entropy_error[igrid]/entropy_error[igrid-1])
537  / log(grid_size[igrid]/grid_size[igrid-1]);
538  pcout << "From grid " << igrid-1
539  << " to grid " << igrid
540  << " dimension: " << dim
541  << " polynomial degree p: " << poly_degree
542  << std::endl
543  << " entropy_error1 " << entropy_error[igrid-1]
544  << " entropy_error2 " << entropy_error[igrid]
545  << " slope " << slope_soln_err
546  << std::endl;
547  }
548 
549  //output_results (igrid);
550  }
551  pcout << " ********************************************" << std::endl
552  << " Convergence rates for p = " << poly_degree << std::endl
553  << " ********************************************" << std::endl;
554  convergence_table.evaluate_convergence_rates("L2_entropy_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
555  convergence_table.set_scientific("dx", true);
556  convergence_table.set_scientific("L2_entropy_error", true);
557  if (pcout.is_active()) convergence_table.write_text(pcout.get_stream());
558 
559  convergence_table_vector.push_back(convergence_table);
560 
561  const double expected_slope = poly_degree+1;
562 
563  const double last_slope = log(entropy_error[n_grids-1]/entropy_error[n_grids-2])
564  / log(grid_size[n_grids-1]/grid_size[n_grids-2]);
565  //double before_last_slope = last_slope;
566  //if ( n_grids > 2 ) {
567  // before_last_slope = log(entropy_error[n_grids-2]/entropy_error[n_grids-3])
568  // / log(grid_size[n_grids-2]/grid_size[n_grids-3]);
569  //}
570  //const double slope_avg = 0.5*(before_last_slope+last_slope);
571  const double slope_avg = last_slope;
572  const double slope_diff = slope_avg-expected_slope;
573 
574  double slope_deficit_tolerance = -std::abs(manu_grid_conv_param.slope_deficit_tolerance);
575  if(poly_degree == 0) slope_deficit_tolerance *= 2; // Otherwise, grid sizes need to be much bigger for p=0
576 
577  if (slope_diff < slope_deficit_tolerance) {
578  pcout << std::endl
579  << "Convergence order not achieved. Average last 2 slopes of "
580  << slope_avg << " instead of expected "
581  << expected_slope << " within a tolerance of "
582  << slope_deficit_tolerance
583  << std::endl;
584  // p=0 just requires too many meshes to get into the asymptotic region.
585  if(poly_degree!=0) fail_conv_poly.push_back(poly_degree);
586  if(poly_degree!=0) fail_conv_slop.push_back(slope_avg);
587  }
588 
589  }
590  pcout << std::endl << std::endl << std::endl << std::endl;
591  pcout << " ********************************************" << std::endl;
592  pcout << " Convergence summary" << std::endl;
593  pcout << " ********************************************" << std::endl;
594  for (auto conv = convergence_table_vector.begin(); conv!=convergence_table_vector.end(); conv++) {
595  if (pcout.is_active()) conv->write_text(pcout.get_stream());
596  pcout << " ********************************************" << std::endl;
597  }
598  int n_fail_poly = fail_conv_poly.size();
599  if (n_fail_poly > 0) {
600  for (int ifail=0; ifail < n_fail_poly; ++ifail) {
601  const double expected_slope = fail_conv_poly[ifail]+1;
602  const double slope_deficit_tolerance = -0.1;
603  pcout << std::endl
604  << "Convergence order not achieved for polynomial p = "
605  << fail_conv_poly[ifail]
606  << ". Slope of "
607  << fail_conv_slop[ifail] << " instead of expected "
608  << expected_slope << " within a tolerance of "
609  << slope_deficit_tolerance
610  << std::endl;
611  }
612  }
613  return n_fail_poly;
614 }
615 
616 
617 #if PHILIP_DIM==2
619 #endif
620 
621 } // Tests namespace
622 } // PHiLiP namespace
623 
unsigned int degree_start
First polynomial degree to start the loop. If diffusion, must be at least 1.
void convert_to_state(AdjointStateEnum state)
Converts the adjoint to specified state.
Definition: adjoint.cpp:78
dealii::LinearAlgebra::distributed::Vector< real > fine_grid_adjoint()
Computes the fine grid adjoint.
Definition: adjoint.cpp:157
real2 evaluate_cell_boundary(const PHiLiP::Physics::PhysicsBase< dim, nstate, real2 > &physics, const unsigned int boundary_id, const dealii::FEFaceValues< dim, dim > &fe_values_boundary, std::vector< real2 > local_solution)
Templated function to evaluate exit pressure integral.
virtual dealii::Point< 2 > push_forward(const dealii::Point< 2 > &chart_point) const override
Corresponding dealii::ChartManifold::push_forward.
virtual dealii::DerivativeForm< 1, 2, 2 > push_forward_gradient(const dealii::Point< 2 > &chart_point) const override
Corresponding dealii::ChartManifold::push_forward_gradient.
Parameters related to the manufactured convergence study.
Performs grid convergence for various polynomial degrees.
Base class from which Advection, Diffusion, ConvectionDiffusion, and Euler is derived.
Definition: physics.h:34
Adjoint class.
Definition: adjoint.h:39
const double gam
Constant heat capacity ratio of fluid.
Definition: euler.h:105
virtual dealii::Point< 2 > pull_back(const dealii::Point< 2 > &space_point) const override
Corresponding dealii::ChartManifold::pull_back.
const MPI_Comm mpi_communicator
MPI communicator.
Definition: tests.h:39
const double density_inf
Definition: euler.h:111
double mach_inf
Mach number at infinity.
Sacado::Fad::DFad< real > evaluate_cell_boundary(const PHiLiP::Physics::PhysicsBase< dim, nstate, Sacado::Fad::DFad< real >> &physics, const unsigned int boundary_id, const dealii::FEFaceValues< dim, dim > &fe_values_boundary, std::vector< Sacado::Fad::DFad< real >> local_solution) override
Corresponding non-templated function for evaluate_cell_boundary.
Files for the baseline physics.
Definition: ADTypes.hpp:10
int run_test() const
Grid convergence on Euler Gaussian Bump.
EulerGaussianBumpAdjoint()=delete
Constructor. Deleted the default constructor since it should not be used.
EulerParam euler_param
Contains parameters for the Euler equations non-dimensionalization.
FreeStreamInitialConditions(const Physics::Euler< dim, nstate, double > euler_physics)
Constructor.
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::Vector< real > dual_weighted_residual()
compute the Dual Weighted Residual (DWR)
Definition: adjoint.cpp:216
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
dealii::LinearAlgebra::distributed::Vector< real > coarse_grid_adjoint()
Computes the coarse grid adjoint.
Definition: adjoint.cpp:187
double ref_length
Reference length.
Initial conditions to initialize our flow with.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: tests.h:20
void reinit()
Reinitialize Adjoint with the same pointers.
Definition: adjoint.cpp:53
double side_slip_angle
Input file provides in degrees, but the value stored here is in radians.
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
virtual std::unique_ptr< dealii::Manifold< 2, 2 > > clone() const override
Corresponding dealii::ChartManifold::clone.
const double entropy_inf
Entropy measure at infinity.
Definition: euler.h:127
Euler equations. Derived from PhysicsBase.
Definition: euler.h:78
static dealii::Point< dim > warp(const dealii::Point< dim > &p)
Warp grid into Gaussian bump.
double angle_of_attack
Input file provides in degrees, but the value stored here is in radians.
double value(const dealii::Point< dim > &, const unsigned int istate) const override
Corresponds to dealii::Function::value.
real2 compute_pressure(const std::array< real2, nstate > &conservative_soln) const
Evaluate pressure from conservative variables.
Definition: euler.cpp:369
void output_results_vtk(const unsigned int cycle)
Outputs the current solution and adjoint values.
Definition: adjoint.cpp:249
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
Functional base class.
Definition: functional.h:43
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::array< real, nstate > convert_primitive_to_conservative(const std::array< real, nstate > &primitive_soln) const
Definition: euler.cpp:199
const double mach_inf_sqr
Definition: euler.h:114
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) ...
dealii::Tensor< 1, dim, double > velocities_inf
Non-dimensionalized Velocity vector at farfield.
Definition: euler.h:136
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
std::array< double, nstate > far_field_conservative
Conservative freestream variables.
real evaluate_cell_boundary(const PHiLiP::Physics::PhysicsBase< dim, nstate, real > &physics, const unsigned int boundary_id, const dealii::FEFaceValues< dim, dim > &fe_values_boundary, std::vector< real > local_solution) override
Corresponding non-templated function for evaluate_cell_boundary.