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_idr.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) 2019 - 2025 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_idr_h
14#define dealii_solver_idr_h
15
16
17#include <deal.II/base/config.h>
18
23
26#include <deal.II/lac/solver.h>
28
29#include <cmath>
30#include <random>
31
33
39namespace internal
40{
44 namespace SolverIDRImplementation
45 {
50 template <typename VectorType>
52 {
53 public:
57 TmpVectors(const unsigned int s_param, VectorMemory<VectorType> &vmem);
58
62 ~TmpVectors() = default;
63
68 VectorType &
69 operator[](const unsigned int i) const;
70
77 VectorType &
78 operator()(const unsigned int i, const VectorType &temp);
79
80 private:
85
89 std::vector<typename VectorMemory<VectorType>::Pointer> data;
90 };
91 } // namespace SolverIDRImplementation
92} // namespace internal
93
116template <typename VectorType = Vector<double>>
118class SolverIDR : public SolverBase<VectorType>
119{
120public:
125 {
129 explicit AdditionalData(const unsigned int s = 2)
130 : s(s)
131 {}
132
133 const unsigned int s;
134 };
135
142
149
153 virtual ~SolverIDR() override = default;
154
158 template <typename MatrixType, typename PreconditionerType>
162 void solve(const MatrixType &A,
163 VectorType &x,
164 const VectorType &b,
165 const PreconditionerType &preconditioner);
166
167protected:
173 virtual void
174 print_vectors(const unsigned int step,
175 const VectorType &x,
176 const VectorType &r,
177 const VectorType &d) const;
178
179private:
183 AdditionalData additional_data;
184};
185
187/*------------------------- Implementation ----------------------------*/
188
189#ifndef DOXYGEN
190
191
192namespace internal
193{
194 namespace SolverIDRImplementation
195 {
196 template <typename VectorType>
197 inline TmpVectors<VectorType>::TmpVectors(const unsigned int s_param,
199 : mem(vmem)
200 , data(s_param)
201 {}
202
203
204
205 template <typename VectorType>
206 inline VectorType &
207 TmpVectors<VectorType>::operator[](const unsigned int i) const
208 {
209 AssertIndexRange(i, data.size());
210
211 Assert(data[i] != nullptr, ExcNotInitialized());
212 return *data[i];
213 }
214
215
216
217 template <typename VectorType>
218 inline VectorType &
219 TmpVectors<VectorType>::operator()(const unsigned int i,
220 const VectorType &temp)
221 {
222 AssertIndexRange(i, data.size());
223 if (data[i] == nullptr)
224 {
225 data[i] = std::move(typename VectorMemory<VectorType>::Pointer(mem));
226 data[i]->reinit(temp, true);
227 }
228 return *data[i];
229 }
230
231
232
233 template <typename VectorType,
234 std::enable_if_t<!IsBlockVector<VectorType>::value, VectorType>
235 * = nullptr>
236 unsigned int
237 n_blocks(const VectorType &)
238 {
239 return 1;
240 }
241
242
243
244 template <typename VectorType,
245 std::enable_if_t<IsBlockVector<VectorType>::value, VectorType> * =
246 nullptr>
247 unsigned int
248 n_blocks(const VectorType &vector)
249 {
250 return vector.n_blocks();
251 }
252
253
254
255 template <typename VectorType,
256 std::enable_if_t<!IsBlockVector<VectorType>::value, VectorType>
257 * = nullptr>
258 VectorType &
259 block(VectorType &vector, const unsigned int b)
260 {
261 AssertDimension(b, 0);
262 return vector;
263 }
264
265
266
267 template <typename VectorType,
268 std::enable_if_t<IsBlockVector<VectorType>::value, VectorType> * =
269 nullptr>
270 typename VectorType::BlockType &
271 block(VectorType &vector, const unsigned int b)
272 {
273 return vector.block(b);
274 }
275
276 } // namespace SolverIDRImplementation
277} // namespace internal
278
279
280
281template <typename VectorType>
285 const AdditionalData &data)
286 : SolverBase<VectorType>(cn, mem)
287 , additional_data(data)
288{}
289
290
291
292template <typename VectorType>
294SolverIDR<VectorType>::SolverIDR(SolverControl &cn, const AdditionalData &data)
296 , additional_data(data)
297{}
298
299
300
301template <typename VectorType>
303void SolverIDR<VectorType>::print_vectors(const unsigned int,
304 const VectorType &,
305 const VectorType &,
306 const VectorType &) const
307{}
308
309
310
311template <typename VectorType>
313template <typename MatrixType, typename PreconditionerType>
317void SolverIDR<VectorType>::solve(const MatrixType &A,
318 VectorType &x,
319 const VectorType &b,
320 const PreconditionerType &preconditioner)
321{
322 LogStream::Prefix prefix("IDR(s)");
323
325 unsigned int step = 0;
326
327 const unsigned int s = additional_data.s;
328
329 // Define temporary vectors which do not do not depend on s
330 typename VectorMemory<VectorType>::Pointer r_pointer(this->memory);
331 typename VectorMemory<VectorType>::Pointer v_pointer(this->memory);
332 typename VectorMemory<VectorType>::Pointer uhat_pointer(this->memory);
333
334 VectorType &r = *r_pointer;
335 VectorType &v = *v_pointer;
336 VectorType &uhat = *uhat_pointer;
337
338 r.reinit(x, true);
339 v.reinit(x, true);
340 uhat.reinit(x, true);
341
342 // Initial residual
343 A.vmult(r, x);
344 r.sadd(-1.0, 1.0, b);
345
346 using value_type = typename VectorType::value_type;
347 using real_type = typename numbers::NumberTraits<value_type>::real_type;
348
349 // Check for convergent initial guess
350 real_type res = r.l2_norm();
351 iteration_state = this->iteration_status(step, res, x);
352 if (iteration_state == SolverControl::success)
353 return;
354
355 // Initialize sets of vectors/matrices whose size dependent on s
360
361 // Random number generator for vector entries of
362 // Q (normal distribution, mean=0 sigma=1)
363 std::mt19937 rng;
364 std::normal_distribution<> normal_distribution(0.0, 1.0);
365 for (unsigned int i = 0; i < s; ++i)
366 {
367 // Initialize vectors
368 G(i, x);
369 U(i, x);
370
371 // Compute random set of s orthonormalized vectors Q
372 // Note: the first vector is chosen to be the initial
373 // residual to match BiCGStab (as is done in comparisons
374 // with BiCGStab in the papers listed in the documentation
375 // of this function)
376 VectorType &tmp_q = Q(i, x);
377 if (i != 0)
378 {
379 for (unsigned int b = 0;
380 b < internal::SolverIDRImplementation::n_blocks(tmp_q);
381 ++b)
382 for (auto index : internal::SolverIDRImplementation::block(tmp_q, b)
383 .locally_owned_elements())
384 internal::SolverIDRImplementation::block(tmp_q, b)(index) =
385 normal_distribution(rng);
386 tmp_q.compress(VectorOperation::insert);
387 }
388 else
389 tmp_q = r;
390
391 for (unsigned int j = 0; j < i; ++j)
392 {
393 v = Q[j];
394 v *= (v * tmp_q) / (tmp_q * tmp_q);
395 tmp_q.add(-1.0, v);
396 }
397
398 if (i != 0)
399 tmp_q *= 1.0 / tmp_q.l2_norm();
400
401 M(i, i) = 1.;
402 }
403
404 value_type omega = 1.;
405
406 bool early_exit = false;
407
408 // Outer iteration
409 while (iteration_state == SolverControl::iterate)
410 {
411 ++step;
412
413 // Compute phi
414 Vector<value_type> phi(s);
415 for (unsigned int i = 0; i < s; ++i)
416 phi(i) = Q[i] * r;
417
418 // Inner iteration over s
419 for (unsigned int k = 0; k < s; ++k)
420 {
421 // Solve M(k:s)*gamma = phi(k:s)
423 {
424 Vector<value_type> phik(s - k);
425 FullMatrix<value_type> Mk(s - k, s - k);
426 std::vector<unsigned int> indices;
427 unsigned int j = 0;
428 for (unsigned int i = k; i < s; ++i, ++j)
429 {
430 indices.push_back(i);
431 phik(j) = phi(i);
432 }
433 Mk.extract_submatrix_from(M, indices, indices);
434
435 FullMatrix<value_type> Mk_inv(s - k, s - k);
436 Mk_inv.invert(Mk);
437 Mk_inv.vmult(gamma, phik);
438 }
439
440 v = r;
441
442 if (step > 1)
443 {
444 for (unsigned int i = k, j = 0; i < s; ++i, ++j)
445 v.add(-gamma(j), G[i]);
446 }
447
448 preconditioner.vmult(uhat, v);
449
450 if (step > 1)
451 {
452 uhat.sadd(omega, gamma(0), U[k]);
453 for (unsigned int i = k + 1, j = 1; i < s; ++i, ++j)
454 uhat.add(gamma(j), U[i]);
455 }
456 else
457 uhat *= omega;
458
459 A.vmult(G[k], uhat);
460
461 // Update G and U
462 // Orthogonalize G[k] to Q0,..,Q_{k-1} and update uhat
463 if (k > 0)
464 {
465 value_type alpha = Q[0] * G[k] / M(0, 0);
466 for (unsigned int i = 1; i < k; ++i)
467 {
468 const value_type alpha_old = alpha;
469 alpha = G[k].add_and_dot(-alpha, G[i - 1], Q[i]) / M(i, i);
470
471 // update uhat every other iteration to reduce vector access
472 if (i % 2 == 1)
473 uhat.add(-alpha_old, U[i - 1], -alpha, U[i]);
474 }
475 M(k, k) = G[k].add_and_dot(-alpha, G[k - 1], Q[k]);
476 if (k % 2 == 1)
477 uhat.add(-alpha, U[k - 1]);
478 }
479 else
480 M(k, k) = G[k] * Q[k];
481
482 U[k].swap(uhat);
483
484 // Update kth column of M
485 for (unsigned int i = k + 1; i < s; ++i)
486 M(i, k) = Q[i] * G[k];
487
488 // Orthogonalize r to Q0,...,Qk, update x
489 {
490 const value_type beta = phi(k) / M(k, k);
491 r.add(-beta, G[k]);
492 x.add(beta, U[k]);
493
494 print_vectors(step, x, r, U[k]);
495
496 // Check for early convergence. If so, store
497 // information in early_exit so that outer iteration
498 // is broken before recomputing the residual
499 res = r.l2_norm();
500 iteration_state = this->iteration_status(step, res, x);
501 if (iteration_state != SolverControl::iterate)
502 {
503 early_exit = true;
504 break;
505 }
506
507 // Update phi
508 if (k + 1 < s)
509 {
510 for (unsigned int i = 0; i < k + 1; ++i)
511 phi(i) = 0.0;
512 for (unsigned int i = k + 1; i < s; ++i)
513 phi(i) -= beta * M(i, k);
514 }
515 }
516 }
517 if (early_exit == true)
518 break;
519
520 // Update r and x
521 preconditioner.vmult(uhat, r);
522 A.vmult(v, uhat);
523
524 omega = (v * r) / (v * v);
525
526 res = std::sqrt(r.add_and_dot(-1.0 * omega, v, r));
527 x.add(omega, uhat);
528
529 print_vectors(step, x, r, uhat);
530
531 // Check for convergence
532 iteration_state = this->iteration_status(step, res, x);
533 if (iteration_state != SolverControl::iterate)
534 break;
535 }
536
537 if (iteration_state != SolverControl::success)
538 AssertThrow(false, SolverControl::NoConvergence(step, res));
539}
540
541
542#endif // DOXYGEN
543
545
546#endif
@ iterate
Continue iteration.
@ success
Stop iteration, goal reached.
virtual void print_vectors(const unsigned int step, const VectorType &x, const VectorType &r, const VectorType &d) const
SolverIDR(SolverControl &cn, const AdditionalData &data=AdditionalData())
void solve(const MatrixType &A, VectorType &x, const VectorType &b, const PreconditionerType &preconditioner)
SolverIDR(SolverControl &cn, VectorMemory< VectorType > &mem, const AdditionalData &data=AdditionalData())
virtual ~SolverIDR() override=default
TmpVectors(const unsigned int s_param, VectorMemory< VectorType > &vmem)
VectorType & operator()(const unsigned int i, const VectorType &temp)
VectorType & operator[](const unsigned int i) const
std::vector< typename VectorMemory< VectorType >::Pointer > data
Definition solver_idr.h:89
#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 Assert(cond, exc)
#define AssertDimension(dim1, dim2)
#define AssertIndexRange(index, range)
static ::ExceptionBase & ExcNotInitialized()
#define AssertThrow(cond, exc)
std::vector< index_type > data
Definition mpi.cc:734
constexpr char U
constexpr char A
Tpetra::Vector< Number, LO, GO, NodeType< MemorySpace > > VectorType
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
long double gamma(const unsigned int n)
::VectorizedArray< Number, width > sqrt(const ::VectorizedArray< Number, width > &)
const unsigned int s
Definition solver_idr.h:133
AdditionalData(const unsigned int s=2)
Definition solver_idr.h:129