4 #include <deal.II/base/convergence_table.h> 6 #include <deal.II/dofs/dof_tools.h> 8 #include <deal.II/grid/grid_generator.h> 9 #include <deal.II/grid/grid_refinement.h> 10 #include <deal.II/grid/grid_tools.h> 11 #include <deal.II/grid/grid_out.h> 12 #include <deal.II/grid/grid_in.h> 14 #include <deal.II/numerics/vector_tools.h> 16 #include <deal.II/lac/affine_constraints.h> 19 #include <deal.II/fe/fe_values.h> 23 #include <deal.II/fe/mapping_q.h> 26 #include "euler_vortex.h" 28 #include "physics/physics_factory.h" 29 #include "physics/manufactured_solution.h" 30 #include "dg/dg_factory.hpp" 31 #include "ode_solver/ode_solver_factory.h" 37 template <
int dim,
int nspecies,
typename real>
41 const dealii::Point<dim> initial_vortex_center,
42 const real vortex_strength,
43 const real vortex_stddev_decay)
45 dealii::Function<dim,real>(dim+2, 0.0)
46 , euler_physics(euler_physics)
47 , vortex_characteristic_length(1.0*euler_physics.ref_length)
48 , initial_vortex_center(initial_vortex_center)
49 , vortex_strength(vortex_strength)
50 , vortex_stddev_decay(vortex_stddev_decay)
52 static_assert(dim==2);
55 template <
int dim,
int nspecies,
typename real>
58 dealii::Point<dim> new_location;
59 const double time = this->get_time();
60 for(
int d=0; d<dim; d++) {
61 new_location[d] = (grid_location[d] - initial_vortex_center[d]) - euler_physics.velocities_inf[d] * time;
66 template <
int dim,
int nspecies,
typename real>
68 ::value (
const dealii::Point<dim> &point,
const unsigned int istate)
const 70 const double variance = vortex_stddev_decay*vortex_stddev_decay;
72 dealii::Point<dim> new_loc = advected_location(point);
73 const double x = new_loc[0];
74 const double y = new_loc[1];
108 const double r2 = (std::pow(x,2.0)+std::pow(y,2.0))/(variance);
109 const double density = euler_physics.density_inf;
110 const double vel_x = euler_physics.velocities_inf[0] - y*vortex_strength/(variance)*exp(-0.5*r2);
111 const double vel_y = euler_physics.velocities_inf[1] + x*vortex_strength/(variance)*exp(-0.5*r2);
112 const double pressure = euler_physics.pressure_inf - euler_physics.density_inf*(vortex_strength*vortex_strength)/(2*variance)*exp(-r2);
114 const std::array<double, 4> primitive_values = {{density, vel_x, vel_y, pressure}};
115 const std::array<double, 4> conservative_values = euler_physics.convert_primitive_to_conservative(primitive_values);
128 return conservative_values[istate];
131 template <
int dim,
int nspecies,
int nstate>
137 template<
int dim,
int nspecies,
int nstate>
142 using GridEnum = ManParam::GridEnum;
146 Assert(dim == 2, dealii::ExcDimensionMismatch(dim, 2));
150 const unsigned int p_start = manu_grid_conv_param.
degree_start;
151 const unsigned int p_end = manu_grid_conv_param.degree_end;
153 const unsigned int n_grids_input = manu_grid_conv_param.number_of_grids;
155 std::vector<int> fail_conv_poly;
156 std::vector<double> fail_conv_slop;
157 std::vector<dealii::ConvergenceTable> convergence_table_vector;
162 const dealii::Point<dim> initial_vortex_center(-0.0,-0.0);
163 const double vortex_strength = euler->mach_inf*4.0;
164 const double vortex_stddev_decay = 1.0;
165 const double half_length = 5*euler->ref_length;
168 initial_vortex_function.set_time(0.0);
170 for (
unsigned int poly_degree = p_start; poly_degree <= p_end; ++poly_degree) {
173 unsigned int n_grids = n_grids_input;
176 std::vector<double> soln_error(n_grids);
177 std::vector<double> grid_size(n_grids);
181 dealii::ConvergenceTable convergence_table;
183 for (
unsigned int igrid=0; igrid<n_grids; ++igrid) {
188 using Triangulation = dealii::parallel::distributed::Triangulation<dim>;
189 std::shared_ptr <Triangulation> grid = std::make_shared<Triangulation> (this->
mpi_communicator,
190 typename dealii::Triangulation<dim>::MeshSmoothing(
191 dealii::Triangulation<dim>::smoothing_on_refinement |
192 dealii::Triangulation<dim>::smoothing_on_coarsening));
195 if ( manu_grid_conv_param.grid_type == GridEnum::hypercube || manu_grid_conv_param.grid_type == GridEnum::sinehypercube ) {
197 std::vector<unsigned int> n_subdivisions(2);
198 n_subdivisions[0] = n_1d_cells[igrid];
199 n_subdivisions[1] = n_1d_cells[igrid];
200 const bool colorize =
true;
201 dealii::Point<dim> p1(-half_length,-half_length), p2(half_length,half_length);
202 dealii::GridGenerator::subdivided_hyper_rectangle (*grid, n_subdivisions, p1, p2, colorize);
203 for (
typename Triangulation::active_cell_iterator cell = grid->begin_active(); cell != grid->end(); ++cell) {
205 for (
unsigned int face=0; face<dealii::GeometryInfo<dim>::faces_per_cell; ++face) {
206 if (cell->face(face)->at_boundary()) {
207 unsigned int current_id = cell->face(face)->boundary_id();
208 if (current_id == 0) {
209 cell->face(face)->set_boundary_id (1004);
210 }
else if (current_id == 1) {
211 cell->face(face)->set_boundary_id (1004);
212 }
else if (current_id == 2) {
213 cell->face(face)->set_boundary_id (1004);
214 }
else if (current_id == 3) {
215 cell->face(face)->set_boundary_id (1004);
217 std::cout <<
"current_face_id " << current_id << std::endl;
227 const double random_factor = manu_grid_conv_param.random_distortion;
228 const bool keep_boundary =
true;
229 if (random_factor > 0.0) dealii::GridTools::distort_random (random_factor, *grid, keep_boundary);
233 dg->allocate_system ();
236 dealii::VectorTools::interpolate(dg->dof_handler, initial_vortex_function, dg->solution);
248 const unsigned int n_active_cells = grid->n_active_cells();
249 const unsigned int n_dofs = dg->dof_handler.n_dofs();
251 <<
"Dimension: " << dim <<
"\t Polynomial degree p: " << poly_degree << std::endl
252 <<
"Grid number: " << igrid+1 <<
"/" << n_grids
253 <<
". Number of active cells: " << n_active_cells
254 <<
". Number of degrees of freedom: " << n_dofs
260 ode_solver->steady_state();
263 const double final_time = ode_solver->current_time;
264 final_vortex_function.set_time(final_time);
267 int overintegrate = 10;
268 dealii::QGauss<dim> quad_extra(dg->max_degree+1+overintegrate);
269 dealii::MappingQ<dim,dim> mappingq(dg->max_degree+overintegrate);
270 dealii::FEValues<dim,dim> fe_values_extra(mappingq, dg->fe_collection[poly_degree], quad_extra,
271 dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
272 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
273 std::array<double,nstate> soln_at_q;
277 std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
279 for (
auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
281 fe_values_extra.reinit (cell);
282 cell->get_dof_indices (dofs_indices);
284 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
286 std::fill(soln_at_q.begin(), soln_at_q.end(), 0);
287 for (
unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
288 const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
289 soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
292 const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
296 for (
int istate=3; istate<4; ++istate) {
297 const double uexact = final_vortex_function.
value(qpoint, istate);
298 l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_extra.JxW(iquad);
303 l2error = sqrt(l2error);
306 double dx = 1.0/pow(n_dofs,(1.0/dim));
308 grid_size[igrid] = dx;
309 soln_error[igrid] = l2error;
311 convergence_table.add_value(
"p", poly_degree);
312 convergence_table.add_value(
"cells", n_active_cells);
313 convergence_table.add_value(
"DoFs", n_dofs);
314 convergence_table.add_value(
"dx", dx);
315 convergence_table.add_value(
"soln_L2_error", l2error);
318 std::cout <<
" Grid size h: " << dx
319 <<
" L2-soln_error: " << l2error
320 <<
" Residual: " << ode_solver->residual_norm
324 const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1])
325 / log(grid_size[igrid]/grid_size[igrid-1]);
326 std::cout <<
"From grid " << igrid-1
327 <<
" to grid " << igrid
328 <<
" dimension: " << dim
329 <<
" polynomial degree p: " << poly_degree
331 <<
" solution_error1 " << soln_error[igrid-1]
332 <<
" solution_error2 " << soln_error[igrid]
333 <<
" slope " << slope_soln_err
338 <<
" ********************************************" 340 <<
" Convergence rates for p = " << poly_degree
342 <<
" ********************************************" 344 convergence_table.evaluate_convergence_rates(
"soln_L2_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
345 convergence_table.set_scientific(
"dx",
true);
346 convergence_table.set_scientific(
"soln_L2_error",
true);
347 convergence_table.write_text(std::cout);
349 convergence_table_vector.push_back(convergence_table);
351 const double expected_slope = poly_degree+1;
353 const double last_slope = log(soln_error[n_grids-1]/soln_error[n_grids-2])
354 / log(grid_size[n_grids-1]/grid_size[n_grids-2]);
355 double before_last_slope = last_slope;
357 before_last_slope = log(soln_error[n_grids-2]/soln_error[n_grids-3])
358 / log(grid_size[n_grids-2]/grid_size[n_grids-3]);
361 const double slope_avg = 0.5*before_last_slope+ 0.5*last_slope;
362 const double slope_diff = slope_avg-expected_slope;
364 double slope_deficit_tolerance = -std::abs(manu_grid_conv_param.slope_deficit_tolerance);
365 if(poly_degree == 0) slope_deficit_tolerance *= 2;
367 if (slope_diff < slope_deficit_tolerance) {
368 std::cout << std::endl
369 <<
"Convergence order not achieved. Average last 2 slopes of " 370 << slope_avg <<
" instead of expected " 371 << expected_slope <<
" within a tolerance of " 372 << slope_deficit_tolerance
375 if(poly_degree!=0) fail_conv_poly.push_back(poly_degree);
376 if(poly_degree!=0) fail_conv_slop.push_back(slope_avg);
380 std::cout << std::endl
384 std::cout <<
" ********************************************" 386 std::cout <<
" Convergence summary" 388 std::cout <<
" ********************************************" 390 for (
auto conv = convergence_table_vector.begin(); conv!=convergence_table_vector.end(); conv++) {
391 conv->write_text(std::cout);
392 std::cout <<
" ********************************************" 395 int n_fail_poly = fail_conv_poly.size();
396 if (n_fail_poly > 0) {
397 for (
int ifail=0; ifail < n_fail_poly; ++ifail) {
398 const double expected_slope = fail_conv_poly[ifail]+1;
399 const double slope_deficit_tolerance = -0.1;
400 std::cout << std::endl
401 <<
"Convergence order not achieved for polynomial p = " 402 << fail_conv_poly[ifail]
404 << fail_conv_slop[ifail] <<
" instead of expected " 405 << expected_slope <<
" within a tolerance of " 406 << slope_deficit_tolerance
413 #if PHILIP_DIM==2 && PHILIP_SPECIES==1 unsigned int degree_start
First polynomial degree to start the loop. If diffusion, must be at least 1.
real value(const dealii::Point< dim > &point, const unsigned int istate=0) const
Manufactured solution exact value.
Parameters related to the manufactured convergence study.
const MPI_Comm mpi_communicator
MPI communicator.
Files for the baseline physics.
EulerVortex()=delete
Constructor. Deleted the default constructor since it should not be used.
Performs grid convergence for various polynomial degrees.
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::Point< dim > advected_location(const dealii::Point< dim > old_location) const
Exact solution using the current time provided by the dealii::Function class.
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
EulerVortexFunction(const Physics::Euler< dim, nspecies, dim+2, real > euler_physics, const dealii::Point< dim > initial_vortex_center, const real vortex_strength, const real vortex_stddev_decay)
Constructor that initializes base_values, amplitudes, frequencies.
int run_test() const
Manufactured grid convergence.
static std::shared_ptr< DGBase< dim, nspecies, 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.
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.
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) ...
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.
Base class of all the tests.