[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
time_refinement_study_reference.cpp
1 #include "time_refinement_study_reference.h"
2 #include "flow_solver/flow_solver_factory.h"
3 #include "flow_solver/flow_solver_cases/periodic_1D_unsteady.h"
4 #include "physics/exact_solutions/exact_solution.h"
5 #include "cmath"
6 
7 namespace PHiLiP {
8 namespace Tests {
9 
10 template <int dim, int nstate>
12  const PHiLiP::Parameters::AllParameters *const parameters_input,
13  const dealii::ParameterHandler &parameter_handler_input)
14  : TestsBase::TestsBase(parameters_input),
15  parameter_handler(parameter_handler_input),
16  n_time_calculations(parameters_input->time_refinement_study_param.number_of_times_to_solve),
17  refine_ratio(parameters_input->time_refinement_study_param.refinement_ratio)
18 {}
19 
20 template <int dim, int nstate>
22 {
24 
25  const double dt = final_time/number_of_timesteps;
26  parameters.ode_solver_param.initial_time_step = dt;
27 
28  parameters.flow_solver_param.final_time = final_time;
29 
31 
32  //Change to RK because at small dt RRK is more costly but doesn't impact solution much
33  using ODESolverEnum = Parameters::ODESolverParam::ODESolverEnum;
34  parameters.ode_solver_param.ode_solver_type = ODESolverEnum::runge_kutta_solver;
35 
36  pcout << "Using timestep size dt = " << dt << " for reference solution." << std::endl;
37 
38  return parameters;
39 }
40 
41 template <int dim, int nstate>
43 {
45 
46  parameters.flow_solver_param.unsteady_data_table_filename += std::to_string(refinement);
47 
48  parameters.ode_solver_param.initial_time_step *= pow(refine_ratio,refinement);
49 
50  //For RRK, do not end at exact time because of how relaxation parameter convergence is calculatd
51  using ODESolverEnum = Parameters::ODESolverParam::ODESolverEnum;
52  if (parameters.ode_solver_param.ode_solver_type == ODESolverEnum::rrk_explicit_solver){
54  }
55 
56  return parameters;
57 }
58 
59 template <int dim, int nstate>
60 dealii::LinearAlgebra::distributed::Vector<double> TimeRefinementStudyReference<dim,nstate>::calculate_reference_solution(
61  double final_time) const
62 {
63  const int number_of_timesteps_for_reference_solution = this->all_parameters->time_refinement_study_param.number_of_timesteps_for_reference_solution;
64  const Parameters::AllParameters params_reference = reinit_params_for_reference_solution(number_of_timesteps_for_reference_solution, final_time);
65  std::unique_ptr<FlowSolver::FlowSolver<dim,nstate>> flow_solver_reference = FlowSolver::FlowSolverFactory<dim,nstate>::select_flow_case(&params_reference, parameter_handler);
66  static_cast<void>(flow_solver_reference->run());
67 
68  pcout << " Actual final time: " << flow_solver_reference->ode_solver->current_time << std::endl;
69 
70  return flow_solver_reference->dg->solution;
71 }
72 
73 template <int dim, int nstate>
75  std::shared_ptr<DGBase<dim,double>> dg,
76  const Parameters::AllParameters parameters,
77  double final_time_actual,
78  dealii::LinearAlgebra::distributed::Vector<double> reference_solution) const
79 {
80  const double final_time_target = parameters.flow_solver_param.final_time;
81 
82  if (abs(final_time_target-final_time_actual)<1E-13){
83 
84  pcout << "Comparing to reference solution at target final_time = " << final_time_target << " ..." << std::endl;
85 
86  //calculate L2 norm of error
87  dealii::LinearAlgebra::distributed::Vector<double> cellwise_difference(reference_solution);
88  cellwise_difference.add(-1.0, dg->solution);
89  const double L2_error = cellwise_difference.l2_norm();
90  return L2_error;
91  }else{
92  //recompute reference solution at actual end time
93  //intended to be used when using ode_solver = rrk_explicit_solver
94 
95  pcout << " -------------------------------------------------------" << std::endl;
96  pcout << " Calculating reference solution at actual final_time = " << final_time_actual << " ..."<<std::endl;
97  pcout << " -------------------------------------------------------" << std::endl;
98  const dealii::LinearAlgebra::distributed::Vector<double> reference_solution_actual = calculate_reference_solution(final_time_actual);
99 
100  dealii::LinearAlgebra::distributed::Vector<double> cellwise_difference(reference_solution_actual);
101  cellwise_difference.add(-1.0, dg->solution);
102  const double L2_error = cellwise_difference.l2_norm();
103  return L2_error;
104  }
105 
106 }
107 
108 template <int dim, int nstate>
110 {
111  using ODESolverEnum = Parameters::ODESolverParam::ODESolverEnum;
112 
113  const double final_time = this->all_parameters->flow_solver_param.final_time;
114  const double initial_time_step = this->all_parameters->ode_solver_param.initial_time_step;
115  const int n_steps = round(final_time/initial_time_step);
116  if (n_steps * initial_time_step != final_time){
117  pcout << "WARNING: final_time is not evenly divisible by initial_time_step!" << std::endl
118  << "Remainder is " << fmod(final_time, initial_time_step)
119  << ". Consider modifying parameters." << std::endl;
120  }
121 
122  int testfail = 0;
123 
124  //pointer to flow_solver_case for computing energy
125  std::unique_ptr<FlowSolver::Periodic1DUnsteady<dim, nstate>> flow_solver_case = std::make_unique<FlowSolver::Periodic1DUnsteady<dim,nstate>>(this->all_parameters);
126 
127  pcout << "\n\n-------------------------------------------------------" << std::endl;
128  pcout << "Calculating reference solution at target final_time = " << std::setprecision(16) << final_time << " ..."<<std::endl;
129  pcout << "-------------------------------------------------------" << std::endl;
130 
131  const double final_time_target = this->all_parameters->flow_solver_param.final_time;
132  const dealii::LinearAlgebra::distributed::Vector<double> reference_solution = calculate_reference_solution(final_time_target);
133 
134  dealii::ConvergenceTable convergence_table;
135  double L2_error_old = 0;
136  double L2_error_conv_rate=0;
137 
138  for (int refinement = 0; refinement < n_time_calculations; ++refinement){
139 
140  pcout << "\n\n-------------------------------------------------------" << std::endl;
141  pcout << "Refinement number " << refinement << " of " << n_time_calculations - 1 << std::endl;
142  pcout << "-------------------------------------------------------" << std::endl;
143 
145  std::unique_ptr<FlowSolver::FlowSolver<dim,nstate>> flow_solver = FlowSolver::FlowSolverFactory<dim,nstate>::select_flow_case(&params, parameter_handler);
146  const double energy_initial = flow_solver_case->compute_energy(flow_solver->dg);
147  static_cast<void>(flow_solver->run());
148 
149  const double final_time_actual = flow_solver->ode_solver->current_time;
150  pcout << " Actual final time: " << final_time_actual << std::endl;
151 
152  const int n_timesteps= flow_solver->ode_solver->current_iteration;
153 
154  //check L2 error
155  const double L2_error = calculate_L2_error_at_final_time_wrt_reference(
156  flow_solver->dg,
157  params,
158  final_time_actual,
159  reference_solution);
160  pcout << "Computed error is " << L2_error << std::endl;
161 
162  const double dt = params.ode_solver_param.initial_time_step;
163  convergence_table.add_value("refinement", refinement);
164  convergence_table.add_value("dt", dt );
165  convergence_table.set_precision("dt", 16);
166  convergence_table.set_scientific("dt", true);
167  convergence_table.add_value("final_time", final_time_actual );
168  convergence_table.set_precision("final_time", 16);
169  convergence_table.add_value("n_timesteps", n_timesteps);
170  convergence_table.add_value("L2_error",L2_error);
171  convergence_table.set_precision("L2_error", 16);
172  convergence_table.evaluate_convergence_rates("L2_error", "dt", dealii::ConvergenceTable::reduction_rate_log2, 1);
173 
174  const double energy_end = flow_solver_case->compute_energy(flow_solver->dg);
175  const double energy_change = energy_initial - energy_end;
176  convergence_table.add_value("energy_change", energy_change);
177  convergence_table.set_precision("energy_change", 16);
178  convergence_table.evaluate_convergence_rates("energy_change", "dt", dealii::ConvergenceTable::reduction_rate_log2, 1);
179 
180  if(params.ode_solver_param.ode_solver_type == ODESolverEnum::rrk_explicit_solver){
181  //for burgers, this is the average gamma over the runtime
182  const double gamma_aggregate_m1 = final_time_actual / (n_timesteps * dt)-1;
183  convergence_table.add_value("gamma_aggregate_m1", gamma_aggregate_m1);
184  convergence_table.set_precision("gamma_aggregate_m1", 16);
185  convergence_table.set_scientific("gamma_aggregate_m1", true);
186  convergence_table.evaluate_convergence_rates("gamma_aggregate_m1", "dt", dealii::ConvergenceTable::reduction_rate_log2, 1);
187  }
188 
189  //Checking convergence order
190  const double expected_order = params.ode_solver_param.rk_order;
191  const double order_tolerance = 0.1;
192  if (refinement > 0) {
193  L2_error_conv_rate = -log(L2_error_old/L2_error)/log(refine_ratio);
194  pcout << "Order at " << refinement << " is " << L2_error_conv_rate << std::endl;
195  if (abs(L2_error_conv_rate - expected_order) > order_tolerance){
196  testfail = 1;
197  pcout << "Expected convergence order was not reached at refinement " << refinement <<std::endl;
198  }
199  }
200  L2_error_old = L2_error;
201  }
202 
203  //Printing and writing convergence table
204  pcout << std::endl;
205  if (pcout.is_active()) {
206  convergence_table.write_text(pcout.get_stream());
207 
208  std::ofstream conv_tab_file;
209  const std::string fname = "temporal_convergence_table.txt";
210  conv_tab_file.open(fname);
211  convergence_table.write_text(conv_tab_file);
212  conv_tab_file.close();
213  }
214 
215  return testfail;
216 }
217 
218 #if PHILIP_DIM==1
220 #endif
221 } // Tests namespace
222 } // PHiLiP namespace
double calculate_L2_error_at_final_time_wrt_reference(std::shared_ptr< DGBase< dim, double >> dg, const Parameters::AllParameters parameters, double final_time_actual, dealii::LinearAlgebra::distributed::Vector< double > reference_solution) const
Calculate L2 error at the final time in the passed parameters.
double final_time
Final solution time.
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)
Parameters::AllParameters reinit_params_and_refine_timestep(int refinement) const
Reinitialize parameters while refining the timestep. Necessary because all_parameters is constant...
Files for the baseline physics.
Definition: ADTypes.hpp:10
int number_of_timesteps_for_reference_solution
For time refinement study with reference solution, number of steps for reference solution.
Parameters::AllParameters reinit_params_for_reference_solution(int number_of_timesteps, double final_time) const
Reinitialize parameters and set initial_timestep according to reference solution and passed final tim...
Main parameter class that contains the various other sub-parameter classes.
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.
static std::unique_ptr< FlowSolver< dim, 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.
const Parameters::AllParameters *const all_parameters
Pointer to all parameters.
Definition: tests.h:20
bool end_exactly_at_final_time
Flag to adjust the last timestep such that the simulation ends exactly at final_time.
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.
TimeRefinementStudyReference(const Parameters::AllParameters *const parameters_input, const dealii::ParameterHandler &parameter_handler_input)
Constructor.
ODESolverEnum ode_solver_type
ODE solver type.
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: tests.h:45
Time refinement study which compares to a reference solution.
DGBase is independent of the number of state variables.
Definition: dg_base.hpp:82
const int n_time_calculations
Number of times to solve for convergence summary.
Base class of all the tests.
Definition: tests.h:17