[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
stability_fr_parameter_range.cpp
1 #include <deal.II/base/tensor.h>
2 #include <deal.II/base/convergence_table.h>
3 
4 #include "stability_fr_parameter_range.h"
5 #include "dg/dg_factory.hpp"
6 #include "ode_solver/ode_solver_base.h"
7 #include <fstream>
8 #include "ode_solver/ode_solver_factory.h"
9 #include "physics/initial_conditions/set_initial_condition.h"
10 #include "physics/initial_conditions/initial_condition_function.h"
11 #include "mesh/grids/straight_periodic_cube.hpp"
12 
13 
14 namespace PHiLiP {
15 namespace Tests {
16 
17 template <int dim, int nstate>
19 : TestsBase::TestsBase(parameters_input)
20 {}
21 
22 template<int dim, int nstate>
24 {
25  double energy = 0.0;
26  dealii::LinearAlgebra::distributed::Vector<double> mass_matrix_times_solution(dg->right_hand_side);
27  if(dg->all_parameters->use_inverse_mass_on_the_fly)
28  dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution);
29  else
30  dg->global_mass_matrix.vmult( mass_matrix_times_solution, dg->solution);
31  //Since we normalize the energy later, don't bother scaling by 0.5
32  //Energy \f$ = 0.5 * \int u^2 d\Omega_m \f$
33  energy = dg->solution * mass_matrix_times_solution;
34 
35  return energy;
36 }
37 
38 template<int dim, int nstate>
39 double StabilityFRParametersRange<dim, nstate>::compute_conservation(std::shared_ptr < PHiLiP::DGBase<dim, double> > &dg, const double poly_degree) const
40 {
41  // Conservation \f$ = \int 1 * u d\Omega_m \f$
42  double conservation = 0.0;
43  dealii::LinearAlgebra::distributed::Vector<double> mass_matrix_times_solution(dg->right_hand_side);
44  if(dg->all_parameters->use_inverse_mass_on_the_fly)
45  dg->apply_global_mass_matrix(dg->solution,mass_matrix_times_solution);
46  else
47  dg->global_mass_matrix.vmult( mass_matrix_times_solution, dg->solution);
48 
49  const unsigned int n_dofs_cell = dg->fe_collection[poly_degree].dofs_per_cell;
50  const unsigned int n_quad_pts = dg->volume_quadrature_collection[poly_degree].size();
51  std::vector<double> ones(n_quad_pts, 1.0);
52  //Projected vector of ones. That is, the interpolation of ones_hat to the volume nodes is 1.
53  std::vector<double> ones_hat(n_dofs_cell);
54  //We have to project the vector of ones because the mass matrix has an interpolation from solution nodes built into it.
55  OPERATOR::vol_projection_operator<dim,2*dim,double> vol_projection(dg->nstate, poly_degree, dg->max_grid_degree);
56  vol_projection.build_1D_volume_operator(dg->oneD_fe_collection[poly_degree], dg->oneD_quadrature_collection[poly_degree]);
57  vol_projection.matrix_vector_mult_1D(ones, ones_hat,
58  vol_projection.oneD_vol_operator);
59 
60  dealii::LinearAlgebra::distributed::Vector<double> ones_hat_global(dg->right_hand_side);
61  std::vector<dealii::types::global_dof_index> dofs_indices (n_dofs_cell);
62  for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
63  if (!cell->is_locally_owned()) continue;
64  cell->get_dof_indices (dofs_indices);
65  for(unsigned int idof=0;idof<n_dofs_cell; idof++){
66  ones_hat_global[dofs_indices[idof]] = ones_hat[idof];
67  }
68  }
69 
70  conservation = ones_hat_global * mass_matrix_times_solution;
71 
72  return conservation;
73 }
74 
75 template <int dim, int nstate>
77 {
78  pcout << " Running stability ESFR parameter range test. " << std::endl;
79  int testfail = 0;
80 
82  double left = all_parameters_new.flow_solver_param.grid_left_bound;
83  double right = all_parameters_new.flow_solver_param.grid_right_bound;
84  const unsigned int n_grids = all_parameters_new.manufactured_convergence_study_param.initial_grid_size+all_parameters_new.manufactured_convergence_study_param.number_of_grids;
85  std::vector<double> grid_size(n_grids);
86  std::vector<double> soln_error(n_grids);
87  std::vector<double> soln_error_inf(n_grids);
88  unsigned int poly_degree = all_parameters_new.manufactured_convergence_study_param.degree_start;
89  dealii::ConvergenceTable convergence_table;
90  const unsigned int igrid_start = all_parameters_new.manufactured_convergence_study_param.initial_grid_size;
91  pcout << " igrid_start" << igrid_start << std::endl;
92  const unsigned int grid_degree = 1;
93 
94  const unsigned int nb_c_value = all_parameters_new.flow_solver_param.number_ESFR_parameter_values;
95  const double c_min = all_parameters_new.flow_solver_param.ESFR_parameter_values_start;
96  const double c_max = all_parameters_new.flow_solver_param.ESFR_parameter_values_end;
97  const double log_c_min = std::log10(c_min);
98  const double log_c_max = std::log10(c_max);
99  std::vector<double> c_array(nb_c_value+1);
100 
101  std::ofstream conv_tab_file;
102  const std::string fname = "convergence_tables.txt";
103  conv_tab_file.open(fname);
104 
105  // Create log space array of c_value
106  for (unsigned int ic = 0; ic < nb_c_value; ic++) {
107  double log_c = log_c_min + (log_c_max - log_c_min) / (nb_c_value - 1) * ic;
108  c_array[ic] = std::pow(10.0, log_c);
109  }
110 
111  c_array[nb_c_value] = all_parameters_new.FR_user_specified_correction_parameter_value;
112 
113  // Loop over c_array to compute slope
114  for (unsigned int ic = 0; ic < nb_c_value+1; ic++) {
115  double c_value = c_array[ic];
116 
117  for(unsigned int igrid = igrid_start; igrid<n_grids; igrid++){
118 
119  #if PHILIP_DIM==1 // dealii::parallel::distributed::Triangulation<dim> does not work for 1D
120  using Triangulation = dealii::Triangulation<dim>;
121  std::shared_ptr<Triangulation> grid = std::make_shared<Triangulation>(
122  typename dealii::Triangulation<dim>::MeshSmoothing(
123  dealii::Triangulation<dim>::smoothing_on_refinement |
124  dealii::Triangulation<dim>::smoothing_on_coarsening));
125  #else
126  using Triangulation = dealii::parallel::distributed::Triangulation<dim>;
127  std::shared_ptr<Triangulation> grid = std::make_shared<Triangulation>(
128  MPI_COMM_WORLD,
129  typename dealii::Triangulation<dim>::MeshSmoothing(
130  dealii::Triangulation<dim>::smoothing_on_refinement |
131  dealii::Triangulation<dim>::smoothing_on_coarsening));
132  #endif
133  //straight grid setup
134  PHiLiP::Grids::straight_periodic_cube<dim, Triangulation>(grid, left, right, pow(2.0, igrid));
135  pcout << "Grid generated and refined" << std::endl;
136  //CFL number
137 
138  // use 0.0001 to be consistent with Ranocha and Gassner papers
139  // all_parameters_new.ode_solver_param.initial_time_step = 0.0001;
140  all_parameters_new.FR_user_specified_correction_parameter_value = c_value;
141  std::cout << "c ESFR " <<all_parameters_new.FR_user_specified_correction_parameter_value << std::endl;
142  //allocate dg
143  std::shared_ptr < PHiLiP::DGBase<dim, double> > dg = PHiLiP::DGFactory<dim,double>::create_discontinuous_galerkin(&all_parameters_new, poly_degree, poly_degree, grid_degree, grid);
144  pcout << "dg created" <<std::endl;
145  dg->allocate_system (false,false,false);
146 
147  //initialize IC
148  pcout<<"Setting up Initial Condition"<<std::endl;
149  // Create initial condition function
150  std::shared_ptr< InitialConditionFunction<dim,nstate,double> > initial_condition_function =
152  SetInitialCondition<dim,nstate,double>::set_initial_condition(initial_condition_function, dg, &all_parameters_new);
153 
154  // Create ODE solver using the factory and providing the DG object
155  std::shared_ptr<ODE::ODESolverBase<dim, double>> ode_solver = ODE::ODESolverFactory<dim, double>::create_ODESolver(dg);
156 
157  //do OOA
158  double finalTime=all_parameters_new.flow_solver_param.final_time;
159 
160  ode_solver->current_iteration = 0;
161 
162  ode_solver->advance_solution_time(finalTime);
163  const unsigned int n_global_active_cells = grid->n_global_active_cells();
164  const unsigned int n_dofs = dg->dof_handler.n_dofs();
165  pcout << "Dimension: " << dim
166  << "\t Polynomial degree p: " << poly_degree
167  << std::endl
168  << "Grid number: " << igrid+1 << "/" << n_grids
169  << ". Number of active cells: " << n_global_active_cells
170  << ". Number of degrees of freedom: " << n_dofs
171  << std::endl;
172 
173  // Overintegrate the error to make sure there is not integration error in the error estimate
174  int overintegrate = 10;
175  dealii::QGauss<dim> quad_extra(poly_degree+1+overintegrate);
176  dealii::FEValues<dim,dim> fe_values_extra(*(dg->high_order_grid->mapping_fe_field), dg->fe_collection[poly_degree], quad_extra,
177  dealii::update_values | dealii::update_JxW_values | dealii::update_quadrature_points);
178  const unsigned int n_quad_pts = fe_values_extra.n_quadrature_points;
179  std::array<double,nstate> soln_at_q;
180 
181  double l2error = 0.0;
182  double linf_error = 0.0;
183 
184  // Integrate solution error and output error
185  const double pi = atan(1)*4.0;
186  std::vector<dealii::types::global_dof_index> dofs_indices (fe_values_extra.dofs_per_cell);
187  for (auto cell = dg->dof_handler.begin_active(); cell!=dg->dof_handler.end(); ++cell) {
188 
189  if (!cell->is_locally_owned()) continue;
190 
191  fe_values_extra.reinit (cell);
192  cell->get_dof_indices (dofs_indices);
193 
194  for (unsigned int iquad=0; iquad<n_quad_pts; ++iquad) {
195 
196  std::fill(soln_at_q.begin(), soln_at_q.end(), 0.0);
197  for (unsigned int idof=0; idof<fe_values_extra.dofs_per_cell; ++idof) {
198  const unsigned int istate = fe_values_extra.get_fe().system_to_component_index(idof).first;
199  soln_at_q[istate] += dg->solution[dofs_indices[idof]] * fe_values_extra.shape_value_component(idof, iquad, istate);
200  }
201 
202  for (int istate=0; istate<nstate; ++istate) {
203  double uexact = 0.0;
204  const dealii::Point<dim> qpoint = (fe_values_extra.quadrature_point(iquad));
205  if (all_parameters->pde_type == PHiLiP::Parameters::AllParameters::PartialDifferentialEquation::burgers_inviscid){
206  for(int idim=0; idim<dim; idim++){
207  uexact += cos(pi*(qpoint[idim]-finalTime));//for grid 1-3
208  }
209  }
210  else if (all_parameters->pde_type == PHiLiP::Parameters::AllParameters::PartialDifferentialEquation::advection){
211  uexact = 1.0;
212  const dealii::Tensor<1,3,double> adv_speeds = Parameters::ManufacturedSolutionParam::get_default_advection_vector();
213  for(int idim=0; idim<dim; idim++){
214  if(left==0){
215  uexact *= sin(2.0*pi*(qpoint[idim]-adv_speeds[idim]*finalTime));//for grid 1-3
216  }
217  if(left==-1){
218  uexact *= sin(pi*(qpoint[idim]- adv_speeds[idim]*finalTime));//for grid 1-3
219  }
220  }
221  }
222  l2error += pow(soln_at_q[istate] - uexact, 2) * fe_values_extra.JxW(iquad);
223  double inf_temp = std::abs(soln_at_q[istate]-uexact);
224  //store pointwise inf error
225  if(inf_temp > linf_error){
226  linf_error = inf_temp;
227  }
228  }
229  }
230  }
231  const double l2error_mpi_sum = std::sqrt(dealii::Utilities::MPI::sum(l2error, mpi_communicator));
232 
233  const double linferror_mpi= (dealii::Utilities::MPI::max(linf_error, this->mpi_communicator));
234 
235  // Convergence table
236  const double dx = 1.0/pow(n_dofs,(1.0/dim));
237  grid_size[igrid] = dx;
238  soln_error[igrid] = l2error_mpi_sum;
239  soln_error_inf[igrid] = linferror_mpi;
240 
241  //Checking convergence order
242  double expected_order = poly_degree + 1;
243  if(c_value > 0.186)
244  expected_order -= 1;
245 
246  //set tolerance to make test pass for ctest. Note that the grids are very coarse (not in asymptotic range)
247  const double order_tolerance = 1.0;
248  if (igrid > 0) {
249  const double slope_soln_err = log(soln_error[igrid] / soln_error[igrid - 1])
250  / log(grid_size[igrid] / grid_size[igrid - 1]);
251 
252  if (abs(slope_soln_err - expected_order) > order_tolerance){
253  testfail = 1;
254  pcout << "Expected convergence order was not reached at refinement " <<std::endl;
255  }
256  }
257 
258  convergence_table.add_value("c", c_value);
259  convergence_table.add_value("p", poly_degree);
260  convergence_table.add_value("cells", n_global_active_cells);
261  convergence_table.add_value("DoFs", n_dofs);
262  convergence_table.add_value("dx", dx);
263  convergence_table.add_value("soln_L2_error", l2error_mpi_sum);
264  convergence_table.add_value("soln_Linf_error", linferror_mpi);
265 
266  pcout << " Grid size h: " << dx
267  << " L2-soln_error: " << l2error_mpi_sum
268  << " Linf-soln_error: " << linferror_mpi
269  << " Residual: " << ode_solver->residual_norm
270  << std::endl;
271 
272  if (igrid > igrid_start) {
273  const double slope_soln_err = log(soln_error[igrid]/soln_error[igrid-1])
274  / log(grid_size[igrid]/grid_size[igrid-1]);
275 
276  const double slope_soln_err_inf = log(soln_error_inf[igrid]/soln_error_inf[igrid-1])
277  / log(grid_size[igrid]/grid_size[igrid-1]);
278  pcout << "From grid " << igrid
279  << " to grid " << igrid+1
280  << " dimension: " << dim
281  << " polynomial degree p: " << poly_degree
282  << std::endl
283  << " solution_error1 " << soln_error[igrid-1]
284  << " solution_error2 " << soln_error[igrid]
285  << " slope " << slope_soln_err
286  << " solution_error1_inf " << soln_error_inf[igrid-1]
287  << " solution_error2_inf " << soln_error_inf[igrid]
288  << " slope " << slope_soln_err_inf
289  << std::endl;
290  }
291 
292  pcout << " ********************************************"
293  << std::endl
294  << " Convergence rates for p = " << poly_degree
295  << std::endl
296  << " ********************************************"
297  << std::endl;
298  convergence_table.evaluate_convergence_rates("soln_L2_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
299  convergence_table.evaluate_convergence_rates("soln_Linf_error", "cells", dealii::ConvergenceTable::reduction_rate_log2, dim);
300  convergence_table.set_scientific("c", true);
301  convergence_table.set_scientific("dx", true);
302  convergence_table.set_scientific("soln_L2_error", true);
303  convergence_table.set_scientific("soln_Linf_error", true);
304  if (pcout.is_active()) convergence_table.write_text(pcout.get_stream());
305  //end of OOA
306  }//end of grid loop
307 
308  convergence_table.write_text(conv_tab_file);
309  convergence_table.clear();
310  }//end of Loop over c_array
311  conv_tab_file.close();
312  return testfail;
313 }
319 
320 } // Tests namespace
321 } // PHiLiP namespace
double final_time
Final solution time.
unsigned int degree_start
First polynomial degree to start the loop. If diffusion, must be at least 1.
PartialDifferentialEquation pde_type
Store the PDE type to be solved.
static dealii::Tensor< 1, 3, double > get_default_advection_vector()
gets the default advection vector
FlowSolverParam flow_solver_param
Contains the parameters for simulation cases (flow solver test)
double ESFR_parameter_values_start
For user defined FR parameter tests, value of starting FR param.
const MPI_Comm mpi_communicator
MPI communicator.
Definition: tests.h:39
StabilityFRParametersRange(const Parameters::AllParameters *const parameters_input)
Constructor.
void build_1D_volume_operator(const dealii::FESystem< 1, 1 > &finite_element, const dealii::Quadrature< 1 > &quadrature)
Assembles the one dimensional operator.
Definition: operators.cpp:1738
int number_ESFR_parameter_values
For user defined FR parameter tests, number of values to be tested.
double ESFR_parameter_values_end
For user defined FR parameter tests, value of final FR param.
Files for the baseline physics.
Definition: ADTypes.hpp:10
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
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.
Definition: dg_factory.cpp:10
double FR_user_specified_correction_parameter_value
User specified flux recontruction correction parameter value.
double compute_conservation(std::shared_ptr< PHiLiP::DGBase< dim, double > > &dg, const double poly_degree) const
Function computes the conservation.
dealii::FullMatrix< double > oneD_vol_operator
Stores the one dimensional volume operator.
Definition: operators.h:355
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
double grid_right_bound
Right bound of domain for hyper_cube mesh based cases.
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
double compute_energy(std::shared_ptr< PHiLiP::DGBase< dim, double > > &dg) const
Function computes the energy.
void matrix_vector_mult_1D(const std::vector< real > &input_vect, std::vector< real > &output_vect, const dealii::FullMatrix< double > &basis_x, const bool adding=false, const double factor=1.0)
Apply the matrix vector operation using the 1D operator in each direction.
Definition: operators.cpp:308
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) ...
Projection operator corresponding to basis functions onto M-norm (L2).
Definition: operators.h:698
static void set_initial_condition(std::shared_ptr< InitialConditionFunction< dim, nstate, double > > initial_condition_function_input, std::shared_ptr< PHiLiP::DGBase< dim, real > > dg_input, const Parameters::AllParameters *const parameters_input)
Applies the given initial condition function to the given dg object.
Base class of all the tests.
Definition: tests.h:17
static std::shared_ptr< InitialConditionFunction< dim, nstate, real > > create_InitialConditionFunction(Parameters::AllParameters const *const param)
Construct InitialConditionFunction object from global parameter file.