[P]arallel [Hi]gh-order [Li]brary for [P]DEs  Latest
Parallel High-Order Library for PDEs through hp-adaptive Discontinuous Galerkin methods
flow_solver.cpp
1 #include "flow_solver.h"
2 #include <iostream>
3 #include <fstream>
4 #include <string>
5 #include <stdlib.h>
6 #include <vector>
7 #include <sstream>
8 #include "reduced_order/pod_basis_offline.h"
9 #include "reduced_order/pod_basis_online.h"
10 #include "physics/initial_conditions/set_initial_condition.h"
11 #include "mesh/mesh_adaptation/mesh_adaptation.h"
12 #include <deal.II/base/timer.h>
13 
14 namespace PHiLiP {
15 
16 namespace FlowSolver {
17 
18 //=========================================================
19 // FLOW SOLVER CLASS
20 //=========================================================
21 template <int dim, int nspecies, int nstate>
23  const PHiLiP::Parameters::AllParameters *const parameters_input,
24  std::shared_ptr<FlowSolverCaseBase<dim, nspecies, nstate>> flow_solver_case_input,
25  const dealii::ParameterHandler &parameter_handler_input)
27 , flow_solver_case(flow_solver_case_input)
28 , parameter_handler(parameter_handler_input)
29 , mpi_communicator(MPI_COMM_WORLD)
30 , mpi_rank(dealii::Utilities::MPI::this_mpi_process(MPI_COMM_WORLD))
31 , n_mpi(dealii::Utilities::MPI::n_mpi_processes(MPI_COMM_WORLD))
32 , pcout(std::cout, mpi_rank==0)
33 , all_param(*parameters_input)
34 , flow_solver_param(all_param.flow_solver_param)
35 , ode_param(all_param.ode_solver_param)
36 , poly_degree(flow_solver_param.poly_degree)
37 , grid_degree(flow_solver_param.grid_degree)
38 , final_time(flow_solver_param.final_time)
39 , input_parameters_file_reference_copy_filename(flow_solver_param.restart_files_directory_name + std::string("/") + std::string("input_copy.prm"))
40 , do_output_solution_at_fixed_times(ode_param.output_solution_at_fixed_times)
41 , number_of_fixed_times_to_output_solution(ode_param.number_of_fixed_times_to_output_solution)
42 , output_solution_at_exact_fixed_times(ode_param.output_solution_at_exact_fixed_times)
43 , do_compute_unsteady_data_and_write_to_table(flow_solver_param.do_compute_unsteady_data_and_write_to_table)
44 , dg(DGFactory<dim,nspecies,double>::create_discontinuous_galerkin(&all_param, poly_degree, flow_solver_param.max_poly_degree_for_adaptation, grid_degree, flow_solver_case->generate_grid()))
45 {
46  flow_solver_case->set_higher_order_grid(dg);
48  pcout << "Note: Allocating DG with AD matrix dRdW only." << std::endl;
49  dg->allocate_system(true,false,false); // FlowSolver only requires dRdW to be allocated
50  } else {
51  pcout << "Note: Allocating DG without AD matrices." << std::endl;
52  dg->allocate_system(false,false,false);
53  }
54 
55 
56  flow_solver_case->display_flow_solver_setup(dg);
57 
59  if(dim == 1) {
60  pcout << "Error: restart_computation_from_file is not possible for 1D. Set to false." << std::endl;
61  std::abort();
62  }
63 
64  if (flow_solver_param.steady_state == true) {
65  pcout << "Error: Restart capability has not been fully implemented / tested for steady state computations." << std::endl;
66  std::abort();
67  }
68 
69  // Initialize solution from restart file
70  pcout << "Initializing solution from restart file..." << std::flush;
71  const std::string restart_filename_without_extension = get_restart_filename_without_extension(flow_solver_param.restart_file_index);
72 #if PHILIP_DIM>1
73  dg->triangulation->load(flow_solver_param.restart_files_directory_name + std::string("/") + restart_filename_without_extension);
74 
75  // Note: Future development with hp-capabilities, see section "Note on usage with DoFHandler with hp-capabilities"
76  // ----- Ref: https://www.dealii.org/current/doxygen/deal.II/classparallel_1_1distributed_1_1SolutionTransfer.html
77  dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
78  solution_no_ghost.reinit(dg->locally_owned_dofs, this->mpi_communicator);
79  dealii::parallel::distributed::SolutionTransfer<dim, dealii::LinearAlgebra::distributed::Vector<double>, dealii::DoFHandler<dim>> solution_transfer(dg->dof_handler);
80  solution_transfer.deserialize(solution_no_ghost);
81  dg->solution = solution_no_ghost; //< assignment
83  dg->triangulation->load(flow_solver_param.restart_files_directory_name + std::string("/") + restart_filename_without_extension + std::string("_time_averaged"));
84  dealii::LinearAlgebra::distributed::Vector<double> time_averaged_solution_no_ghost;
85  time_averaged_solution_no_ghost.reinit(dg->locally_owned_dofs, this->mpi_communicator);
86  dealii::parallel::distributed::SolutionTransfer<dim, dealii::LinearAlgebra::distributed::Vector<double>, dealii::DoFHandler<dim>> time_averaged_solution_transfer(dg->dof_handler);
87  time_averaged_solution_transfer.deserialize(time_averaged_solution_no_ghost);
88  dg->time_averaged_solution = time_averaged_solution_no_ghost; //< assignment
89  }
90 #endif
91  pcout << "done." << std::endl;
92  } else {
93  // Initialize solution
95  }
96  dg->solution.update_ghost_values();
97 
101  std::shared_ptr<ProperOrthogonalDecomposition::OfflinePOD<dim,nspecies>> pod = std::make_shared<ProperOrthogonalDecomposition::OfflinePOD<dim,nspecies>>(dg);
103  } else {
105  }
106 
107  // Allocate ODE solver after initializing DG
108  ode_solver->allocate_ode_system();
109 
110  // Storing a time_dependent POD
114  if(unsteady_FOM_POD_bool && nspecies == 1){
115  std::shared_ptr<dealii::TrilinosWrappers::SparseMatrix> system_matrix(
116  dg,
117  &dg->system_matrix
118  );
119  time_pod = std::make_shared<ProperOrthogonalDecomposition::OnlinePOD<dim,nspecies>>(system_matrix);
120  time_pod->addSnapshot(dg->solution);
121  }
122 
123  // output a copy of the input parameters file
125  pcout << "Writing a reference copy of the inputted parameters (.prm) file... " << std::flush;
126  if(mpi_rank==0) {
128  }
129  pcout << "done." << std::endl;
130  }
131 
132  // For outputting solution at fixed times
135 
136  // Get output_solution_fixed_times from string
137  const std::string output_solution_fixed_times_string = this->ode_param.output_solution_fixed_times_string;
138  std::string line = output_solution_fixed_times_string;
139  std::string::size_type sz1;
140  this->output_solution_fixed_times[0] = std::stod(line,&sz1);
141  for(unsigned int i=1; i<this->number_of_fixed_times_to_output_solution; ++i) {
142  line = line.substr(sz1);
143  sz1 = 0;
144  this->output_solution_fixed_times[i] = std::stod(line,&sz1);
145  }
146  }
147 }
148 
149 template <int dim, int nspecies, int nstate>
150 std::vector<std::string> FlowSolver<dim,nspecies,nstate>::get_data_table_column_names(const std::string string_input) const
151 {
152  /* returns the column names of a dealii::TableHandler object
153  given the first line of the file */
154 
155  // Create object of istringstream and initialize assign input string
156  std::istringstream iss(string_input);
157  std::string word;
158 
159  // extract each name (no spaces)
160  std::vector<std::string> names;
161  while(iss >> word) {
162  names.push_back(word.c_str());
163  }
164  return names;
165 }
166 
167 template <int dim, int nspecies, int nstate>
168 std::string FlowSolver<dim,nspecies,nstate>::get_restart_filename_without_extension(const unsigned int restart_index_input) const {
169  // returns the restart file index as a string with appropriate padding
170  std::string restart_index_string = std::to_string(restart_index_input);
171  const unsigned int length_of_index_with_padding = 5;
172  const unsigned int number_of_zeros = length_of_index_with_padding - restart_index_string.length();
173  restart_index_string.insert(0, number_of_zeros, '0');
174 
175  const std::string prefix = "restart-";
176  const std::string restart_filename_without_extension = prefix+restart_index_string;
177 
178  return restart_filename_without_extension;
179 }
180 
181 template <int dim, int nspecies, int nstate>
183  std::string data_table_filename,
184  const std::shared_ptr <dealii::TableHandler> data_table) const
185 {
186  if(mpi_rank==0) {
187  std::string line;
188  std::string::size_type sz1;
189 
190  std::ifstream FILE (data_table_filename);
191  std::getline(FILE, line); // read first line: column headers
192 
193  // check that the file is not empty
194  if (line.empty()) {
195  pcout << "Error: Trying to read empty file named " << data_table_filename << std::endl;
196  std::abort();
197  }
198 
199  const std::vector<std::string> data_column_names = get_data_table_column_names(line);
200  const int number_of_columns = data_column_names.size();
201 
202  std::getline(FILE, line); // read first line of data
203 
204  // check that there indeed is data to be read
205  if (line.empty()) {
206  pcout << "Error: Table has no data to be read" << std::endl;
207  std::abort();
208  }
209 
210  std::vector<double> current_line_values(number_of_columns);
211  while (!line.empty()) {
212  std::string dummy_line = line;
213 
214  current_line_values[0] = std::stod(dummy_line,&sz1);
215  for(int i=1; i<number_of_columns; ++i) {
216  dummy_line = dummy_line.substr(sz1);
217  sz1 = 0;
218  current_line_values[i] = std::stod(dummy_line,&sz1);
219  }
220 
221  // Add data entries to table
222  for(int i=0; i<number_of_columns; ++i) {
223  data_table->add_value(data_column_names[i], current_line_values[i]);
224  data_table->set_precision(data_column_names[i], 16);
225  data_table->set_scientific(data_column_names[i], true);
226  }
227  std::getline(FILE, line); // read next line
228  }
229  }
230 }
231 
232 template <int dim, int nspecies, int nstate>
233 std::string FlowSolver<dim,nspecies,nstate>::double_to_string(const double value_input) const {
234  // converts a double to a string with full precision
235  std::stringstream ss;
236  ss << std::scientific << std::setprecision(16) << value_input;
237  std::string double_to_string = ss.str();
238  return double_to_string;
239 }
240 
241 template <int dim, int nspecies, int nstate>
243  const unsigned int restart_index_input,
244  const double time_step_input) const {
245  // write the restart parameter file
246  if(mpi_rank==0) {
247  // read a copy of the current parameters file
248  std::ifstream CURRENT_FILE(input_parameters_file_reference_copy_filename);
249 
250  // create write file with appropriate postfix given the restart index input
251  const std::string restart_filename = get_restart_filename_without_extension(restart_index_input)+std::string(".prm");
252  std::ofstream RESTART_FILE(flow_solver_param.restart_files_directory_name + std::string("/") + restart_filename);
253 
254  // Lines to identify the subsections in the .prm file
255  /* WARNING: (2) These must be in the order they appear in the .prm file
256  */
257  std::vector<std::string> subsection_line;
258  subsection_line.push_back("subsection ODE solver");
259  subsection_line.push_back("subsection flow_solver");
260  // Number of subsections to change values in
261  int number_of_subsections = subsection_line.size();
262 
263 
264  /* WARNING: (1) Must put a space before and after each parameter string as done below
265  * (2) These must be in the order they appear in the .prm file
266  */
267  // -- names
268  std::vector<std::string> ODE_solver_restart_parameter_names;
269  ODE_solver_restart_parameter_names.push_back(" initial_desired_time_for_output_solution_every_dt_time_intervals ");
270  ODE_solver_restart_parameter_names.push_back(" initial_iteration ");
271  ODE_solver_restart_parameter_names.push_back(" initial_time ");
272  ODE_solver_restart_parameter_names.push_back(" initial_time_step ");
273  // -- corresponding values
274  std::vector<std::string> ODE_solver_restart_parameter_values;
275  ODE_solver_restart_parameter_values.push_back(double_to_string(ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals));
276  ODE_solver_restart_parameter_values.push_back(std::to_string(ode_solver->current_iteration));
277  ODE_solver_restart_parameter_values.push_back(double_to_string(ode_solver->current_time));
278  ODE_solver_restart_parameter_values.push_back(double_to_string(time_step_input));
279 
280 
281  /* WARNING: (1) Must put a space before and after each parameter string as done below
282  * (2) These must be in the order they appear in the .prm file
283  */
284  // -- Names
285  std::vector<std::string> flow_solver_restart_parameter_names;
286  flow_solver_restart_parameter_names.push_back(" output_restart_files ");
287  flow_solver_restart_parameter_names.push_back(" restart_computation_from_file ");
288  flow_solver_restart_parameter_names.push_back(" restart_file_index ");
289  // -- Corresponding values
290  std::vector<std::string> flow_solver_restart_parameter_values;
291  flow_solver_restart_parameter_values.push_back(std::string("true"));
292  flow_solver_restart_parameter_values.push_back(std::string("true"));
293  flow_solver_restart_parameter_values.push_back(std::to_string(restart_index_input));
294 
295 
296  // Number of parameters in each subsection
297  std::vector<int> number_of_subsection_parameters;
298  number_of_subsection_parameters.push_back(ODE_solver_restart_parameter_names.size());
299  number_of_subsection_parameters.push_back(flow_solver_restart_parameter_names.size());
300 
301  // Initialize for the while loop
302  int i_subsection = 0;
303  std::string line;
304 
305  // read line until end of file
306  while (std::getline(CURRENT_FILE, line)) {
307  // check if the desired subsection has been reached
308  if (line == subsection_line[i_subsection]) {
309  RESTART_FILE << line << "\n"; // write line
310 
311  int i_parameter = 0;
312  std::string name;
313  std::string value_string;
314 
315  if (i_subsection==0) {
316  name = ODE_solver_restart_parameter_names[i_parameter];
317  value_string = ODE_solver_restart_parameter_values[i_parameter];
318  } else if (i_subsection==1) {
319  name = flow_solver_restart_parameter_names[i_parameter];
320  value_string = flow_solver_restart_parameter_values[i_parameter];
321  }
322 
323  while (line!="end") {
324  std::getline(CURRENT_FILE, line); // read line
325  std::string::size_type found = line.find(name);
326 
327  // found the line corresponding to the desired parameter
328  if (found!=std::string::npos) {
329 
330  // construct the updated line
331  std::string updated_line = line;
332  std::string::size_type position_to_replace = line.find_last_of("=")+2;
333  std::string part_of_line_to_replace = line.substr(position_to_replace);
334  updated_line.replace(position_to_replace,part_of_line_to_replace.length(),value_string);
335 
336  // write updated line to restart file
337  RESTART_FILE << updated_line << "\n";
338 
339  // update the parameter index, name, and value
340  if ((i_parameter+1) < number_of_subsection_parameters[i_subsection]) ++i_parameter; // to avoid going out of bounds
341  if (i_subsection==0) {
342  name = ODE_solver_restart_parameter_names[i_parameter];
343  value_string = ODE_solver_restart_parameter_values[i_parameter];
344  } else if (i_subsection==1) {
345  name = flow_solver_restart_parameter_names[i_parameter];
346  value_string = flow_solver_restart_parameter_values[i_parameter];
347  }
348  } else {
349  // write line (that does correspond to the desired parameter) to the restart file
350  RESTART_FILE << line << "\n";
351  }
352  }
353  // update the subsection index
354  if ((i_subsection+1) < number_of_subsections) ++i_subsection; // to avoid going out of bounds
355  } else {
356  // write line (that is not in a desired subsection) to the restart file
357  RESTART_FILE << line << "\n";
358  }
359  }
360  }
361 }
362 
363 #if PHILIP_DIM>1
364 template <int dim, int nspecies, int nstate>
366  const unsigned int current_restart_index,
367  const double time_step_input,
368  const std::shared_ptr <dealii::TableHandler> unsteady_data_table) const
369 {
370  pcout << " ... Writing restart files ... " << std::endl;
371  const std::string restart_filename_without_extension = get_restart_filename_without_extension(current_restart_index);
372 
373  // solution files
374  dealii::parallel::distributed::SolutionTransfer<dim, dealii::LinearAlgebra::distributed::Vector<double>, dealii::DoFHandler<dim>> solution_transfer(dg->dof_handler);
375  // Note: Future development with hp-capabilities, see section "Note on usage with DoFHandler with hp-capabilities"
376  // ----- Ref: https://www.dealii.org/current/doxygen/deal.II/classparallel_1_1distributed_1_1SolutionTransfer.html
377  solution_transfer.prepare_for_serialization(dg->solution);
378  dg->triangulation->save(flow_solver_param.restart_files_directory_name + std::string("/") + restart_filename_without_extension);
379 
381  // time-averaged solution files
382  dealii::parallel::distributed::SolutionTransfer<dim, dealii::LinearAlgebra::distributed::Vector<double>, dealii::DoFHandler<dim>> time_averaged_solution_transfer(dg->dof_handler);
383  time_averaged_solution_transfer.prepare_for_serialization(dg->time_averaged_solution);
384  dg->triangulation->save(flow_solver_param.restart_files_directory_name + std::string("/") + restart_filename_without_extension + std::string("_time_averaged"));
385  }
386  // unsteady data table
387  if(mpi_rank==0) {
388  std::string restart_unsteady_data_table_filename = flow_solver_param.unsteady_data_table_filename+std::string("-")+restart_filename_without_extension+std::string(".txt");
389  std::ofstream unsteady_data_table_file(flow_solver_param.restart_files_directory_name + std::string("/") + restart_unsteady_data_table_filename);
390  unsteady_data_table->write_text(unsteady_data_table_file);
391  }
392 
393  // parameter file; written last to ensure necessary data/solution files have been written before
394  write_restart_parameter_file(current_restart_index, time_step_input);
395 }
396 #endif
397 
398 template <int dim, int nspecies, int nstate>
400 {
401  std::unique_ptr<MeshAdaptation<dim,nspecies,double>> meshadaptation = std::make_unique<MeshAdaptation<dim,nspecies,double>>(this->dg, &(this->all_param.mesh_adaptation_param));
402  const int total_adaptation_cycles = this->all_param.mesh_adaptation_param.total_mesh_adaptation_cycles;
403  double residual_norm = this->dg->get_residual_l2norm();
404 
405  pcout<<"Running mesh adaptation cycles..."<<std::endl;
406  while (meshadaptation->current_mesh_adaptation_cycle < total_adaptation_cycles)
407  {
408  // Check if steady state solution is being used.
410  {
411  pcout<<"Mesh adaptation is currently implemented for steady state flows and the current residual norm isn't sufficiently low. "
412  <<"The solution has not converged. If p or hp adaptation is being used, issues with convergence might occur when integrating face terms with lower quad points at "
413  <<"the face of adjacent elements with different p. Try increasing overintegration in the parameters file to fix it."<<std::endl;
414  std::abort();
415  }
416 
417  meshadaptation->adapt_mesh();
418  this->ode_solver->steady_state();
419  residual_norm = this->ode_solver->residual_norm;
420  flow_solver_case->steady_state_postprocessing(dg);
421  }
422 
423  pcout<<"Finished running mesh adaptation cycles."<<std::endl;
424 }
425 
426 template <int dim, int nspecies, int nstate>
428 {
429  pcout << "Running Flow Solver..." << std::endl;
432  pcout << " ... Writing vtk solution file at initial time ..." << std::endl;
433  dg->output_results_vtk(ode_solver->current_iteration);
435  pcout << " ... Writing vtk solution file at initial time ..." << std::endl;
436  dg->output_results_vtk(ode_solver->current_iteration);
437  ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals += ode_param.output_solution_start_time + ode_param.output_solution_every_dt_time_intervals;
439  pcout << " ... Writing vtk solution file at initial time ..." << std::endl;
440  dg->output_results_vtk(ode_solver->current_iteration);
441  }
442  }
443  // Boolean to store solutions in POD object
447 
448  // Index of current desired fixed time to output solution
449  unsigned int index_of_current_desired_fixed_time_to_output_solution = 0;
450 
451  // determine index_of_current_desired_fixed_time_to_output_solution if restarting solution
453  // use current_time to determine if restarting the computation from a non-zero initial time
454  for(unsigned int i=0; i<this->number_of_fixed_times_to_output_solution; ++i) {
455  if(this->ode_solver->current_time < this->output_solution_fixed_times[i]) {
456  index_of_current_desired_fixed_time_to_output_solution = i;
457  break;
458  }
459  }
460  }
461 
462  //----------------------------------------------------
463  // Select unsteady or steady-state
464  //----------------------------------------------------
465  if(flow_solver_param.steady_state == false){
466  //----------------------------------------------------
467  // UNSTEADY FLOW
468  //----------------------------------------------------
469  // Initializing restart related variables
470  //----------------------------------------------------
471 #if PHILIP_DIM>1
472  double current_desired_time_for_output_restart_files_every_dt_time_intervals = ode_solver->current_time;
473  unsigned int current_restart_file_number = 1;
476  while(current_desired_time_for_output_restart_files_every_dt_time_intervals <= ode_solver->current_time) {
477  current_desired_time_for_output_restart_files_every_dt_time_intervals += flow_solver_param.output_restart_files_every_dt_time_intervals;
478  }
479  }
480  }
482  current_restart_file_number = flow_solver_param.restart_file_index + 1;
483  }
484 #endif
485  //--------------------------------------------------------------------
486  // Initialize the time at which we write the unsteady data table
487  //--------------------------------------------------------------------
488  double current_desired_time_for_write_unsteady_data_table_file_every_dt_time_intervals = ode_solver->current_time;
490  while(current_desired_time_for_write_unsteady_data_table_file_every_dt_time_intervals <= ode_solver->current_time) {
491  current_desired_time_for_write_unsteady_data_table_file_every_dt_time_intervals += flow_solver_param.write_unsteady_data_table_file_every_dt_time_intervals;
492  }
493  }
494  //----------------------------------------------------
495  // Initialize time step
496  //----------------------------------------------------
497  double time_step = 0.0;
499  pcout << "WARNING: CFL-adaptation and error-adaptation cannot be used at the same time. Aborting!" << std::endl;
500  std::abort();
501  }
502  else if(flow_solver_param.adaptive_time_step == true) {
503  pcout << "Setting initial adaptive time step... " << std::flush;
504  time_step = flow_solver_case->get_adaptive_time_step_initial(dg);
505  } else if(flow_solver_param.error_adaptive_time_step == true) {
506  pcout << "Setting initial error adaptive time step... " << std::flush;
507  time_step = ode_solver->get_automatic_initial_step_size(time_step,false);
508  } else {
509  pcout << "Setting constant time step... " << std::flush;
510  time_step = flow_solver_case->get_constant_time_step(dg);
511  }
512 
513  /* If restarting computation from file, it should give the same time step as written in file,
514  a warning is thrown if this is not the case */
516  const double restart_time_step = ode_param.initial_time_step;
517  if(std::abs(time_step-restart_time_step) > 1E-13) {
518  pcout << "WARNING: Computed initial time step does not match value in restart parameter file within the tolerance. "
519  << "Diff is: " << std::abs(time_step-restart_time_step) << std::endl;
520  }
521  }
522  flow_solver_case->set_time_step(time_step);
523  dg->set_unsteady_model_time_step(time_step);
524  pcout << "done." << std::endl;
525  //----------------------------------------------------
526  // dealii::TableHandler and data at initial time
527  //----------------------------------------------------
528  std::shared_ptr<dealii::TableHandler> unsteady_data_table = std::make_shared<dealii::TableHandler>();
530  pcout << "Initializing data table from corresponding restart file... " << std::flush;
531  const std::string restart_filename_without_extension = get_restart_filename_without_extension(flow_solver_param.restart_file_index);
532  const std::string restart_unsteady_data_table_filename = flow_solver_param.unsteady_data_table_filename+std::string("-")+restart_filename_without_extension+std::string(".txt");
533  initialize_data_table_from_file(flow_solver_param.restart_files_directory_name + std::string("/") + restart_unsteady_data_table_filename,unsteady_data_table);
534  pcout << "done." << std::endl;
535 
536  flow_solver_case->modify_dg_object(dg);
537  } else {
538  // no restart:
540  pcout << "Writing unsteady data computed at initial time... " << std::endl;
541  flow_solver_case->compute_unsteady_data_and_write_to_table(ode_solver, dg, unsteady_data_table, true);
542  pcout << "done." << std::endl;
543  }
544  }
545  //----------------------------------------------------
546  // Time advancement loop with on-the-fly post-processing
547  //----------------------------------------------------
548  double next_time_step = time_step;
549  std::shared_ptr<dealii::TableHandler> timer_values_table = std::make_shared<dealii::TableHandler>();
550  pcout << "Advancing solution in time... " << std::endl;
551  pcout << "Timer starting. " << std::endl;
552  dealii::Timer timer(this->mpi_communicator,false);
553  timer.start();
554  while(ode_solver->current_time < final_time)
555  {
556  time_step = next_time_step; // update time step
557 
558  // check if we need to decrease the time step
559  if((ode_solver->current_time+time_step) > final_time && flow_solver_param.end_exactly_at_final_time) {
560  // decrease time step to finish exactly at specified final time
561  time_step = final_time - ode_solver->current_time;
562  } else if (this->output_solution_at_exact_fixed_times && (this->do_output_solution_at_fixed_times && (this->number_of_fixed_times_to_output_solution > 0))) { // change this to some parameter
563  const double next_time = ode_solver->current_time + time_step;
564  const double desired_time = this->output_solution_fixed_times[index_of_current_desired_fixed_time_to_output_solution];
565  // Check if current time is an output time
566  const bool is_output_time = ((ode_solver->current_time<desired_time) && (next_time>desired_time));
567  if(is_output_time) time_step = desired_time - ode_solver->current_time;
568  }
569 
570  // update time step in flow_solver_case
571  flow_solver_case->set_time_step(time_step);
572  dg->set_unsteady_model_time_step(time_step);
573 
574  ode_solver->step_in_time(time_step,false);
575 
576  bool do_write_unsteady_data_table_file = false;
578  const bool is_write_time = ((ode_solver->current_time <= current_desired_time_for_write_unsteady_data_table_file_every_dt_time_intervals) &&
579  ((ode_solver->current_time + time_step) > current_desired_time_for_write_unsteady_data_table_file_every_dt_time_intervals))
580  || (ode_solver->current_time > current_desired_time_for_write_unsteady_data_table_file_every_dt_time_intervals);
581  if (is_write_time) {
582  do_write_unsteady_data_table_file = true;
583  current_desired_time_for_write_unsteady_data_table_file_every_dt_time_intervals += flow_solver_param.write_unsteady_data_table_file_every_dt_time_intervals;
584  }
585  } else {
586  do_write_unsteady_data_table_file = true;
587  }
588 
589  // Compute time-averaged solution and Reynolds stresses for turbulent cases
591  flow_solver_case->compute_time_averaged_solution(ode_solver, dg, time_step);
593  flow_solver_case->compute_Reynolds_stress(ode_solver, dg, time_step);
594  }
595  }
596 
597  // Compute the unsteady quantities, write to the dealii table, and output to file
599  flow_solver_case->compute_unsteady_data_and_write_to_table(ode_solver, dg, unsteady_data_table, do_write_unsteady_data_table_file);
600  }
601  // update next time step
602 
604  next_time_step = flow_solver_case->get_adaptive_time_step(dg);
605  } else if (flow_solver_param.error_adaptive_time_step == true) {
606  next_time_step = ode_solver->get_automatic_error_adaptive_step_size(time_step,false);
607  } else {
608  next_time_step = flow_solver_case->get_constant_time_step(dg);
609  }
610 
611 
612 
613 #if PHILIP_DIM>1
615  // Output restart files
617  const bool is_output_time = ((ode_solver->current_time <= current_desired_time_for_output_restart_files_every_dt_time_intervals) &&
618  ((ode_solver->current_time + next_time_step) > current_desired_time_for_output_restart_files_every_dt_time_intervals))
619  || (ode_solver->current_time > current_desired_time_for_output_restart_files_every_dt_time_intervals);
620  if (is_output_time) {
621  output_restart_files(current_restart_file_number, next_time_step, unsteady_data_table);
622  current_desired_time_for_output_restart_files_every_dt_time_intervals += flow_solver_param.output_restart_files_every_dt_time_intervals;
623  current_restart_file_number += 1;
624  }
625  } else /*if (flow_solver_param.output_restart_files_every_x_steps > 0)*/ {
626  const bool is_output_iteration = (ode_solver->current_iteration % flow_solver_param.output_restart_files_every_x_steps == 0);
627  if (is_output_iteration) {
628  const unsigned int file_number = ode_solver->current_iteration / flow_solver_param.output_restart_files_every_x_steps;
629  output_restart_files(file_number, next_time_step, unsteady_data_table);
630  }
631  }
632  }
633 #endif
634 
635  // Output vtk solution files for post-processing in Paraview
637  const bool is_output_iteration = (ode_solver->current_iteration % ode_param.output_solution_every_x_steps == 0);
638  if (is_output_iteration) {
639  pcout << " ... Writing vtk solution file ..." << std::endl;
640  const unsigned int file_number = ode_solver->current_iteration / ode_param.output_solution_every_x_steps;
641  dg->output_results_vtk(file_number,ode_solver->current_time);
642  }
644  const bool is_output_time = ((ode_solver->current_time <= ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals) &&
645  ((ode_solver->current_time + next_time_step) > ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals))
646  || (ode_solver->current_time > ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals);
647  if (is_output_time) {
648  pcout << " ... Writing vtk solution file ..." << std::endl;
649  const unsigned int file_number = int(round(ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals / ode_param.output_solution_every_dt_time_intervals));
650  dg->output_results_vtk(file_number,ode_solver->current_time);
651  ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals += ode_param.output_solution_every_dt_time_intervals;
652  }
654  const double next_time = ode_solver->current_time + next_time_step;
655  const double desired_time = this->output_solution_fixed_times[index_of_current_desired_fixed_time_to_output_solution];
656  // Check if current time is an output time
657  bool is_output_time = false; // default initialization
659  is_output_time = ode_solver->current_time == desired_time;
660  } else {
661  is_output_time = ((ode_solver->current_time<=desired_time) && (next_time>desired_time));
662  }
663  if(is_output_time) {
664  pcout << " ... Writing vtk solution file ..." << std::endl;
665  const int file_number = index_of_current_desired_fixed_time_to_output_solution+1; // +1 because initial time is 0
666  dg->output_results_vtk(file_number,ode_solver->current_time);
667 
668  // Update index s.t. it never goes out of bounds
669  if(index_of_current_desired_fixed_time_to_output_solution
671  index_of_current_desired_fixed_time_to_output_solution += 1;
672  }
673  }
674  }
675  // Add snapshots to snapshot matrix
676  if(unsteady_FOM_POD_bool && nspecies==1){
677  const bool is_snapshot_iteration = (ode_solver->current_iteration % all_param.reduced_order_param.output_snapshot_every_x_timesteps == 0);
678  if(is_snapshot_iteration) time_pod->addSnapshot(dg->solution);
679  }
680  } // close while
681 
682  // Print POD Snapshots to file
683  if(unsteady_FOM_POD_bool && nspecies==1){
684  std::ofstream snapshot_file("solution_snapshots_iteration_" + std::to_string(ode_solver->current_iteration) + ".txt"); // Change ode_solver->current_iteration to size of matrix
685  unsigned int precision = 16;
686  time_pod->dealiiSnapshotMatrix.print_formatted(snapshot_file, precision, true, 0, "0");
687  snapshot_file.close();
688  }
689 
690  timer.stop();
691  pcout << "Timer stopped. " << std::endl;
692  const double cpu_time = timer.cpu_time();
693  const double total_wall_time = dealii::Utilities::MPI::sum(timer.wall_time(), this->mpi_communicator);
694  const double number_of_time_steps = (double)ode_solver->current_iteration;
695  const double avg_cpu_time_per_time_step = cpu_time/number_of_time_steps;
696  const double avg_total_wall_time_per_time_step = total_wall_time/number_of_time_steps;
697  pcout << "Elapsed CPU time: " << cpu_time << " seconds." << std::endl;
698  pcout << "Elapsed total wall time (mpi max): " << total_wall_time << " seconds." << std::endl;
699  pcout << "Average CPU time per time step: " << avg_cpu_time_per_time_step << " seconds." << std::endl;
700  pcout << "Average total wall time per time step: " << avg_total_wall_time_per_time_step << " seconds." << std::endl;
701  // writing timing to file
702  if(mpi_rank==0) {
703  // add values to table
704  flow_solver_case->add_value_to_data_table(cpu_time,"total_cpu_time",timer_values_table);
705  flow_solver_case->add_value_to_data_table(total_wall_time,"total_wall_time",timer_values_table);
706  flow_solver_case->add_value_to_data_table(avg_cpu_time_per_time_step,"avg_cpu_time",timer_values_table);
707  flow_solver_case->add_value_to_data_table(avg_total_wall_time_per_time_step,"avg_wall_time",timer_values_table);
708  std::string timing_table_filename = std::string("timer_values.txt");
709  std::ofstream timer_values_table_file(timing_table_filename);
710  timer_values_table->write_text(timer_values_table_file);
711  }
712  } else {
713  //----------------------------------------------------
714  // Steady-state solution
715  //----------------------------------------------------
717  if(flow_solver_param.steady_state_polynomial_ramping && (ode_param.ode_solver_type != ODEEnum::pod_galerkin_solver && ode_param.ode_solver_type != ODEEnum::pod_petrov_galerkin_solver && ode_param.ode_solver_type != ODEEnum::hyper_reduced_petrov_galerkin_solver)) {
718  ode_solver->initialize_steady_polynomial_ramping(poly_degree);
719  }
720 
721  ode_solver->steady_state();
722  flow_solver_case->steady_state_postprocessing(dg);
723 
724  const bool use_isotropic_mesh_adaptation = (all_param.mesh_adaptation_param.total_mesh_adaptation_cycles > 0)
725  && (all_param.mesh_adaptation_param.mesh_adaptation_type != Parameters::MeshAdaptationParam::MeshAdaptationType::anisotropic_adaptation);
726 
727  if(use_isotropic_mesh_adaptation)
728  {
730  }
731  }
732  pcout << "done." << std::endl;
733  return 0;
734 }
735 
736 #if PHILIP_SPECIES==1
737  #if PHILIP_DIM==1
740  #endif
741 
742  #if PHILIP_DIM!=1
743  // Define a sequence of nstate in the range [1, 6]
744  #define POSSIBLE_NSTATE (1)(2)(3)(4)(5)(6)
745 
746  // Define a macro to instantiate FlowSolverCaseBase for a specific nstate
747  #define INSTANTIATE_FLOWSOLVER(r, data, nstate) \
748  template class FlowSolver <PHILIP_DIM, PHILIP_SPECIES,nstate>;
749  BOOST_PP_SEQ_FOR_EACH(INSTANTIATE_FLOWSOLVER, _, POSSIBLE_NSTATE)
750  #endif
751 #else
753 #endif
754 } // FlowSolver namespace
755 } // PHiLiP namespace
756 
bool do_compute_Reynolds_stress
Flag for computing time-averaged Reynolds stresses.
Proper Orthogonal Decomposition with Galerkin projection.
double output_solution_start_time
Time at which to start outputting the solution.
void write_restart_parameter_file(const unsigned int restart_index_input, const double constant_time_step_input) const
Writes a parameter file (.prm) for restarting the computation with.
double output_restart_files_every_dt_time_intervals
Outputs the restart files at time intervals of dt.
bool error_adaptive_time_step
Computes time step based on error.
bool steady_state
Flag for solving steady state solution.
bool adaptive_time_step
Flag for computing the time step on the fly.
const unsigned int number_of_fixed_times_to_output_solution
Number of fixed times to output the solution.
Definition: flow_solver.h:109
const double final_time
Final time of solution.
Definition: flow_solver.h:103
Selects which flow case to simulate.
Definition: flow_solver.h:64
const MPI_Comm mpi_communicator
MPI communicator.
Definition: flow_solver.h:91
const Parameters::FlowSolverParam flow_solver_param
Flow solver parameters.
Definition: flow_solver.h:99
dealii::Table< 1, double > output_solution_fixed_times
Fixed times at which to output the solution.
Definition: flow_solver.h:148
const Parameters::ODESolverParam ode_param
ODE solver parameters.
Definition: flow_solver.h:100
const std::string input_parameters_file_reference_copy_filename
Name of the reference copy of inputted parameters file; for restart purposes.
Definition: flow_solver.h:106
bool restart_computation_from_file
Restart computation from restart file.
int output_solution_every_x_steps
Outputs the solution every x steps to .vtk file.
int total_mesh_adaptation_cycles
Total/maximum number of mesh adaptation cycles while solving a problem.
Proper Orthogonal Decomposition with Petrov-Galerkin projection (LSPG) and ECSW Hyper-reduction.
bool output_restart_files
Output the restart files.
Files for the baseline physics.
Definition: ADTypes.hpp:10
int run() const override
Simply runs the flow solver and returns 0 upon completion.
double time_to_start_averaging
Flag for starting time-averaged solution.
const int mpi_rank
MPI rank.
Definition: flow_solver.h:92
ReducedOrderModelParam reduced_order_param
Contains parameters for the Reduced-Order model.
const bool output_solution_at_exact_fixed_times
Flag for outputting the solution at exact fixed times by decreasing the time step on the fly...
Definition: flow_solver.h:110
Explicit RK using the relaxation Runge-Kutta method (Ketcheson, 2019)
double output_solution_every_dt_time_intervals
Outputs the solution every dt time intervals to .vtk file.
Main parameter class that contains the various other sub-parameter classes.
bool allocate_matrix_dRdW
Flag to signal that automatic differentiation (AD) matrix dRdW must be allocated. ...
MeshAdaptationParam mesh_adaptation_param
Constains parameters for mesh adaptation.
bool steady_state_polynomial_ramping
Flag for steady state polynomial ramping.
double write_unsteady_data_table_file_every_dt_time_intervals
Writes the unsteady data table file at time intervals of dt.
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.
Definition: flow_solver.h:77
MeshAdaptationType mesh_adaptation_type
Selection of mesh adaptation type.
const unsigned int poly_degree
Polynomial order.
Definition: flow_solver.h:101
std::string output_solution_fixed_times_string
String of fixed solution output times.
This class creates a new DGBase object.
Definition: dg_factory.hpp:16
double initial_time_step
Time step used in ODE solver.
std::shared_ptr< FlowSolverCaseBase< dim, nspecies, nstate > > flow_solver_case
Pointer to Flow Solver Case.
Definition: flow_solver.h:74
unsigned int restart_file_index
Index of desired restart file for restarting the computation from.
void perform_steady_state_mesh_adaptation() const
Performs mesh adaptation.
static void set_initial_condition(std::shared_ptr< InitialConditionFunction< dim, nspecies, nstate, double > > initial_condition_function_input, std::shared_ptr< PHiLiP::DGBase< dim, nspecies, real > > dg_input, const Parameters::AllParameters *const parameters_input)
Applies the given initial condition function to the given dg object.
double nonlinear_steady_residual_tolerance
Tolerance to determine steady-state convergence.
int output_restart_files_every_x_steps
Outputs the restart files every x steps.
bool do_compute_time_averaged_solution
Flag for computing time-averaged solution.
const bool do_compute_unsteady_data_and_write_to_table
Flag for computing unsteady data and writting to table.
Definition: flow_solver.h:111
std::vector< std::string > get_data_table_column_names(const std::string string_input) const
bool end_exactly_at_final_time
Flag to adjust the last timestep such that the simulation ends exactly at final_time.
std::shared_ptr< DGBase< dim, nspecies, double > > dg
Pointer to dg so it can be accessed externally.
Definition: flow_solver.h:115
ODESolverEnum ode_solver_type
ODE solver type.
std::shared_ptr< ODE::ODESolverBase< dim, nspecies, double > > ode_solver
Pointer to ode solver so it can be accessed externally.
Definition: flow_solver.h:118
const Parameters::AllParameters all_param
All parameters.
Definition: flow_solver.h:98
int output_snapshot_every_x_timesteps
Number of timesteps before putting solution in snapshot matrix.
std::string get_restart_filename_without_extension(const unsigned int restart_index_input) const
Returns the restart filename without extension given a restart index (adds padding appropriately) ...
std::string restart_files_directory_name
Name of directory for writing and reading restart files.
static std::shared_ptr< ODESolverBase< dim, nspecies, real, MeshType > > create_ODESolver(std::shared_ptr< DGBase< dim, nspecies, real, MeshType > > dg_input)
Creates either implicit or explicit ODE solver based on parameter value(no POD basis given) ...
Base class of all the flow solvers.
Definition: flow_solver.h:49
const bool do_output_solution_at_fixed_times
Flag for outputting solution at fixed times.
Definition: flow_solver.h:108
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: flow_solver.h:97
void initialize_data_table_from_file(std::string data_table_filename_with_extension, const std::shared_ptr< dealii::TableHandler > data_table) const
Initializes the data table from an existing file.
std::string double_to_string(const double value_input) const
Converts a double to a string with scientific format and with full precision.