4 #include <deal.II/base/convergence_table.h> 6 #include <deal.II/distributed/tria.h> 7 #include <deal.II/distributed/grid_refinement.h> 9 #include <deal.II/distributed/solution_transfer.h> 10 #include <deal.II/dofs/dof_tools.h> 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> 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> 22 #include <deal.II/numerics/vector_tools.h> 23 #include <deal.II/numerics/data_out.h> 25 #include <deal.II/fe/fe_values.h> 27 #include <deal.II/fe/mapping_q.h> 29 #include "euler_gaussian_bump_adjoint.h" 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" 36 #include "functional/functional.h" 37 #include "functional/adjoint.h" 39 #include <deal.II/distributed/solution_transfer.h> 42 #include "linear_solver/linear_solver.h" 44 #include "post_processor/physics_post_processor.h" 104 template <
int dim,
int nstate,
typename real>
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){
118 if(boundary_id == 1002){
122 unsigned int n_quad_pts = fe_values_boundary.n_quadrature_points;
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);
137 l2error += pressure * fe_values_boundary.JxW(iquad);
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);}
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);}
200 template <
int dim,
int nstate>
209 : dealii::Function<dim,double>(nstate)
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;
221 double value (
const dealii::Point<dim> &,
const unsigned int istate)
const override 223 return farfield_conservative[istate];
228 template <
int dim,
int nstate>
234 const double y_height = 0.8;
235 const double bump_height = 0.0625;
236 const double coeff_expx = -25;
237 const double coeff_expy = -30;
238 template <
int dim,
int nstate>
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;
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]);
253 double x_phys = space_point[0];
254 double y_phys = space_point[1];
255 double x_ref = x_phys;
257 double y_ref = y_phys;
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);
264 y_ref = y_ref -
function/derivative;
265 if(std::abs(
function) < 1e-15)
break;
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);
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;
274 dealii::Point<2> p(x_ref, y_ref);
280 double x_ref = chart_point[0];
281 double y_ref = chart_point[1];
282 double x_phys = x_ref;
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);
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;
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);
304 return std::make_unique<BumpManifoldAdjoint>();
308 template<
int dim,
int nstate>
313 using GridEnum = ManParam::GridEnum;
322 const unsigned int p_start = manu_grid_conv_param.
degree_start;
323 const unsigned int p_end = manu_grid_conv_param.degree_end;
325 const unsigned int n_grids_input = manu_grid_conv_param.number_of_grids;
346 pcout <<
"Farfield conditions: "<< std::endl;
347 for (
int s=0;s<nstate;s++) {
348 pcout << initial_conditions.farfield_conservative[s] << std::endl;
351 std::vector<int> fail_conv_poly;
352 std::vector<double> fail_conv_slop;
353 std::vector<dealii::ConvergenceTable> convergence_table_vector;
355 for (
unsigned int poly_degree = p_start; poly_degree <= p_end; ++poly_degree) {
358 unsigned int n_grids = n_grids_input;
359 if (poly_degree <= 1) n_grids = n_grids_input;
361 std::vector<double> entropy_error(n_grids);
362 std::vector<double> grid_size(n_grids);
366 dealii::ConvergenceTable convergence_table;
368 std::vector<unsigned int> n_subdivisions(dim);
371 n_subdivisions[1] = n_1d_cells[0];
372 n_subdivisions[0] = 9*n_subdivisions[1];
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);
379 dealii::GridGenerator::subdivided_hyper_rectangle (grid, n_subdivisions, p1, p2, colorize);
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);
386 if (current_id == 1) cell->face(face)->set_boundary_id (1002);
387 if (current_id == 0) cell->face(face)->set_boundary_id (1003);
393 dealii::GridTools::transform (&
warp, grid);
398 unsigned int manifold_id=0;
399 grid.reset_all_manifolds();
400 grid.set_all_manifold_ids(manifold_id);
401 grid.set_manifold ( manifold_id, bump_manifold );
409 dg->allocate_system ();
410 dealii::VectorTools::interpolate(dg->dof_handler, initial_conditions, dg->solution);
414 ode_solver->initialize_steady_polynomial_ramping (poly_degree);
422 dealii::Vector<float> estimated_error_per_cell(grid.n_active_cells());
423 for (
unsigned int igrid=0; igrid<n_grids; ++igrid) {
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();
433 dealii::parallel::distributed::GridRefinement::refine_and_coarsen_fixed_number(grid,
435 estimated_error_per_cell,
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();
446 estimated_error_per_cell.reinit(grid.n_active_cells());
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
458 ode_solver->steady_state();
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;
472 std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
474 const double entropy_inf = euler_physics_double.
entropy_inf;
477 for (
auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
479 if (!cell->is_locally_owned())
continue;
480 fe_values_extra.reinit (cell);
481 cell->get_dof_indices (dofs_indices);
483 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
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);
492 const double uexact = entropy_inf;
493 l2error += pow(entropy - uexact, 2) * fe_values_extra.JxW(iquad);
496 const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error,
mpi_communicator));
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;
518 double dx = 1.0/pow(n_dofs,(1.0/dim));
520 grid_size[igrid] = dx;
521 entropy_error[igrid] = l2error_mpi_sum;
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);
530 pcout <<
" Grid size h: " << dx
531 <<
" L2-entropy_error: " << l2error_mpi_sum
532 <<
" Residual: " << ode_solver->residual_norm
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
543 <<
" entropy_error1 " << entropy_error[igrid-1]
544 <<
" entropy_error2 " << entropy_error[igrid]
545 <<
" slope " << slope_soln_err
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());
559 convergence_table_vector.push_back(convergence_table);
561 const double expected_slope = poly_degree+1;
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]);
571 const double slope_avg = last_slope;
572 const double slope_diff = slope_avg-expected_slope;
574 double slope_deficit_tolerance = -std::abs(manu_grid_conv_param.slope_deficit_tolerance);
575 if(poly_degree == 0) slope_deficit_tolerance *= 2;
577 if (slope_diff < slope_deficit_tolerance) {
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
585 if(poly_degree!=0) fail_conv_poly.push_back(poly_degree);
586 if(poly_degree!=0) fail_conv_slop.push_back(slope_avg);
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;
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;
604 <<
"Convergence order not achieved for polynomial p = " 605 << fail_conv_poly[ifail]
607 << fail_conv_slop[ifail] <<
" instead of expected " 608 << expected_slope <<
" within a tolerance of " 609 << slope_deficit_tolerance
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.
dealii::LinearAlgebra::distributed::Vector< real > fine_grid_adjoint()
Computes the fine grid adjoint.
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.
const double gam
Constant heat capacity ratio of fluid.
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.
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.
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)
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
dealii::LinearAlgebra::distributed::Vector< real > coarse_grid_adjoint()
Computes the coarse grid adjoint.
double ref_length
Reference length.
Initial conditions to initialize our flow with.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
void reinit()
Reinitialize Adjoint with the same pointers.
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.
virtual std::unique_ptr< dealii::Manifold< 2, 2 > > clone() const override
Corresponding dealii::ChartManifold::clone.
const double entropy_inf
Entropy measure at infinity.
Euler equations. Derived from PhysicsBase.
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.
void output_results_vtk(const unsigned int cycle)
Outputs the current solution and adjoint values.
dealii::ConditionalOStream pcout
ConditionalOStream.
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.
std::array< real, nstate > convert_primitive_to_conservative(const std::array< real, nstate > &primitive_soln) const
const double mach_inf_sqr
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.
Base class of all the tests.
real compute_entropy_measure(const std::array< real, nstate > &conservative_soln) const
Evaluate entropy from conservative variables.
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.