deal.II version GIT relicensing-6842-g793a97d2aa 2026-10-02 14:00:01+00:00
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
Loading...
Searching...
No Matches
solver_qmrs.h
Go to the documentation of this file.
1// -----------------------------------------------------------------------------
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception OR LGPL-2.1-or-later
4// Copyright (C) 1999 - 2024 by the deal.II authors
5//
6// This file is part of the deal.II library.
7//
8// Detailed license information governing the source code and contributions
9// can be found in LICENSE.md and CONTRIBUTING.md at the top level directory.
10//
11// -----------------------------------------------------------------------------
12
13#ifndef dealii_solver_qmrs_h
14#define dealii_solver_qmrs_h
15
16#include <deal.II/base/config.h>
17
21
22#include <deal.II/lac/solver.h>
24
25#include <cmath>
26
28
91template <typename VectorType = Vector<double>>
93class SolverQMRS : public SolverBase<VectorType>
94{
95public:
121 {
128 explicit AdditionalData(const bool left_preconditioning = false,
129 const double solver_tolerance = 1.e-9,
130 const bool breakdown_testing = true,
131 const double breakdown_threshold = 1.e-16)
132 : left_preconditioning(left_preconditioning)
133 , solver_tolerance(solver_tolerance)
134 , breakdown_testing(breakdown_testing)
135 , breakdown_threshold(breakdown_threshold)
136 {}
137
142
147
152
158 };
159
166
172
176 template <typename MatrixType, typename PreconditionerType>
180 void solve(const MatrixType &A,
181 VectorType &x,
182 const VectorType &b,
183 const PreconditionerType &preconditioner);
184
190 virtual void
191 print_vectors(const unsigned int step,
192 const VectorType &x,
193 const VectorType &r,
194 const VectorType &d) const;
195
196protected:
200 AdditionalData additional_data;
201
202private:
208 {
211
213 const double last_residual);
214 };
215
220 template <typename MatrixType, typename PreconditionerType>
222 iterate(const MatrixType &A,
223 VectorType &x,
224 const VectorType &b,
225 const PreconditionerType &preconditioner,
226 VectorType &r,
227 VectorType &u,
228 VectorType &q,
229 VectorType &t,
230 VectorType &d);
231
235 unsigned int step;
236};
237
239/*------------------------- Implementation ----------------------------*/
240
241#ifndef DOXYGEN
242
243
244template <typename VectorType>
247 const SolverControl::State state,
248 const double last_residual)
249 : state(state)
250 , last_residual(last_residual)
251{}
252
253
254
255template <typename VectorType>
259 const AdditionalData &data)
260 : SolverBase<VectorType>(cn, mem)
261 , additional_data(data)
262 , step(0)
263{}
264
265
266
267template <typename VectorType>
270 const AdditionalData &data)
272 , additional_data(data)
273 , step(0)
274{}
275
276
277
278template <typename VectorType>
280void SolverQMRS<VectorType>::print_vectors(const unsigned int,
281 const VectorType &,
282 const VectorType &,
283 const VectorType &) const
284{}
285
286
287
288template <typename VectorType>
290template <typename MatrixType, typename PreconditionerType>
294void SolverQMRS<VectorType>::solve(const MatrixType &A,
295 VectorType &x,
296 const VectorType &b,
297 const PreconditionerType &preconditioner)
298{
299 LogStream::Prefix prefix("SQMR");
300
301
302 // temporary vectors, allocated through the @p VectorMemory object at the
303 // start of the actual solution process and deallocated at the end.
304 typename VectorMemory<VectorType>::Pointer Vr(this->memory);
305 typename VectorMemory<VectorType>::Pointer Vu(this->memory);
306 typename VectorMemory<VectorType>::Pointer Vq(this->memory);
307 typename VectorMemory<VectorType>::Pointer Vt(this->memory);
308 typename VectorMemory<VectorType>::Pointer Vd(this->memory);
309
310
311 // resize the vectors, but do not set
312 // the values since they'd be overwritten
313 // soon anyway.
314 Vr->reinit(x, true);
315 Vu->reinit(x, true);
316 Vq->reinit(x, true);
317 Vt->reinit(x, true);
318 Vd->reinit(x, true);
319
320 step = 0;
321
322 IterationResult state(SolverControl::failure, 0);
323
324 do
325 {
326 if (step > 0)
327 deallog << "Restart step " << step << std::endl;
328 state = iterate(A, x, b, preconditioner, *Vr, *Vu, *Vq, *Vt, *Vd);
329 }
330 while (state.state == SolverControl::iterate);
331
332
333 // in case of failure: throw exception
334 AssertThrow(state.state == SolverControl::success,
335 SolverControl::NoConvergence(step, state.last_residual));
336 // otherwise exit as normal
337}
338
339
340
341template <typename VectorType>
343template <typename MatrixType, typename PreconditionerType>
345 SolverQMRS<VectorType>::iterate(const MatrixType &A,
346 VectorType &x,
347 const VectorType &b,
348 const PreconditionerType &preconditioner,
349 VectorType &r,
350 VectorType &u,
351 VectorType &q,
352 VectorType &t,
353 VectorType &d)
354{
356
357 int it = 0;
358
359 double tau, rho, theta = 0;
360 double res;
361
362 // Compute the start residual
363 A.vmult(r, x);
364 r.sadd(-1., 1., b);
365
366 // Doing the initial preconditioning
367 if (additional_data.left_preconditioning)
368 {
369 // Left preconditioning
370 preconditioner.vmult(t, r);
371 q = t;
372 }
373 else
374 {
375 // Right preconditioning
376 t = r;
377 preconditioner.vmult(q, t);
378 }
379
380 tau = t.norm_sqr();
381 res = std::sqrt(tau);
382
383 if (this->iteration_status(step, res, x) == SolverControl::success)
384 return IterationResult(SolverControl::success, res);
385
386 rho = q * r;
387
388 while (state == SolverControl::iterate)
389 {
390 ++step;
391 ++it;
392 //--------------------------------------------------------------
393 // Step 1: apply the system matrix and compute one inner product
394 //--------------------------------------------------------------
395 A.vmult(t, q);
396 const double sigma = q * t;
397
398 // Check the breakdown criterion
399 if (additional_data.breakdown_testing == true &&
400 std::fabs(sigma) < additional_data.breakdown_threshold)
401 return IterationResult(SolverControl::iterate, res);
402 // Update the residual
403 const double alpha = rho / sigma;
404 r.add(-alpha, t);
405
406 //--------------------------------------------------------------
407 // Step 2: update the solution vector
408 //--------------------------------------------------------------
409 const double theta_old = theta;
410
411 // Apply the preconditioner
412 if (additional_data.left_preconditioning)
413 {
414 // Left Preconditioning
415 preconditioner.vmult(t, r);
416 }
417 else
418 {
419 // Right Preconditioning
420 t = r;
421 }
422
423 // Double updates
424 theta = t * t / tau;
425 const double psi = 1. / (1. + theta);
426 tau *= theta * psi;
427
428 // Actual update of the solution vector
429 d.sadd(psi * theta_old, psi * alpha, q);
430 x += d;
431
432 print_vectors(step, x, r, d);
433
434 // Check for convergence
435 // Compute a simple and cheap upper bound of the norm of the residual
436 // vector b-Ax
437 res = std::sqrt((it + 1) * tau);
438 // If res lies close enough, within the desired tolerance, calculate the
439 // exact residual
440 if (res < additional_data.solver_tolerance)
441 {
442 A.vmult(u, x);
443 u.sadd(-1., 1., b);
444 res = u.l2_norm();
445 }
446 state = this->iteration_status(step, res, x);
447 if ((state == SolverControl::success) ||
448 (state == SolverControl::failure))
449 return IterationResult(state, res);
450
451 //--------------------------------------------------------------
452 // Step 3: check breakdown criterion and update the vectors
453 //--------------------------------------------------------------
454 if (additional_data.breakdown_testing == true &&
455 std::fabs(sigma) < additional_data.breakdown_threshold)
456 return IterationResult(SolverControl::iterate, res);
457
458 const double rho_old = rho;
459
460 // Applying the preconditioner
461 if (additional_data.left_preconditioning)
462 {
463 // Left preconditioning
464 u = t;
465 }
466 else
467 {
468 // Right preconditioning
469 preconditioner.vmult(u, t);
470 }
471
472 // Double and vector updates
473 rho = u * r;
474 const double beta = rho / rho_old;
475 q.sadd(beta, 1., u);
476 }
477 return IterationResult(SolverControl::success, res);
478}
479
480#endif // DOXYGEN
481
483
484#endif
@ iterate
Continue iteration.
@ success
Stop iteration, goal reached.
@ failure
Stop iteration, goal not reached.
virtual void print_vectors(const unsigned int step, const VectorType &x, const VectorType &r, const VectorType &d) const
IterationResult iterate(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner, VectorType &r, VectorType &u, VectorType &q, VectorType &t, VectorType &d)
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
unsigned int step
SolverQMRS(SolverControl &cn, VectorMemory< VectorType > &mem, const AdditionalData &data=AdditionalData())
SolverQMRS(SolverControl &cn, const AdditionalData &data=AdditionalData())
#define DEAL_II_NAMESPACE_OPEN
Definition config.h:38
#define DEAL_II_CXX20_REQUIRES(condition)
Definition config.h:249
#define DEAL_II_NAMESPACE_CLOSE
Definition config.h:39
#define AssertThrow(cond, exc)
LogStream deallog
Definition logstream.cc:36
std::vector< index_type > data
Definition mpi.cc:734
constexpr char A
Tpetra::Vector< Number, LO, GO, NodeType< MemorySpace > > VectorType
SymmetricTensor< 2, dim, Number > d(const Tensor< 2, dim, Number > &F, const Tensor< 2, dim, Number > &dF_dt)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
AdditionalData(const bool left_preconditioning=false, const double solver_tolerance=1.e-9, const bool breakdown_testing=true, const double breakdown_threshold=1.e-16)
SolverControl::State state
IterationResult(const SolverControl::State state, const double last_residual)