3 #include <deal.II/base/convergence_table.h> 5 #include <deal.II/dofs/dof_tools.h> 7 #include <deal.II/distributed/tria.h> 9 #include <deal.II/grid/grid_generator.h> 10 #include <deal.II/grid/grid_refinement.h> 11 #include <deal.II/grid/grid_tools.h> 12 #include <deal.II/grid/grid_out.h> 13 #include <deal.II/grid/grid_in.h> 15 #include <deal.II/grid/grid_tools.h> 18 #include <deal.II/numerics/vector_tools.h> 20 #include <deal.II/fe/fe_values.h> 25 #include "euler_entropy_waves.h" 26 #include <deal.II/fe/mapping_q.h> 28 #include "physics/physics_factory.h" 29 #include "dg/dg_factory.hpp" 30 #include "ode_solver/ode_solver_factory.h" 36 template <
int dim,
typename real>
39 : dealii::Function<dim,real>(dim+2, 0.0)
40 , euler_physics(euler_physics)
41 , dimensional_density_inf(dimensional_density_inf)
44 for(
int d=0;d<dim;d++) {
49 template <
int dim,
typename real>
51 ::value (
const dealii::Point<dim> &point,
const unsigned int istate)
const 54 const real char_length = euler_physics.ref_length;
55 real sum_location = 0.0;;
56 for(
int d=0;d<dim;d++) {
57 sum_location += point[d];
60 const double time = this->get_time();
61 const real density = 1.0 + 1.0/dimensional_density_inf * sin ( 2.0*dealii::numbers::PI*char_length* (sum_location - Q_inf * time) );
62 const dealii::Tensor<1,dim,real> velocities = euler_physics.velocities_inf;
63 const real pressure = euler_physics.pressure_inf;
65 std::array<real, dim+2> primitive_values;
66 primitive_values[0] = density;
67 for(
int d=0;d<dim;d++) {
68 primitive_values[1+d] = velocities[d];
70 primitive_values[dim+1] = pressure;
71 const std::array<real, dim+2> conservative_values = euler_physics.convert_primitive_to_conservative(primitive_values);
73 return conservative_values[istate];
76 template <
int dim,
int nstate>
82 template<
int dim,
int nstate>
87 using GridEnum = ManParam::GridEnum;
91 Assert(dim == 2, dealii::ExcDimensionMismatch(dim, 2));
95 const unsigned int p_start = manu_grid_conv_param.
degree_start;
96 const unsigned int p_end = manu_grid_conv_param.degree_end;
98 const unsigned int n_grids_input = manu_grid_conv_param.number_of_grids;
100 std::vector<int> fail_conv_poly;
101 std::vector<double> fail_conv_slop;
102 std::vector<dealii::ConvergenceTable> convergence_table_vector;
107 const double dimensional_density_inf = 1.0;
109 initial_vortex_function.set_time(0.0);
112 final_vortex_function.set_time(1.0);
114 for (
unsigned int poly_degree = p_start; poly_degree <= p_end; ++poly_degree) {
117 unsigned int n_grids = n_grids_input;
118 if (poly_degree <= 1) n_grids = n_grids_input + 2;
120 std::vector<double> soln_error(n_grids);
121 std::vector<double> grid_size(n_grids);
125 dealii::ConvergenceTable convergence_table;
129 using Triangulation = dealii::Triangulation<dim>;
131 using Triangulation = dealii::parallel::distributed::Triangulation<dim>;
134 std::vector<dealii::GridTools::PeriodicFacePair<typename Triangulation::cell_iterator > > periodicity_vector;
135 for (
unsigned int igrid=0; igrid<n_grids; ++igrid) {
140 std::shared_ptr <Triangulation> grid = std::make_shared<Triangulation> (
144 typename dealii::Triangulation<dim>::MeshSmoothing(
145 dealii::Triangulation<dim>::smoothing_on_refinement |
146 dealii::Triangulation<dim>::smoothing_on_coarsening));
149 if ( manu_grid_conv_param.grid_type == GridEnum::hypercube || manu_grid_conv_param.grid_type == GridEnum::sinehypercube ) {
151 std::vector<unsigned int> n_subdivisions(2);
152 n_subdivisions[0] = n_1d_cells[igrid];
153 n_subdivisions[1] = n_1d_cells[igrid];
154 const bool colorize =
true;
155 dealii::Point<dim> p1(0.0,0.0), p2(1.0,1.0);
156 for (
int d=0;d<dim;d++) {
160 dealii::GridGenerator::subdivided_hyper_rectangle (*grid, n_subdivisions, p1, p2, colorize);
162 dealii::FullMatrix<double> rotation_matrix(dim);
163 rotation_matrix[1][0] = 1.;
164 rotation_matrix[0][1] = 1.;
165 for (
int d=0;d<dim;d++) {
166 dealii::GridTools::collect_periodic_faces< Triangulation > (*grid, 2*d, 2*d+1, d, periodicity_vector, dealii::Tensor<1, dim>(),
169 grid->add_periodicity(periodicity_vector);
195 const double random_factor = manu_grid_conv_param.random_distortion;
196 const bool keep_boundary =
true;
197 if (random_factor > 0.0) dealii::GridTools::distort_random (random_factor, *grid, keep_boundary);
201 dg->allocate_system ();
204 dealii::VectorTools::interpolate(dg->dof_handler, initial_vortex_function, dg->solution);
209 unsigned int n_active_cells = grid->n_active_cells();
211 <<
"Dimension: " << dim
212 <<
"\t Polynomial degree p: " << poly_degree
214 <<
"Grid number: " << igrid+1 <<
"/" << n_grids
215 <<
". Number of active cells: " << n_active_cells
216 <<
". Number of degrees of freedom: " << dg->dof_handler.n_dofs()
220 ode_solver->steady_state();
223 int overintegrate = 10;
224 dealii::QGauss<dim> quad_extra(dg->max_degree+1+overintegrate);
225 dealii::FEValues<dim,dim> fe_values_extra(dealii::MappingQ<dim>(dg->max_degree+overintegrate), dg->fe_collection[poly_degree], quad_extra,
226 dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
231 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
232 std::array<double,nstate> soln_at_q;
237 typename dealii::DoFHandler<dim>::active_cell_iterator
238 cell = dg->dof_handler.begin_active(),
239 endc = dg->dof_handler.end();
241 std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
242 for (; cell!=endc; ++cell) {
244 fe_values_extra.reinit (cell);
245 cell->get_dof_indices (dofs_indices);
247 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
249 std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
250 for (
unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
251 const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
252 soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
255 const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
260 for (
int istate=0; istate<nstate; ++istate) {
261 const double uexact = physics->manufactured_solution_function->value(qpoint, istate);
262 l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_extra.JxW(iquad);
267 l2error = sqrt(l2error);
270 double dx = 1.0/pow(n_active_cells,(1.0/dim));
271 dx = dealii::GridTools::maximal_cell_diameter(*grid);
272 grid_size[igrid] = dx;
273 soln_error[igrid] = l2error;
275 convergence_table.add_value(
"p", poly_degree);
276 convergence_table.add_value(
"cells", grid->n_active_cells());
277 convergence_table.add_value(
"dx", dx);
278 convergence_table.add_value(
"soln_L2_error", l2error);
281 std::cout <<
" Grid size h: " << dx
282 <<
" L2-soln_error: " << l2error
283 <<
" Residual: " << ode_solver->residual_norm
287 const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1])
288 / log(grid_size[igrid]/grid_size[igrid-1]);
289 std::cout <<
"From grid " << igrid-1
290 <<
" to grid " << igrid
291 <<
" dimension: " << dim
292 <<
" polynomial degree p: " << poly_degree
294 <<
" solution_error1 " << soln_error[igrid-1]
295 <<
" solution_error2 " << soln_error[igrid]
296 <<
" slope " << slope_soln_err
301 <<
" ********************************************" 303 <<
" Convergence rates for p = " << poly_degree
305 <<
" ********************************************" 307 convergence_table.evaluate_convergence_rates(
"soln_L2_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
308 convergence_table.set_scientific(
"dx",
true);
309 convergence_table.set_scientific(
"soln_L2_error",
true);
310 convergence_table.write_text(std::cout);
312 convergence_table_vector.push_back(convergence_table);
314 const double expected_slope = poly_degree+1;
316 const double last_slope = log(soln_error[n_grids-1]/soln_error[n_grids-2])
317 / log(grid_size[n_grids-1]/grid_size[n_grids-2]);
318 double before_last_slope = last_slope;
320 before_last_slope = log(soln_error[n_grids-2]/soln_error[n_grids-3])
321 / log(grid_size[n_grids-2]/grid_size[n_grids-3]);
323 const double slope_avg = 0.5*(before_last_slope+last_slope);
324 const double slope_diff = slope_avg-expected_slope;
326 double slope_deficit_tolerance = -0.1;
327 if(poly_degree == 0) slope_deficit_tolerance = -0.2;
329 if (slope_diff < slope_deficit_tolerance) {
330 std::cout << std::endl
331 <<
"Convergence order not achieved. Average last 2 slopes of " 332 << slope_avg <<
" instead of expected " 333 << expected_slope <<
" within a tolerance of " 334 << slope_deficit_tolerance
337 if(poly_degree!=0) fail_conv_poly.push_back(poly_degree);
338 if(poly_degree!=0) fail_conv_slop.push_back(slope_avg);
342 std::cout << std::endl
346 std::cout <<
" ********************************************" 348 std::cout <<
" Convergence summary" 350 std::cout <<
" ********************************************" 352 for (
auto conv = convergence_table_vector.begin(); conv!=convergence_table_vector.end(); conv++) {
353 conv->write_text(std::cout);
354 std::cout <<
" ********************************************" 357 int n_fail_poly = fail_conv_poly.size();
358 if (n_fail_poly > 0) {
359 for (
int ifail=0; ifail < n_fail_poly; ++ifail) {
360 const double expected_slope = fail_conv_poly[ifail]+1;
361 const double slope_deficit_tolerance = -0.1;
362 std::cout << std::endl
363 <<
"Convergence order not achieved for polynomial p = " 364 << fail_conv_poly[ifail]
366 << fail_conv_slop[ifail] <<
" instead of expected " 367 << expected_slope <<
" within a tolerance of " 368 << slope_deficit_tolerance
unsigned int degree_start
First polynomial degree to start the loop. If diffusion, must be at least 1.
Parameters related to the manufactured convergence study.
const MPI_Comm mpi_communicator
MPI communicator.
Files for the baseline physics.
int run_test() const
Manufactured grid convergence.
real value(const dealii::Point< dim > &point, const unsigned int istate=0) const
Manufactured solution exact value.
unsigned int dimension
Number of dimensions. Note that it has to match the executable PHiLiP_xD.
Main parameter class that contains the various other sub-parameter classes.
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
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.
EulerEntropyWaves()=delete
Constructor. Deleted the default constructor since it should not be used.
Exact entropy waves solution.
Performs grid convergence for various polynomial degrees.
EulerEntropyWavesFunction(const Physics::Euler< dim, dim+2, real > euler_physics, const real dimensional_density_inf)
Constructor that initializes base_values, amplitudes, frequencies.
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::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.
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.