4 #include <deal.II/base/convergence_table.h> 5 #include <deal.II/fe/fe_values.h> 7 #include "multispecies_vortex_advection.h" 8 #include "physics/initial_conditions/initial_condition_function.h" 9 #include "flow_solver/flow_solver_factory.h" 14 template <
int dim,
int nspecies,
int nstate>
17 const dealii::ParameterHandler& parameter_handler_input)
20 , parameter_handler(parameter_handler_input)
29 if (flow_case == Parameters::FlowSolverParam::FlowCaseType::multi_species_vortex_advection) {
31 }
else if (flow_case == Parameters::FlowSolverParam::FlowCaseType::multi_species_vortex_advection_high_temp) {
36 template <
int dim,
int nspecies,
int nstate>
40 const unsigned int number_of_degrees_of_freedom_per_state = dg->dof_handler.n_dofs()/nstate;
41 double time_step = 1e-5;
44 double maximum_local_wave_speed = 0.0;
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);
52 const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
53 std::array<double,nstate> soln_at_q;
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);
61 for (
unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
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);
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;
72 maximum_local_wave_speed = dealii::Utilities::MPI::max(maximum_local_wave_speed, this->
mpi_communicator);
76 time_step = cfl_number * approximate_grid_spacing / maximum_local_wave_speed;
81 template <
int dim,
int nspecies,
int nstate>
84 const int poly_degree,
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;
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;
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;
107 fe_values_extra.reinit(cell);
108 cell->get_dof_indices(dofs_indices);
110 for (
unsigned int iquad = 0; iquad < n_quad_pts; ++iquad) {
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);
117 double temperature_at_q = this->
real_gas_physics->compute_temperature(soln_at_q);
119 const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
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);
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);
132 lerror_primitive[istate][2] = std::max(abs(soln_at_q_primitive[istate]-soln_exact_primitive[istate]), lerror_primitive[istate][2]);
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]);
140 std::array<std::array<double,3>,nstate+1> lerror_mpi;
141 for(
int istate = 0; istate < nstate+1; ++istate) {
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);
146 lerror_mpi[istate][1] = pow(lerror_mpi[istate][1], 1.0/2.0);
148 lerror_mpi[istate][2] = dealii::Utilities::MPI::max(lerror_primitive[istate][2], this->
mpi_communicator);
154 template <
int dim,
int nspecies,
int nstate>
157 pcout <<
" Running Multispecies Vortex Advection test. " << std::endl;
158 pcout << dim <<
" " << nstate << std::endl;
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;
169 if(expected_order==0.0)
172 for (
unsigned int igrid = 1; igrid < n_grids; igrid++) {
174 pcout <<
"\n" <<
"Creating FlowSolver" << std::endl;
185 const unsigned int n_global_active_cells = flow_solver->dg->triangulation->n_global_active_cells();
188 const double final_time_actual = flow_solver->ode_solver->current_time;
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
195 <<
"Grid number: " << igrid + 1 <<
"/" << n_grids
196 <<
". Number of active cells: " << n_global_active_cells
197 <<
". Number of degrees of freedom: " << n_dofs
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);
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];
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]);
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
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]);
232 if (igrid == n_grids - 1)
233 final_order = slope_soln_err;
235 this->
pcout <<
"From grid " << igrid - 1
236 <<
" to grid " << igrid
237 <<
" dimension: " << dim
238 <<
" polynomial degree p: " << poly_degree
240 <<
" solution_error1 " << soln_error_l2[igrid - 1]
241 <<
" solution_error2 " << soln_error_l2[igrid]
242 <<
" slope " << slope_soln_err
246 this->
pcout <<
" ********************************************" 248 <<
" Convergence rates for p = " << poly_degree
250 <<
" ********************************************" 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());
273 std::ofstream table_file(
"convergence_rates.txt");
274 convergence_table.write_text(table_file);
279 if(final_order > expected_order - 0.1) {
280 std::cout <<
"Expected order is reached!" << std::endl;
284 std::cout <<
"Expected order of " << expected_order <<
" is not reached!" << std::endl;
285 std::cout <<
"Final order is " << final_order << std::endl;
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.
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.
Parameters related to the manufactured convergence study.
unsigned int grid_degree
Parameters related to mesh generation.
const MPI_Comm mpi_communicator
MPI communicator.
Files for the baseline physics.
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 ¶meter_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.
MultispeciesVortexAdvection(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler ¶meter_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.
int run_test() const override
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.
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.
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.
unsigned int number_of_grids
Number of grid in the grid study.