4 #include <deal.II/base/convergence_table.h> 5 #include <deal.II/fe/fe_values.h> 7 #include "bound_preserving_limiter_tests.h" 9 #include "physics/initial_conditions/initial_condition_function.h" 10 #include "flow_solver/flow_solver_factory.h" 15 template <
int dim,
int nstate>
18 const dealii::ParameterHandler& parameter_handler_input)
21 , parameter_handler(parameter_handler_input)
24 template <
int dim,
int nstate>
33 const unsigned int number_of_degrees_of_freedom_per_state = dg->dof_handler.n_dofs()/nstate;
35 const unsigned int n_global_active_cells = dg->triangulation->n_global_active_cells();
36 const unsigned int n_dofs_cfl = dg->dof_handler.n_dofs() / nstate;
37 double delta_x = (PHILIP_DIM == 2) ? (right - left) / pow(n_global_active_cells, (1.0 / dim)) : (right - left) / pow(n_dofs_cfl, (1.0 / dim));
38 double time_step = 1e-5;
48 if(flow_case == flow_case_enum::advection_limiter)
49 time_step = (PHILIP_DIM == 2) ? (1.0 / 14.0) * delta_x : (1.0 / 3.0) * pow(delta_x, 2.0);
51 if(flow_case == flow_case_enum::burgers_limiter)
52 time_step = (PHILIP_DIM == 2) ? (1.0 / 14.0) * delta_x : (1.0 / 24.0) * delta_x;
54 if (flow_case == flow_case_enum::low_density){
56 double maximum_local_wave_speed = 0.0;
59 int overintegrate = 10;
60 dealii::QGauss<dim> quad_extra(dg->max_degree+1+overintegrate);
61 dealii::FEValues<dim,dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[dg->max_degree], quad_extra,
62 dealii::update_values | dealii::update_gradients | dealii::update_JxW_values | dealii::update_quadrature_points);
64 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
65 std::array<double,nstate> soln_at_q;
67 std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
68 for (
auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
69 if (!cell->is_locally_owned())
continue;
70 fe_values_extra.reinit (cell);
71 cell->get_dof_indices (dofs_indices);
73 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
75 std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
76 for (
unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
77 const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
78 soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
80 double local_wave_speed = 0.0;
81 if(nstate == dim + 2) {
94 if(local_wave_speed > maximum_local_wave_speed) maximum_local_wave_speed = local_wave_speed;
97 maximum_local_wave_speed = dealii::Utilities::MPI::max(maximum_local_wave_speed, this->
mpi_communicator);
101 time_step = cfl_number * approximate_grid_spacing / maximum_local_wave_speed;
107 template <
int dim,
int nstate>
113 const double pi = atan(1) * 4.0;
116 if (flow_case == Parameters::FlowSolverParam::FlowCaseType::low_density && dim == 2) {
117 uexact = 0.01 + exp(-500.0*(pow(qpoint[0], 2.0)+pow(qpoint[1], 2.0)));
119 if (flow_case == Parameters::FlowSolverParam::FlowCaseType::low_density && dim == 1) {
120 uexact = 0.01 + exp(-500.0*pow(qpoint[0], 2.0));
123 for (
int idim = 0; idim < dim; idim++) {
124 if (flow_case == Parameters::FlowSolverParam::FlowCaseType::burgers_limiter)
125 uexact *= cos(pi * (qpoint[idim] - final_time));
126 if (flow_case == Parameters::FlowSolverParam::FlowCaseType::advection_limiter)
127 uexact *= sin(2.0 * pi * (qpoint[idim] - adv_speeds[idim] * final_time));
134 template <
int dim,
int nstate>
137 const int poly_degree,
138 const double final_time)
const 141 int overintegrate = 10;
142 dealii::QGauss<dim> quad_extra(poly_degree + 1 + overintegrate);
143 dealii::FEValues<dim, dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra,
144 dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
145 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
146 std::array<double, nstate> soln_at_q;
148 double l1error = 0.0;
149 double l2error = 0.0;
150 double linferror = 0.0;
153 std::vector<dealii::types::global_dof_index> dofs_indices(fe_values_extra.dofs_per_cell);
155 for (
auto cell = dg->dof_handler.begin_active(); cell != dg->dof_handler.end(); ++cell) {
156 if (!cell->is_locally_owned())
continue;
158 fe_values_extra.reinit(cell);
159 cell->get_dof_indices(dofs_indices);
161 for (
unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
163 std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
164 for (
unsigned int idof = 0; idof < fe_values_extra.dofs_per_cell; ++idof) {
165 const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
166 soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
169 const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
173 l1error += pow(abs(soln_at_q[0] - uexact), 1.0) * fe_values_extra.JxW(iquad);
174 l2error += pow(abs(soln_at_q[0] - uexact), 2.0) * fe_values_extra.JxW(iquad);
176 linferror = std::max(abs(soln_at_q[0]-uexact), linferror);
180 double l1error_mpi = dealii::Utilities::MPI::sum(l1error, this->
mpi_communicator);
182 double l2error_mpi = dealii::Utilities::MPI::sum(l2error, this->
mpi_communicator);
183 l2error_mpi = pow(l2error_mpi, 1.0/2.0);
185 double linferror_mpi = dealii::Utilities::MPI::max(linferror, this->
mpi_communicator);
187 std::array<double,3> lerror_mpi;
188 lerror_mpi[0] = l1error_mpi;
189 lerror_mpi[1] = l2error_mpi;
190 lerror_mpi[2] = linferror_mpi;
194 template <
int dim,
int nstate>
197 pcout <<
" Running Bound Preserving Limiter test. " << std::endl;
198 pcout << dim <<
" " << nstate << std::endl;
212 template <
int dim,
int nstate>
215 pcout <<
"\n" <<
"Creating FlowSolver" << std::endl;
223 if (flow_case == Parameters::FlowSolverParam::FlowCaseType::low_density) {
242 template <
int dim,
int nstate>
249 dealii::ConvergenceTable convergence_table;
250 std::vector<double> grid_size(n_grids);
251 std::vector<double> soln_error_l2(n_grids);
252 double final_order = 0.0;
255 for (
unsigned int igrid = 3; igrid < n_grids; igrid++) {
257 pcout <<
"\n" <<
"Creating FlowSolver" << std::endl;
267 if (flow_case == Parameters::FlowSolverParam::FlowCaseType::low_density) {
277 const unsigned int n_global_active_cells = flow_solver->dg->triangulation->n_global_active_cells();
286 const double final_time_actual = flow_solver->ode_solver->current_time;
289 const unsigned int n_dofs = flow_solver->dg->dof_handler.n_dofs();
290 this->
pcout <<
"Dimension: " << dim
291 <<
"\t Polynomial degree p: " << poly_degree
293 <<
"Grid number: " << igrid + 1 <<
"/" << n_grids
294 <<
". Number of active cells: " << n_global_active_cells
295 <<
". Number of degrees of freedom: " << n_dofs
298 const std::array<double,3> lerror_mpi_sum =
calculate_l_n_error(flow_solver->dg, poly_degree, final_time_actual);
301 const double dx = 1.0 / pow(n_dofs, (1.0 / dim));
302 grid_size[igrid] = dx;
303 soln_error_l2[igrid] = lerror_mpi_sum[1];
305 convergence_table.add_value(
"p", poly_degree);
306 convergence_table.add_value(
"cells", n_global_active_cells);
307 convergence_table.add_value(
"DoFs", n_dofs);
308 convergence_table.add_value(
"dx", dx);
309 convergence_table.add_value(
"soln_L1_error", lerror_mpi_sum[0]);
310 convergence_table.add_value(
"soln_L2_error", lerror_mpi_sum[1]);
311 convergence_table.add_value(
"soln_Linf_error", lerror_mpi_sum[2]);
313 this->
pcout <<
" Grid size h: " << dx
314 <<
" L1-soln_error: " << lerror_mpi_sum[0]
315 <<
" L2-soln_error: " << lerror_mpi_sum[1]
316 <<
" Linf-soln_error: " << lerror_mpi_sum[2]
317 <<
" Residual: " << flow_solver->ode_solver->residual_norm
321 const double slope_soln_err = log(soln_error_l2[igrid] / soln_error_l2[igrid - 1])
322 / log(grid_size[igrid] / grid_size[igrid - 1]);
324 if (igrid == n_grids - 1)
325 final_order = slope_soln_err;
327 this->
pcout <<
"From grid " << igrid - 1
328 <<
" to grid " << igrid
329 <<
" dimension: " << dim
330 <<
" polynomial degree p: " << poly_degree
332 <<
" solution_error1 " << soln_error_l2[igrid - 1]
333 <<
" solution_error2 " << soln_error_l2[igrid]
334 <<
" slope " << slope_soln_err
338 this->
pcout <<
" ********************************************" 340 <<
" Convergence rates for p = " << poly_degree
342 <<
" ********************************************" 344 convergence_table.evaluate_convergence_rates(
"soln_L1_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
345 convergence_table.evaluate_convergence_rates(
"soln_L2_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
346 convergence_table.evaluate_convergence_rates(
"soln_Linf_error",
"cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
347 convergence_table.set_scientific(
"dx",
true);
348 convergence_table.set_scientific(
"soln_L1_error",
true);
349 convergence_table.set_scientific(
"soln_L2_error",
true);
350 convergence_table.set_scientific(
"soln_Linf_error",
true);
351 if (this->
pcout.is_active()) convergence_table.write_text(this->pcout.get_stream());
353 std::ofstream table_file(
"convergence_rates.txt");
354 convergence_table.write_text(table_file);
359 if(abs(final_order - expected_order) < 1e-4)
FlowCaseType
Selects the flow case to be simulated.
LimiterParam limiter_param
Contains parameters for limiter.
FlowCaseType flow_case_type
Selected FlowCaseType from the input file.
unsigned int number_of_grid_elements_per_dimension
Number of grid elements per dimension for hyper_cube mesh based cases.
static dealii::Tensor< 1, 3, double > get_default_advection_vector()
gets the default advection vector
double courant_friedrichs_lewy_number
Courant-Friedrich-Lewy (CFL) number for constant time step.
FlowSolverParam flow_solver_param
Contains the parameters for simulation cases (flow solver test)
Parameters related to the manufactured convergence study.
Class used to run tests that verify implementation of bound preserving limiters.
const MPI_Comm mpi_communicator
MPI communicator.
double constant_time_step
Constant time step.
std::array< double, 3 > calculate_l_n_error(std::shared_ptr< DGBase< dim, double >> flow_solver_dg, const int poly_degree, const double final_time) const
Calculate and return the L2 Error.
double mach_inf
Mach number at infinity.
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.
Files for the baseline physics.
bool use_OOA
Flag to perform convergence analysis for Limiter Tests (ie. burgers_limiter, advection_limiter, low_density)
int run_convergence_test() const
Runs convergence test and prints out results in console.
EulerParam euler_param
Contains parameters for the Euler equations non-dimensionalization.
unsigned int poly_degree
Polynomial order (P) of the basis functions for DG.
Main parameter class that contains the various other sub-parameter classes.
BoundPreservingLimiterTests(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler ¶meter_handler_input)
Constructor.
double grid_left_bound
Left bound of domain for hyper_cube mesh based cases.
ManufacturedConvergenceStudyParam manufactured_convergence_study_param
Contains parameters for manufactured convergence study.
double ref_length
Reference length.
static std::unique_ptr< FlowSolver< dim, nstate > > select_flow_case(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler ¶meter_handler_input)
Factory to return the correct flow solver given input file.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
double expected_order_at_final_time
For limiter convergence tests, specify expected order at final time.
double side_slip_angle
Input file provides in degrees, but the value stored here is in radians.
unsigned int number_of_grid_elements_x
Number of subdivisions in x direction for a rectangle grid.
int run_full_limiter_test() const
Runs full test and outputs VTK files.
int number_of_mesh_refinements
Number of refinements for naca0012 and Gaussian bump based cases.
real max_convective_eigenvalue(const std::array< real, nstate > &soln) const override
Maximum convective eigenvalue.
double angle_of_attack
Input file provides in degrees, but the value stored here is in radians.
unsigned int number_of_grid_elements_y
Number of subdivisions in y direction for a rectangle grid.
double get_time_step(std::shared_ptr< DGBase< dim, double >> dg) const
Function to compute the initial adaptive time step.
dealii::ConditionalOStream pcout
ConditionalOStream.
double grid_right_bound
Right bound of domain for hyper_cube mesh based cases.
double calculate_uexact(const dealii::Point< dim > qpoint, const dealii::Tensor< 1, 3, double > adv_speeds, double final_time) const
Calculate and return the exact value at the point depending on the case being run.
DGBase is independent of the number of state variables.
int run_test() const override
Base class of all the tests.
unsigned int number_of_grids
Number of grid in the grid study.