[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 nstate>
23  const PHiLiP::Parameters::AllParameters *const parameters_input,
24  std::shared_ptr<FlowSolverCaseBase<dim, 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 , dg(DGFactory<dim,double>::create_discontinuous_galerkin(&all_param, poly_degree, flow_solver_param.max_poly_degree_for_adaptation, grid_degree, flow_solver_case->generate_grid()))
44 {
45  flow_solver_case->set_higher_order_grid(dg);
47  pcout << "Note: Allocating DG with AD matrix dRdW only." << std::endl;
48  dg->allocate_system(true,false,false); // FlowSolver only requires dRdW to be allocated
49  } else {
50  pcout << "Note: Allocating DG without AD matrices." << std::endl;
51  dg->allocate_system(false,false,false);
52  }
53 
54 
55  flow_solver_case->display_flow_solver_setup(dg);
56 
58  if(dim == 1) {
59  pcout << "Error: restart_computation_from_file is not possible for 1D. Set to false." << std::endl;
60  std::abort();
61  }
62 
63  if (flow_solver_param.steady_state == true) {
64  pcout << "Error: Restart capability has not been fully implemented / tested for steady state computations." << std::endl;
65  std::abort();
66  }
67 
68  // Initialize solution from restart file
69  pcout << "Initializing solution from restart file..." << std::flush;
70  const std::string restart_filename_without_extension = get_restart_filename_without_extension(flow_solver_param.restart_file_index);
71 #if PHILIP_DIM>1
72  dg->triangulation->load(flow_solver_param.restart_files_directory_name + std::string("/") + restart_filename_without_extension);
73 
74  // Note: Future development with hp-capabilities, see section "Note on usage with DoFHandler with hp-capabilities"
75  // ----- Ref: https://www.dealii.org/current/doxygen/deal.II/classparallel_1_1distributed_1_1SolutionTransfer.html
76  dealii::LinearAlgebra::distributed::Vector<double> solution_no_ghost;
77  solution_no_ghost.reinit(dg->locally_owned_dofs, this->mpi_communicator);
78  dealii::parallel::distributed::SolutionTransfer<dim, dealii::LinearAlgebra::distributed::Vector<double>, dealii::DoFHandler<dim>> solution_transfer(dg->dof_handler);
79  solution_transfer.deserialize(solution_no_ghost);
80  dg->solution = solution_no_ghost; //< assignment
81 #endif
82  pcout << "done." << std::endl;
83  } else {
84  // Initialize solution
86  }
87  dg->solution.update_ghost_values();
88 
92  std::shared_ptr<ProperOrthogonalDecomposition::OfflinePOD<dim>> pod = std::make_shared<ProperOrthogonalDecomposition::OfflinePOD<dim>>(dg);
94  } else {
96  }
97 
98  // Allocate ODE solver after initializing DG
99  ode_solver->allocate_ode_system();
100 
101  // Storing a time_dependent POD
105  if(unsteady_FOM_POD_bool){
106  std::shared_ptr<dealii::TrilinosWrappers::SparseMatrix> system_matrix(
107  dg,
108  &dg->system_matrix
109  );
110  time_pod = std::make_shared<ProperOrthogonalDecomposition::OnlinePOD<dim>>(system_matrix);
111  time_pod->addSnapshot(dg->solution);
112  }
113 
114  // output a copy of the input parameters file
116  pcout << "Writing a reference copy of the inputted parameters (.prm) file... " << std::flush;
117  if(mpi_rank==0) {
119  }
120  pcout << "done." << std::endl;
121  }
122 
123  // For outputting solution at fixed times
126 
127  // Get output_solution_fixed_times from string
128  const std::string output_solution_fixed_times_string = this->ode_param.output_solution_fixed_times_string;
129  std::string line = output_solution_fixed_times_string;
130  std::string::size_type sz1;
131  this->output_solution_fixed_times[0] = std::stod(line,&sz1);
132  for(unsigned int i=1; i<this->number_of_fixed_times_to_output_solution; ++i) {
133  line = line.substr(sz1);
134  sz1 = 0;
135  this->output_solution_fixed_times[i] = std::stod(line,&sz1);
136  }
137  }
138 }
139 
140 template <int dim, int nstate>
141 std::vector<std::string> FlowSolver<dim,nstate>::get_data_table_column_names(const std::string string_input) const
142 {
143  /* returns the column names of a dealii::TableHandler object
144  given the first line of the file */
145 
146  // Create object of istringstream and initialize assign input string
147  std::istringstream iss(string_input);
148  std::string word;
149 
150  // extract each name (no spaces)
151  std::vector<std::string> names;
152  while(iss >> word) {
153  names.push_back(word.c_str());
154  }
155  return names;
156 }
157 
158 template <int dim, int nstate>
159 std::string FlowSolver<dim,nstate>::get_restart_filename_without_extension(const unsigned int restart_index_input) const {
160  // returns the restart file index as a string with appropriate padding
161  std::string restart_index_string = std::to_string(restart_index_input);
162  const unsigned int length_of_index_with_padding = 5;
163  const unsigned int number_of_zeros = length_of_index_with_padding - restart_index_string.length();
164  restart_index_string.insert(0, number_of_zeros, '0');
165 
166  const std::string prefix = "restart-";
167  const std::string restart_filename_without_extension = prefix+restart_index_string;
168 
169  return restart_filename_without_extension;
170 }
171 
172 template <int dim, int nstate>
174  std::string data_table_filename,
175  const std::shared_ptr <dealii::TableHandler> data_table) const
176 {
177  if(mpi_rank==0) {
178  std::string line;
179  std::string::size_type sz1;
180 
181  std::ifstream FILE (data_table_filename);
182  std::getline(FILE, line); // read first line: column headers
183 
184  // check that the file is not empty
185  if (line.empty()) {
186  pcout << "Error: Trying to read empty file named " << data_table_filename << std::endl;
187  std::abort();
188  }
189 
190  const std::vector<std::string> data_column_names = get_data_table_column_names(line);
191  const int number_of_columns = data_column_names.size();
192 
193  std::getline(FILE, line); // read first line of data
194 
195  // check that there indeed is data to be read
196  if (line.empty()) {
197  pcout << "Error: Table has no data to be read" << std::endl;
198  std::abort();
199  }
200 
201  std::vector<double> current_line_values(number_of_columns);
202  while (!line.empty()) {
203  std::string dummy_line = line;
204 
205  current_line_values[0] = std::stod(dummy_line,&sz1);
206  for(int i=1; i<number_of_columns; ++i) {
207  dummy_line = dummy_line.substr(sz1);
208  sz1 = 0;
209  current_line_values[i] = std::stod(dummy_line,&sz1);
210  }
211 
212  // Add data entries to table
213  for(int i=0; i<number_of_columns; ++i) {
214  data_table->add_value(data_column_names[i], current_line_values[i]);
215  data_table->set_precision(data_column_names[i], 16);
216  data_table->set_scientific(data_column_names[i], true);
217  }
218  std::getline(FILE, line); // read next line
219  }
220  }
221 }
222 
223 template <int dim, int nstate>
224 std::string FlowSolver<dim,nstate>::double_to_string(const double value_input) const {
225  // converts a double to a string with full precision
226  std::stringstream ss;
227  ss << std::scientific << std::setprecision(16) << value_input;
228  std::string double_to_string = ss.str();
229  return double_to_string;
230 }
231 
232 template <int dim, int nstate>
234  const unsigned int restart_index_input,
235  const double time_step_input) const {
236  // write the restart parameter file
237  if(mpi_rank==0) {
238  // read a copy of the current parameters file
239  std::ifstream CURRENT_FILE(input_parameters_file_reference_copy_filename);
240 
241  // create write file with appropriate postfix given the restart index input
242  const std::string restart_filename = get_restart_filename_without_extension(restart_index_input)+std::string(".prm");
243  std::ofstream RESTART_FILE(flow_solver_param.restart_files_directory_name + std::string("/") + restart_filename);
244 
245  // Lines to identify the subsections in the .prm file
246  /* WARNING: (2) These must be in the order they appear in the .prm file
247  */
248  std::vector<std::string> subsection_line;
249  subsection_line.push_back("subsection ODE solver");
250  subsection_line.push_back("subsection flow_solver");
251  // Number of subsections to change values in
252  int number_of_subsections = subsection_line.size();
253 
254 
255  /* WARNING: (1) Must put a space before and after each parameter string as done below
256  * (2) These must be in the order they appear in the .prm file
257  */
258  // -- names
259  std::vector<std::string> ODE_solver_restart_parameter_names;
260  ODE_solver_restart_parameter_names.push_back(" initial_desired_time_for_output_solution_every_dt_time_intervals ");
261  ODE_solver_restart_parameter_names.push_back(" initial_iteration ");
262  ODE_solver_restart_parameter_names.push_back(" initial_time ");
263  ODE_solver_restart_parameter_names.push_back(" initial_time_step ");
264  // -- corresponding values
265  std::vector<std::string> ODE_solver_restart_parameter_values;
266  ODE_solver_restart_parameter_values.push_back(double_to_string(ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals));
267  ODE_solver_restart_parameter_values.push_back(std::to_string(ode_solver->current_iteration));
268  ODE_solver_restart_parameter_values.push_back(double_to_string(ode_solver->current_time));
269  ODE_solver_restart_parameter_values.push_back(double_to_string(time_step_input));
270 
271 
272  /* WARNING: (1) Must put a space before and after each parameter string as done below
273  * (2) These must be in the order they appear in the .prm file
274  */
275  // -- Names
276  std::vector<std::string> flow_solver_restart_parameter_names;
277  flow_solver_restart_parameter_names.push_back(" output_restart_files ");
278  flow_solver_restart_parameter_names.push_back(" restart_computation_from_file ");
279  flow_solver_restart_parameter_names.push_back(" restart_file_index ");
280  // -- Corresponding values
281  std::vector<std::string> flow_solver_restart_parameter_values;
282  flow_solver_restart_parameter_values.push_back(std::string("true"));
283  flow_solver_restart_parameter_values.push_back(std::string("true"));
284  flow_solver_restart_parameter_values.push_back(std::to_string(restart_index_input));
285 
286 
287  // Number of parameters in each subsection
288  std::vector<int> number_of_subsection_parameters;
289  number_of_subsection_parameters.push_back(ODE_solver_restart_parameter_names.size());
290  number_of_subsection_parameters.push_back(flow_solver_restart_parameter_names.size());
291 
292  // Initialize for the while loop
293  int i_subsection = 0;
294  std::string line;
295 
296  // read line until end of file
297  while (std::getline(CURRENT_FILE, line)) {
298  // check if the desired subsection has been reached
299  if (line == subsection_line[i_subsection]) {
300  RESTART_FILE << line << "\n"; // write line
301 
302  int i_parameter = 0;
303  std::string name;
304  std::string value_string;
305 
306  if (i_subsection==0) {
307  name = ODE_solver_restart_parameter_names[i_parameter];
308  value_string = ODE_solver_restart_parameter_values[i_parameter];
309  } else if (i_subsection==1) {
310  name = flow_solver_restart_parameter_names[i_parameter];
311  value_string = flow_solver_restart_parameter_values[i_parameter];
312  }
313 
314  while (line!="end") {
315  std::getline(CURRENT_FILE, line); // read line
316  std::string::size_type found = line.find(name);
317 
318  // found the line corresponding to the desired parameter
319  if (found!=std::string::npos) {
320 
321  // construct the updated line
322  std::string updated_line = line;
323  std::string::size_type position_to_replace = line.find_last_of("=")+2;
324  std::string part_of_line_to_replace = line.substr(position_to_replace);
325  updated_line.replace(position_to_replace,part_of_line_to_replace.length(),value_string);
326 
327  // write updated line to restart file
328  RESTART_FILE << updated_line << "\n";
329 
330  // update the parameter index, name, and value
331  if ((i_parameter+1) < number_of_subsection_parameters[i_subsection]) ++i_parameter; // to avoid going out of bounds
332  if (i_subsection==0) {
333  name = ODE_solver_restart_parameter_names[i_parameter];
334  value_string = ODE_solver_restart_parameter_values[i_parameter];
335  } else if (i_subsection==1) {
336  name = flow_solver_restart_parameter_names[i_parameter];
337  value_string = flow_solver_restart_parameter_values[i_parameter];
338  }
339  } else {
340  // write line (that does correspond to the desired parameter) to the restart file
341  RESTART_FILE << line << "\n";
342  }
343  }
344  // update the subsection index
345  if ((i_subsection+1) < number_of_subsections) ++i_subsection; // to avoid going out of bounds
346  } else {
347  // write line (that is not in a desired subsection) to the restart file
348  RESTART_FILE << line << "\n";
349  }
350  }
351  }
352 }
353 
354 #if PHILIP_DIM>1
355 template <int dim, int nstate>
357  const unsigned int current_restart_index,
358  const double time_step_input,
359  const std::shared_ptr <dealii::TableHandler> unsteady_data_table) const
360 {
361  pcout << " ... Writing restart files ... " << std::endl;
362  const std::string restart_filename_without_extension = get_restart_filename_without_extension(current_restart_index);
363 
364  // solution files
365  dealii::parallel::distributed::SolutionTransfer<dim, dealii::LinearAlgebra::distributed::Vector<double>, dealii::DoFHandler<dim>> solution_transfer(dg->dof_handler);
366  // Note: Future development with hp-capabilities, see section "Note on usage with DoFHandler with hp-capabilities"
367  // ----- Ref: https://www.dealii.org/current/doxygen/deal.II/classparallel_1_1distributed_1_1SolutionTransfer.html
368  solution_transfer.prepare_for_serialization(dg->solution);
369  dg->triangulation->save(flow_solver_param.restart_files_directory_name + std::string("/") + restart_filename_without_extension);
370 
371  // unsteady data table
372  if(mpi_rank==0) {
373  std::string restart_unsteady_data_table_filename = flow_solver_param.unsteady_data_table_filename+std::string("-")+restart_filename_without_extension+std::string(".txt");
374  std::ofstream unsteady_data_table_file(flow_solver_param.restart_files_directory_name + std::string("/") + restart_unsteady_data_table_filename);
375  unsteady_data_table->write_text(unsteady_data_table_file);
376  }
377 
378  // parameter file; written last to ensure necessary data/solution files have been written before
379  write_restart_parameter_file(current_restart_index, time_step_input);
380 }
381 #endif
382 
383 template <int dim, int nstate>
385 {
386  std::unique_ptr<MeshAdaptation<dim,double>> meshadaptation = std::make_unique<MeshAdaptation<dim,double>>(this->dg, &(this->all_param.mesh_adaptation_param));
387  const int total_adaptation_cycles = this->all_param.mesh_adaptation_param.total_mesh_adaptation_cycles;
388  double residual_norm = this->dg->get_residual_l2norm();
389 
390  pcout<<"Running mesh adaptation cycles..."<<std::endl;
391  while (meshadaptation->current_mesh_adaptation_cycle < total_adaptation_cycles)
392  {
393  // Check if steady state solution is being used.
395  {
396  pcout<<"Mesh adaptation is currently implemented for steady state flows and the current residual norm isn't sufficiently low. "
397  <<"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 "
398  <<"the face of adjacent elements with different p. Try increasing overintegration in the parameters file to fix it."<<std::endl;
399  std::abort();
400  }
401 
402  meshadaptation->adapt_mesh();
403  this->ode_solver->steady_state();
404  residual_norm = this->ode_solver->residual_norm;
405  flow_solver_case->steady_state_postprocessing(dg);
406  }
407 
408  pcout<<"Finished running mesh adaptation cycles."<<std::endl;
409 }
410 
411 template <int dim, int nstate>
413 {
414  pcout << "Running Flow Solver..." << std::endl;
417  pcout << " ... Writing vtk solution file at initial time ..." << std::endl;
418  dg->output_results_vtk(ode_solver->current_iteration);
420  pcout << " ... Writing vtk solution file at initial time ..." << std::endl;
421  dg->output_results_vtk(ode_solver->current_iteration);
422  ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals += ode_param.output_solution_every_dt_time_intervals;
424  pcout << " ... Writing vtk solution file at initial time ..." << std::endl;
425  dg->output_results_vtk(ode_solver->current_iteration);
426  }
427  }
428  // Boolean to store solutions in POD object
432 
433  // Index of current desired fixed time to output solution
434  unsigned int index_of_current_desired_fixed_time_to_output_solution = 0;
435 
436  // determine index_of_current_desired_fixed_time_to_output_solution if restarting solution
438  // use current_time to determine if restarting the computation from a non-zero initial time
439  for(unsigned int i=0; i<this->number_of_fixed_times_to_output_solution; ++i) {
440  if(this->ode_solver->current_time < this->output_solution_fixed_times[i]) {
441  index_of_current_desired_fixed_time_to_output_solution = i;
442  break;
443  }
444  }
445  }
446 
447  //----------------------------------------------------
448  // Select unsteady or steady-state
449  //----------------------------------------------------
450  if(flow_solver_param.steady_state == false){
451  //----------------------------------------------------
452  // UNSTEADY FLOW
453  //----------------------------------------------------
454  // Initializing restart related variables
455  //----------------------------------------------------
456 #if PHILIP_DIM>1
457  double current_desired_time_for_output_restart_files_every_dt_time_intervals = ode_solver->current_time; // when used, same as the initial time
458 #endif
459  //----------------------------------------------------
460  // Initialize time step
461  //----------------------------------------------------
462  double time_step = 0.0;
464  pcout << "WARNING: CFL-adaptation and error-adaptation cannot be used at the same time. Aborting!" << std::endl;
465  std::abort();
466  }
467  else if(flow_solver_param.adaptive_time_step == true) {
468  pcout << "Setting initial adaptive time step... " << std::flush;
469  time_step = flow_solver_case->get_adaptive_time_step_initial(dg);
470  } else if(flow_solver_param.error_adaptive_time_step == true) {
471  pcout << "Setting initial error adaptive time step... " << std::flush;
472  time_step = ode_solver->get_automatic_initial_step_size(time_step,false);
473  } else {
474  pcout << "Setting constant time step... " << std::flush;
475  time_step = flow_solver_case->get_constant_time_step(dg);
476  }
477 
478  /* If restarting computation from file, it should give the same time step as written in file,
479  a warning is thrown if this is not the case */
481  const double restart_time_step = ode_param.initial_time_step;
482  if(std::abs(time_step-restart_time_step) > 1E-13) {
483  pcout << "WARNING: Computed initial time step does not match value in restart parameter file within the tolerance. "
484  << "Diff is: " << std::abs(time_step-restart_time_step) << std::endl;
485  }
486  }
487  flow_solver_case->set_time_step(time_step);
488  pcout << "done." << std::endl;
489  //----------------------------------------------------
490  // dealii::TableHandler and data at initial time
491  //----------------------------------------------------
492  std::shared_ptr<dealii::TableHandler> unsteady_data_table = std::make_shared<dealii::TableHandler>();
494  pcout << "Initializing data table from corresponding restart file... " << std::flush;
495  const std::string restart_filename_without_extension = get_restart_filename_without_extension(flow_solver_param.restart_file_index);
496  const std::string restart_unsteady_data_table_filename = flow_solver_param.unsteady_data_table_filename+std::string("-")+restart_filename_without_extension+std::string(".txt");
497  initialize_data_table_from_file(flow_solver_param.restart_files_directory_name + std::string("/") + restart_unsteady_data_table_filename,unsteady_data_table);
498  pcout << "done." << std::endl;
499  } else {
500  // no restart:
501  pcout << "Writing unsteady data computed at initial time... " << std::endl;
502  flow_solver_case->compute_unsteady_data_and_write_to_table(ode_solver, dg, unsteady_data_table);
503  pcout << "done." << std::endl;
504  }
505  //----------------------------------------------------
506  // Time advancement loop with on-the-fly post-processing
507  //----------------------------------------------------
508  double next_time_step = time_step;
509  pcout << "Advancing solution in time... " << std::endl;
510  pcout << "Timer starting. " << std::endl;
511  dealii::Timer timer(this->mpi_communicator,false);
512  timer.start();
513  while(ode_solver->current_time < final_time)
514  {
515  time_step = next_time_step; // update time step
516 
517  // check if we need to decrease the time step
518  if((ode_solver->current_time+time_step) > final_time && flow_solver_param.end_exactly_at_final_time) {
519  // decrease time step to finish exactly at specified final time
520  time_step = final_time - ode_solver->current_time;
521  } 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
522  const double next_time = ode_solver->current_time + time_step;
523  const double desired_time = this->output_solution_fixed_times[index_of_current_desired_fixed_time_to_output_solution];
524  // Check if current time is an output time
525  const bool is_output_time = ((ode_solver->current_time<desired_time) && (next_time>desired_time));
526  if(is_output_time) time_step = desired_time - ode_solver->current_time;
527  }
528 
529  // update time step in flow_solver_case
530  flow_solver_case->set_time_step(time_step);
531 
532  ode_solver->step_in_time(time_step,false);
533 
534  // Compute the unsteady quantities, write to the dealii table, and output to file
535  flow_solver_case->compute_unsteady_data_and_write_to_table(ode_solver, dg, unsteady_data_table);
536  // update next time step
537 
539  next_time_step = flow_solver_case->get_adaptive_time_step(dg);
540  } else if (flow_solver_param.error_adaptive_time_step == true) {
541  next_time_step = ode_solver->get_automatic_error_adaptive_step_size(time_step,false);
542  } else {
543  next_time_step = flow_solver_case->get_constant_time_step(dg);
544  }
545 
546 
547 
548 #if PHILIP_DIM>1
550  // Output restart files
552  const bool is_output_time = ((ode_solver->current_time <= current_desired_time_for_output_restart_files_every_dt_time_intervals) &&
553  ((ode_solver->current_time + next_time_step) > current_desired_time_for_output_restart_files_every_dt_time_intervals));
554  if (is_output_time) {
555  const unsigned int file_number = int(round(current_desired_time_for_output_restart_files_every_dt_time_intervals / flow_solver_param.output_restart_files_every_dt_time_intervals));
556  output_restart_files(file_number, next_time_step, unsteady_data_table);
557  current_desired_time_for_output_restart_files_every_dt_time_intervals += flow_solver_param.output_restart_files_every_dt_time_intervals;
558  }
559  } else /*if (flow_solver_param.output_restart_files_every_x_steps > 0)*/ {
560  const bool is_output_iteration = (ode_solver->current_iteration % flow_solver_param.output_restart_files_every_x_steps == 0);
561  if (is_output_iteration) {
562  const unsigned int file_number = ode_solver->current_iteration / flow_solver_param.output_restart_files_every_x_steps;
563  output_restart_files(file_number, next_time_step, unsteady_data_table);
564  }
565  }
566  }
567 #endif
568 
569  // Output vtk solution files for post-processing in Paraview
571  const bool is_output_iteration = (ode_solver->current_iteration % ode_param.output_solution_every_x_steps == 0);
572  if (is_output_iteration) {
573  pcout << " ... Writing vtk solution file ..." << std::endl;
574  const unsigned int file_number = ode_solver->current_iteration / ode_param.output_solution_every_x_steps;
575  dg->output_results_vtk(file_number,ode_solver->current_time);
576  }
578  const bool is_output_time = ((ode_solver->current_time <= ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals) &&
579  ((ode_solver->current_time + next_time_step) > ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals));
580  if (is_output_time) {
581  pcout << " ... Writing vtk solution file ..." << std::endl;
582  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));
583  dg->output_results_vtk(file_number,ode_solver->current_time);
584  ode_solver->current_desired_time_for_output_solution_every_dt_time_intervals += ode_param.output_solution_every_dt_time_intervals;
585  }
587  const double next_time = ode_solver->current_time + next_time_step;
588  const double desired_time = this->output_solution_fixed_times[index_of_current_desired_fixed_time_to_output_solution];
589  // Check if current time is an output time
590  bool is_output_time = false; // default initialization
592  is_output_time = ode_solver->current_time == desired_time;
593  } else {
594  is_output_time = ((ode_solver->current_time<=desired_time) && (next_time>desired_time));
595  }
596  if(is_output_time) {
597  pcout << " ... Writing vtk solution file ..." << std::endl;
598  const int file_number = index_of_current_desired_fixed_time_to_output_solution+1; // +1 because initial time is 0
599  dg->output_results_vtk(file_number,ode_solver->current_time);
600 
601  // Update index s.t. it never goes out of bounds
602  if(index_of_current_desired_fixed_time_to_output_solution
604  index_of_current_desired_fixed_time_to_output_solution += 1;
605  }
606  }
607  }
608  // Add snapshots to snapshot matrix
609  if(unsteady_FOM_POD_bool){
610  const bool is_snapshot_iteration = (ode_solver->current_iteration % all_param.reduced_order_param.output_snapshot_every_x_timesteps == 0);
611  if(is_snapshot_iteration) time_pod->addSnapshot(dg->solution);
612  }
613  } // close while
614 
615  // Print POD Snapshots to file
616  if(unsteady_FOM_POD_bool){
617  std::ofstream snapshot_file("solution_snapshots_iteration_" + std::to_string(ode_solver->current_iteration) + ".txt"); // Change ode_solver->current_iteration to size of matrix
618  unsigned int precision = 16;
619  time_pod->dealiiSnapshotMatrix.print_formatted(snapshot_file, precision, true, 0, "0");
620  snapshot_file.close();
621  }
622 
623  timer.stop();
624  pcout << "Timer stopped. " << std::endl;
625  const double max_wall_time = dealii::Utilities::MPI::max(timer.wall_time(), this->mpi_communicator);
626  pcout << "Elapsed wall time (mpi max): " << max_wall_time << " seconds." << std::endl;
627  pcout << "Elapsed CPU time: " << timer.cpu_time() << " seconds." << std::endl;
628  } else {
629  //----------------------------------------------------
630  // Steady-state solution
631  //----------------------------------------------------
633  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)) {
634  ode_solver->initialize_steady_polynomial_ramping(poly_degree);
635  }
636 
637  ode_solver->steady_state();
638  flow_solver_case->steady_state_postprocessing(dg);
639 
640  const bool use_isotropic_mesh_adaptation = (all_param.mesh_adaptation_param.total_mesh_adaptation_cycles > 0)
641  && (all_param.mesh_adaptation_param.mesh_adaptation_type != Parameters::MeshAdaptationParam::MeshAdaptationType::anisotropic_adaptation);
642 
643  if(use_isotropic_mesh_adaptation)
644  {
646  }
647  }
648  pcout << "done." << std::endl;
649  return 0;
650 }
651 
652 #if PHILIP_DIM==1
655 #endif
656 
657 #if PHILIP_DIM!=1
658 template class FlowSolver <PHILIP_DIM,1>;
659 template class FlowSolver <PHILIP_DIM,2>;
660 template class FlowSolver <PHILIP_DIM,3>;
661 template class FlowSolver <PHILIP_DIM,4>;
662 template class FlowSolver <PHILIP_DIM,5>;
663 template class FlowSolver <PHILIP_DIM,6>;
664 #endif
665 
666 } // FlowSolver namespace
667 } // PHiLiP namespace
668 
Proper Orthogonal Decomposition with Galerkin projection.
std::string double_to_string(const double value_input) const
Converts a double to a string with scientific format and with full precision.
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.
const MPI_Comm mpi_communicator
MPI communicator.
Definition: flow_solver.h:91
dealii::Table< 1, double > output_solution_fixed_times
Fixed times at which to output the solution.
Definition: flow_solver.h:147
bool steady_state
Flag for solving steady state solution.
bool adaptive_time_step
Flag for computing the time step on the fly.
Selects which flow case to simulate.
Definition: flow_solver.h:64
dealii::ConditionalOStream pcout
ConditionalOStream.
Definition: flow_solver.h:97
std::shared_ptr< FlowSolverCaseBase< dim, nstate > > flow_solver_case
Pointer to Flow Solver Case.
Definition: flow_solver.h:74
void perform_steady_state_mesh_adaptation() const
Performs mesh adaptation.
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.
std::shared_ptr< DGBase< dim, double > > dg
Pointer to dg so it can be accessed externally.
Definition: flow_solver.h:114
int total_mesh_adaptation_cycles
Total/maximum number of mesh adaptation cycles while solving a problem.
const Parameters::FlowSolverParam flow_solver_param
Flow solver parameters.
Definition: flow_solver.h:99
Proper Orthogonal Decomposition with Petrov-Galerkin projection (LSPG) and ECSW Hyper-reduction.
bool output_restart_files
Output the restart files.
const int mpi_rank
MPI rank.
Definition: flow_solver.h:92
Files for the baseline physics.
Definition: ADTypes.hpp:10
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) ...
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
ReducedOrderModelParam reduced_order_param
Contains parameters for the Reduced-Order model.
Explicit RK using the relaxation Runge-Kutta method (Ketcheson, 2019)
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::vector< std::string > get_data_table_column_names(const std::string string_input) const
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.
const Parameters::AllParameters all_param
All parameters.
Definition: flow_solver.h:98
const Parameters::ODESolverParam ode_param
ODE solver parameters.
Definition: flow_solver.h:100
MeshAdaptationType mesh_adaptation_type
Selection of mesh adaptation type.
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.
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.
unsigned int restart_file_index
Index of desired restart file for restarting the computation from.
double nonlinear_steady_residual_tolerance
Tolerance to determine steady-state convergence.
int run() const override
Simply runs the flow solver and returns 0 upon completion.
int output_restart_files_every_x_steps
Outputs the restart files every x steps.
bool end_exactly_at_final_time
Flag to adjust the last timestep such that the simulation ends exactly at final_time.
std::shared_ptr< ODE::ODESolverBase< dim, double > > ode_solver
Pointer to ode solver so it can be accessed externally.
Definition: flow_solver.h:117
ODESolverEnum ode_solver_type
ODE solver type.
int output_snapshot_every_x_timesteps
Number of timesteps before putting solution in snapshot matrix.
const bool do_output_solution_at_fixed_times
Flag for outputting solution at fixed times.
Definition: flow_solver.h:108
const double final_time
Final time of solution.
Definition: flow_solver.h:103
std::string restart_files_directory_name
Name of directory for writing and reading restart files.
const unsigned int number_of_fixed_times_to_output_solution
Number of fixed times to output the solution.
Definition: flow_solver.h:109
Base class of all the flow solvers.
Definition: flow_solver.h:49
const unsigned int poly_degree
Polynomial order.
Definition: flow_solver.h:101
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) ...
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.
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
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.
Definition: flow_solver.h:77