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,
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,
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,
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 nstate>
137 template<
int dim,
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
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.
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.
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.
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.
real value(const dealii::Point< dim > &point, const unsigned int istate=0) const
Manufactured solution exact value.
dealii::Point< dim > advected_location(const dealii::Point< dim > old_location) const
Exact solution using the current time provided by the dealii::Function class.
int run_test() const
Manufactured grid convergence.
EulerVortexFunction(const Physics::Euler< dim, 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.
EulerVortex()=delete
Constructor. Deleted the default constructor since it should not be used.
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) ...
Base class of all the tests.