[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
general_refinement_study.cpp
1 #include "general_refinement_study.h"
2 #include "flow_solver/flow_solver_factory.h"
3 #include "flow_solver/flow_solver_cases/periodic_1D_unsteady.h"
4 #include "flow_solver/flow_solver_cases/periodic_entropy_tests.h"
5 #include "physics/exact_solutions/exact_solution.h"
6 #include "cmath"
7 
8 namespace PHiLiP {
9 namespace Tests {
10 
11 template <int dim, int nstate>
13  const PHiLiP::Parameters::AllParameters *const parameters_input,
14  const dealii::ParameterHandler &parameter_handler_input,
15  const RefinementType refinement_type_input)
16  : TestsBase::TestsBase(parameters_input),
17  parameter_handler(parameter_handler_input),
18  refinement_type(refinement_type_input),
19  n_calculations(parameters_input->time_refinement_study_param.number_of_times_to_solve),
20  refine_ratio(parameters_input->time_refinement_study_param.refinement_ratio)
21 {}
22 
23 template <int dim, int nstate>
25 {
26  PHiLiP::Parameters::AllParameters parameters = *(parameters_in);
27 
28  if (how == RefinementType::timestep){
29  parameters.ode_solver_param.initial_time_step *= pow(refine_ratio,refinement);
30  } else if (how == RefinementType::cell_length){
31  if (abs(refine_ratio - 2.0 ) > 1E-13) {
32  this->pcout << "Warning: h refinement will use a refinement factor of 2." << std::endl
33  << "User input time_refinement_study_param.refinement_ratio will be ignored." << std::endl;
34  }
35  parameters.flow_solver_param.number_of_grid_elements_per_dimension *= pow(2, refinement);
36  }
37 
38  //For RRK, do not end at exact time because of how relaxation parameter convergence is calculated
39  using ODESolverEnum = Parameters::ODESolverParam::ODESolverEnum;
40  if (parameters.ode_solver_param.ode_solver_type == ODESolverEnum::rrk_explicit_solver){
42  }
43 
44  return parameters;
45 }
46 
47 template <int dim, int nstate>
48 double GeneralRefinementStudy<dim,nstate>::calculate_Lp_error_at_final_time_wrt_function(std::shared_ptr<DGBase<dim,double>> dg, const Parameters::AllParameters parameters, double final_time, int norm_p) const
49 {
50  //generate exact solution at final time
51  std::shared_ptr<ExactSolutionFunction<dim,nstate,double>> exact_solution_function;
52  exact_solution_function = ExactSolutionFactory<dim,nstate,double>::create_ExactSolutionFunction(parameters.flow_solver_param, final_time);
53  this->pcout << "End time: " << final_time << std::endl;
54  double Lp_error=0;
55  int overintegrate = 10;
56 
57  int poly_degree = parameters.grid_refinement_study_param.poly_degree;
58  dealii::Vector<double> difference_per_cell(dg->solution.size());
59 
60  dealii::VectorTools::NormType norm_type;
61  if (norm_p == 1) norm_type = dealii::VectorTools::L1_norm;
62  else if (norm_p == 2) norm_type = dealii::VectorTools::L2_norm;
63  else if (norm_p<0) norm_type = dealii::VectorTools::Linfty_norm;
64  else {
65  pcout << "Norm not defined. Aborting... " << std::endl;
66  std::abort();
67  }
68 
69  dealii::VectorTools::integrate_difference(dg->dof_handler,
70  dg->solution,
71  *exact_solution_function,
72  difference_per_cell,
73  dealii::QGauss<dim>(poly_degree + overintegrate), //overintegrating
74  norm_type);
75  Lp_error = dealii::VectorTools::compute_global_error(*dg->triangulation,
76  difference_per_cell,
77  norm_type);
78  return Lp_error;
79 }
80 
81 template <int dim, int nstate>
83  const Parameters::AllParameters params,
84  double L2_error_old,
85  std::shared_ptr<dealii::ConvergenceTable> convergence_table,
86  int refinement,
87  const double expected_order) const
88 {
89  int testfail=0;
90  const double final_time_actual = flow_solver->ode_solver->current_time;
91 
92  //check Lp error
93  const double L1_error = calculate_Lp_error_at_final_time_wrt_function(flow_solver->dg, params,final_time_actual, 1);
94  const double L2_error = calculate_Lp_error_at_final_time_wrt_function(flow_solver->dg, params,final_time_actual, 2);
95  const double Linfty_error = calculate_Lp_error_at_final_time_wrt_function(flow_solver->dg, params,final_time_actual, -1);
96  pcout << "Computed errors are: " << std::endl
97  << " L1: " << L1_error << std::endl
98  << " L2: " << L2_error << std::endl
99  << " Linfty: " << Linfty_error << std::endl;
100 
101 
102 
103  // hard-coded for LSRK test
105  && params.ode_solver_param.atol == 1e-4 && params.ode_solver_param.rtol == 1e-4
107  double L2_error_expected = 2.14808703658e-5;
108  pcout << " Expected L2 error is: " << L2_error_expected << std::endl;
109  if (L2_error > L2_error_expected + 1e-9 || L2_error < L2_error_expected - 1e-9){
110  testfail = 1;
111  pcout << "Expected L2 error for RK3(2)5F[3S*+] using an atol = rtol = 1e-4 was not reached " << refinement <<std::endl;
112  }
113  }
114 
115  std::string step_string;
116  double step=1.0;
117  if (refinement_type == RefinementType::timestep){
118  step_string = "dt";
119  step = params.ode_solver_param.initial_time_step;
120  }else if (refinement_type == RefinementType::cell_length){
121  step_string = "h";
123  }
124  convergence_table->add_value("refinement", refinement);
125  convergence_table->add_value(step_string, step );
126  convergence_table->set_precision(step_string, 16);
127  convergence_table->add_value("n_cells_per_dim",params.flow_solver_param.number_of_grid_elements_per_dimension);
128  convergence_table->set_scientific(step_string, true);
129  convergence_table->add_value("L1_error",L1_error);
130  convergence_table->set_precision("L1_error", 16);
131  convergence_table->evaluate_convergence_rates("L1_error", step_string, dealii::ConvergenceTable::reduction_rate_log2, 1);
132  convergence_table->add_value("L2_error",L2_error);
133  convergence_table->set_precision("L2_error", 16);
134  convergence_table->evaluate_convergence_rates("L2_error", step_string, dealii::ConvergenceTable::reduction_rate_log2, 1);
135  convergence_table->add_value("Linfty_error",Linfty_error);
136  convergence_table->set_precision("Linfty_error", 16);
137  convergence_table->evaluate_convergence_rates("Linfty_error", step_string, dealii::ConvergenceTable::reduction_rate_log2, 1);
138 
139  using ODESolverEnum = Parameters::ODESolverParam::ODESolverEnum;
140  if(params.ode_solver_param.ode_solver_type == ODESolverEnum::rrk_explicit_solver){
141  const double dt = params.ode_solver_param.initial_time_step;
142  const int n_timesteps= flow_solver->ode_solver->current_iteration;
143  pcout << " at dt = " << dt << std::endl;
144  //for burgers, this is the average gamma over the runtime
145  const double gamma_aggregate_m1 = final_time_actual / (n_timesteps * dt)-1;
146  convergence_table->add_value("gamma_aggregate_m1", gamma_aggregate_m1);
147  convergence_table->set_precision("gamma_aggregate_m1", 16);
148  convergence_table->set_scientific("gamma_aggregate_m1", true);
149  convergence_table->evaluate_convergence_rates("gamma_aggregate_m1", step_string, dealii::ConvergenceTable::reduction_rate_log2, 1);
150  }
151 
152  const double order_tolerance = 0.1;
153  if (refinement > 0) {
154  double L2_error_conv_rate = abs(log(L2_error_old/L2_error)/log(refine_ratio));
155  pcout << "L2 order at " << refinement << " is " << L2_error_conv_rate << std::endl;
156  if ((L2_error_conv_rate ) < expected_order - order_tolerance){
157  // Fail if the found convergence order is lower than the expected order.
158  testfail = 1;
159  pcout << "Expected convergence order was not reached at refinement " << refinement <<std::endl;
160  }
161 
162  // output current time refinement results to console
163  if (refinement < n_calculations-1 && pcout.is_active()) convergence_table->write_text(pcout.get_stream());
164  }
165  return std::make_tuple(L2_error,testfail);
166 }
167 
168 template <int dim, int nstate>
169 int GeneralRefinementStudy<dim,nstate>::run_refinement_study_and_write_result(const Parameters::AllParameters *parameters_in, const double expected_order, const bool check_only_last_refinement, const bool append_to_file) const{
170 
171  const double final_time = parameters_in->flow_solver_param.final_time;
172  const double initial_time_step = parameters_in->ode_solver_param.initial_time_step;
173  const int n_steps = floor(final_time/initial_time_step);
174  if (n_steps * initial_time_step != final_time){
175  pcout << "WARNING: final_time is not evenly divisible by initial_time_step!" << std::endl
176  << "Remainder is " << fmod(final_time, initial_time_step)
177  << ". Consider modifying parameters." << std::endl;
178  }
179 
180  int testfail = 0;
181 
182  std::shared_ptr<dealii::ConvergenceTable> convergence_table = std::make_shared<dealii::ConvergenceTable>();
183  double L2_error_old = 0;
184  double L2_error=0;
185 
186  for (int refinement = 0; refinement < n_calculations; ++refinement){
187 
188  pcout << "\n\n---------------------------------------------" << std::endl;
189  pcout << "Refinement number " << refinement << " of " << n_calculations - 1 << std::endl;
190  pcout << "---------------------------------------------" << std::endl;
191 
192  const Parameters::AllParameters params = reinit_params_and_refine(parameters_in,refinement, refinement_type);
193  std::shared_ptr<FlowSolver::FlowSolver<dim,nstate>> flow_solver = std::move(FlowSolver::FlowSolverFactory<dim,nstate>::select_flow_case(&params, parameter_handler));
194  static_cast<void>(flow_solver->run());
195 
196  pcout << "Finished flowsolver." << std::endl;
197  std::tuple<double, int> out_tuple = process_and_write_conv_tables(
198  flow_solver,
199  params,
200  L2_error_old,
201  convergence_table,
202  refinement,
203  expected_order);
204  L2_error = std::get<0>(out_tuple);
205  int local_testfail = std::get<1>(out_tuple);
206 
207  if (local_testfail == 1) {
208  this->pcout<< "Expected order was not reached at refinement " << refinement << std::endl;
209  }
210 
211  if (check_only_last_refinement && refinement == n_calculations - 1) {
212  testfail = local_testfail;
213  } else if (!check_only_last_refinement) {
214  // check all refinements
215  testfail = (local_testfail == 1 || testfail == 1) ? 1 : 0;
216  }
217  L2_error_old = L2_error;
218  }
219 
220  //Printing and writing convergence table
221  pcout << std::endl;
222  if (pcout.is_active()){
223  convergence_table->write_text(pcout.get_stream());
224 
225  std::ofstream conv_tab_file;
226  const std::string fname = "convergence_table.txt";
227  if (append_to_file == true) {
228  conv_tab_file.open(fname, std::ios::app);
229  } else{
230  conv_tab_file.open(fname);
231  }
232  convergence_table->write_text(conv_tab_file);
233  conv_tab_file.close();
234  }
235 
236 
237  return testfail;
238 }
239 
240 template <int dim, int nstate>
242 {
243  // setting expected order
244  double expected_order_=0;
245  if (refinement_type == RefinementType::timestep){
246  expected_order_ = this->all_parameters->ode_solver_param.rk_order;
247  } else if (refinement_type == RefinementType::cell_length){
248  expected_order_ = this->all_parameters->flow_solver_param.poly_degree + 1;
249  }
250  const double expected_order = expected_order_;
251 
252  int testfail = this->run_refinement_study_and_write_result(this->all_parameters, expected_order);
253 
254  return testfail;
255 }
256 
257 #if PHILIP_DIM==1
259 #else
262 #endif
263 } // Tests namespace
264 } // PHiLiP namespace
double final_time
Final solution time.
GeneralRefinementStudy(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler &parameter_handler_input, const RefinementType refinement_type_input)
Constructor.
Advection time refinement study.
unsigned int number_of_grid_elements_per_dimension
Number of grid elements per dimension for hyper_cube mesh based cases.
double calculate_Lp_error_at_final_time_wrt_function(std::shared_ptr< DGBase< dim, double >> dg, const Parameters::AllParameters parameters, double final_time, int norm_p) const
TimeRefinementStudyParam time_refinement_study_param
Contains the parameters for time refinement study.
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::AllParameters reinit_params_and_refine(const Parameters::AllParameters *parameters_in, int refinement, const RefinementType how) const
Reinitialize parameters while refining the timestep. Necessary because all_parameters is constant...
Files for the baseline physics.
Definition: ADTypes.hpp:10
int run_refinement_study_and_write_result(const Parameters::AllParameters *parameters_in, const double expected_order, const bool check_only_last_refinement=false, const bool append_to_file=false) const
Run the refinements.
GridRefinementStudyParam grid_refinement_study_param
Contains the parameters for grid refinement study.
static std::shared_ptr< ExactSolutionFunction< dim, nstate, real > > create_ExactSolutionFunction(const Parameters::FlowSolverParam &flow_solver_parameters, const double time_compare)
Construct ExactSolutionFunction object from global parameter file.
const RefinementType refinement_type
Type of refinement to run.
const int n_calculations
Number of times to solve for convergence summary.
unsigned int poly_degree
Polynomial order (P) of the basis functions for DG.
Main parameter class that contains the various other sub-parameter classes.
const double refine_ratio
Ratio to refine by.
double grid_left_bound
Left bound of domain for hyper_cube mesh based cases.
int rk_order
Order of the RK method; assigned based on runge_kutta_method.
ODESolverParam ode_solver_param
Contains parameters for ODE solver.
double initial_time_step
Time step used in ODE solver.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: tests.h:20
Fourth-order, three register low-storage Runge-Kutta method.
bool end_exactly_at_final_time
Flag to adjust the last timestep such that the simulation ends exactly at final_time.
RKMethodEnum runge_kutta_method
Runge-kutta method.
ODESolverEnum ode_solver_type
ODE solver type.
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.
virtual std::tuple< double, int > process_and_write_conv_tables(std::shared_ptr< FlowSolver::FlowSolver< dim, nstate >> flow_solver, const Parameters::AllParameters params, double L2_error_old, std::shared_ptr< dealii::ConvergenceTable > convergence_table, int refinement, const double expected_order) const
Calculate the L2 error and return local testfail for the converged flowsolver.
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
double grid_right_bound
Right bound of domain for hyper_cube mesh based cases.
int number_of_times_to_solve
number of times to run the calculation
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
unsigned int poly_degree
Initial solution polynomial degree.
Base class of all the tests.
Definition: tests.h:17
Create specified flow solver as FlowSolver object.