Dune::Copasi
Loading...
Searching...
No Matches
block_jacobi.hh
Go to the documentation of this file.
1#ifndef DUNE_COPASI_SOLVER_ISTL_BLOCK_JACOBI_HH
2#define DUNE_COPASI_SOLVER_ISTL_BLOCK_JACOBI_HH
3
6
7#include <dune/pdelab/common/algebra.hh>
8
9#include <dune/istl/preconditioner.hh>
10#include <dune/istl/solver.hh>
11
12#include <memory>
13
15
16template<Concept::AssembledLinearOperator O, class Alloc = std::allocator<void>>
17class BlockJacobi final : public Preconditioner<typename O::domain_type, typename O::range_type>
18{
19 using M = typename O::matrix_type;
20 using X = typename O::domain_type;
21 using Y = typename O::range_type;
22
23public:
24 BlockJacobi(const std::shared_ptr<const O>& op,
25 const ParameterTree& config,
26 const Alloc& alloc = Alloc())
27 : _alloc(alloc)
28 , _op(op)
29 , _config{ config }
30 , _parallel{ _config.get("parallel", false) }
31 , _iterations{ _config.get("iterations", std::size_t{ 1 }) }
32 , _weight{ _config.get("relaxation", 1.) }
33 {
34 }
35
36 void pre(X& x, Y& b) override
37 {
38 if (_parallel)
39 this->pre(PDELab::Execution::par, x, b);
40 else
41 this->pre(PDELab::Execution::seq, x, b);
42 }
43
44 void pre(auto policy, X& /* x */, Y& /* b */)
45 {
46 const ParameterTree& sub_solver = _config.sub("diagonal_solver");
47 if constexpr (IsNumber<typename M::block_type>{}) {
48 if (sub_solver.getSubKeys().size() != 0)
49 spdlog::warn("'diagona_solver' contains sub-sections that will be ignored");
50 if (sub_solver.get("type", "DenseInverse") != "DenseInverse")
51 spdlog::warn("Block jacobi at this level is scalar, meaning that the diagonal solver can only be 'DenseInverse'");
52 }
53
54 const M& mat = _op->getmat();
55 // store inverse of diagonal entries
56 _diag_inv.resize(mat.M());
57 PDELab::forEach(policy, mat, [&](const auto& row, auto i) {
58 auto row_it = row.begin();
59 for (; row_it != row.end() and row_it.index() != i; ++row_it) {
60 };
61 if (row_it == row.end())
62 throw format_exception(MathError{}, "BlockJacobi can only be done on matrices with diagonal entries");
63 if constexpr (IsNumber<typename M::block_type>{}) {
64 _diag_inv[i] = 1. / (*row_it);
65 } else {
66 auto i_str = fmt::format("{}", i);
68 (sub_solver.hasSub(i_str)) ? sub_solver.sub(i_str) : sub_solver;
69
70 using MatrixAdapter = Dune::
71 MatrixAdapter<typename M::block_type, typename X::value_type, typename Y::value_type>;
72 using MatrixAdapterAlloc =
73 typename std::allocator_traits<Alloc>::template rebind_alloc<MatrixAdapter>;
75 auto diag_op = std::allocate_shared<MatrixAdapter>(maalloc, *row_it);
76 _diag_inv[i] = makeInverseOperator(diag_op, sub_solver_i, _alloc, Impl::ADLTag{});
77 }
78 });
79 }
80
81 void apply(X& v, const Y& rhs) override
82 {
83 if (_parallel)
84 this->apply(PDELab::Execution::par, v, rhs);
85 else
86 this->apply(PDELab::Execution::seq, v, rhs);
87 }
88
89 void apply(auto policy, X& v, const Y& rhs)
90 {
91 Y b = rhs;
92 // we need a copy to avoid overriding old iterates, but is not needed if there is only one block
93 std::optional<X> x_tmp;
94 const M& mat = _op->getmat();
95
96 using Xi = typename X::value_type;
97 [[maybe_unused]] std::optional<Xi> vi;
98 X& x = (v.size() > 1) ? x_tmp.emplace(v) : v;
99 x = v;
100 for (std::size_t it = 0; it != _iterations; ++it) {
101 PDELab::forEach(policy, mat, [=, &b, &x, &diag_inv = _diag_inv](const auto& row, auto i) mutable {
102 if constexpr (IsNumber<typename M::block_type>{}) {
103 // compute (b-Ax)
104 for (auto col = row.begin(); col != row.end(); ++col)
105 b[i] -= (*col) * v[col.index()];
106 // solve v for Dv=(b-Ax); then x=x+v
107 x[i] += _weight * diag_inv[i] * b[i];
108 } else {
109 // compute (b-Ax)
111 for (auto col = row.begin(); col != row.end(); ++col)
112 col->mmv(v[col.index()], b[i]);
113 // solve v for Dv=(b-Ax); then x=x+v
114 auto& vir = vi ? *vi : vi.emplace();
115 // copy 'x' in 'vi' is just to get the sizes right
116 vir = x[i];
117 diag_inv[i]->apply(vir, b[i], res);
118 PDELab::axpy(x[i], _weight, vir);
119 }
120 });
121 if (v.size() > 1)
122 v = x;
123 }
124 }
125
126 void post(X&) override {}
127
128 SolverCategory::Category category() const override { return SolverCategory::sequential; }
129
130 static auto factory()
131 {
132 return [](const std::shared_ptr<LinearOperator<X, Y>>& op,
133 const ParameterTree& config,
134 const Alloc& alloc) -> std::shared_ptr<Preconditioner<X, Y>> {
135 // make an allocator for this preconditioner
136 using PrecAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<BlockJacobi>;
138
139 // cast operator to something the preconditioner expects
140 auto aop = std::dynamic_pointer_cast<O>(op);
141 if (not aop)
142 throw format_exception(InvalidStateException{}, "Linear operator does not hold a matrix!");
143 // construct preconditioner instance
144 return std::allocate_shared<BlockJacobi>(palloc, aop, config);
145 };
146 }
147
148private:
149 using DiagInverse = std::conditional_t<
150 IsNumber<typename M::block_type>::value,
151 typename M::block_type,
152 std::shared_ptr<InverseOperator<typename X::value_type, typename Y::value_type>>>;
153
154 using DiagInverseAlloc =
155 typename std::allocator_traits<Alloc>::template rebind_alloc<DiagInverse>;
156
157 Alloc _alloc;
158 std::shared_ptr<const O> _op;
159 std::vector<DiagInverse, DiagInverseAlloc> _diag_inv;
160 ParameterTree _config;
161 bool _parallel;
162 std::size_t _iterations;
163 double _weight;
164};
165
166} // namespace Dune::Copasi::ISTL
167
168#endif // DUNE_COPASI_SOLVER_ISTL_BLOCK_JACOBI_HH
Definition block_jacobi.hh:18
void apply(auto policy, X &v, const Y &rhs)
Definition block_jacobi.hh:89
void pre(X &x, Y &b) override
Definition block_jacobi.hh:36
void apply(X &v, const Y &rhs) override
Definition block_jacobi.hh:81
BlockJacobi(const std::shared_ptr< const O > &op, const ParameterTree &config, const Alloc &alloc=Alloc())
Definition block_jacobi.hh:24
void pre(auto policy, X &, Y &)
Definition block_jacobi.hh:44
void post(X &) override
Definition block_jacobi.hh:126
static auto factory()
Definition block_jacobi.hh:130
SolverCategory::Category category() const override
Definition block_jacobi.hh:128
Definition block_jacobi.hh:14
std::shared_ptr< InverseOperator< typename Op::domain_type, typename Op::range_type > > makeInverseOperator(const std::shared_ptr< Op > &op, const ParameterTree &config, const Alloc &alloc=Alloc())
Definition inverse.hh:65
auto format_exception(Exception &&e, fmt::format_string< Args... > format, Args &&... args)
Definition exceptions.hh:23
constexpr bool is_bitflags_v
Alias for Bitflag indicator.
Definition bit_flags.hh:24