ASPECT
block_stokes_preconditioner.h
Go to the documentation of this file.
1 // ------------------------------------------------------
2 //
3 // SPDX-License-Identifier: GPL-2.0-or-later
4 //
5 // SPDX-FileCopyrightText: Copyright (C) 2011-2026 by the ASPECT authors.
6 //
7 // This file is part of ASPECT.
8 //
9 // Detailed license information governing the source code and
10 // contributions can be found in the folder LICENSES and in
11 // LICENSE and CONTRIBUTING.md at the top level directory.
12 //
13 // ------------------------------------------------------
14 
15 
16 #ifndef _aspect_block_stokes_preconditioner_h
17 #define _aspect_block_stokes_preconditioner_h
18 
20 #include <deal.II/lac/solver_cg.h>
21 
22 
25 
26 namespace aspect
27 {
28 
29  namespace internal
30  {
37  template <class PreconditionerA, class VectorType, class ABlockType>
39  {
40  public:
51  InverseVelocityBlock(const ABlockType &matrix,
52  const PreconditionerA &preconditioner,
53  const bool do_solve_A,
54  const bool A_block_is_symmetric,
55  const double solver_tolerance);
56 
57  void vmult(VectorType &dst,
58  const VectorType &src) const;
59 
60  unsigned int n_iterations() const;
61 
62  private:
63  mutable unsigned int n_iterations_;
64  const ABlockType &matrix;
65  const PreconditionerA &preconditioner;
66  const bool do_solve_A;
68  const double solver_tolerance;
69  };
70 
71 
72 
73  template <class PreconditionerA,class VectorType, class ABlockType>
75  const ABlockType &matrix,
76  const PreconditionerA &preconditioner,
77  const bool do_solve_A,
78  const bool A_block_is_symmetric,
79  const double solver_tolerance)
80  : n_iterations_ (0),
81  matrix (matrix),
82  preconditioner (preconditioner),
83  do_solve_A (do_solve_A),
84  A_block_is_symmetric (A_block_is_symmetric),
85  solver_tolerance (solver_tolerance)
86  {}
87 
88 
89 
94  template <class PreconditionerA, class VectorType, class ABlockType>
96  const VectorType &src) const
97  {
98 
99  // Either solve with the top left block
100  // or just apply one preconditioner sweep (for the first few
101  // iterations of our two-stage outer GMRES iteration)
102  if (do_solve_A == true)
103  {
104  SolverControl solver_control(10000, src.l2_norm() * solver_tolerance);
106 
107  try
108  {
109  dst = 0.0;
110 
112  {
113  SolverCG<VectorType> solver(solver_control, mem);
114  solver.solve(matrix, dst, src, preconditioner);
115  }
116  else
117  {
118  // Use BiCGStab for non-symmetric matrices.
119  // BiCGStab can also solve indefinite systems if necessary.
120  // Do not compute the exact residual, as this
121  // is more expensive, and we only need an approximate solution.
123  solver(solver_control,
124  mem,
125  typename SolverBicgstab<VectorType>::AdditionalData(/*exact_residual=*/ false));
126  solver.solve(matrix, dst, src, preconditioner);
127  }
128  n_iterations_ += solver_control.last_step();
129  }
130  catch (const std::exception &exc)
131  {
132  // if the solver fails, report the error from processor 0 with some additional
133  // information about its location, and throw a quiet exception on all other
134  // processors
135  Utilities::throw_linear_solver_failure_exception("iterative (top left) solver",
136  "BlockSchurPreconditioner::vmult",
137  std::vector<SolverControl> {solver_control},
138  exc,
139  src.get_mpi_communicator());
140  }
141  }
142  else
143  {
144  preconditioner.vmult (dst, src);
145  n_iterations_ += 1;
146  }
147  }
148 
149 
150 
151  template <class PreconditionerA, class VectorType, class ABlockType>
153  {
154  return n_iterations_;
155  }
156 
161  template <class AInvOperator, class SInvOperator, class BTOperator, class VectorType>
163 #if DEAL_II_VERSION_GTE(9,7,0)
165 #else
167 #endif
168 
169  {
170  public:
178  const AInvOperator &A_inverse_operator,
179  const SInvOperator &S_inverse_operator,
180  const BTOperator &BT_operator);
181 
185  void vmult (VectorType &dst,
186  const VectorType &src) const;
187 
188  private:
193  const AInvOperator &A_inverse_operator;
194  const SInvOperator &S_inverse_operator;
195  const BTOperator &BT_operator;
196  mutable VectorType tmp;
197  };
198 
199 
200  template <class AInvOperator, class SInvOperator, class BTOperator, class VectorType>
203  const AInvOperator &A_inverse_operator,
204  const SInvOperator &S_inverse_operator,
205  const BTOperator &BT_operator)
206  :
207  A_inverse_operator (A_inverse_operator),
208  S_inverse_operator (S_inverse_operator),
209  BT_operator (BT_operator)
210  {}
211 
212 
213 
214  template <class AInvOperator, class SInvOperator, class BTOperator, class VectorType>
215  void
217  vmult (VectorType &dst,
218  const VectorType &src) const
219  {
220  if (tmp.size() == 0)
221  tmp.reinit(src);
222 
223 
224  dst=0.0;
225 
226  // first apply the Schur Complement inverse operator.
227  {
228  S_inverse_operator.vmult(dst.block(1),src.block(1));
229  dst.block(1) *= -1.0;
230  }
231 
232 
233  // apply the top right block: B^T or J^{up}
234  {
235  // For matrix-free usage, the BT operator needs to operate on the whole vector,
236  // but the matrix-based version is a SparseMatrix::vmult() that requires passing the
237  // individual blocks.
238  if constexpr (std::is_same_v<VectorType, ::LinearAlgebra::distributed::BlockVector<double>>)
239  BT_operator.vmult(tmp, dst);
240 
241  else
242  BT_operator.vmult(tmp.block(0), dst.block(1));
243 
244  tmp.block(0) *= -1.0;
245  tmp.block(0) += src.block(0);
246  }
247 
248  A_inverse_operator.vmult(dst.block(0), tmp.block(0));
249  }
250 
251 
252 
253  template<class OperatorType, class StokesMatrixType, class SchurComplementMatrixType, class VectorType>
255  {
256  public:
265  SchurApproximation(const OperatorType &schur_preconditioner,
266  const StokesMatrixType &stokes_matrix,
267  const SchurComplementMatrixType &Schur_complement_block,
268  const bool do_solve_Schur_complement,
269  const double Schur_complement_tolerance);
270  void vmult( VectorType &dst, const VectorType &src) const;
271  unsigned int n_iterations() const;
272 
273  private:
274  const OperatorType &schur_preconditioner;
275  const StokesMatrixType &stokes_matrix;
276  const SchurComplementMatrixType &Schur_complement_block;
279  mutable unsigned int n_iterations_Schur_complement_;
280 
281 
282  };
283 
284 
285 
286  template <class OperatorType, class StokesMatrixType, class SchurComplementMatrixType, class VectorType>
288  const StokesMatrixType &stokes_matrix,
289  const SchurComplementMatrixType &Schur_complement_block,
290  const bool do_solve_Schur_complement,
291  const double Schur_complement_tolerance)
292  :
293  schur_preconditioner(schur_preconditioner),
294  stokes_matrix(stokes_matrix),
295  Schur_complement_block(Schur_complement_block),
296  do_solve_Schur_complement(do_solve_Schur_complement),
297  Schur_complement_tolerance(Schur_complement_tolerance),
298  n_iterations_Schur_complement_(0)
299  {}
300 
301 
302  template<class OperatorType, class StokesMatrixType, class SchurComplementMatrixType, class VectorType>
304  const VectorType &src) const
305  {
307  {
308 
309  SolverControl solver_control(100, src.l2_norm() * Schur_complement_tolerance,true);
310 
311  SolverCG<VectorType> solver(solver_control);
312  // Trilinos reports a breakdown in case src=dst=0, even
313  // though it should return convergence without
314  // iterating. We simply skip solving in this case.
315  if (src.l2_norm() > 1e-50)
316  {
317  try
318  {
319  // explicitly zero out because GMRES does not guarantee that dst is zeroed out
320  dst = 0.0;
321 
322  solver.solve(Schur_complement_block,
323  dst, src,
325  n_iterations_Schur_complement_ += solver_control.last_step();
326  }
327  // if the solver fails, report the error from processor 0 with some additional
328  // information about its location, and throw a quiet exception on all other
329  // processors
330  catch (const std::exception &exc)
331  {
332  Utilities::throw_linear_solver_failure_exception("iterative (bottom right) solver",
333  "BlockSchurPreconditioner::vmult",
334  std::vector<SolverControl> {solver_control},
335  exc,
336  src.get_mpi_communicator());
337  }
338  }
339  }
340  else
341  {
342  dst = 0.0;
343  schur_preconditioner.vmult(dst,src);
345  }
346  }
347  template<class OperatorType, class StokesMatrixType, class SchurComplementMatrixType, class VectorType>
349  {
351  }
352 
353 
354  }
355 }
356 
357 
358 
359 #endif
InverseVelocityBlock(const ABlockType &matrix, const PreconditionerA &preconditioner, const bool do_solve_A, const bool A_block_is_symmetric, const double solver_tolerance)
void throw_linear_solver_failure_exception(const std::string &solver_name, const std::string &function_name, const std::vector< SolverControl > &solver_controls, const std::exception &exc, const MPI_Comm mpi_communicator, const std::string &output_filename="")
void vmult(VectorType &dst, const VectorType &src) const
SymmetricTensor< 2, dim, Number > e(const Tensor< 2, dim, Number > &F)
SchurApproximation(const OperatorType &schur_preconditioner, const StokesMatrixType &stokes_matrix, const SchurComplementMatrixType &Schur_complement_block, const bool do_solve_Schur_complement, const double Schur_complement_tolerance)
Constructor.
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
BlockSchurPreconditioner(const AInvOperator &A_inverse_operator, const SInvOperator &S_inverse_operator, const BTOperator &BT_operator)
Constructor.
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
const SchurComplementMatrixType & Schur_complement_block
void vmult(VectorType &dst, const VectorType &src) const
void vmult(VectorType &dst, const VectorType &src) const