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.