23#ifndef EXADG_FLUID_STRUCTURE_INTERACTION_ACCELERATION_SCHEMES_PARTITIONED_SOLVER_H_
24#define EXADG_FLUID_STRUCTURE_INTERACTION_ACCELERATION_SCHEMES_PARTITIONED_SOLVER_H_
27#include <exadg/fluid_structure_interaction/acceleration_schemes/linear_algebra.h>
28#include <exadg/fluid_structure_interaction/acceleration_schemes/parameters.h>
29#include <exadg/fluid_structure_interaction/single_field_solvers/fluid.h>
30#include <exadg/fluid_structure_interaction/single_field_solvers/structure.h>
31#include <exadg/utilities/print_solver_results.h>
32#include <exadg/utilities/timer_tree.h>
38template<
int dim,
typename Number>
39class PartitionedSolver
42 typedef dealii::LinearAlgebra::distributed::Vector<Number> VectorType;
45 PartitionedSolver(
Parameters const & parameters, MPI_Comm
const & comm);
52 solve(std::function<
void(VectorType &, VectorType
const &,
unsigned int)>
const &
53 apply_dirichlet_neumann_scheme);
56 print_iterations(dealii::ConditionalOStream
const & pcout)
const;
58 std::shared_ptr<TimerTree>
62 get_structure_velocity(VectorType & velocity_structure,
unsigned int const iteration)
const;
66 get_structure_displacement(VectorType & displacement_structure,
67 unsigned int const iteration)
const;
70 check_convergence(VectorType
const & residual)
const;
73 print_solver_info_header(
unsigned int const iteration)
const;
76 print_solver_info_converged(
unsigned int const iteration)
const;
81 dealii::ConditionalOStream pcout;
83 std::shared_ptr<SolverFluid<dim, Number>> fluid;
84 std::shared_ptr<SolverStructure<dim, Number>> structure;
87 std::vector<std::shared_ptr<std::vector<VectorType>>> D_history, R_history, Z_history;
90 std::shared_ptr<TimerTree> timer_tree;
96 std::pair<unsigned int, unsigned long long> partitioned_iterations;
99template<
int dim,
typename Number>
100PartitionedSolver<dim, Number>::PartitionedSolver(
Parameters const & parameters,
101 MPI_Comm
const & comm)
102 : parameters(parameters),
103 pcout(std::cout, dealii::
Utilities::MPI::this_mpi_process(comm) == 0),
104 partitioned_iterations({0, 0})
106 timer_tree = std::make_shared<TimerTree>();
109template<
int dim,
typename Number>
111PartitionedSolver<dim, Number>::setup(std::shared_ptr<SolverFluid<dim, Number>> fluid_,
112 std::shared_ptr<SolverStructure<dim, Number>> structure_)
115 structure = structure_;
118template<
int dim,
typename Number>
120PartitionedSolver<dim, Number>::check_convergence(VectorType
const & residual)
const
122 double const residual_norm = residual.l2_norm();
123 double const ref_norm_abs = std::sqrt(structure->pde_operator->get_number_of_dofs());
124 double const ref_norm_rel = structure->time_integrator->get_velocity_np().l2_norm() *
125 structure->time_integrator->get_time_step_size();
127 bool const converged = (residual_norm < parameters.abs_tol * ref_norm_abs) or
128 (residual_norm < parameters.rel_tol * ref_norm_rel);
133template<
int dim,
typename Number>
135PartitionedSolver<dim, Number>::print_solver_info_header(
unsigned int const iteration)
const
137 if(fluid->time_integrator->print_solver_info())
140 <<
"======================================================================" << std::endl
141 <<
" Partitioned FSI: iteration counter = " << std::left << std::setw(8) << iteration
143 <<
"======================================================================" << std::endl;
147template<
int dim,
typename Number>
149PartitionedSolver<dim, Number>::print_solver_info_converged(
unsigned int const iteration)
const
151 if(fluid->time_integrator->print_solver_info())
154 <<
"Partitioned FSI iteration converged in " << iteration <<
" iterations." << std::endl;
158template<
int dim,
typename Number>
160PartitionedSolver<dim, Number>::print_iterations(dealii::ConditionalOStream
const & pcout)
const
162 std::vector<std::string> names;
163 std::vector<double> iterations_avg;
165 names = {
"Partitioned iterations"};
166 iterations_avg.resize(1);
168 (double)partitioned_iterations.second / std::max(1.0, (
double)partitioned_iterations.first);
170 print_list_of_iterations(pcout, names, iterations_avg);
173template<
int dim,
typename Number>
174std::shared_ptr<TimerTree>
175PartitionedSolver<dim, Number>::get_timings()
const
180template<
int dim,
typename Number>
182PartitionedSolver<dim, Number>::get_structure_velocity(VectorType & velocity_structure,
183 unsigned int iteration)
const
187 if(parameters.initial_guess_coupling_scheme ==
188 InitialGuessCouplingScheme::SolutionExtrapolatedToEndOfTimeStep)
190 structure->time_integrator->extrapolate_velocity_to_np(velocity_structure);
192 else if(parameters.initial_guess_coupling_scheme ==
193 InitialGuessCouplingScheme::ConvergedSolutionOfPreviousTimeStep)
195 velocity_structure = structure->time_integrator->get_velocity_n();
201 "Behavior for this `InitialGuessCouplingScheme` is not defined."));
206 velocity_structure = structure->time_integrator->get_velocity_np();
210template<
int dim,
typename Number>
212PartitionedSolver<dim, Number>::get_structure_displacement(VectorType & displacement_structure,
213 unsigned int const iteration)
const
217 if(this->parameters.initial_guess_coupling_scheme ==
218 InitialGuessCouplingScheme::SolutionExtrapolatedToEndOfTimeStep)
220 structure->time_integrator->extrapolate_displacement_to_np(displacement_structure);
222 else if(this->parameters.initial_guess_coupling_scheme ==
223 InitialGuessCouplingScheme::ConvergedSolutionOfPreviousTimeStep)
225 displacement_structure = structure->time_integrator->get_displacement_n();
231 "Behavior for this `InitialGuessCouplingScheme` is not defined."));
236 displacement_structure = structure->time_integrator->get_displacement_np();
240template<
int dim,
typename Number>
242PartitionedSolver<dim, Number>::solve(
243 std::function<
void(VectorType &, VectorType
const &,
unsigned int)>
const &
244 apply_dirichlet_neumann_scheme)
250 if(parameters.acceleration_method == AccelerationMethod::Aitken)
253 structure->pde_operator->initialize_dof_vector(r_old);
254 structure->pde_operator->initialize_dof_vector(d);
256 bool converged =
false;
258 while(not(converged) and k < parameters.partitioned_iter_max)
260 print_solver_info_header(k);
262 get_structure_displacement(d, k);
264 VectorType d_tilde(d);
265 apply_dirichlet_neumann_scheme(d_tilde, d, k);
268 VectorType r = d_tilde;
270 converged = check_convergence(r);
280 omega = parameters.omega_init;
284 VectorType delta_r = r;
285 delta_r.add(-1.0, r_old);
286 omega *= -(r_old * delta_r) / delta_r.norm_sqr();
292 structure->time_integrator->set_displacement(d);
294 timer_tree->insert({
"Aitken"}, timer.wall_time());
301 else if(parameters.acceleration_method == AccelerationMethod::IQN_ILS)
303 std::shared_ptr<std::vector<VectorType>> D, R;
304 D = std::make_shared<std::vector<VectorType>>();
305 R = std::make_shared<std::vector<VectorType>>();
307 VectorType d, d_tilde, d_tilde_old, r, r_old;
308 structure->pde_operator->initialize_dof_vector(d);
309 structure->pde_operator->initialize_dof_vector(d_tilde);
310 structure->pde_operator->initialize_dof_vector(d_tilde_old);
311 structure->pde_operator->initialize_dof_vector(r);
312 structure->pde_operator->initialize_dof_vector(r_old);
314 unsigned int const q = parameters.reused_time_steps;
315 unsigned int const n = fluid->time_integrator->get_number_of_time_steps();
317 bool converged =
false;
318 while(not(converged) and k < parameters.partitioned_iter_max)
320 print_solver_info_header(k);
322 get_structure_displacement(d, k);
324 apply_dirichlet_neumann_scheme(d_tilde, d, k);
329 converged = check_convergence(r);
337 if(k == 0 and (q == 0 or n == 0))
339 d.add(parameters.omega_init, r);
346 VectorType delta_d_tilde = d_tilde;
347 delta_d_tilde.add(-1.0, d_tilde_old);
348 D->push_back(delta_d_tilde);
350 VectorType delta_r = r;
351 delta_r.add(-1.0, r_old);
352 R->push_back(delta_r);
356 std::vector<VectorType> Q = *R;
357 for(
auto R_q : R_history)
358 for(
auto delta_r : *R_q)
359 Q.push_back(delta_r);
360 std::vector<VectorType> D_all = *D;
361 for(
auto D_q : D_history)
362 for(
auto delta_d : *D_q)
363 D_all.push_back(delta_d);
365 AssertThrow(D_all.size() == Q.size(),
366 dealii::ExcMessage(
"D, Q vectors must have same size."));
368 unsigned int const k_all = Q.size();
373 compute_QR_decomposition(Q, U);
375 std::vector<Number> rhs(k_all, 0.0);
376 for(
unsigned int i = 0; i < k_all; ++i)
377 rhs[i] = -Number(Q[i] * r);
380 std::vector<Number> alpha(k_all, 0.0);
381 backward_substitution(U, alpha, rhs);
385 for(
unsigned int i = 0; i < k_all; ++i)
386 d.add(alpha[i], D_all[i]);
390 d.add(parameters.omega_init, r);
394 d_tilde_old = d_tilde;
397 structure->time_integrator->set_displacement(d);
399 timer_tree->insert({
"IQN-ILS"}, timer.wall_time());
410 D_history.push_back(D);
411 R_history.push_back(R);
412 if(D_history.size() > q)
413 D_history.erase(D_history.begin());
414 if(R_history.size() > q)
415 R_history.erase(R_history.begin());
417 timer_tree->insert({
"IQN-ILS"}, timer.wall_time());
419 else if(parameters.acceleration_method == AccelerationMethod::IQN_IMVLS)
421 std::shared_ptr<std::vector<VectorType>> D, R;
422 D = std::make_shared<std::vector<VectorType>>();
423 R = std::make_shared<std::vector<VectorType>>();
425 std::vector<VectorType> B;
427 VectorType d, d_tilde, d_tilde_old, r, r_old, b, b_old;
428 structure->pde_operator->initialize_dof_vector(d);
429 structure->pde_operator->initialize_dof_vector(d_tilde);
430 structure->pde_operator->initialize_dof_vector(d_tilde_old);
431 structure->pde_operator->initialize_dof_vector(r);
432 structure->pde_operator->initialize_dof_vector(r_old);
433 structure->pde_operator->initialize_dof_vector(b);
434 structure->pde_operator->initialize_dof_vector(b_old);
436 std::shared_ptr<Matrix<Number>> U;
437 std::vector<VectorType> Q;
439 unsigned int const q = parameters.reused_time_steps;
440 unsigned int const n = fluid->time_integrator->get_number_of_time_steps();
442 bool converged =
false;
443 while(not(converged) and k < parameters.partitioned_iter_max)
445 print_solver_info_header(k);
447 get_structure_displacement(d, k);
449 apply_dirichlet_neumann_scheme(d_tilde, d, k);
454 converged = check_convergence(r);
463 inv_jacobian_times_residual(b, D_history, R_history, Z_history, r);
465 if(k == 0 and (q == 0 or n == 0))
467 d.add(parameters.omega_init, r);
477 VectorType delta_d_tilde = d_tilde;
478 delta_d_tilde.add(-1.0, d_tilde_old);
479 D->push_back(delta_d_tilde);
481 VectorType delta_r = r;
482 delta_r.add(-1.0, r_old);
483 R->push_back(delta_r);
485 VectorType delta_b = delta_d_tilde;
486 delta_b.add(1.0, b_old);
487 delta_b.add(-1.0, b);
488 B.push_back(delta_b);
491 U = std::make_shared<Matrix<Number>>(k);
493 compute_QR_decomposition(Q, *U);
495 std::vector<Number> rhs(k, 0.0);
496 for(
unsigned int i = 0; i < k; ++i)
497 rhs[i] = -Number(Q[i] * r);
500 std::vector<Number> alpha(k, 0.0);
501 backward_substitution(*U, alpha, rhs);
503 for(
unsigned int i = 0; i < k; ++i)
504 d.add(alpha[i], B[i]);
508 d_tilde_old = d_tilde;
512 structure->time_integrator->set_displacement(d);
514 timer_tree->insert({
"IQN-IMVLS"}, timer.wall_time());
525 D_history.push_back(D);
526 R_history.push_back(R);
527 if(D_history.size() > q)
528 D_history.erase(D_history.begin());
529 if(R_history.size() > q)
530 R_history.erase(R_history.begin());
533 std::shared_ptr<std::vector<VectorType>> Z;
534 Z = std::make_shared<std::vector<VectorType>>();
536 backward_substitution_multiple_rhs(*U, *Z, Q);
537 Z_history.push_back(Z);
538 if(Z_history.size() > q)
539 Z_history.erase(Z_history.begin());
541 timer_tree->insert({
"IQN-IMVLS"}, timer.wall_time());
545 AssertThrow(
false, dealii::ExcMessage(
"This AccelerationMethod is not implemented."));
548 partitioned_iterations.first += 1;
549 partitioned_iterations.second += k;
551 print_solver_info_converged(k);
Definition linear_algebra.h:40
Definition structure.h:36
Definition interpolate.h:34
Definition parameters.h:54