MFEM v4.10.0
Finite element discretization library
Loading...
Searching...
No Matches
ginkgo.hpp
Go to the documentation of this file.
1// Copyright (c) 2010-2026, Lawrence Livermore National Security, LLC. Produced
2// at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3// LICENSE and NOTICE for details. LLNL-CODE-806117.
4//
5// This file is part of the MFEM library. For more information and source code
6// availability visit https://mfem.org.
7//
8// MFEM is free software; you can redistribute it and/or modify it under the
9// terms of the BSD-3 license. We welcome feedback and contributions, see file
10// CONTRIBUTING.md for details.
11
12#ifndef MFEM_GINKGO
13#define MFEM_GINKGO
14
15#include "../config/config.hpp"
16
17#ifdef MFEM_USE_GINKGO
18
19#include "operator.hpp"
20#include "sparsemat.hpp"
21#include "solvers.hpp"
22
23#include <ginkgo/ginkgo.hpp>
24
25#include <iomanip>
26#include <ios>
27#include <string>
28#include <vector>
29#include <fstream>
30#include <iostream>
31#include <type_traits>
32
33#define MFEM_GINKGO_VERSION \
34 ((GKO_VERSION_MAJOR*100 + GKO_VERSION_MINOR)*100 + GKO_VERSION_PATCH)
35
36namespace mfem
37{
38namespace Ginkgo
39{
40
41template <typename T> using gko_array = gko::array<T>;
42#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
43// for interoperability with hypre integer types
45 std::conditional_t<sizeof(HYPRE_Int) == sizeof(std::int32_t), std::int32_t,
46 std::conditional_t<sizeof(HYPRE_Int) == sizeof(std::int64_t), std::int64_t, void>>;
48 std::conditional_t<sizeof(HYPRE_BigInt) == sizeof(std::int32_t), std::int32_t,
49 std::conditional_t<sizeof(HYPRE_BigInt) == sizeof(std::int64_t), std::int64_t, void>>;
50static_assert(!std::is_void_v<gko_hypre_int>,
51 "HYPRE_Int type is incompatible with Ginkgo");
52static_assert(!std::is_void_v<gko_hypre_bigint>,
53 "HYPRE_BigInt type is incompatible with Ginkgo");
54#endif
55
56/**
57* @defgroup Ginkgo Ginkgo interface
58*
59* @brief Wrappers for using the Ginkgo library of high-performance linear
60* solvers and preconditioners with MFEM.
61*/
62
63/**
64* Helper class for a case where a wrapped MFEM Vector
65* should be owned by Ginkgo, and deleted when the wrapper
66* object goes out of scope.
67*/
68template <typename T>
70{
71public:
72 using pointer = T *;
73
74 // Destroys an MFEM object. Requires object to have a Destroy() method.
75 void operator()(pointer ptr) const noexcept { ptr->Destroy(); }
76};
77
78/**
79* This class wraps an MFEM vector object for Ginkgo's use. It
80* allows Ginkgo and MFEM to operate directly on the same
81* data, and is necessary to use MFEM Operators with Ginkgo
82* solvers.
83*
84* @ingroup Ginkgo
85*/
86
87class VectorWrapper : public gko::matrix::Dense<real_t>
88{
89public:
90 VectorWrapper(std::shared_ptr<const gko::Executor> exec,
91 gko::size_type size, Vector *mfem_vec,
92 bool ownership = false)
93 : gko::matrix::Dense<real_t>(
94 exec,
95 gko::dim<2> {size, 1},
97 size,
98 mfem_vec->ReadWrite(
99 exec != exec->get_master() ? true : false)),
100 1)
101 {
102 // This controls whether or not we want Ginkgo to own its MFEM Vector.
103 // Normally, when we are wrapping an MFEM Vector created outside
104 // Ginkgo, we do not want ownership to be true. However, Ginkgo
105 // creates its own temporary vectors as part of its solvers, and
106 // these will be owned (and deleted) by Ginkgo.
107 if (ownership)
108 {
109 using deleter = gko_mfem_destroy<Vector>;
110 wrapped_vec = std::unique_ptr<Vector,
111 std::function<void(Vector *)>>(
112 mfem_vec, deleter{});
113 }
114 else
115 {
116 using deleter = gko::null_deleter<Vector>;
117 wrapped_vec = std::unique_ptr<Vector,
118 std::function<void(Vector *)>>(
119 mfem_vec, deleter{});
120 }
121 }
122
123 static std::unique_ptr<VectorWrapper> create(
124 std::shared_ptr<const gko::Executor> exec,
125 gko::size_type size,
126 Vector *mfem_vec,
127 bool ownership = false)
128 {
129 return std::unique_ptr<VectorWrapper>(
130 new VectorWrapper(exec, size, mfem_vec, ownership));
131 }
132
133 // Return reference to MFEM Vector object
134 Vector &get_mfem_vec_ref() { return *(this->wrapped_vec.get()); }
135
136 // Return const reference to MFEM Vector object
137 const Vector &get_mfem_vec_const_ref() const { return *(this->wrapped_vec.get()); }
138
139 // Override base Dense class implementation for creating new vectors
140 // with same executor and size as self
141 std::unique_ptr<gko::matrix::Dense<real_t>>
142 create_with_same_config() const override
143 {
144 Vector *mfem_vec = new Vector(
145 this->get_size()[0],
146 this->wrapped_vec.get()->GetMemory().GetMemoryType());
147
148 mfem_vec->UseDevice(this->wrapped_vec.get()->UseDevice());
149
150 // If this function is called, Ginkgo is creating this
151 // object and should control the memory, so ownership is
152 // set to true
153 return VectorWrapper::create(this->get_executor(),
154 this->get_size()[0],
155 mfem_vec,
156 true);
157 }
158
159 // Override base Dense class implementation for creating new vectors
160 // with same executor and type as self, but with a different size.
161 // This function will create "one large VectorWrapper" of size
162 // size[0] * size[1], since MFEM Vectors only have one dimension.
163 std::unique_ptr<gko::matrix::Dense<real_t>> create_with_type_of_impl(
164 std::shared_ptr<const gko::Executor> exec,
165 const gko::dim<2> &size,
166 gko::size_type stride) const override
167 {
168 // Only stride of 1 is allowed for VectorWrapper type
169 if (stride > 1)
170 {
171 throw gko::Error(
172 __FILE__, __LINE__,
173 "VectorWrapper cannot be created with stride > 1");
174 }
175 // Compute total size of new Vector
176 gko::size_type total_size = size[0]*size[1];
177 Vector *mfem_vec = new Vector(
178 total_size,
179 this->wrapped_vec.get()->GetMemory().GetMemoryType());
180
181 mfem_vec->UseDevice(this->wrapped_vec.get()->UseDevice());
182
183 // If this function is called, Ginkgo is creating this
184 // object and should control the memory, so ownership is
185 // set to true
187 this->get_executor(), total_size, mfem_vec,
188 true);
189 }
190
191 // Override base Dense class implementation for creating new sub-vectors
192 // from a larger vector.
193 std::unique_ptr<gko::matrix::Dense<real_t>> create_submatrix_impl(
194 const gko::span &rows,
195 const gko::span &columns,
196 const gko::size_type stride) override
197 {
198
199 gko::size_type num_rows = rows.end - rows.begin;
200 gko::size_type num_cols = columns.end - columns.begin;
201 // Data in the Dense matrix will be stored in row-major format.
202 // Check that we only have one column, and that the stride = 1
203 // (only allowed value for VectorWrappers).
204 if (num_cols > 1 || stride > 1)
205 {
206 throw gko::BadDimension(
207 __FILE__, __LINE__, __func__, "new_submatrix", num_rows,
208 num_cols,
209 "VectorWrapper submatrix must have one column and stride = 1");
210 }
211 int data_size = static_cast<int>(num_rows * num_cols);
212 int start = static_cast<int>(rows.begin);
213 // Create a new MFEM Vector pointing to this starting point in the data
214 Vector *mfem_vec = new Vector();
215 mfem_vec->MakeRef(*(this->wrapped_vec.get()), start, data_size);
216 mfem_vec->UseDevice(this->wrapped_vec.get()->UseDevice());
217
218 // If this function is called, Ginkgo is creating this
219 // object and should control the memory, so ownership is
220 // set to true (but MFEM doesn't own and won't delete
221 // the data, at it's only a reference to the parent Vector)
223 this->get_executor(), data_size, mfem_vec,
224 true);
225 }
226
227private:
228 std::unique_ptr<Vector, std::function<void(Vector *)>> wrapped_vec;
229};
230
231/**
232* This class wraps an MFEM Operator for Ginkgo, to make its Mult()
233* function available to Ginkgo, provided the input and output vectors
234* are of the VectorWrapper type.
235* Note that this class does NOT take ownership of the MFEM Operator.
236*
237* @ingroup Ginkgo
238*/
240 : public gko::EnableLinOp<OperatorWrapper>,
241 public gko::EnableCreateMethod<OperatorWrapper>
242{
243public:
244 OperatorWrapper(std::shared_ptr<const gko::Executor> exec,
245 gko::size_type size = 0,
246 const Operator *oper = NULL)
247 : gko::EnableLinOp<OperatorWrapper>(exec, gko::dim<2> {size, size}),
248 gko::EnableCreateMethod<OperatorWrapper>()
249 {
250 this->wrapped_oper = oper;
251 }
252
253protected:
254 void apply_impl(const gko::LinOp *b, gko::LinOp *x) const override;
255 void apply_impl(const gko::LinOp *alpha, const gko::LinOp *b,
256 const gko::LinOp *beta, gko::LinOp *x) const override;
257
258private:
259 const Operator *wrapped_oper;
260};
261
262#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
263// Parallel (distributed) wrappers
265 : public gko::EnableLinOp<ParallelOperatorWrapper>,
266 public gko::experimental::distributed::DistributedBase,
267 public gko::EnableCreateMethod<ParallelOperatorWrapper>
268{
269public:
270 ParallelOperatorWrapper(std::shared_ptr<const gko::Executor> exec,
271 gko::experimental::mpi::communicator comm,
272 gko::size_type size = 0,
273 const Operator *oper = NULL)
274 : gko::EnableLinOp<ParallelOperatorWrapper>(exec, gko::dim<2> {size, size}),
275 gko::experimental::distributed::DistributedBase(comm),
276 gko::EnableCreateMethod<ParallelOperatorWrapper>()
277 {
278 this->wrapped_oper = oper;
279 }
280
281protected:
282 void apply_impl(const gko::LinOp *b, gko::LinOp *x) const override;
283 void apply_impl(const gko::LinOp *alpha, const gko::LinOp *b,
284 const gko::LinOp *beta, gko::LinOp *x) const override;
285
286private:
287 const Operator *wrapped_oper;
288};
289
291 gko::experimental::distributed::Vector<real_t>
292{
293public:
294 ParallelVectorWrapper(std::shared_ptr<const gko::Executor> exec,
295 gko::experimental::mpi::communicator comm,
296 Ginkgo::VectorWrapper *wrapped_local_mfem_vec,
297 HYPRE_BigInt global_rows, HYPRE_BigInt global_cols)
298 : gko::experimental::distributed::Vector<real_t>(
299 exec,
300 comm,
301 gko::dim<2>(global_rows, global_cols),
302 gko::make_dense_view(gko::as<gko::matrix::Dense<real_t>>
303 (wrapped_local_mfem_vec))
304 )
305 {
306 this->local_wrapped_vec = std::unique_ptr<Ginkgo::VectorWrapper>
307 (wrapped_local_mfem_vec);
308 }
309
310 static std::unique_ptr<ParallelVectorWrapper> create(
311 std::shared_ptr<const gko::Executor> exec,
312 gko::experimental::mpi::communicator comm,
313 Ginkgo::VectorWrapper *wrapped_local_mfem_vec,
314 HYPRE_BigInt global_rows, HYPRE_BigInt global_cols)
315 {
316 return std::unique_ptr<ParallelVectorWrapper>(
317 new ParallelVectorWrapper(exec, comm, wrapped_local_mfem_vec, global_rows,
318 global_cols));
319 }
320
321 // Return pointer to local VectorWrapper object
322 Ginkgo::VectorWrapper *get_local_wrapped_vec() { return (this->local_wrapped_vec.get()); }
323
324 // Return pointer to local VectorWrapper object, const version
325 const Ginkgo::VectorWrapper *get_local_wrapped_vec_const() const { return (this->local_wrapped_vec.get()); }
326
327 // Override base Dense class implementation for creating new vectors
328 // with same executor and size as self
329 std::unique_ptr<gko::experimental::distributed::Vector<real_t>>
330 create_with_same_config() const override
331 {
332 mfem::Vector *mfem_vec = new mfem::Vector(
333 this->get_local_vector()->get_size()[0],
334 (this->local_wrapped_vec.get()->get_mfem_vec_const_ref()).GetMemory().GetMemoryType());
335
336 mfem_vec->UseDevice((
337 this->local_wrapped_vec.get()->get_mfem_vec_const_ref()).UseDevice());
338 Ginkgo::VectorWrapper *gko_local_vec = new Ginkgo::VectorWrapper(
339 this->get_executor(),
340 this->get_local_vector()->get_size()[0],
341 mfem_vec,
342 true);
343
344 auto new_dist_vec = ParallelVectorWrapper::create(this->get_executor(),
345 this->get_communicator(),
346 gko_local_vec,
347 this->get_size()[0],
348 this->get_size()[1]);
349 return new_dist_vec;
350 }
351
352 // Override base class implementation for creating new vectors
353 // with same executor and type as self, but with a different size.
354 // This function will create "one large VectorWrapper" locally, with
355 // local size size[0] * size[1], since MFEM Vectors only have one dimension.
356 std::unique_ptr<gko::experimental::distributed::Vector<real_t>>
358 std::shared_ptr<const gko::Executor> exec,
359 const gko::dim<2> &global_size,
360 const gko::dim<2> &local_size,
361 gko::size_type stride) const override
362 {
363 // Only stride of 1 is allowed for (Parallel)VectorWrapper type
364 if (stride > 1)
365 {
366 throw gko::Error(
367 __FILE__, __LINE__,
368 "ParallelVectorWrapper cannot be created with stride > 1");
369 }
370 // Compute total size of new MFEM Vector
371 gko::size_type total_local_size = local_size[0]*local_size[1];
372 mfem::Vector *local_mfem_vec = new mfem::Vector(
373 total_local_size,
374 (this->local_wrapped_vec.get()->get_mfem_vec_const_ref()).GetMemory().GetMemoryType());
375 local_mfem_vec->UseDevice(
376 this->local_wrapped_vec.get()->get_mfem_vec_const_ref().UseDevice());
377
378 Ginkgo::VectorWrapper *gko_local_vec = new Ginkgo::VectorWrapper(
379 this->get_executor(),
380 total_local_size,
381 local_mfem_vec,
382 true);
383
384 auto new_dist_vec = ParallelVectorWrapper::create(this->get_executor(),
385 this->get_communicator(),
386 gko_local_vec,
387 global_size[0],
388 global_size[1]);
389 return new_dist_vec;
390 }
391
392 // Override base Vector class implementation for creating new sub-vectors from
393 // a larger vector.
394 std::unique_ptr<gko::experimental::distributed::Vector<real_t>>
396 gko::local_span rows, gko::local_span columns,
397 gko::dim<2> global_size) override
398 {
399 gko::size_type num_rows = rows.end - rows.begin;
400 gko::size_type num_cols = columns.end - columns.begin;
401 // Data in the Dense matrix will be stored in row-major format.
402 // Check that we only have one column.
403 if (num_cols > 1)
404 {
405 throw gko::BadDimension(
406 __FILE__, __LINE__, __func__, "new_submatrix", num_rows,
407 num_cols,
408 "ParallelVectorWrapper submatrix must have one column");
409 }
410 int data_size = static_cast<int>(num_rows * num_cols);
411 int start = static_cast<int>(rows.begin);
412 // Create a new MFEM Vector pointing to this starting point in the data
413 mfem::Vector *local_mfem_vec = new mfem::Vector();
414 local_mfem_vec->MakeRef(this->local_wrapped_vec.get()->get_mfem_vec_ref(),
415 start, data_size);
416 local_mfem_vec->UseDevice(
417 this->local_wrapped_vec.get()->get_mfem_vec_const_ref().UseDevice());
418
419 Ginkgo::VectorWrapper *gko_local_vec = new Ginkgo::VectorWrapper(
420 this->get_executor(),
421 data_size,
422 local_mfem_vec,
423 true);
424
425 auto new_dist_vec = ParallelVectorWrapper::create(this->get_executor(),
426 this->get_communicator(),
427 gko_local_vec,
428 global_size[0],
429 global_size[1]);
430 return new_dist_vec;
431
432 }
433
434private:
435 std::unique_ptr<Ginkgo::VectorWrapper> local_wrapped_vec;
436};
437#endif // check for MPI
438
439// Utility function which gets the scalar value of a Ginkgo gko::matrix::Dense
440// matrix representing the norm of a vector.
441template <typename ValueType=real_t>
442real_t get_norm(const gko::matrix::Dense<ValueType> *norm)
443{
444 // Put the value on CPU thanks to the master executor
445 auto cpu_norm = clone(norm->get_executor()->get_master(), norm);
446 // Return the scalar value contained at position (0, 0)
447 return cpu_norm->at(0, 0);
448}
449
450#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
451// Utility function which gets the scalar value of a Ginkgo
452// matrix representing the norm of a distributed vector.
453template <typename ValueType=real_t>
454real_t get_norm(const gko::experimental::distributed::Vector<ValueType> *norm)
455{
456 // Put the value on CPU thanks to the master executor
457 auto cpu_norm = clone(norm->get_executor()->get_master(),
458 norm->get_local_vector());
459 // Return the scalar value contained at position (0, 0)
460 return cpu_norm->at(0, 0);
461}
462#endif
463
464// Utility function which computes the norm of a Ginkgo gko::matrix::Dense
465// vector.
466template <typename VecType, typename ValueType=real_t>
467real_t compute_norm(const VecType *b)
468{
469 // Get the executor of the vector
470 auto exec = b->get_executor();
471 // Initialize a result scalar containing the value 0.0.
472 auto b_norm = gko::initialize<gko::matrix::Dense<ValueType>>({0.0}, exec);
473 // Use the dense `compute_norm2` function to compute the norm.
474 b->compute_norm2(b_norm);
475 // Use the other utility function to return the norm contained in `b_norm``
476 return get_norm<ValueType>(b_norm.get());
477}
478
479/**
480 * Custom gko::log::Logger base class for logging the final residual norm and
481 * iteration count. This is necessary because some solvers (e.g., IR) will not
482 * have the final residual available if they stop due to reaching maximum
483 * iterations prior to convergence, and the standard Convergence logger will not
484 * respect the use of derived types (VectorWrapper/ParallelVectorWrapper) when
485 * computing the final residual.
486 *
487 * This base class should not be used directly; solvers should use
488 * EnableConvergenceLogger, which has vector type as a template parameter,
489 * instead.
490 *
491 * @ingroup Ginkgo
492 */
493class ConvergenceLogger : public gko::log::Logger
494{
495
496public:
498
500
502
503 // Ginkgo 1.5 and older: version for solver that doesn't log implicit res norm
504 void on_iteration_complete(const gko::LinOp *op,
505 const gko::size_type &iteration,
506 const gko::LinOp *residual,
507 const gko::LinOp *solution,
508 const gko::LinOp *residual_norm) const override
509 {
510 MFEM_ABORT("Error: Ginkgo logging function for v1.5 or older was called");
511 }
512 // Ginkgo 1.5 and older: version with implicit residual norm
513 void on_iteration_complete(const gko::LinOp *op,
514 const gko::size_type &iteration,
515 const gko::LinOp *residual,
516 const gko::LinOp *solution,
517 const gko::LinOp *residual_norm,
518 const gko::LinOp *implicit_sq_residual_norm) const override
519 {
520 MFEM_ABORT("Error: Ginkgo logging function for v1.5 or older was called");
521 }
522 // Ginkgo 1.6 and newer
523 void on_iteration_complete(const gko::LinOp *op,
524 const gko::LinOp *rhs,
525 const gko::LinOp *solution,
526 const gko::size_type &iteration,
527 const gko::LinOp *residual,
528 const gko::LinOp *residual_norm,
529 const gko::LinOp *implicit_sq_residual_norm,
530 const gko::array<gko::stopping_status>* status,
531 bool stopped) const override
532 {
533 if (stopped)
534 {
535 this->convergence_iteration_complete_core(iteration, residual, solution,
536 residual_norm,
537 implicit_sq_residual_norm, status);
538 }
539 }
540
541 // Construct the logger and store the system matrix and b vectors
543 :
544 gko::log::Logger(gko::log::Logger::iteration_complete_mask) {}
545
546protected:
547 virtual void convergence_iteration_complete_core(const gko::size_type
548 &iteration,
549 const gko::LinOp *residual,
550 const gko::LinOp *solution,
551 const gko::LinOp *residual_norm,
552 const gko::LinOp *implicit_sq_residual_norm,
553 const gko::array<gko::stopping_status>* status) const = 0;
554
555 // Final number of iterations
556 mutable gko::size_type num_iterations;
557 // Final residual norm
559 // Whether or not convergence was achieved
560 mutable bool convergence_status;
561
562};
563
564/**
565 * This class adds ConvergenceLogger functionality that depends on the type of
566 * vector used to initialize the log. This is the version should be used by Ginkgo
567 * solvers.
568 */
569template <typename VecType>
571{
572public:
573 // Construct the logger and store the system matrix and b vectors
574 EnableConvergenceLogger(std::shared_ptr<const gko::Executor> exec,
575 const gko::LinOp *matrix, const VecType *b,
576 bool compute_real_residual=false)
577 :
579 matrix {matrix},
580 b{b},
581 compute_real_residual{compute_real_residual} {}
582
583private:
584 // Customize the logging hook which is called when an iteration is
585 // completed (here, only after the solver has stopped).
586 void convergence_iteration_complete_core(const gko::size_type &iteration,
587 const gko::LinOp *residual,
588 const gko::LinOp *solution,
589 const gko::LinOp *residual_norm,
590 const gko::LinOp *implicit_sq_residual_norm,
591 const gko::array<gko::stopping_status>* status) const override
592 {
593 gko::array<gko::stopping_status> tmp(status->get_executor()->get_master(),
594 *status);
595 convergence_status = true;
596 for (int i = 0; i < status->get_size(); i++)
597 {
598 if (!tmp.get_data()[i].has_converged())
599 {
600 convergence_status = false;
601 break;
602 }
603 }
604 num_iterations = iteration;
605 // If the solver shares the current solution vector and we want to
606 // compute the residual from that
607 bool has_residual_or_norm = (residual || residual_norm ||
608 implicit_sq_residual_norm);
609 if ((solution && compute_real_residual) || (solution && !has_residual_or_norm))
610 {
611 res = std::move(VecType::create_with_config_of(b).release());
612 // Store the matrix's executor
613 auto exec = matrix->get_executor();
614 // Compute the real residual vector by calling apply on the system
615 // First, compute res = A * x
616 matrix->apply(solution, res);
617 // Now do res = res - b, depending on which vector/oper type
618 auto neg_one = gko::initialize<gko::matrix::Dense<real_t>>({-1.0}, exec);
619 res->add_scaled(neg_one, b);
620 // Compute the norm of the residual vector and store it in residual_norm_
622 }
623 else
624 {
625 // If the solver shares an implicit or recurrent residual norm, log its value
626 if (implicit_sq_residual_norm)
627 {
628 auto dense_norm = gko::as<gko::matrix::Dense<real_t>>
629 (implicit_sq_residual_norm);
630 // Add the norm to the `residual_norms` vector
631 final_residual_norm = std::sqrt(get_norm<real_t>(dense_norm));
632 }
633 // Otherwise, use the recurrent residual vector
634 else if (residual_norm)
635 {
636 auto dense_norm = gko::as<gko::matrix::Dense<real_t>>(residual_norm);
638 }
639 else if (residual)
640 {
641 // Compute the residual vector's norm and store in final_residual_norm
642 auto dense_residual = gko::as<VecType>(residual);
644 }
645 }
646 }
647
648 // Pointer to the system matrix
649 const gko::LinOp *matrix;
650 // Pointer to the right hand sides
651 const VecType *b;
652 // Pointer to the residual workspace vector
653 mutable VecType *res;
654 // Whether or not to compute the residual at every iteration,
655 // rather than using the recurrent norm
656 const bool compute_real_residual;
657};
658
659/**
660 * Custom logger base class which intercepts the residual norm scalar and
661 * solution vector in order to print a table of real vs recurrent (internal
662 * to the solvers) residual norms.
663 *
664 * This base class should not be used directly; solvers should use
665 * EnableResidualLogger, which has vector type as a template parameter,
666 * instead.
667 *
668 * @ingroup Ginkgo
669 */
670class ResidualLogger : public gko::log::Logger
671{
672public:
673 // Output the logger's data in a table format
674 void write() const
675 {
676 // Print a header for the table
678 {
679 mfem::out << "Iteration log with real residual norms:" << std::endl;
680 }
681 else
682 {
683 mfem::out << "Iteration log with residual norms:" << std::endl;
684 }
685 mfem::out << '|' << std::setw(10) << "Iteration" << '|' << std::setw(25)
686 << "Residual Norm" << '|' << std::endl;
687 // Print a separation line. Note that for creating `10` characters
688 // `std::setw()` should be set to `11`.
689 mfem::out << '|' << std::setfill('-') << std::setw(11) << '|' <<
690 std::setw(26) << '|' << std::setfill(' ') << std::endl;
691 // Print the data one by one in the form
692 mfem::out << std::scientific;
693 for (std::size_t i = 0; i < iterations.size(); i++)
694 {
695 mfem::out << '|' << std::setw(10) << iterations[i] << '|'
696 << std::setw(25) << residual_norms[i] << '|' << std::endl;
697 }
698 // std::defaultfloat could be used here but some compilers do not support
699 // it properly, e.g. the Intel compiler
700 mfem::out.unsetf(std::ios_base::floatfield);
701 // Print a separation line
702 mfem::out << '|' << std::setfill('-') << std::setw(11) << '|' <<
703 std::setw(26) << '|' << std::setfill(' ') << std::endl;
704 }
705
706 // Ginkgo 1.5 and older: version for solver that doesn't log implicit res norm
707 void on_iteration_complete(const gko::LinOp *op,
708 const gko::size_type &iteration,
709 const gko::LinOp *residual,
710 const gko::LinOp *solution,
711 const gko::LinOp *residual_norm) const override
712 {
713 this->iteration_complete_core(iteration, residual, solution, residual_norm,
714 nullptr);
715 }
716 // Ginkgo 1.5 and older: version with implicit residual norm
717 void on_iteration_complete(const gko::LinOp *op,
718 const gko::size_type &iteration,
719 const gko::LinOp *residual,
720 const gko::LinOp *solution,
721 const gko::LinOp *residual_norm,
722 const gko::LinOp *implicit_sq_residual_norm) const override
723 {
724 this->iteration_complete_core(iteration, residual, solution, residual_norm,
725 implicit_sq_residual_norm);
726 }
727 // Ginkgo 1.6 and newer
728 void on_iteration_complete(const gko::LinOp *op,
729 const gko::LinOp *rhs,
730 const gko::LinOp *solution,
731 const gko::size_type &iteration,
732 const gko::LinOp *residual,
733 const gko::LinOp *residual_norm,
734 const gko::LinOp *implicit_sq_residual_norm,
735 const gko::array<gko::stopping_status>* status,
736 bool stopped) const override
737 {
738 this->iteration_complete_core(iteration, residual, solution, residual_norm,
739 implicit_sq_residual_norm);
740 }
741
742 // Construct the logger and store the system matrix and b vectors
744 :
745 gko::log::Logger(gko::log::Logger::iteration_complete_mask),
747
748protected:
749 virtual void iteration_complete_core(const gko::size_type &iteration,
750 const gko::LinOp *residual,
751 const gko::LinOp *solution,
752 const gko::LinOp *residual_norm,
753 const gko::LinOp *implicit_sq_residual_norm) const = 0;
754
755 // Vector which stores all the residual norms
756 mutable std::vector<real_t> residual_norms{};
757 // Vector which stores all the iteration numbers
758 mutable std::vector<std::size_t> iterations{};
759 // Whether or not to compute the residual at every iteration,
760 // rather than using the recurrent norm
762};
763
764/**
765 * This class adds ResidualLogger functionality that depends on the type of
766 * vector used to initialize the log. This is the version should be used by Ginkgo
767 * solvers.
768 */
769template <typename VecType>
771{
772public:
773 // Construct the logger and store the system matrix and b vectors
774 EnableResidualLogger(std::shared_ptr<const gko::Executor> exec,
775 const gko::LinOp *matrix, const VecType *b,
776 bool compute_real_residual=false)
777 :
779 matrix {matrix},
780 b{b}
781 {
782 if (compute_real_residual == true)
783 {
784 res = std::move(VecType::create_with_config_of(b).release());
785 }
786 else
787 {
788 res = NULL;
789 }
790 }
791
792private:
793 // Customize the logging hook which is called every time an iteration is
794 // completed.
795 void iteration_complete_core(const gko::size_type &iteration,
796 const gko::LinOp *residual,
797 const gko::LinOp *solution,
798 const gko::LinOp *residual_norm,
799 const gko::LinOp *implicit_sq_residual_norm) const override
800 {
801 // If the solver shares the current solution vector and we want to
802 // compute the residual from that
803 bool has_residual_or_norm = (residual || residual_norm ||
804 implicit_sq_residual_norm);
805 if ((solution && compute_real_residual) || (solution && !has_residual_or_norm))
806 {
807 if (res ==
808 NULL) // Need to allocate res vector if compute_real_residual is false
809 {
810 res = std::move(VecType::create_with_config_of(b).release());
811 }
812 // Store the matrix's executor
813 auto exec = matrix->get_executor();
814 // Compute the real residual vector by calling apply on the system
815 // First, compute res = A * x
816 matrix->apply(solution, res);
817 // Now do res = res - b, depending on which vector/oper type
818 auto neg_one = gko::initialize<gko::matrix::Dense<real_t>>({-1.0}, exec);
819 res->add_scaled(neg_one, b);
820 // Compute the norm of the residual vector and add it to the
821 // `residual_norms` vector
823 }
824 else
825 {
826 // If the solver shares an implicit or recurrent residual norm, log its value
827 if (implicit_sq_residual_norm)
828 {
829 auto dense_norm = gko::as<gko::matrix::Dense<real_t>>
830 (implicit_sq_residual_norm);
831 // Add the norm to the `residual_norms` vector
832 residual_norms.push_back(std::sqrt(get_norm<real_t>(dense_norm)));
833 }
834 // Otherwise, use the recurrent residual norm
835 else if (residual_norm)
836 {
837 auto dense_norm = gko::as<gko::matrix::Dense<real_t>>(residual_norm);
838 // Add the norm to the `residual_norms` vector
839 residual_norms.push_back(get_norm<real_t>(dense_norm));
840 }
841 // Compute the residual vector's norm
842 else
843 {
844 auto dense_residual = gko::as<VecType>(residual);
845 auto norm = compute_norm<VecType, real_t>(dense_residual);
846 // Add the computed norm to the `residual_norms` vector
847 residual_norms.push_back(norm);
848 }
849 }
850 // Add the current iteration number to the `iterations` vector
851 iterations.push_back(iteration);
852 }
853
854 // Pointer to the system matrix
855 const gko::LinOp *matrix;
856 // Pointer to the right hand sides
857 const VecType *b;
858 // Pointer to the residual workspace vector
859 mutable VecType *res;
860};
861
862/**
863* This class wraps a Ginkgo Executor for use in MFEM.
864* Note that objects in the Ginkgo namespace intended to work
865* together, e.g. a Ginkgo solver and preconditioner, should use the same
866* GinkgoExecutor object. In general, most users will want to create
867* one GinkgoExecutor object for use with all Ginkgo-related objects.
868* The wrapper can be created to match MFEM's device configuration.
869*/
871{
872public:
873 // Types of Ginkgo Executors.
875 {
876 /// Reference CPU Executor.
878 /// OpenMP CPU Executor.
879 OMP = 1,
880 /// CUDA GPU Executor.
881 CUDA = 2,
882 /// HIP GPU Executor.
883 HIP = 3
884 };
885 /**
886 * Constructor.
887 * Takes an @p GinkgoExecType argument and creates an Executor.
888 * In Ginkgo, GPU Executors must have an associated host Executor.
889 * This routine will select a CPU Executor based on the OpenMP support
890 * for Ginkgo.
891 */
892 GinkgoExecutor(ExecType exec_type);
893
894 /**
895 * Constructor.
896 * Takes an @p GinkgoExecType argument and creates an Executor.
897 * In Ginkgo, GPU Executors must have an associated host Executor.
898 * This routine allows for explicit setting of the CPU Executor
899 * for GPU backends.
900 */
901 GinkgoExecutor(ExecType exec_type, ExecType host_exec_type);
902
903 /**
904 * Constructor.
905 * Takes an MFEM @p Device object and creates an Executor
906 * that "matches" (e.g., if MFEM is using the CPU, Ginkgo
907 * will choose the Reference or OmpExecutor based on MFEM's
908 * configuration and Ginkgo's capabilities; if MFEM is using
909 * CUDA, Ginkgo will choose the CudaExecutor with a default
910 * CPU Executor based on Ginkgo's OpenMP support).
911 */
912 GinkgoExecutor(Device &mfem_device);
913
914 /**
915 * Constructor.
916 * Takes an MFEM @p Device object and creates an Executor
917 * that "matches", but allows the user to specify the host
918 * Executor for GPU backends.
919 */
920 GinkgoExecutor(Device &mfem_device, ExecType host_exec_type);
921
922 /**
923 * Destructor.
924 */
925 virtual ~GinkgoExecutor() = default;
926
927 std::shared_ptr<gko::Executor> GetExecutor() const
928 {
929 return this->executor;
930 };
931
932private:
933 std::shared_ptr<gko::Executor> executor;
934
935};
936
937/**
938* This class forms the base class for all of Ginkgo's preconditioners. The
939* various derived classes only take the additional data that is specific to them.
940* The entire collection of preconditioners that Ginkgo implements is available
941* at the Ginkgo documentation and manual pages,
942* https://ginkgo-project.github.io/ginkgo/doc/develop.
943*
944* @ingroup Ginkgo
945*/
947{
948public:
949 /**
950 * Constructor.
951 *
952 * The @p exec defines the paradigm where the solution is computed.
953 * Ginkgo currently supports four different executor types:
954 *
955 * + OmpExecutor specifies that the data should be stored and the
956 * associated operations executed on an OpenMP-supporting device (e.g.
957 * host CPU);
958 * + CudaExecutor specifies that the data should be stored and the
959 * operations executed on the NVIDIA GPU accelerator;
960 * + HipExecutor specifies that the data should be stored and the
961 * operations executed on the GPU accelerator using HIP;
962 * + ReferenceExecutor executes a non-optimized reference implementation,
963 * which can be used to debug the library.
964 */
966
967 /**
968 * Constructor.
969 * This is the parallel version. @p comm is either the MPI Communicator
970 * used by the distributed matrix which will be used to generate the
971 * preconditioner, or the communicator used by MFEM for its own preconditioner
972 * which will be wrapped by Ginkgo (see the MFEMPreconditioner class).
973 */
974#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
975 GinkgoPreconditioner(GinkgoExecutor &exec, MPI_Comm comm);
976#endif
977
978 /**
979 * Destructor.
980 */
981 virtual ~GinkgoPreconditioner() = default;
982
983 /**
984 * Generate the preconditioner for the given matrix @p op,
985 * which must be of MFEM SparseMatrix or HypreParMatrix type.
986 * Calling this function is only required when creating a
987 * preconditioner for use with another MFEM solver; to use with
988 * a Ginkgo solver, get the LinOpFactory pointer through @p GetFactory()
989 * and pass to the Ginkgo solver constructor.
990 */
991 void SetOperator(const Operator &op) override;
992
993 /**
994 * Apply the preconditioner to input vector @p x, with out @p y.
995 */
996 void Mult(const Vector &x, Vector &y) const override;
997
998 /**
999 * Return a pointer to the LinOpFactory that will generate the preconditioner
1000 * with the parameters set through the specific constructor.
1001 */
1002 const std::shared_ptr<gko::LinOpFactory> GetFactory() const
1003 {
1004 return this->precond_gen;
1005 };
1006
1007 /**
1008 * Return a pointer to the generated preconditioner for a specific matrix
1009 * (that has previously been set with @p SetOperator).
1010 */
1011 const std::shared_ptr<gko::LinOp> GetGeneratedPreconditioner() const
1012 {
1013 return this->generated_precond;
1014 };
1015
1016 /**
1017 * Return whether this GinkgoPreconditioner object has an explicitly-
1018 * generated preconditioner, built for a specific matrix.
1019 */
1021 {
1022 return this->has_generated_precond;
1023 };
1024
1025protected:
1026 /**
1027 * The Ginkgo generated solver factory object.
1028 */
1029 std::shared_ptr<gko::LinOpFactory> precond_gen;
1030
1031 /**
1032 * Generated Ginkgo preconditioner for a specific matrix, created through
1033 * @p SetOperator(), or a wrapped MFEM preconditioner.
1034 * Must exist to use @p Mult().
1035 */
1036 std::shared_ptr<gko::LinOp> generated_precond;
1037
1038 /**
1039 * The execution paradigm in Ginkgo. The choices are between
1040 * `gko::OmpExecutor`, `gko::CudaExecutor` and `gko::ReferenceExecutor`
1041 * and more details can be found in Ginkgo's documentation.
1042 */
1043 std::shared_ptr<gko::Executor> executor;
1044
1045#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1046 /**
1047 * Pointer to Ginkgo's communicator.
1048 */
1049 std::shared_ptr<gko::experimental::mpi::communicator> gko_comm;
1050#endif
1051
1052 /**
1053 * Whether or not we have generated a specific preconditioner for
1054 * a matrix.
1055 */
1057
1058};
1059
1060/**
1061* This class forms the base class for all of Ginkgo's iterative solvers.
1062* It is not intended to be used directly by MFEM applications. The various
1063* derived classes only take the additional data that is specific to them
1064* and solve the given linear system. The entire collection of solvers that
1065* Ginkgo implements is available at the Ginkgo documentation and manual pages,
1066* https://ginkgo-project.github.io/ginkgo/doc/develop.
1067*
1068* @ingroup Ginkgo
1069*/
1071{
1072public:
1073 /**
1074 * Return a pointer to the LinOpFactory that will generate the solver
1075 * with the parameters set through the specific constructor.
1076 */
1077 const std::shared_ptr<gko::LinOpFactory> GetFactory() const
1078 {
1079 return this->solver_gen;
1080 };
1081
1082 void SetPrintLevel(int print_lvl) { print_level = print_lvl; }
1083
1084 int GetNumIterations() const { return final_iter; }
1085 int GetConverged() const { return converged; }
1086 real_t GetFinalNorm() const { return final_norm; }
1087
1088 /**
1089 * If the Operator is a SparseMatrix, set up a Ginkgo Csr matrix
1090 * to use its data directly. If the Operator is not a matrix,
1091 * create an OperatorWrapper for it and store.
1092 */
1093 void SetOperator(const Operator &op) override;
1094
1095 /**
1096 * Solve the linear system <tt>Ay=x</tt>. Dependent on the information
1097 * provided by derived classes one of Ginkgo's linear solvers is chosen.
1098 */
1099 void Mult(const Vector &x, Vector &y) const override;
1100
1101 /**
1102 * Return whether this GinkgoIterativeSolver object will use
1103 * VectorWrapper types for input and output vectors.
1104 * Note that Mult() will automatically create these wrappers if needed.
1105 */
1107 {
1108 return this->needs_wrapped_vecs;
1109 };
1110
1111 /**
1112 * Destructor.
1113 */
1114 virtual ~GinkgoIterativeSolver() = default;
1115
1116protected:
1117 /**
1118 * Constructor.
1119 *
1120 * The @p exec defines the paradigm where the solution is computed.
1121 * @p use_implicit_res_norm is for internal use by the derived classes
1122 * for specific Ginkgo solvers; it indicates whether the solver makes
1123 * an implicit residual norm estimate available for convergence checking.
1124 * Each derived class automatically sets the correct value when calling this
1125 * base class constructor.
1126 *
1127 */
1130
1131#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1132 /**
1133 * Version for distributed solvers: takes MPI Communicator as an additional
1134 * argument.
1135 */
1137 MPI_Comm comm,
1139#endif
1140
1147 mutable int final_iter;
1148 mutable int converged;
1149
1150 /**
1151 * The Ginkgo solver factory object, to generate specific solvers.
1152 */
1153 std::shared_ptr<gko::LinOpFactory> solver_gen;
1154
1155 /**
1156 * The Ginkgo solver object, generated for a specific operator.
1157 */
1158 std::shared_ptr<gko::LinOp> solver;
1159
1160 /**
1161 * The residual criterion object that controls the reduction of the residual
1162 * relative to the initial residual.
1163 */
1164 std::shared_ptr<gko::stop::ResidualNorm<real_t>::Factory>
1166
1167 /**
1168 * The residual criterion object that controls the reduction of the residual
1169 * based on an absolute tolerance.
1170 */
1171 std::shared_ptr<gko::stop::ResidualNorm<real_t>::Factory>
1173
1174 /**
1175 * The implicit residual criterion object that controls the reduction of the residual
1176 * relative to the initial residual, based on an implicit residual norm value.
1177 */
1178 std::shared_ptr<gko::stop::ImplicitResidualNorm<real_t>::Factory>
1180
1181 /**
1182 * The implicit residual criterion object that controls the reduction of the residual
1183 * based on an absolute tolerance, based on an implicit residual norm value.
1184 */
1185 std::shared_ptr<gko::stop::ImplicitResidualNorm<real_t>::Factory>
1187
1188 /**
1189 * The convergence logger used to check for convergence.
1190 */
1191 mutable std::shared_ptr<ConvergenceLogger> convergence_logger;
1192
1193 /**
1194 * The residual logger object used to log residual history.
1195 */
1196 mutable std::shared_ptr<ResidualLogger> residual_logger;
1197
1198 /**
1199 * The Ginkgo combined factory object is used to create a combined stopping
1200 * criterion to be passed to the solver.
1201 */
1202 std::shared_ptr<gko::stop::Combined::Factory> combined_factory;
1203
1204 /**
1205 * The execution paradigm in Ginkgo. The choices are between
1206 * `gko::OmpExecutor`, `gko::CudaExecutor` and `gko::ReferenceExecutor`
1207 * and more details can be found in Ginkgo's documentation.
1208 */
1209 std::shared_ptr<gko::Executor> executor;
1210
1211#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1212 /**
1213 * Pointer to Ginkgo's communicator.
1214 */
1215 std::shared_ptr<gko::experimental::mpi::communicator> gko_comm;
1216
1217 /**
1218 * Whether or not we need to ensure the diagonal matrix is sorted
1219 * (only true if using Schwarz preconditioner with L1 smoothing).
1220 * This requirement will be removed in a future release of Ginkgo.
1221 */
1223#endif
1224
1225 /**
1226 * Whether or not we need to use VectorWrapper types with this solver.
1227 */
1229
1230 /**
1231 * Whether or not we need to use VectorWrapper types with the preconditioner
1232 * or an inner solver. This value is set upon creation of the
1233 * GinkgoIterativeSolver object and should never change.
1234 */
1236
1237 /** Rebuild the Ginkgo stopping criterion factory with the latest values
1238 * of rel_tol, abs_tol, and max_iter.
1239 */
1240 void update_stop_factory();
1241
1242private:
1243 /**
1244 * Initialize the Ginkgo logger object with event masks. Refer to the logging
1245 * event masks in Ginkgo's .../include/ginkgo/core/log/logger.hpp.
1246 */
1247 void
1248 initialize_ginkgo_log(gko::matrix::Dense<real_t>* b) const;
1249
1250#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1251 void
1252 initialize_ginkgo_log(ParallelVectorWrapper* b) const;
1253#endif
1254
1255 /**
1256 * Pointer to either a Ginkgo CSR matrix or an OperatorWrapper wrapping
1257 * an MFEM Operator (for matrix-free evaluation).
1258 */
1259 std::shared_ptr<gko::LinOp> system_oper;
1260
1261};
1262
1263/**
1264 * This class adds helper functions for updating Ginkgo factories
1265 * and solvers, when the full class type is needed. The derived classes
1266 * should inherit from this class, rather than from GinkgoIterativeSolver
1267 * directly.
1268 */
1269template<typename SolverType>
1271{
1272public:
1275
1276#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1280#endif
1281
1283 {
1284 rel_tol = rtol;
1285 this->update_stop_factory();
1286 auto current_params = gko::as<typename SolverType::Factory>
1287 (solver_gen)->get_parameters();
1288 this->solver_gen = current_params.with_criteria(this->combined_factory)
1289 .on(this->executor);
1290 if (solver)
1291 {
1292 gko::as<SolverType>(solver)->set_stop_criterion_factory(combined_factory);
1293 }
1294 }
1295
1297 {
1298 abs_tol = atol;
1299 this->update_stop_factory();
1300 auto current_params = gko::as<typename SolverType::Factory>
1301 (solver_gen)->get_parameters();
1302 this->solver_gen = current_params.with_criteria(this->combined_factory)
1303 .on(this->executor);
1304 if (solver)
1305 {
1306 gko::as<SolverType>(solver)->set_stop_criterion_factory(combined_factory);
1307 }
1308 }
1309
1310 void SetMaxIter(int max_it)
1311 {
1312 max_iter = max_it;
1313 this->update_stop_factory();
1314 auto current_params = gko::as<typename SolverType::Factory>
1315 (solver_gen)->get_parameters();
1316 this->solver_gen = current_params.with_criteria(this->combined_factory)
1317 .on(this->executor);
1318 if (solver)
1319 {
1320 gko::as<SolverType>(solver)->set_stop_criterion_factory(combined_factory);
1321 }
1322 }
1323
1324#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1325protected:
1326 // This will be true if we are using a Schwarz preconditioner with L1 smooothing.
1327 // (The need for this should be removed in a future Ginkgo release.)
1329 {
1330 bool needs_sorted_diag = false;
1331 auto current_params = gko::as<typename SolverType::Factory>
1332 (solver_gen)->get_parameters();
1333 using schwarz =
1334 gko::experimental::distributed::preconditioner::Schwarz<real_t, int, gko_hypre_bigint>;
1335 auto schwarz_factory = gko::as<typename schwarz::Factory>
1336 (current_params.preconditioner);
1337 if (schwarz_factory != NULL)
1338 {
1339 auto schwarz_factory_params = schwarz_factory->get_parameters();
1340 if (schwarz_factory_params.l1_smoother == true)
1341 {
1342 needs_sorted_diag = true;
1343 }
1344 }
1345 return needs_sorted_diag;
1346 }
1347#endif
1348};
1349
1350
1351/**
1352 * An implementation of the solver interface using the Ginkgo CG solver.
1353 *
1354 * @ingroup Ginkgo
1355 */
1356class CGSolver : public EnableGinkgoSolver<gko::solver::Cg<real_t>>
1357{
1358public:
1359 /**
1360 * Constructor.
1361 *
1362 * @param[in] exec The execution paradigm for the solver.
1363 */
1364 CGSolver(GinkgoExecutor &exec);
1365
1366#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1367 /**
1368 * Constructor.
1369 *
1370 * @param[in] exec The execution paradigm for the solver.
1371 * @param[in] comm MPI communicator to use for communication.
1372 */
1373 CGSolver(GinkgoExecutor &exec, MPI_Comm comm);
1374#endif
1375
1376 /**
1377 * Constructor.
1378 *
1379 * @param[in] exec The execution paradigm for the solver.
1380 * @param[in] preconditioner The preconditioner for the solver.
1381 */
1383 const GinkgoPreconditioner &preconditioner);
1384
1385#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1386 /**
1387 * Constructor.
1388 *
1389 * @param[in] exec The execution paradigm for the solver.
1390 * @param[in] comm MPI communicator to use for communication.
1391 * @param[in] preconditioner The preconditioner for the solver.
1392 */
1394 MPI_Comm comm,
1395 const GinkgoPreconditioner &preconditioner);
1396#endif
1397};
1398
1399
1400/**
1401 * An implementation of the solver interface using the Ginkgo BiCGStab solver.
1402 *
1403 * @ingroup Ginkgo
1404 */
1405class BICGSTABSolver : public EnableGinkgoSolver<gko::solver::Bicgstab<real_t>>
1406{
1407public:
1408 /**
1409 * Constructor.
1410 *
1411 * @param[in] exec The execution paradigm for the solver.
1412 */
1414
1415#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1416 /**
1417 * Constructor.
1418 *
1419 * @param[in] exec The execution paradigm for the solver.
1420 * @param[in] comm MPI communicator to use for communication.
1421 */
1422 BICGSTABSolver(GinkgoExecutor &exec, MPI_Comm comm);
1423#endif
1424
1425 /**
1426 * Constructor.
1427 *
1428 * @param[in] exec The execution paradigm for the solver.
1429 * @param[in] preconditioner The preconditioner for the solver.
1430 */
1432 const GinkgoPreconditioner &preconditioner);
1433
1434#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1435 /**
1436 * Constructor.
1437 *
1438 * @param[in] exec The execution paradigm for the solver.
1439 * @param[in] comm MPI communicator to use for communication.
1440 * @param[in] preconditioner The preconditioner for the solver.
1441 */
1442 BICGSTABSolver(GinkgoExecutor &exec, MPI_Comm comm,
1443 const GinkgoPreconditioner &preconditioner);
1444#endif
1445};
1446
1447/**
1448 * An implementation of the solver interface using the Ginkgo CGS solver.
1449 *
1450 * CGS or the conjugate gradient square method is an iterative type Krylov
1451 * subspace method which is suitable for general systems.
1452 *
1453 * @ingroup Ginkgo
1454 */
1455class CGSSolver : public EnableGinkgoSolver<gko::solver::Cgs<real_t>>
1456{
1457public:
1458 /**
1459 * Constructor.
1460 *
1461 * @param[in] exec The execution paradigm for the solver.
1462 */
1464
1465#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1466 /**
1467 * Constructor.
1468 *
1469 * @param[in] exec The execution paradigm for the solver.
1470 * @param[in] comm MPI communicator to use for communication.
1471 */
1472 CGSSolver(GinkgoExecutor &exec, MPI_Comm comm);
1473#endif
1474
1475 /**
1476 * Constructor.
1477 *
1478 * @param[in] exec The execution paradigm for the solver.
1479 * @param[in] preconditioner The preconditioner for the solver.
1480 */
1482 const GinkgoPreconditioner &preconditioner);
1483
1484#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1485 /**
1486 * Constructor.
1487 *
1488 * @param[in] exec The execution paradigm for the solver.
1489 * @param[in] comm MPI communicator to use for communication.
1490 * @param[in] preconditioner The preconditioner for the solver.
1491 */
1492 CGSSolver(GinkgoExecutor &exec, MPI_Comm comm,
1493 const GinkgoPreconditioner &preconditioner);
1494#endif
1495};
1496
1497/**
1498 * An implementation of the solver interface using the Ginkgo FCG solver.
1499 *
1500 * FCG or the flexible conjugate gradient method is an iterative type Krylov
1501 * subspace method which is suitable for symmetric positive definite methods.
1502 *
1503 * Though this method performs very well for symmetric positive definite
1504 * matrices, it is in general not suitable for general matrices.
1505 *
1506 * In contrast to the standard CG based on the Polack-Ribiere formula, the
1507 * flexible CG uses the Fletcher-Reeves formula for creating the orthonormal
1508 * vectors spanning the Krylov subspace. This increases the computational cost
1509 * of every Krylov solver iteration but allows for non-constant preconditioners.
1510 *
1511 * @ingroup Ginkgo
1512 */
1513class FCGSolver : public EnableGinkgoSolver<gko::solver::Fcg<real_t>>
1514{
1515public:
1516 /**
1517 * Constructor.
1518 *
1519 * @param[in] exec The execution paradigm for the solver.
1520 */
1522
1523#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1524 /**
1525 * Constructor.
1526 *
1527 * @param[in] exec The execution paradigm for the solver.
1528 * @param[in] comm MPI communicator to use for communication.
1529 */
1530 FCGSolver(GinkgoExecutor &exec, MPI_Comm comm);
1531#endif
1532
1533 /**
1534 * Constructor.
1535 *
1536 * @param[in] exec The execution paradigm for the solver.
1537 * @param[in] preconditioner The preconditioner for the solver.
1538 */
1540 const GinkgoPreconditioner &preconditioner);
1541
1542#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1543 /**
1544 * Constructor.
1545 *
1546 * @param[in] exec The execution paradigm for the solver.
1547 * @param[in] comm MPI communicator to use for communication.
1548 * @param[in] preconditioner The preconditioner for the solver.
1549 */
1550 FCGSolver(GinkgoExecutor &exec, MPI_Comm comm,
1551 const GinkgoPreconditioner &preconditioner);
1552#endif
1553};
1554
1555/**
1556 * An implementation of the solver interface using the Ginkgo GMRES solver.
1557 *
1558 * @ingroup Ginkgo
1559 */
1560class GMRESSolver : public EnableGinkgoSolver<gko::solver::Gmres<real_t>>
1561{
1562public:
1563 /**
1564 * Constructor.
1565 *
1566 * @param[in] exec The execution paradigm for the solver.
1567 * @param[in] dim The Krylov dimension of the solver. Value of 0 will
1568 * let Ginkgo use its own internal default value.
1569 */
1570 GMRESSolver(GinkgoExecutor &exec, int dim = 0);
1571
1572#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1573 /**
1574 * Constructor.
1575 *
1576 * @param[in] exec The execution paradigm for the solver.
1577 * @param[in] comm MPI communicator to use for communication.
1578 * @param[in] dim The Krylov dimension of the solver. Value of 0 will
1579 * let Ginkgo use its own internal default value.
1580 */
1581 GMRESSolver(GinkgoExecutor &exec, MPI_Comm comm, int dim = 0);
1582#endif
1583
1584 /**
1585 * Constructor.
1586 *
1587 * @param[in] exec The execution paradigm for the solver.
1588 * @param[in] preconditioner The preconditioner for the solver.
1589 * @param[in] dim The Krylov dimension of the solver. Value of 0 will
1590 * let Ginkgo use its own internal default value.
1591 */
1593 const GinkgoPreconditioner &preconditioner,
1594 int dim = 0);
1595
1596#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1597 /**
1598 * Constructor.
1599 *
1600 * @param[in] exec The execution paradigm for the solver.
1601 * @param[in] comm MPI communicator to use for communication.
1602 * @param[in] preconditioner The preconditioner for the solver.
1603 * @param[in] dim The Krylov dimension of the solver. Value of 0 will
1604 * let Ginkgo use its own internal default value.
1605 */
1607 MPI_Comm comm,
1608 const GinkgoPreconditioner &preconditioner,
1609 int dim = 0);
1610#endif
1611
1612 /**
1613 * Change the Krylov dimension of the solver.
1614 */
1615 void SetKDim(int dim);
1616
1617protected:
1618 int m; // Dimension of Krylov subspace
1619};
1620
1621using gko::solver::cb_gmres::storage_precision;
1622/**
1623 * An implementation of the solver interface using the Ginkgo
1624 * Compressed Basis GMRES solver. With CB-GMRES, the Krylov basis
1625 * is "compressed" by storing in a lower precision. Currently, computations
1626 * are always performed in the MFEM-defined `real_t` precision, when using this
1627 * MFEM integration.
1628 * The Ginkgo storage precision options are accessed
1629 * through Ginkgo::storage_precision::*. The default choice
1630 * is Ginkgo::storage_precision::reduce1, i.e., store in float
1631 * instead of double or half instead of float.
1632 *
1633 * @ingroup Ginkgo
1634 */
1635class CBGMRESSolver : public EnableGinkgoSolver<gko::solver::CbGmres<real_t>>
1636{
1637public:
1638 /**
1639 * Constructor.
1640 *
1641 * @param[in] exec The execution paradigm for the solver.
1642 * @param[in] dim The Krylov dimension of the solver. Value of 0 will
1643 * let Ginkgo use its own internal default value.
1644 * @param[in] prec The storage precision used in the CB-GMRES. Options
1645 * are: keep (keep `real_t` precision), reduce1 (double -> float
1646 * or float -> half), reduce2 (double -> half or float -> half),
1647 * integer (`real_t` -> int64), ireduce1 (double -> int32 or
1648 * float -> int16), ireduce2 (double -> int16 or float -> int16).
1649 * See Ginkgo documentation for more about CB-GMRES.
1650 */
1651 CBGMRESSolver(GinkgoExecutor &exec, int dim = 0,
1652 storage_precision prec = storage_precision::reduce1);
1653
1654 /**
1655 * Constructor.
1656 *
1657 * @param[in] exec The execution paradigm for the solver.
1658 * @param[in] preconditioner The preconditioner for the solver.
1659 * @param[in] dim The Krylov dimension of the solver. Value of 0 will
1660 * let Ginkgo use its own internal default value.
1661 * @param[in] prec The storage precision used in the CB-GMRES. Options
1662 * are: keep (keep `real_t` precision), reduce1 (double -> float
1663 * or float -> half), reduce2 (double -> half or float -> half),
1664 * integer (`real_t` -> int64), ireduce1 (double -> int32 or
1665 * float -> int16), ireduce2 (double -> int16 or float -> int16).
1666 * See Ginkgo documentation for more about CB-GMRES.
1667 */
1669 const GinkgoPreconditioner &preconditioner,
1670 int dim = 0,
1671 storage_precision prec = storage_precision::reduce1);
1672
1673 /**
1674 * Change the Krylov dimension of the solver.
1675 */
1676 void SetKDim(int dim);
1677
1678protected:
1679 int m; // Dimension of Krylov subspace
1680};
1681
1682/**
1683 * An implementation of the solver interface using the Ginkgo IR solver.
1684 *
1685 * Iterative refinement (IR) is an iterative method that uses another coarse
1686 * method to approximate the error of the current solution via the current
1687 * residual.
1688 *
1689 * @ingroup Ginkgo
1690 */
1691class IRSolver : public EnableGinkgoSolver<gko::solver::Ir<real_t>>
1692{
1693public:
1694 /**
1695 * Constructor.
1696 *
1697 * @param[in] exec The execution paradigm for the solver.
1698 */
1699 IRSolver(GinkgoExecutor &exec);
1700
1701#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1702 /**
1703 * Constructor.
1704 *
1705 * @param[in] exec The execution paradigm for the solver.
1706 * @param[in] comm MPI communicator to use for communication.
1707 */
1708 IRSolver(GinkgoExecutor &exec, MPI_Comm comm);
1709#endif
1710
1711 /**
1712 * Constructor.
1713 *
1714 * @param[in] exec The execution paradigm for the solver.
1715 * @param[in] inner_solver The inner solver for the main solver.
1716 */
1718 const GinkgoIterativeSolver &inner_solver);
1719
1720#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1721 /**
1722 * Constructor.
1723 *
1724 * @param[in] exec The execution paradigm for the solver.
1725 * @param[in] comm MPI communicator to use for communication.
1726 * @param[in] inner_solver The inner solver for the main solver.
1727 */
1729 MPI_Comm comm,
1730 const GinkgoIterativeSolver &inner_solver);
1731#endif
1732};
1733
1734/**
1735 * An implementation of the preconditioner interface using the Ginkgo Jacobi
1736 * preconditioner.
1737 *
1738 * @ingroup Ginkgo
1739 */
1741{
1742public:
1743 /**
1744 * Constructor.
1745 *
1746 * @param[in] exec The execution paradigm for the preconditioner.
1747 * @param[in] storage_opt The storage optimization parameter.
1748 * @param[in] accuracy The relative accuracy for the adaptive version.
1749 * @param[in] max_block_size Maximum block size.
1750 * See the Ginkgo documentation for more information on these parameters.
1751 */
1753 GinkgoExecutor &exec,
1754 const std::string &storage_opt = "none",
1755 const real_t accuracy = 1.e-1,
1756 const int max_block_size = 32
1757 );
1758};
1759
1760/**
1761 * An implementation of the preconditioner interface using the Ginkgo
1762 * Incomplete LU preconditioner (ILU(0)).
1763 *
1764 * @ingroup Ginkgo
1765 */
1767{
1768public:
1769 /**
1770 * Constructor.
1771 *
1772 * @param[in] exec The execution paradigm for the preconditioner.
1773 * @param[in] factorization_type The factorization type: "exact" or
1774 * "parilu".
1775 * @param[in] sweeps The number of sweeps to do in the ParIlu
1776 * factorization algorithm. A value of 0 tells Ginkgo to use its
1777 * internal default value. This parameter is ignored in the case
1778 * of an exact factorization.
1779 * @param[in] skip_sort Only set this to true if the input matrix
1780 * that will be used to generate this preconditioner is guaranteed
1781 * to be sorted by column.
1782 *
1783 * Note: The use of this preconditioner will sort any input matrix
1784 * given to it, potentially changing the order of the stored values.
1785 */
1787 GinkgoExecutor &exec,
1788 const std::string &factorization_type = "exact",
1789 const int sweeps = 0,
1790 const bool skip_sort = false
1791 );
1792};
1793
1794/**
1795 * An implementation of the preconditioner interface using the Ginkgo
1796 * Incomplete LU-Incomplete Sparse Approximate Inverse preconditioner.
1797 * The Ilu-ISAI preconditioner differs from the Ilu preconditioner in
1798 * that Incomplete Sparse Approximate Inverses (ISAIs) are formed
1799 * to approximate solving the triangular systems defined by L and U.
1800 * When the preconditioner is applied, these ISAI matrices are applied
1801 * through matrix-vector multiplication.
1802 *
1803 * @ingroup Ginkgo
1804 */
1806{
1807public:
1808 /**
1809 * Constructor.
1810 *
1811 * @param[in] exec The execution paradigm for the preconditioner.
1812 * @param[in] factorization_type The factorization type: "exact" or
1813 * "parilu".
1814 * @param[in] sweeps The number of sweeps to do in the ParIlu
1815 * factorization algorithm. A value of 0 tells Ginkgo to use its
1816 * internal default value. This parameter is ignored in the case
1817 * of an exact factorization.
1818 * @param[in] sparsity_power Parameter determining the sparsity pattern of
1819 * the ISAI approximations.
1820 * @param[in] skip_sort Only set this to true if the input matrix
1821 * that will be used to generate this preconditioner is guaranteed
1822 * to be sorted by column.
1823 * See the Ginkgo documentation for more information on these parameters.
1824 *
1825 * Note: The use of this preconditioner will sort any input matrix
1826 * given to it, potentially changing the order of the stored values.
1827 */
1829 GinkgoExecutor &exec,
1830 const std::string &factorization_type = "exact",
1831 const int sweeps = 0,
1832 const int sparsity_power = 1,
1833 const bool skip_sort = false
1834 );
1835};
1836
1837/**
1838 * An implementation of the preconditioner interface using the Ginkgo
1839 * Incomplete Cholesky preconditioner (IC(0)).
1840 *
1841 * @ingroup Ginkgo
1842 */
1844{
1845public:
1846 /**
1847 * Constructor.
1848 *
1849 * @param[in] exec The execution paradigm for the preconditioner.
1850 * @param[in] factorization_type The factorization type: "exact" or
1851 * "paric".
1852 * @param[in] sweeps The number of sweeps to do in the ParIc
1853 * factorization algorithm. A value of 0 tells Ginkgo to use its
1854 * internal default value. This parameter is ignored in the case
1855 * of an exact factorization.
1856 * @param[in] skip_sort Only set this to true if the input matrix
1857 * that will be used to generate this preconditioner is guaranteed
1858 * to be sorted by column.
1859 *
1860 * Note: The use of this preconditioner will sort any input matrix
1861 * given to it, potentially changing the order of the stored values.
1862 */
1864 GinkgoExecutor &exec,
1865 const std::string &factorization_type = "exact",
1866 const int sweeps = 0,
1867 const bool skip_sort = false
1868 );
1869};
1870
1871/**
1872 * An implementation of the preconditioner interface using the Ginkgo
1873 * Incomplete Cholesky-Incomplete Sparse Approximate Inverse preconditioner.
1874 * The Ic-ISAI preconditioner differs from the Ic preconditioner in
1875 * that Incomplete Sparse Approximate Inverses (ISAIs) are formed
1876 * to approximate solving the triangular systems defined by L and L^T.
1877 * When the preconditioner is applied, these ISAI matrices are applied
1878 * through matrix-vector multiplication.
1879 *
1880 * @ingroup Ginkgo
1881 */
1883{
1884public:
1885 /**
1886 * Constructor.
1887 *
1888 * @param[in] exec The execution paradigm for the preconditioner.
1889 * @param[in] factorization_type The factorization type: "exact" or
1890 * "paric".
1891 * @param[in] sweeps The number of sweeps to do in the ParIc
1892 * factorization algorithm. A value of 0 tells Ginkgo to use its
1893 * internal default value. This parameter is ignored in the case
1894 * of an exact factorization.
1895 * @param[in] sparsity_power Parameter determining the sparsity pattern of
1896 * the ISAI approximations.
1897 * @param[in] skip_sort Only set this to true if the input matrix
1898 * that will be used to generate this preconditioner is guaranteed
1899 * to be sorted by column.
1900 * See the Ginkgo documentation for more information on these parameters.
1901 *
1902 * Note: The use of this preconditioner will sort any input matrix
1903 * given to it, potentially changing the order of the stored values.
1904 */
1906 GinkgoExecutor &exec,
1907 const std::string &factorization_type = "exact",
1908 const int sweeps = 0,
1909 const int sparsity_power = 1,
1910 const bool skip_sort = false
1911 );
1912};
1913
1914#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1915/**
1916 * An implementation of the preconditioner interface using the Ginkgo
1917 * Schwarz preconditioner, a simple domain decomposition method for
1918 * distributed problems. The local solver should be another
1919 * GinkgoPreconditioner or GinkgoIterativeSolver type. Furthermore, the
1920 * local solver should be "Ginkgo native", i.e., not an MFEM Solver
1921 * wrapped with the MFEMPreconditioner.
1922 *
1923 * @ingroup Ginkgo
1924 */
1926{
1927public:
1928 /**
1929 * Constructor.
1930 *
1931 * @param[in] exec The execution paradigm for the preconditioner.
1932 * @param[in] comm The MPI Communicator associated with the problem.
1933 * @param[in] local_solver The local solver. Must be derived from
1934 * GinkgoIterativeSolver or GinkgoPreconditioner.
1935 * @param[in] l1_smoother Whether to use L1 smoothing, where the sum of
1936 * each row is added to the diagonal. Only possible
1937 * if using an assembled matrix operator and if
1938 * local_solver does not already have a generated
1939 * solver/preconditioner for the matrix.
1940 * See the Ginkgo documentation for more information on this preconditioner.
1941 *
1942 */
1944 GinkgoExecutor &exec,
1945 MPI_Comm comm,
1946 Solver &local_solver,
1947 const bool l1_smoother = false
1948 );
1949
1950 /**
1951 * Generate the preconditioner for the given matrix @p op,
1952 * which must be of MFEM HypreParMatrix type.
1953 * Calling this function is only required when creating a
1954 * preconditioner for use with another MFEM solver; to use with
1955 * a Ginkgo solver, get the LinOpFactory pointer through @p GetFactory()
1956 * and pass to the Ginkgo solver constructor.
1957 * The SchwarzPreconditioner currently needs its own override because
1958 * it potentially requires sorting of the diagonal matrix in the case of L1
1959 * smoothing.
1960 */
1961 void SetOperator(const Operator &op) override;
1962};
1963#endif
1964
1965/**
1966 * A wrapper that allows Ginkgo to use MFEM preconditioners.
1967 *
1968 * @ingroup Ginkgo
1969 */
1971{
1972public:
1973 /**
1974 * Constructor.
1975 *
1976 * @param[in] exec The execution paradigm for the preconditioner.
1977 * @param[in] mfem_precond The MFEM Preconditioner to wrap.
1978 */
1980 GinkgoExecutor &exec,
1981 const Solver &mfem_precond
1982 );
1983
1984#if defined(MFEM_USE_MPI) && GINKGO_BUILD_MPI
1985 /**
1986 * Constructor.
1987 *
1988 * @param[in] exec The execution paradigm for the preconditioner.
1989 * @param[in] mfem_precond The MFEM Preconditioner to wrap.
1990 * @param[in] comm The MPI Communicator that MFEM will use with this
1991 * preconditioner.
1992 */
1994 GinkgoExecutor &exec,
1995 const Solver &mfem_precond,
1996 MPI_Comm comm
1997 );
1998#endif
1999
2000 /**
2001 * SetOperator is not allowed for this type of preconditioner;
2002 * this function overrides the base class in order to give an
2003 * error if SetOperator() is called for this class.
2004 */
2005 void SetOperator(const Operator &op) override
2006 {
2007 MFEM_ABORT("Ginkgo::MFEMPreconditioner must be constructed "
2008 "with the MFEM Operator that it will wrap as an argument;\n"
2009 "calling SetOperator() is not allowed.");
2010 };
2011};
2012} // namespace Ginkgo
2013
2014} // namespace mfem
2015
2016#endif // MFEM_USE_GINKGO
2017
2018#endif // MFEM_GINKGO
The MFEM Device class abstracts hardware devices such as GPUs, as well as programming models such as ...
Definition device.hpp:129
BICGSTABSolver(GinkgoExecutor &exec)
Definition ginkgo.cpp:1027
CBGMRESSolver(GinkgoExecutor &exec, int dim=0, storage_precision prec=storage_precision::reduce1)
Definition ginkgo.cpp:1414
CGSSolver(GinkgoExecutor &exec)
Definition ginkgo.cpp:1102
CGSolver(GinkgoExecutor &exec)
Definition ginkgo.cpp:951
void on_iteration_complete(const gko::LinOp *op, const gko::size_type &iteration, const gko::LinOp *residual, const gko::LinOp *solution, const gko::LinOp *residual_norm, const gko::LinOp *implicit_sq_residual_norm) const override
Definition ginkgo.hpp:513
void on_iteration_complete(const gko::LinOp *op, const gko::LinOp *rhs, const gko::LinOp *solution, const gko::size_type &iteration, const gko::LinOp *residual, const gko::LinOp *residual_norm, const gko::LinOp *implicit_sq_residual_norm, const gko::array< gko::stopping_status > *status, bool stopped) const override
Definition ginkgo.hpp:523
void on_iteration_complete(const gko::LinOp *op, const gko::size_type &iteration, const gko::LinOp *residual, const gko::LinOp *solution, const gko::LinOp *residual_norm) const override
Definition ginkgo.hpp:504
virtual void convergence_iteration_complete_core(const gko::size_type &iteration, const gko::LinOp *residual, const gko::LinOp *solution, const gko::LinOp *residual_norm, const gko::LinOp *implicit_sq_residual_norm, const gko::array< gko::stopping_status > *status) const =0
EnableConvergenceLogger(std::shared_ptr< const gko::Executor > exec, const gko::LinOp *matrix, const VecType *b, bool compute_real_residual=false)
Definition ginkgo.hpp:574
EnableGinkgoSolver(GinkgoExecutor &exec, MPI_Comm comm, bool use_implicit_res_norm)
Definition ginkgo.hpp:1277
EnableGinkgoSolver(GinkgoExecutor &exec, bool use_implicit_res_norm)
Definition ginkgo.hpp:1273
EnableResidualLogger(std::shared_ptr< const gko::Executor > exec, const gko::LinOp *matrix, const VecType *b, bool compute_real_residual=false)
Definition ginkgo.hpp:774
FCGSolver(GinkgoExecutor &exec)
Definition ginkgo.cpp:1174
GMRESSolver(GinkgoExecutor &exec, int dim=0)
Definition ginkgo.cpp:1246
std::shared_ptr< gko::Executor > GetExecutor() const
Definition ginkgo.hpp:927
GinkgoExecutor(ExecType exec_type)
Definition ginkgo.cpp:33
virtual ~GinkgoExecutor()=default
@ CUDA
CUDA GPU Executor.
Definition ginkgo.hpp:881
@ HIP
HIP GPU Executor.
Definition ginkgo.hpp:883
@ REFERENCE
Reference CPU Executor.
Definition ginkgo.hpp:877
@ OMP
OpenMP CPU Executor.
Definition ginkgo.hpp:879
void SetOperator(const Operator &op) override
Definition ginkgo.cpp:856
void Mult(const Vector &x, Vector &y) const override
Definition ginkgo.cpp:653
std::shared_ptr< gko::stop::Combined::Factory > combined_factory
Definition ginkgo.hpp:1202
std::shared_ptr< gko::experimental::mpi::communicator > gko_comm
Definition ginkgo.hpp:1215
std::shared_ptr< gko::stop::ResidualNorm< real_t >::Factory > abs_criterion
Definition ginkgo.hpp:1172
std::shared_ptr< gko::stop::ImplicitResidualNorm< real_t >::Factory > imp_abs_criterion
Definition ginkgo.hpp:1186
std::shared_ptr< ConvergenceLogger > convergence_logger
Definition ginkgo.hpp:1191
std::shared_ptr< gko::stop::ResidualNorm< real_t >::Factory > rel_criterion
Definition ginkgo.hpp:1165
const std::shared_ptr< gko::LinOpFactory > GetFactory() const
Definition ginkgo.hpp:1077
std::shared_ptr< ResidualLogger > residual_logger
Definition ginkgo.hpp:1196
GinkgoIterativeSolver(GinkgoExecutor &exec, bool use_implicit_res_norm)
Definition ginkgo.cpp:350
void SetPrintLevel(int print_lvl)
Definition ginkgo.hpp:1082
std::shared_ptr< gko::stop::ImplicitResidualNorm< real_t >::Factory > imp_rel_criterion
Definition ginkgo.hpp:1179
std::shared_ptr< gko::LinOpFactory > solver_gen
Definition ginkgo.hpp:1153
virtual ~GinkgoIterativeSolver()=default
std::shared_ptr< gko::Executor > executor
Definition ginkgo.hpp:1209
std::shared_ptr< gko::LinOp > solver
Definition ginkgo.hpp:1158
void SetOperator(const Operator &op) override
Definition ginkgo.cpp:1644
std::shared_ptr< gko::Executor > executor
Definition ginkgo.hpp:1043
const std::shared_ptr< gko::LinOpFactory > GetFactory() const
Definition ginkgo.hpp:1002
void Mult(const Vector &x, Vector &y) const override
Definition ginkgo.cpp:1590
virtual ~GinkgoPreconditioner()=default
std::shared_ptr< gko::LinOp > generated_precond
Definition ginkgo.hpp:1036
std::shared_ptr< gko::experimental::mpi::communicator > gko_comm
Definition ginkgo.hpp:1049
GinkgoPreconditioner(GinkgoExecutor &exec)
Definition ginkgo.cpp:1565
std::shared_ptr< gko::LinOpFactory > precond_gen
Definition ginkgo.hpp:1029
const std::shared_ptr< gko::LinOp > GetGeneratedPreconditioner() const
Definition ginkgo.hpp:1011
IRSolver(GinkgoExecutor &exec)
Definition ginkgo.cpp:1516
IcIsaiPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const int sparsity_power=1, const bool skip_sort=false)
Definition ginkgo.cpp:1869
IcPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const bool skip_sort=false)
Definition ginkgo.cpp:1833
IluIsaiPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const int sparsity_power=1, const bool skip_sort=false)
Definition ginkgo.cpp:1776
IluPreconditioner(GinkgoExecutor &exec, const std::string &factorization_type="exact", const int sweeps=0, const bool skip_sort=false)
Definition ginkgo.cpp:1742
JacobiPreconditioner(GinkgoExecutor &exec, const std::string &storage_opt="none", const real_t accuracy=1.e-1, const int max_block_size=32)
Definition ginkgo.cpp:1711
MFEMPreconditioner(GinkgoExecutor &exec, const Solver &mfem_precond)
Definition ginkgo.cpp:2015
void SetOperator(const Operator &op) override
Definition ginkgo.hpp:2005
OperatorWrapper(std::shared_ptr< const gko::Executor > exec, gko::size_type size=0, const Operator *oper=NULL)
Definition ginkgo.hpp:244
void apply_impl(const gko::LinOp *b, gko::LinOp *x) const override
Definition ginkgo.cpp:477
ParallelOperatorWrapper(std::shared_ptr< const gko::Executor > exec, gko::experimental::mpi::communicator comm, gko::size_type size=0, const Operator *oper=NULL)
Definition ginkgo.hpp:270
void apply_impl(const gko::LinOp *b, gko::LinOp *x) const override
Definition ginkgo.cpp:562
std::unique_ptr< gko::experimental::distributed::Vector< real_t > > create_submatrix_impl(gko::local_span rows, gko::local_span columns, gko::dim< 2 > global_size) override
Definition ginkgo.hpp:395
static std::unique_ptr< ParallelVectorWrapper > create(std::shared_ptr< const gko::Executor > exec, gko::experimental::mpi::communicator comm, Ginkgo::VectorWrapper *wrapped_local_mfem_vec, HYPRE_BigInt global_rows, HYPRE_BigInt global_cols)
Definition ginkgo.hpp:310
const Ginkgo::VectorWrapper * get_local_wrapped_vec_const() const
Definition ginkgo.hpp:325
std::unique_ptr< gko::experimental::distributed::Vector< real_t > > create_with_same_config() const override
Definition ginkgo.hpp:330
Ginkgo::VectorWrapper * get_local_wrapped_vec()
Definition ginkgo.hpp:322
ParallelVectorWrapper(std::shared_ptr< const gko::Executor > exec, gko::experimental::mpi::communicator comm, Ginkgo::VectorWrapper *wrapped_local_mfem_vec, HYPRE_BigInt global_rows, HYPRE_BigInt global_cols)
Definition ginkgo.hpp:294
std::unique_ptr< gko::experimental::distributed::Vector< real_t > > create_with_type_of_impl(std::shared_ptr< const gko::Executor > exec, const gko::dim< 2 > &global_size, const gko::dim< 2 > &local_size, gko::size_type stride) const override
Definition ginkgo.hpp:357
ResidualLogger(bool compute_real_residual)
Definition ginkgo.hpp:743
void on_iteration_complete(const gko::LinOp *op, const gko::size_type &iteration, const gko::LinOp *residual, const gko::LinOp *solution, const gko::LinOp *residual_norm, const gko::LinOp *implicit_sq_residual_norm) const override
Definition ginkgo.hpp:717
virtual void iteration_complete_core(const gko::size_type &iteration, const gko::LinOp *residual, const gko::LinOp *solution, const gko::LinOp *residual_norm, const gko::LinOp *implicit_sq_residual_norm) const =0
void on_iteration_complete(const gko::LinOp *op, const gko::size_type &iteration, const gko::LinOp *residual, const gko::LinOp *solution, const gko::LinOp *residual_norm) const override
Definition ginkgo.hpp:707
void on_iteration_complete(const gko::LinOp *op, const gko::LinOp *rhs, const gko::LinOp *solution, const gko::size_type &iteration, const gko::LinOp *residual, const gko::LinOp *residual_norm, const gko::LinOp *implicit_sq_residual_norm, const gko::array< gko::stopping_status > *status, bool stopped) const override
Definition ginkgo.hpp:728
std::vector< std::size_t > iterations
Definition ginkgo.hpp:758
std::vector< real_t > residual_norms
Definition ginkgo.hpp:756
void SetOperator(const Operator &op) override
Definition ginkgo.cpp:1972
SchwarzPreconditioner(GinkgoExecutor &exec, MPI_Comm comm, Solver &local_solver, const bool l1_smoother=false)
Definition ginkgo.cpp:1915
static std::unique_ptr< VectorWrapper > create(std::shared_ptr< const gko::Executor > exec, gko::size_type size, Vector *mfem_vec, bool ownership=false)
Definition ginkgo.hpp:123
std::unique_ptr< gko::matrix::Dense< real_t > > create_with_same_config() const override
Definition ginkgo.hpp:142
std::unique_ptr< gko::matrix::Dense< real_t > > create_submatrix_impl(const gko::span &rows, const gko::span &columns, const gko::size_type stride) override
Definition ginkgo.hpp:193
std::unique_ptr< gko::matrix::Dense< real_t > > create_with_type_of_impl(std::shared_ptr< const gko::Executor > exec, const gko::dim< 2 > &size, gko::size_type stride) const override
Definition ginkgo.hpp:163
VectorWrapper(std::shared_ptr< const gko::Executor > exec, gko::size_type size, Vector *mfem_vec, bool ownership=false)
Definition ginkgo.hpp:90
const Vector & get_mfem_vec_const_ref() const
Definition ginkgo.hpp:137
void operator()(pointer ptr) const noexcept
Definition ginkgo.hpp:75
Abstract operator.
Definition operator.hpp:27
Base class for solvers.
Definition operator.hpp:855
Vector data type.
Definition vector.hpp:82
virtual void UseDevice(bool use_dev) const
Enable execution of Vector operations using the mfem::Device.
Definition vector.hpp:145
void MakeRef(Vector &base, int offset, int size)
Reset the Vector to be a reference to a sub-vector of base.
Definition vector.hpp:709
const real_t alpha
Definition ex15.cpp:369
int dim
Definition ex24.cpp:53
HYPRE_Int HYPRE_BigInt
real_t b
Definition lissajous.cpp:42
real_t get_norm(const gko::matrix::Dense< ValueType > *norm)
Definition ginkgo.hpp:442
std::conditional_t< sizeof(HYPRE_BigInt)==sizeof(std::int32_t), std::int32_t, std::conditional_t< sizeof(HYPRE_BigInt)==sizeof(std::int64_t), std::int64_t, void > > gko_hypre_bigint
Definition ginkgo.hpp:47
std::conditional_t< sizeof(HYPRE_Int)==sizeof(std::int32_t), std::int32_t, std::conditional_t< sizeof(HYPRE_Int)==sizeof(std::int64_t), std::int64_t, void > > gko_hypre_int
Definition ginkgo.hpp:44
gko::array< T > gko_array
Definition ginkgo.hpp:41
real_t compute_norm(const VecType *b)
Definition ginkgo.hpp:467
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition globals.hpp:66
float real_t
Definition config.hpp:46
struct schwarz_common schwarz
MFEM_HOST_DEVICE real_t norm(const Complex &z)