4 #include <deal.II/base/convergence_table.h> 6 #include <deal.II/dofs/dof_tools.h> 8 #include <deal.II/distributed/tria.h> 9 #include <deal.II/grid/tria.h> 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> 17 #include <deal.II/numerics/vector_tools.h> 19 #include <deal.II/fe/fe_values.h> 21 #include "ADTypes.hpp" 26 #include "physics/physics_factory.h" 27 #include "physics/manufactured_solution.h" 28 #include "dg/dg_factory.hpp" 29 #include "dg/weak_dg.hpp" 30 #include "ode_solver/ode_solver_factory.h" 39 template <
int dim,
int nspecies,
typename real>
43 using dealii::Function<dim,real>::value;
44 using dealii::Function<dim,real>::gradient;
45 using dealii::Function<dim,real>::hessian;
46 using dealii::Function<dim,real>::vector_gradient;
62 virtual real
value (
const dealii::Point<dim,real> &point,
const unsigned int )
const override 66 for (
int d=0;d<dim;d++) {
77 virtual dealii::Tensor<1,dim,real>
gradient (
const dealii::Point<dim,real> &point,
const unsigned int )
const override 82 for (
int d=0;d<dim;d++) {
83 gradient[d] = cos(point[d]);
92 virtual dealii::SymmetricTensor<2,dim,real>
hessian (
const dealii::Point<dim,real> &point,
const unsigned int )
const override 94 dealii::SymmetricTensor<2,dim,real>
hessian;
97 for (
int d=0;d<dim;d++) {
98 hessian[d][d] = -sin(point[d]);
104 template <
int dim,
int nspecies,
int nstate>
108 pcout <<
"Evaluating solution integral..." << std::endl;
109 double solution_integral = 0.0;
116 int overintegrate = 10;
117 dealii::QGauss<dim> quad_extra(dg.
max_degree+1+overintegrate);
120 dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
121 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
122 std::array<double,nstate> soln_at_q;
124 const bool linear_output =
false;
126 if (linear_output) power = 1;
130 std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
131 for (
auto cell : dg.
dof_handler.active_cell_iterators()) {
133 if (!cell->is_locally_owned())
continue;
135 fe_values_extra.reinit (cell);
136 cell->get_dof_indices (dofs_indices);
138 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
141 std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
142 for (
unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
143 const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
144 soln_at_q[istate] += dg.
solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
147 for (
int s=0; s<
nstate; s++) {
148 solution_integral += pow(soln_at_q[0], power) * fe_values_extra.JxW(iquad);
153 const double solution_integral_mpi_sum = dealii::Utilities::MPI::sum(solution_integral, mpi_communicator);
154 return solution_integral_mpi_sum;
158 template <
int dim,
int nspecies>
164 const double time = 0.)
165 : dealii::Function<dim>(n_components, time)
168 virtual double value(
const dealii::Point<dim> &p,
169 const unsigned int )
const override 171 const double PI = std::atan(1) * 4.0;
172 return std::sin(p[0]*2.0*PI);
176 template <
int dim,
int nspecies,
int nstate>
182 template <
int dim,
int nspecies,
int nstate>
186 dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
192 template<
int dim,
int nspecies,
int nstate>
197 using Triangulation = dealii::Triangulation<dim>;
199 using Triangulation = dealii::parallel::distributed::Triangulation<dim>;
203 using GridEnum = ManParam::GridEnum;
212 const unsigned int p_start = manu_grid_conv_param.
degree_start;
213 const unsigned int p_end = manu_grid_conv_param.degree_end;
215 const unsigned int n_grids_input = manu_grid_conv_param.number_of_grids;
223 std::shared_ptr shocked_1d1state_double = std::make_shared < Shocked1D1State<dim,nspecies,double> > (nstate);
224 std::shared_ptr shocked_1d1state_fad = std::make_shared < Shocked1D1State<dim,nspecies,FadType> > (nstate);
225 std::shared_ptr shocked_1d1state_rad = std::make_shared < Shocked1D1State<dim,nspecies,RadType> > (nstate);
226 std::shared_ptr shocked_1d1state_fad_fad = std::make_shared < Shocked1D1State<dim,nspecies,FadFadType> > (nstate);
227 std::shared_ptr shocked_1d1state_rad_fad = std::make_shared < Shocked1D1State<dim,nspecies,RadFadType> > (nstate);
228 physics_double->manufactured_solution_function = shocked_1d1state_double;
229 physics_fad->manufactured_solution_function = shocked_1d1state_fad;
230 physics_fad_fad->manufactured_solution_function = shocked_1d1state_fad_fad;
231 physics_rad_fad->manufactured_solution_function = shocked_1d1state_rad_fad;
234 double exact_solution_integral;
235 pcout <<
"Evaluating EXACT solution integral..." << std::endl;
239 std::shared_ptr<Triangulation> grid_super_fine = std::make_shared<Triangulation>(
243 typename dealii::Triangulation<dim>::MeshSmoothing(
244 dealii::Triangulation<dim>::smoothing_on_refinement |
245 dealii::Triangulation<dim>::smoothing_on_coarsening));
246 dealii::GridGenerator::subdivided_hyper_cube(*grid_super_fine, n_1d_cells[n_grids_input-1]);
247 std::shared_ptr dg_super_fine = std::make_shared< DGWeak<dim,nspecies,1,double> > (¶m, p_end, p_end, p_end+1, grid_super_fine);
248 dg_super_fine->set_physics(physics_double, physics_fad, physics_rad, physics_fad_fad, physics_rad_fad);
249 dg_super_fine->allocate_system ();
253 pcout <<
"Exact solution integral is " << exact_solution_integral << std::endl;
256 std::vector<int> fail_conv_poly;
257 std::vector<double> fail_conv_slop;
258 std::vector<dealii::ConvergenceTable> convergence_table_vector;
260 for (
unsigned int poly_degree = p_start; poly_degree <= p_end; ++poly_degree) {
263 unsigned int n_grids = n_grids_input;
264 if (poly_degree <= 1) n_grids = n_grids_input + 1;
266 std::vector<double> soln_error(n_grids);
267 std::vector<double> output_error(n_grids);
268 std::vector<double> grid_size(n_grids);
272 dealii::ConvergenceTable convergence_table;
274 std::shared_ptr<Triangulation> grid = std::make_shared<Triangulation>(
278 typename dealii::Triangulation<dim>::MeshSmoothing(
279 dealii::Triangulation<dim>::smoothing_on_refinement |
280 dealii::Triangulation<dim>::smoothing_on_coarsening));
282 dealii::Vector<float> estimated_error_per_cell;
283 for (
unsigned int igrid=n_grids-1; igrid<n_grids; ++igrid) {
285 dealii::GridGenerator::subdivided_hyper_cube(*grid, n_1d_cells[igrid]);
286 for (
auto cell = grid->begin_active(); cell != grid->end(); ++cell) {
288 cell->set_material_id(9002);
289 for (
unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
290 if (cell->face(face)->at_boundary()) cell->face(face)->set_boundary_id (1000);
293 std::vector<dealii::GridTools::PeriodicFacePair<typename Triangulation::cell_iterator> > matched_pairs;
294 dealii::GridTools::collect_periodic_faces(*grid,0,1,0,matched_pairs);
295 grid->add_periodicity(matched_pairs);
299 std::shared_ptr dg = std::make_shared< DGWeak<dim,nspecies,1,double> > (¶m, poly_degree, poly_degree, poly_degree+1, grid);
300 dg->set_physics(physics_double, physics_fad, physics_rad, physics_fad_fad, physics_rad_fad);
301 dg->allocate_system ();
306 const unsigned int n_global_active_cells = grid->n_global_active_cells();
307 const unsigned int n_dofs = dg->dof_handler.n_dofs();
308 pcout <<
"Dimension: " << dim
309 <<
"\t Polynomial degree p: " << poly_degree
311 <<
"Grid number: " << igrid+1 <<
"/" << n_grids
312 <<
". Number of active cells: " << n_global_active_cells
313 <<
". Number of degrees of freedom: " << n_dofs
320 ode_solver->steady_state();
323 int overintegrate = 10;
324 dealii::QGauss<dim> quad_extra(dg->max_degree+overintegrate);
326 dealii::FEValues<dim,dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra,
327 dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
328 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
329 std::array<double,nstate> soln_at_q;
335 std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
336 estimated_error_per_cell.reinit(grid->n_active_cells());
337 for (
auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
339 if (!cell->is_locally_owned())
continue;
341 fe_values_extra.reinit (cell);
342 cell->get_dof_indices (dofs_indices);
344 double cell_l2error = 0;
345 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
347 std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
348 for (
unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
349 const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
350 soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
353 const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
355 for (
int istate=0; istate<nstate; ++istate) {
356 const double uexact = physics_double->manufactured_solution_function->value(qpoint, istate);
359 cell_l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_extra.JxW(iquad);
362 estimated_error_per_cell[cell->active_cell_index()] = cell_l2error;
363 l2error += cell_l2error;
366 const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error,
mpi_communicator));
371 const double dx = 1.0/pow(n_dofs,(1.0/dim));
372 grid_size[igrid] = dx;
373 soln_error[igrid] = l2error_mpi_sum;
374 output_error[igrid] = std::abs(solution_integral - exact_solution_integral);
376 convergence_table.add_value(
"p", poly_degree);
377 convergence_table.add_value(
"cells", n_global_active_cells);
378 convergence_table.add_value(
"DoFs", n_dofs);
379 convergence_table.add_value(
"dx", dx);
380 convergence_table.add_value(
"soln_L2_error", l2error_mpi_sum);
381 convergence_table.add_value(
"output_error", output_error[igrid]);
384 pcout <<
" Grid size h: " << dx
385 <<
" L2-soln_error: " << l2error_mpi_sum
386 <<
" Residual: " << ode_solver->residual_norm
389 pcout <<
" output_exact: " << exact_solution_integral
390 <<
" output_discrete: " << solution_integral
391 <<
" output_error: " << output_error[igrid]
395 pcout <<
" ********************************************" 397 <<
" Convergence rates for p = " << poly_degree
399 <<
" ********************************************" 401 convergence_table.evaluate_convergence_rates(
"soln_L2_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
402 convergence_table.evaluate_convergence_rates(
"output_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
403 convergence_table.set_scientific(
"dx",
true);
404 convergence_table.set_scientific(
"soln_L2_error",
true);
405 convergence_table.set_scientific(
"output_error",
true);
406 if (
pcout.is_active()) convergence_table.write_text(
pcout.get_stream());
408 convergence_table_vector.push_back(convergence_table);
411 pcout << std::endl << std::endl << std::endl << std::endl;
412 pcout <<
" ********************************************" << std::endl;
413 pcout <<
" Convergence summary" << std::endl;
414 pcout <<
" ********************************************" << std::endl;
415 for (
auto conv = convergence_table_vector.begin(); conv!=convergence_table_vector.end(); conv++) {
416 if (
pcout.is_active()) conv->write_text(
pcout.get_stream());
417 pcout <<
" ********************************************" << std::endl;
419 int n_fail_poly = fail_conv_poly.size();
420 if (n_fail_poly > 0) {
421 for (
int ifail=0; ifail < n_fail_poly; ++ifail) {
422 const double expected_slope = fail_conv_poly[ifail]+1;
423 const double slope_deficit_tolerance = -std::abs(manu_grid_conv_param.slope_deficit_tolerance);
425 <<
"Convergence order not achieved for polynomial p = " 426 << fail_conv_poly[ifail]
428 << fail_conv_slop[ifail] <<
" instead of expected " 429 << expected_slope <<
" within a tolerance of " 430 << slope_deficit_tolerance
437 template <
int dim,
int nspecies,
int nstate>
441 dealii::Point<dim> q = p;
443 if (dim >= 2) q[0] += 1*std::sin(q[dim-1]);
444 if (dim >= 3) q[1] += 1*std::cos(q[dim-1]);
448 template <
int dim,
int nspecies,
int nstate>
450 ::print_mesh_info(
const dealii::Triangulation<dim> &triangulation,
const std::string &filename)
const 452 pcout <<
"Mesh info:" << std::endl
453 <<
" dimension: " << dim << std::endl
454 <<
" no. of cells: " << triangulation.n_global_active_cells() << std::endl;
455 std::map<dealii::types::boundary_id, unsigned int> boundary_count;
456 for (
auto cell : triangulation.active_cell_iterators()) {
457 for (
unsigned int face=0; face < dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
458 if (cell->face(face)->at_boundary()) boundary_count[cell->face(face)->boundary_id()]++;
461 pcout <<
" boundary indicators: ";
462 for (
const std::pair<const dealii::types::boundary_id, unsigned int> &pair : boundary_count) {
463 pcout << pair.first <<
"(" << pair.second <<
" times) ";
467 std::ofstream out (filename);
468 dealii::GridOut grid_out;
469 grid_out.write_eps (triangulation, out);
470 pcout <<
" written to " << filename << std::endl << std::endl;
474 #if PHILIP_SPECIES==1 int run_test() const
Manufactured grid convergence.
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.
Parameters related to the manufactured convergence study.
Manufactured solution used for grid studies to check convergence orders.
const MPI_Comm mpi_communicator
MPI communicator.
Files for the baseline physics.
std::shared_ptr< HighOrderGrid< dim, real, MeshType > > high_order_grid
High order grid that will provide the MappingFEField.
Shocked 1D solution for 1 state variable.
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.
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.
dealii::DoFHandler< dim > dof_handler
Finite Element Collection to represent the high-order grid.
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
dealii::IndexSet locally_owned_dofs
Locally own degrees of freedom.
Shocked1D1State(const unsigned int nstate=1)
Constructor that initializes base_values, amplitudes, frequencies.
virtual dealii::Tensor< 1, dim, real > gradient(const dealii::Point< dim, real > &point, const unsigned int) const override
Gradient of the exact manufactured solution.
virtual double value(const dealii::Point< dim > &p, const unsigned int) const override
Initial value.
virtual real value(const dealii::Point< dim, real > &point, const unsigned int) const override
Manufactured solution exact value.
const unsigned int nstate
dealii::LinearAlgebra::distributed::Vector< double > solution
Current modal coefficients of the solution.
static dealii::Point< dim > warp(const dealii::Point< dim > &p)
Warps mesh into sinusoidal.
void initialize_perturbed_solution(DGBase< dim, nspecies, double > &dg, const Physics::PhysicsBase< dim, nspecies, nstate, double > &physics) const
Initialize the solution with the exact solution.
const unsigned int max_degree
Maximum degree used for p-refi1nement.
virtual dealii::SymmetricTensor< 2, dim, real > hessian(const dealii::Point< dim, real > &point, const unsigned int) const override
Hessian of the exact manufactured solution.
static std::shared_ptr< PhysicsBase< dim, nspecies, nstate, real > > create_Physics(const Parameters::AllParameters *const parameters_input, std::shared_ptr< ModelBase< dim, nspecies, nstate, real > > model_input=nullptr)
Factory to return the correct physics given input file.
double integrate_solution_over_domain(DGBase< dim, nspecies, double > &dg) const
L2-Integral of the solution over the entire domain.
dealii::ConditionalOStream pcout
ConditionalOStream.
const dealii::hp::FECollection< dim > fe_collection
Finite Element Collection for p-finite-element to represent the solution.
static std::shared_ptr< ODESolverBase< dim, nspecies, real, MeshType > > create_ODESolver(std::shared_ptr< DGBase< dim, nspecies, real, MeshType > > dg_input)
Creates either implicit or explicit ODE solver based on parameter value(no POD basis given) ...
DGBase is independent of the number of state variables.
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.
Shock1D()=delete
Constructor. Deleted the default constructor since it should not be used.
SineInitialCondition(const unsigned int n_components=1, const double time=0.)
Constructor.
Base class of all the tests.