1 #include "flow_solver.h"     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>    16 namespace FlowSolver {
    21 template <
int dim, 
int nstate>
    25     const dealii::ParameterHandler ¶meter_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()))
    47         pcout << 
"Note: Allocating DG with AD matrix dRdW only." << std::endl;
    48         dg->allocate_system(
true,
false,
false); 
    50         pcout << 
"Note: Allocating DG without AD matrices." << std::endl;
    51         dg->allocate_system(
false,
false,
false);
    59             pcout << 
"Error: restart_computation_from_file is not possible for 1D. Set to false." << std::endl;
    64             pcout << 
"Error: Restart capability has not been fully implemented / tested for steady state computations." << std::endl;
    69         pcout << 
"Initializing solution from restart file..." << std::flush;
    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; 
    82         pcout << 
"done." << std::endl;
    87     dg->solution.update_ghost_values();
    92         std::shared_ptr<ProperOrthogonalDecomposition::OfflinePOD<dim>> pod = std::make_shared<ProperOrthogonalDecomposition::OfflinePOD<dim>>(
dg);
   105     if(unsteady_FOM_POD_bool){
   106         std::shared_ptr<dealii::TrilinosWrappers::SparseMatrix> system_matrix(
   110         time_pod = std::make_shared<ProperOrthogonalDecomposition::OnlinePOD<dim>>(system_matrix); 
   111         time_pod->addSnapshot(
dg->solution);
   116         pcout << 
"Writing a reference copy of the inputted parameters (.prm) file... " << std::flush;
   120         pcout << 
"done." << std::endl;
   129         std::string line = output_solution_fixed_times_string;
   130         std::string::size_type sz1;
   133             line = line.substr(sz1);
   140 template <
int dim, 
int nstate>
   147     std::istringstream iss(string_input);
   151     std::vector<std::string> names;
   153         names.push_back(word.c_str());
   158 template <
int dim, 
int nstate>
   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');
   166     const std::string prefix = 
"restart-";
   167     const std::string restart_filename_without_extension = prefix+restart_index_string;
   169     return restart_filename_without_extension;
   172 template <
int dim, 
int nstate>
   174     std::string data_table_filename,
   175     const std::shared_ptr <dealii::TableHandler> data_table)
 const   179         std::string::size_type sz1;
   181         std::ifstream FILE (data_table_filename);
   182         std::getline(FILE, line); 
   186             pcout << 
"Error: Trying to read empty file named " << data_table_filename << std::endl;
   191         const int number_of_columns = data_column_names.size();
   193         std::getline(FILE, line); 
   197             pcout << 
"Error: Table has no data to be read" << std::endl;
   201         std::vector<double> current_line_values(number_of_columns);
   202         while (!line.empty()) {
   203             std::string dummy_line = line;
   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);
   209                 current_line_values[i] = std::stod(dummy_line,&sz1);
   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);
   218             std::getline(FILE, line); 
   223 template <
int dim, 
int nstate>
   226     std::stringstream ss;
   227     ss << std::scientific << std::setprecision(16) << value_input;
   232 template <
int dim, 
int nstate>
   234     const unsigned int restart_index_input,
   235     const double time_step_input)
 const {
   248         std::vector<std::string> subsection_line;
   249         subsection_line.push_back(
"subsection ODE solver");
   250         subsection_line.push_back(
"subsection flow_solver");
   252         int number_of_subsections = subsection_line.size();
   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 ");
   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));
   269         ODE_solver_restart_parameter_values.push_back(
double_to_string(time_step_input));
   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 ");
   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));
   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());
   293         int i_subsection = 0;
   297         while (std::getline(CURRENT_FILE, line)) {
   299             if (line == subsection_line[i_subsection]) {
   300                 RESTART_FILE << line << 
"\n"; 
   304                 std::string value_string;
   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];
   314                 while (line!=
"end") {
   315                     std::getline(CURRENT_FILE, line); 
   316                     std::string::size_type found = line.find(name);
   319                     if (found!=std::string::npos) {
   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);
   328                         RESTART_FILE << updated_line << 
"\n";
   331                         if ((i_parameter+1) < number_of_subsection_parameters[i_subsection]) ++i_parameter; 
   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];
   341                         RESTART_FILE << line << 
"\n";
   345                 if ((i_subsection+1) < number_of_subsections) ++i_subsection; 
   348                 RESTART_FILE << line << 
"\n";
   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   361     pcout << 
"  ... Writing restart files ... " << std::endl;
   365     dealii::parallel::distributed::SolutionTransfer<dim, dealii::LinearAlgebra::distributed::Vector<double>, dealii::DoFHandler<dim>> solution_transfer(
dg->dof_handler);
   368     solution_transfer.prepare_for_serialization(
dg->solution);
   375         unsteady_data_table->write_text(unsteady_data_table_file);
   383 template <
int dim, 
int nstate>
   386     std::unique_ptr<MeshAdaptation<dim,double>> meshadaptation = std::make_unique<MeshAdaptation<dim,double>>(this->
dg, &(this->
all_param.
mesh_adaptation_param));
   388     double residual_norm = this->dg->get_residual_l2norm();
   390     pcout<<
"Running mesh adaptation cycles..."<<std::endl;
   391     while (meshadaptation->current_mesh_adaptation_cycle < total_adaptation_cycles)
   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;
   402         meshadaptation->adapt_mesh();
   404         residual_norm = this->
ode_solver->residual_norm;
   408     pcout<<
"Finished running mesh adaptation cycles."<<std::endl; 
   411 template <
int dim, 
int nstate>
   414     pcout << 
"Running Flow Solver..." << std::endl;
   417             pcout << 
"  ... Writing vtk solution file at initial time ..." << std::endl;
   420             pcout << 
"  ... Writing vtk solution file at initial time ..." << std::endl;
   424             pcout << 
"  ... Writing vtk solution file at initial time ..." << std::endl;
   434     unsigned int index_of_current_desired_fixed_time_to_output_solution = 0;
   440             if(this->
ode_solver->current_time < this->output_solution_fixed_times[i]) {
   441                 index_of_current_desired_fixed_time_to_output_solution = i;
   457         double current_desired_time_for_output_restart_files_every_dt_time_intervals = 
ode_solver->current_time; 
   462         double time_step = 0.0;
   464             pcout << 
"WARNING: CFL-adaptation and error-adaptation cannot be used at the same time. Aborting!" << std::endl;
   468             pcout << 
"Setting initial adaptive time step... " << std::flush;
   471             pcout << 
"Setting initial error adaptive time step... " << std::flush;
   472             time_step = 
ode_solver->get_automatic_initial_step_size(time_step,
false);
   474             pcout << 
"Setting constant time step... " << std::flush;
   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;
   488         pcout << 
"done." << std::endl;
   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;
   498             pcout << 
"done." << std::endl;
   501             pcout << 
"Writing unsteady data computed at initial time... " << std::endl;
   503             pcout << 
"done." << std::endl;
   508         double next_time_step = time_step;
   509         pcout << 
"Advancing solution in time... " << std::endl;
   510         pcout << 
"Timer starting. " << std::endl;
   515             time_step = next_time_step; 
   522                 const double next_time = 
ode_solver->current_time + time_step;
   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;
   541                 next_time_step = 
ode_solver->get_automatic_error_adaptive_step_size(time_step,
false); 
   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) {
   556                         output_restart_files(file_number, next_time_step, unsteady_data_table);
   561                     if (is_output_iteration) {
   563                         output_restart_files(file_number, next_time_step, unsteady_data_table);
   572                 if (is_output_iteration) {
   573                     pcout << 
"  ... Writing vtk solution file ..." << std::endl;
   575                     dg->output_results_vtk(file_number,
ode_solver->current_time);
   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;
   583                     dg->output_results_vtk(file_number,
ode_solver->current_time);
   587                 const double next_time = 
ode_solver->current_time + next_time_step;
   590                 bool is_output_time = 
false; 
   592                     is_output_time = 
ode_solver->current_time == desired_time;
   594                     is_output_time = ((
ode_solver->current_time<=desired_time) && (next_time>desired_time));
   597                     pcout << 
"  ... Writing vtk solution file ..." << std::endl;
   598                     const int file_number = index_of_current_desired_fixed_time_to_output_solution+1; 
   599                     dg->output_results_vtk(file_number,
ode_solver->current_time);
   602                     if(index_of_current_desired_fixed_time_to_output_solution 
   604                         index_of_current_desired_fixed_time_to_output_solution += 1;
   609             if(unsteady_FOM_POD_bool){
   611                 if(is_snapshot_iteration) time_pod->addSnapshot(
dg->solution);
   616         if(unsteady_FOM_POD_bool){
   617             std::ofstream snapshot_file(
"solution_snapshots_iteration_" + std::to_string(
ode_solver->current_iteration) + 
".txt"); 
   618             unsigned int precision = 16;
   619             time_pod->dealiiSnapshotMatrix.print_formatted(snapshot_file, precision, 
true, 0, 
"0"); 
   620             snapshot_file.close();
   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;
   643         if(use_isotropic_mesh_adaptation)
   648     pcout << 
"done." << std::endl;
 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. 
dealii::Table< 1, double > output_solution_fixed_times
Fixed times at which to output the solution. 
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. 
dealii::ConditionalOStream pcout
ConditionalOStream. 
std::shared_ptr< FlowSolverCaseBase< dim, nstate > > flow_solver_case
Pointer to Flow Solver Case. 
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. 
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. 
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. 
Files for the baseline physics. 
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. 
ReducedOrderModelParam reduced_order_param
Contains parameters for the Reduced-Order model. 
Explicit RK using the relaxation Runge-Kutta method (Ketcheson, 2019) 
ODESolverEnum
Types of ODE solver. 
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. 
const Parameters::ODESolverParam ode_param
ODE solver parameters. 
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. 
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. 
ODESolverEnum ode_solver_type
ODE solver type. 
std::string unsteady_data_table_filename
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. 
const double final_time
Final time of solution. 
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. 
Base class of all the flow solvers. 
const unsigned int poly_degree
Polynomial order. 
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...
const dealii::ParameterHandler & parameter_handler
Parameter handler for storing the .prm file being ran.