[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
multispecies_vortex_advection.cpp
1 #include <stdlib.h> /* srand, rand */
2 #include <iostream>
3 
4 #include <deal.II/base/convergence_table.h>
5 #include <deal.II/fe/fe_values.h>
6 
7 #include "multispecies_vortex_advection.h"
8 #include "physics/initial_conditions/initial_condition_function.h"
9 #include "flow_solver/flow_solver_factory.h"
10 
11 namespace PHiLiP {
12 namespace Tests {
13 
14 template <int dim, int nspecies, int nstate>
16  const PHiLiP::Parameters::AllParameters* const parameters_input,
17  const dealii::ParameterHandler& parameter_handler_input)
18  :
19  TestsBase::TestsBase(parameters_input)
20  , parameter_handler(parameter_handler_input)
21 {
22  //create the Physics object
25 
26  using flow_case_enum = Parameters::FlowSolverParam::FlowCaseType;
27  flow_case_enum flow_case = parameters_input->flow_solver_param.flow_case_type;
28 
29  if (flow_case == Parameters::FlowSolverParam::FlowCaseType::multi_species_vortex_advection) {
30  this->high_temp = false;
31  } else if (flow_case == Parameters::FlowSolverParam::FlowCaseType::multi_species_vortex_advection_high_temp) {
32  this->high_temp = true;
33  }
34 }
35 
36 template <int dim, int nspecies, int nstate>
38 {
40  const unsigned int number_of_degrees_of_freedom_per_state = dg->dof_handler.n_dofs()/nstate;
41  double time_step = 1e-5;
42 
43  // Initialize the maximum local wave speed to zero
44  double maximum_local_wave_speed = 0.0;
45 
46  // Overintegrate the error to make sure there is not integration error in the error estimate
47  int overintegrate = 10;
48  dealii::QGauss<dim> quad_extra(dg->max_degree+1+overintegrate);
49  dealii::FEValues<dim,dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[dg->max_degree], quad_extra,
50  dealii::update_values | dealii::update_gradients | dealii::update_JxW_values | dealii::update_quadrature_points);
51 
52  const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
53  std::array<double,nstate> soln_at_q;
54 
55  std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
56  for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
57  if (!cell->is_locally_owned()) continue;
58  fe_values_extra.reinit (cell);
59  cell->get_dof_indices (dofs_indices);
60 
61  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
62 
63  std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
64  for (unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
65  const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
66  soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
67  }
68  double local_wave_speed = this->real_gas_physics->max_convective_eigenvalue(soln_at_q);
69  if(local_wave_speed > maximum_local_wave_speed) maximum_local_wave_speed = local_wave_speed;
70  }
71  }
72  maximum_local_wave_speed = dealii::Utilities::MPI::max(maximum_local_wave_speed, this->mpi_communicator);
73 
74  const double approximate_grid_spacing = (all_parameters_new.flow_solver_param.grid_right_bound-all_parameters_new.flow_solver_param.grid_left_bound)/pow(number_of_degrees_of_freedom_per_state,(1.0/dim));
75  const double cfl_number = all_parameters_new.flow_solver_param.courant_friedrichs_lewy_number;
76  time_step = cfl_number * approximate_grid_spacing / maximum_local_wave_speed;
77 
78  return time_step;
79 }
80 
81 template <int dim, int nspecies, int nstate>
83  std::shared_ptr<DGBase<dim, nspecies, double>> dg,
84  const int poly_degree,
85  const double /*final_time*/,
86  std::shared_ptr<FlowSolver::FlowSolver<dim, nspecies, nstate>> flow_solver) const
87 {
88  // Overintegrate the error to make sure there is not integration error in the error estimate
89  int overintegrate = 10;
90  dealii::QGauss<dim> quad_extra(poly_degree + 1 + overintegrate);
91  dealii::FEValues<dim, dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra,
92  dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
93  const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
94  std::array<double, nstate> soln_at_q, soln_exact_primitive;
95 
96  std::array<std::array<double,3>,nstate+1> lerror_primitive;
97  for (int istate = 0; istate < nstate+1; ++istate) {
98  lerror_primitive[istate][0] = 0.0;
99  lerror_primitive[istate][1] = 0.0;
100  lerror_primitive[istate][2] = 0.0;
101  }
102  // Integrate every cell and compute L2
103  std::vector<dealii::types::global_dof_index> dofs_indices(fe_values_extra.dofs_per_cell);
104  for (auto cell = dg->dof_handler.begin_active(); cell != dg->dof_handler.end(); ++cell) {
105  if (!cell->is_locally_owned()) continue;
106 
107  fe_values_extra.reinit(cell);
108  cell->get_dof_indices(dofs_indices);
109 
110  for (unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
111 
112  std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
113  for (unsigned int idof = 0; idof < fe_values_extra.dofs_per_cell; ++idof) {
114  const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
115  soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
116  }
117  double temperature_at_q = this->real_gas_physics->compute_temperature(soln_at_q);
118 
119  const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
120 
121  std::array<double, nstate> soln_exact;
122  for(int istate = 0; istate < nstate; istate++)
123  soln_exact[istate] = flow_solver->flow_solver_case->initial_condition_function->value(qpoint,istate);
124  soln_exact_primitive = this->real_gas_physics->convert_conservative_to_primitive(soln_exact);
125  double temperature_exact = this->real_gas_physics->compute_temperature(soln_exact);
126 
127  for(int istate = 0; istate < nstate; ++istate) {
128  std::array<double, nstate> soln_at_q_primitive = this->real_gas_physics->convert_conservative_to_primitive(soln_at_q);
129  lerror_primitive[istate][0] += pow(abs(soln_at_q_primitive[istate] - soln_exact_primitive[istate]), 1.0) * fe_values_extra.JxW(iquad);
130  lerror_primitive[istate][1] += pow(abs(soln_at_q_primitive[istate] - soln_exact_primitive[istate]), 2.0) * fe_values_extra.JxW(iquad);
131  //L-infinity norm
132  lerror_primitive[istate][2] = std::max(abs(soln_at_q_primitive[istate]-soln_exact_primitive[istate]), lerror_primitive[istate][2]);
133  }
134  lerror_primitive[nstate][0] += pow(abs(temperature_at_q - temperature_exact), 1.0) * fe_values_extra.JxW(iquad);
135  lerror_primitive[nstate][1] += pow(abs(temperature_at_q - temperature_exact), 2.0) * fe_values_extra.JxW(iquad);
136  lerror_primitive[nstate][2] = std::max(abs(temperature_at_q-temperature_exact), lerror_primitive[nstate][2]);
137  }
138  }
139  //MPI sum
140  std::array<std::array<double,3>,nstate+1> lerror_mpi;
141  for(int istate = 0; istate < nstate+1; ++istate) {
142 
143  lerror_mpi[istate][0] = dealii::Utilities::MPI::sum(lerror_primitive[istate][0], this->mpi_communicator);
144  lerror_mpi[istate][1] = dealii::Utilities::MPI::sum(lerror_primitive[istate][1], this->mpi_communicator);
145 
146  lerror_mpi[istate][1] = pow(lerror_mpi[istate][1], 1.0/2.0);
147 
148  lerror_mpi[istate][2] = dealii::Utilities::MPI::max(lerror_primitive[istate][2], this->mpi_communicator);
149  }
150 
151  return lerror_mpi;
152 }
153 
154 template <int dim, int nspecies, int nstate>
156 {
157  pcout << " Running Multispecies Vortex Advection test. " << std::endl;
158  pcout << dim << " " << nstate << std::endl;
160 
162 
163  const unsigned int n_grids = manu_grid_conv_param.number_of_grids;
164  dealii::ConvergenceTable convergence_table;
165  std::vector<double> grid_size(n_grids);
166  std::vector<double> soln_error_l2(n_grids);
167  double final_order = 0.0;
168  double expected_order = all_parameters_new.flow_solver_param.expected_order_at_final_time;
169  if(expected_order==0.0)
170  expected_order = all_parameters_new.flow_solver_param.poly_degree + 1.0;
171 
172  for (unsigned int igrid = 1; igrid < n_grids; igrid++) {
173 
174  pcout << "\n" << "Creating FlowSolver" << std::endl;
175 
181 
182  // Create flow solver to access DG object which is needed to calculate time step
183  std::shared_ptr<FlowSolver::FlowSolver<dim, nspecies, nstate>> flow_solver = FlowSolver::FlowSolverFactory<dim, nspecies, nstate>::select_flow_case(&param, parameter_handler);
184 
185  const unsigned int n_global_active_cells = flow_solver->dg->triangulation->n_global_active_cells();
186  const int poly_degree = all_parameters_new.flow_solver_param.poly_degree;
187  flow_solver->run();
188  const double final_time_actual = flow_solver->ode_solver->current_time;
189 
190  // output results
191  const unsigned int n_dofs = flow_solver->dg->dof_handler.n_dofs();
192  this->pcout << "Dimension: " << dim
193  << "\t Polynomial degree p: " << poly_degree
194  << std::endl
195  << "Grid number: " << igrid + 1 << "/" << n_grids
196  << ". Number of active cells: " << n_global_active_cells
197  << ". Number of degrees of freedom: " << n_dofs
198  << std::endl;
199 
200  const std::array<std::array<double,3>,nstate+1> lerror_mpi_sum = calculate_l_n_error(flow_solver->dg, poly_degree, final_time_actual, flow_solver);
201 
202  // Convergence table
203  const double dx = 10.0 / pow(n_dofs, (1.0 / dim));
204  grid_size[igrid] = dx;
205  soln_error_l2[igrid] = lerror_mpi_sum[0][1];
206 
207  convergence_table.add_value("p", poly_degree);
208  convergence_table.add_value("cells", n_global_active_cells);
209  convergence_table.add_value("DoFs", n_dofs);
210  convergence_table.add_value("dx", dx);
211  convergence_table.add_value("density_L1", lerror_mpi_sum[0][0]);
212  convergence_table.add_value("density_L2", lerror_mpi_sum[0][1]);
213  convergence_table.add_value("density_Linf", lerror_mpi_sum[0][2]);
214  convergence_table.add_value("pressure_L1", lerror_mpi_sum[dim+1][0]);
215  convergence_table.add_value("pressure_L2", lerror_mpi_sum[dim+1][1]);
216  convergence_table.add_value("pressure_Linf", lerror_mpi_sum[dim+1][2]);
217  convergence_table.add_value("Y_H2_L1", lerror_mpi_sum[dim+2][0]);
218  convergence_table.add_value("Y_H2_L2", lerror_mpi_sum[dim+2][1]);
219  convergence_table.add_value("Y_H2_Linf", lerror_mpi_sum[dim+2][2]);
220 
221  this->pcout << " Grid size h: " << dx
222  << " Density L1-soln_error: " << lerror_mpi_sum[0][0]
223  << " Density L2-soln_error: " << lerror_mpi_sum[0][1]
224  << " Density Linf-soln_error: " << lerror_mpi_sum[0][2]
225  << " Residual: " << flow_solver->ode_solver->residual_norm
226  << std::endl;
227 
228  if (igrid > 0) {
229  const double slope_soln_err = log(soln_error_l2[igrid] / soln_error_l2[igrid - 1])
230  / log(grid_size[igrid] / grid_size[igrid - 1]);
231 
232  if (igrid == n_grids - 1)
233  final_order = slope_soln_err;
234 
235  this->pcout << "From grid " << igrid - 1
236  << " to grid " << igrid
237  << " dimension: " << dim
238  << " polynomial degree p: " << poly_degree
239  << std::endl
240  << " solution_error1 " << soln_error_l2[igrid - 1]
241  << " solution_error2 " << soln_error_l2[igrid]
242  << " slope " << slope_soln_err
243  << std::endl;
244  }
245 
246  this->pcout << " ********************************************"
247  << std::endl
248  << " Convergence rates for p = " << poly_degree
249  << std::endl
250  << " ********************************************"
251  << std::endl;
252  convergence_table.evaluate_convergence_rates("density_L1", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
253  convergence_table.evaluate_convergence_rates("density_L2", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
254  convergence_table.evaluate_convergence_rates("density_Linf", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
255  convergence_table.evaluate_convergence_rates("pressure_L1", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
256  convergence_table.evaluate_convergence_rates("pressure_L2", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
257  convergence_table.evaluate_convergence_rates("pressure_Linf", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
258  convergence_table.evaluate_convergence_rates("Y_H2_L1", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
259  convergence_table.evaluate_convergence_rates("Y_H2_L2", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
260  convergence_table.evaluate_convergence_rates("Y_H2_Linf", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
261  convergence_table.set_scientific("dx", true);
262  convergence_table.set_scientific("density_L1", true);
263  convergence_table.set_scientific("density_L2", true);
264  convergence_table.set_scientific("density_Linf", true);
265  convergence_table.set_scientific("pressure_L1", true);
266  convergence_table.set_scientific("pressure_L2", true);
267  convergence_table.set_scientific("pressure_Linf", true);
268  convergence_table.set_scientific("Y_H2_L1", true);
269  convergence_table.set_scientific("Y_H2_L2", true);
270  convergence_table.set_scientific("Y_H2_Linf", true);
271  if (this->pcout.is_active()) convergence_table.write_text(this->pcout.get_stream());
272 
273  std::ofstream table_file("convergence_rates.txt");
274  convergence_table.write_text(table_file);
275 
276 
277  }//end of grid loop
278 
279  if(final_order > expected_order - 0.1) {
280  std::cout << "Expected order is reached!" << std::endl;
281  return 0;
282  }
283  else {
284  std::cout << "Expected order of " << expected_order << " is not reached!" << std::endl;
285  std::cout << "Final order is " << final_order << std::endl;
286  return 1;
287  }
288 }
289 
290 #if PHILIP_SPECIES>1
292 #endif
293 } // Tests namespace
294 } // PHiLiP namespace
FlowCaseType
Selects the flow case to be simulated.
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.
RealGas equations. Derived from PhysicsBase.
Definition: real_gas.h:18
double courant_friedrichs_lewy_number
Courant-Friedrichs-Lewy (CFL) number for constant time step.
FlowSolverParam flow_solver_param
Contains the parameters for simulation cases (flow solver test)
Selects which flow case to simulate.
Definition: flow_solver.h:64
Parameters related to the manufactured convergence study.
unsigned int grid_degree
Parameters related to mesh generation.
const MPI_Comm mpi_communicator
MPI communicator.
Definition: tests.h:39
Files for the baseline physics.
Definition: ADTypes.hpp:10
Class used to run tests that verify implementation of multispecies.
double get_time_step(std::shared_ptr< DGBase< dim, nspecies, double >> dg) const
Function to compute the initial adaptive time step.
static std::unique_ptr< FlowSolver< dim, nspecies, nstate > > select_flow_case(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler &parameter_handler_input)
Factory to return the correct flow solver given input file.
unsigned int poly_degree
Polynomial order (P) of the basis functions for DG.
Main parameter class that contains the various other sub-parameter classes.
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.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: tests.h:20
MultispeciesVortexAdvection(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler &parameter_handler_input)
Constructor.
double expected_order_at_final_time
For limiter convergence tests, specify expected order at final time.
unsigned int number_of_grid_elements_x
Number of subdivisions in x direction for a rectangle grid.
std::array< std::array< double, 3 >, nstate+1 > calculate_l_n_error(std::shared_ptr< DGBase< dim, nspecies, double >> flow_solver_dg, const int poly_degree, const double final_time, std::shared_ptr< FlowSolver::FlowSolver< dim, nspecies, nstate >> flow_solver) const
Calculate and return the L2 Error.
bool high_temp
Flag to determine which exact solution is used.
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.
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
double grid_right_bound
Right bound of domain for hyper_cube mesh based cases.
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
std::shared_ptr< Physics::RealGas< dim, nspecies, nstate, double > > real_gas_physics
Real Gas physics pointer for computing physical quantities.
Base class of all the tests.
Definition: tests.h:17