Fluid structure interaction suite
stokes.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2022 by Luca Heltai
4 //
5 // This file is part of the FSI-suite platform, based on the deal.II library.
6 //
7 // The FSI-suite platform is free software; you can use it, redistribute it,
8 // and/or modify it under the terms of the GNU Lesser General Public License as
9 // published by the Free Software Foundation; either version 3.0 of the License,
10 // or (at your option) any later version. The full text of the license can be
11 // found in the file LICENSE at the top level of the FSI-suite platform
12 // distribution.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include "pdes/stokes.h"
17 
18 #include <deal.II/dofs/dof_tools.h>
19 
21 
23 
24 using namespace dealii;
25 
26 namespace PDEs
27 {
28  template <int dim, class LacType>
30  : LinearProblem<dim, dim, LacType>(
31  ParsedTools::Components::blocks_to_names({"u", "p"}, {dim, 1}),
32  "Stokes")
33  , constants("/Stokes/Constants", {"eta"}, {1.0}, {"Viscosity"})
34  , schur_preconditioner("/Stokes/Solver/Schur preconditioner")
35  , schur_solver("/Stokes/Solver/Schur solver",
36  "cg",
38  5)
39  , velocity(0)
40  , pressure(dim)
41  {
42  // Fix first pressure dof to zero
43  this->add_constraints_call_back.connect([&]() {
44  // search for first pressure dof
45  if (this->mpi_rank == 0)
46  {
47  unsigned int first_pressure_dof = 0;
48  for (unsigned int i = 0; i < this->finite_element().dofs_per_cell;
49  ++i)
50  {
51  if (this->finite_element().system_to_component_index(i).first ==
52  dim)
53  {
54  first_pressure_dof = i;
55  break;
56  }
57  }
58  std::vector<types::global_dof_index> dof_indices(
59  this->finite_element().dofs_per_cell);
60  for (const auto &cell : this->dof_handler.active_cell_iterators())
61  if (cell->is_locally_owned())
62  {
63  cell->get_dof_indices(dof_indices);
64  this->constraints.add_line(dof_indices[first_pressure_dof]);
65  break;
66  }
67  }
68  });
69  }
70 
71 
72 
73  template <int dim, class LacType>
74  void
76  const typename DoFHandler<dim>::active_cell_iterator &cell,
77  ScratchData &scratch,
78  CopyData &copy)
79  {
80  auto &cell_matrix = copy.matrices[0];
81  auto &cell_rhs = copy.vectors[0];
82 
83  cell->get_dof_indices(copy.local_dof_indices[0]);
84 
85  const auto &fe_values = scratch.reinit(cell);
86  cell_matrix = 0;
87  cell_rhs = 0;
88 
89  for (const unsigned int q_index : fe_values.quadrature_point_indices())
90  {
91  for (const unsigned int i : fe_values.dof_indices())
92  {
93  const auto &eps_v =
94  fe_values[velocity].symmetric_gradient(i, q_index);
95  const auto &div_v = fe_values[velocity].divergence(i, q_index);
96  const auto &q = fe_values[pressure].value(i, q_index);
97 
98  for (const unsigned int j : fe_values.dof_indices())
99  {
100  const auto &eps_u =
101  fe_values[velocity].symmetric_gradient(j, q_index);
102  const auto &div_u = fe_values[velocity].divergence(j, q_index);
103  const auto &p = fe_values[pressure].value(j, q_index);
104  // We assemble also the mass matrix for the pressure, to be
105  // used as a preconditioner
106  cell_matrix(i, j) +=
107  (constants["eta"] * scalar_product(eps_v, eps_u) - div_v * p -
108  div_u * q + p * q / constants["eta"]) *
109  fe_values.JxW(q_index); // dx
110  }
111 
112  cell_rhs(i) +=
113  (fe_values.shape_value(i, q_index) * // phi_i(x_q)
114  this->forcing_term.value(fe_values.quadrature_point(q_index),
115  this->finite_element()
116  .system_to_component_index(i)
117  .first) * // f(x_q)
118  fe_values.JxW(q_index)); // dx
119  }
120  }
121  }
122 
123 
124 
125  template <int dim, class LacType>
126  void
128  {
129  TimerOutput::Scope timer_section(this->timer, "solve");
130 
131  using BVec = typename LacType::BlockVector;
132  using Vec = typename BVec::BlockType;
133  using LinOp = LinearOperator<Vec>;
134  using BlockLinOp = BlockLinearOperator<BVec>;
135 
136  const auto &m = this->matrix;
137 
138  const auto A = linear_operator<Vec>(m.block(0, 0));
139  const auto Bt = linear_operator<Vec>(m.block(0, 1));
140  const auto B = linear_operator<Vec>(m.block(1, 0));
141  const auto Mp = linear_operator<Vec>(m.block(1, 1));
142  const auto Zero = Mp * 0.0;
143 
144 
145  auto AA = block_operator<2, 2, BVec>({{{{A, Bt}}, {{B, Zero}}}});
146 
147  if constexpr (std::is_same<LacType, LAC::LATrilinos>::value)
148  {
149  std::vector<std::vector<bool>> constant_modes;
150  DoFTools::extract_constant_modes(this->dof_handler,
151  this->finite_element().component_mask(
152  velocity),
153  constant_modes);
154  this->preconditioner.set_constant_modes(constant_modes);
155  const auto n_modes = std::count_if(constant_modes[0].begin(),
156  constant_modes[0].end(),
157  [](const bool &b) { return b; });
158  deallog << "Constant modes: " << n_modes << "/"
159  << constant_modes[0].size() << std::endl;
160  }
161  // auto AA = block_operator<BVec>(m);
162  // AA.block(1, 1) *= 0;
163 
164 
165  this->preconditioner.initialize(m.block(0, 0));
166  schur_preconditioner.initialize(m.block(1, 1));
167 
168  auto precA = linear_operator<Vec>(A, this->preconditioner);
169 
170  const auto S = -1.0 * B * precA * Bt;
171  auto precM = linear_operator<Vec>(Mp, schur_preconditioner);
172  // auto precS = schur_solver(S, precM);
173  auto precS = schur_solver(Mp, precM);
174 
175  std::array<LinOp, 2> diag_ops = {{precA, precS}};
176  auto diagprecAA = block_diagonal_operator<2, BVec>(diag_ops);
177 
178  deallog << "Preconditioners initialized" << std::endl;
179 
180  // If we use gmres or another non symmetric solver, use a non-symmetric
181  // preconditioner
182  if (this->inverse_operator.get_solver_name() != "minres")
183  {
184  const auto precAA = block_forward_substitution(AA, diagprecAA);
185  const auto inv = this->inverse_operator(AA, precAA);
186  this->solution = inv * this->rhs;
187  }
188  else
189  {
190  const auto inv = this->inverse_operator(AA, diagprecAA);
191  this->solution = inv * this->rhs;
192  }
193 
194  this->constraints.distribute(this->solution);
195  this->locally_relevant_solution = this->solution;
196  }
197 
198  template class Stokes<2, LAC::LAdealii>;
199  template class Stokes<3, LAC::LAdealii>;
200 
201  template class Stokes<2, LAC::LATrilinos>;
202  template class Stokes<3, LAC::LATrilinos>;
203 
204  template class Stokes<2, LAC::LAPETSc>;
205  template class Stokes<3, LAC::LAPETSc>;
206 } // namespace PDEs
void reinit(const Triangulation< dim, spacedim > &tria)
Construct a LinearProblem.
Solve the Stokes problem, in parallel.
Definition: stokes.h:33
virtual void solve() override
Make sure we initialize the right type of linear solver.
Definition: stokes.cc:127
typename LinearProblem< dim, dim, LacType >::CopyData CopyData
Definition: stokes.h:48
virtual void assemble_system_one_cell(const typename DoFHandler< dim >::active_cell_iterator &cell, ScratchData &scratch, CopyData &copy) override
Explicitly assemble the Stokes problem on a single cell.
Definition: stokes.cc:75
typename LinearProblem< dim, dim, LacType >::ScratchData ScratchData
Definition: stokes.h:46
LinearOperator< Domain, Range, typename BlockPayload::BlockType > block_forward_substitution(const BlockLinearOperator< Range, Domain, BlockPayload > &block_operator, const BlockLinearOperator< Domain, Range, BlockPayload > &diagonal_inverse)
LinearOperator< Domain, Range, Payload > inverse_operator(const LinearOperator< Range, Domain, Payload > &op, Solver &solver, const Preconditioner &preconditioner)
LogStream deallog
void extract_constant_modes(const DoFHandler< dim, spacedim > &dof_handler, const ComponentMask &component_mask, std::vector< std::vector< bool > > &constant_modes)
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
PDEs::Stokes< dim, LAC::LAPETSc > Stokes
Definition: stokes.h:80
We collect in this namespace all PDEs that are relevant to Fluid Structure Interaction Problems.
@ iteration_number
Use IterationNumberControl.
std::string blocks_to_names(const std::vector< std::string > &components, const std::vector< unsigned int > &multiplicities)
Build component names from block names and multiplicities.
Definition: components.cc:40
We collect in this namespace some wrappers around commonly used deal.II classes, derived from the Par...