opm-simulators
PreconditionerWithUpdate.hpp
1 /*
2  Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
3 
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 #ifndef OPM_PRECONDITIONERWITHUPDATE_HEADER_INCLUDED
21 #define OPM_PRECONDITIONERWITHUPDATE_HEADER_INCLUDED
22 
23 #include <dune/istl/preconditioner.hh>
24 #include <memory>
25 #include <tuple>
26 #include <utility>
27 
28 namespace Dune
29 {
30 
32 template <class X, class Y>
33 class PreconditionerWithUpdate : public Preconditioner<X, Y>
34 {
35 public:
36  virtual void update() = 0;
37 
38  // Force derived classes to define if preconditioner has perfect update
39  virtual bool hasPerfectUpdate() const = 0;
40 };
41 
42 template <class OriginalPreconditioner>
43 class DummyUpdatePreconditioner : public PreconditionerWithUpdate<typename OriginalPreconditioner::domain_type,
44  typename OriginalPreconditioner::range_type>
45 {
46 public:
47  template <class... Args>
48  explicit DummyUpdatePreconditioner(Args&&... args)
49  : orig_precond_(std::forward<Args>(args)...)
50  {
51  }
52 
53  using X = typename OriginalPreconditioner::domain_type;
54  using Y = typename OriginalPreconditioner::range_type;
55 
56  virtual void pre(X& x, Y& b) override
57  {
58  orig_precond_.pre(x, b);
59  }
60 
61  virtual void apply(X& v, const Y& d) override
62  {
63  orig_precond_.apply(v, d);
64  }
65 
66  virtual void post(X& x) override
67  {
68  orig_precond_.post(x);
69  }
70 
71  virtual SolverCategory::Category category() const override
72  {
73  return orig_precond_.category();
74  }
75 
76  // The update() function does nothing for a wrapped preconditioner.
77  virtual void update() override
78  {
79  }
80 
81  virtual bool hasPerfectUpdate() const override {
82  return true;
83  }
84 
85 private:
86  OriginalPreconditioner orig_precond_;
87 };
88 
89 template <class OriginalPreconditioner, class... Args>
90 std::shared_ptr<DummyUpdatePreconditioner<OriginalPreconditioner>>
91 getDummyUpdateWrapper(Args&&... args)
92 {
93  return std::make_shared<DummyUpdatePreconditioner<OriginalPreconditioner>>(std::forward<Args>(args)...);
94 }
95 
96 template <class X, class Y>
98 {
99 public:
100  explicit DirectSolverUpdatePreconditioner(SolverCategory::Category category)
101  : category_(category)
102  , needs_rebuild_(false)
103  {
104  }
105 
106  void update() override
107  {
108  needs_rebuild_ = true;
109  }
110 
111  bool hasPerfectUpdate() const override
112  {
113  return true;
114  }
115 
116  bool needsRebuild() const
117  {
118  return needs_rebuild_;
119  }
120 
121  void resetNeedsRebuild()
122  {
123  needs_rebuild_ = false;
124  }
125 
126  void pre([[maybe_unused]] X& x, [[maybe_unused]] Y& y) override
127  {
128  }
129 
130  void post([[maybe_unused]] X& x) override
131  {
132  }
133 
134  void apply([[maybe_unused]] X& x, [[maybe_unused]] const Y& y) override
135  {
136  }
137 
138  SolverCategory::Category category() const override
139  {
140  return category_;
141  }
142 
143 private:
144  SolverCategory::Category category_;
145  bool needs_rebuild_;
146 };
147 
150 template <class OriginalPreconditioner>
152  virtual std::unique_ptr<
153  Preconditioner<typename OriginalPreconditioner::domain_type, typename OriginalPreconditioner::range_type>>
154  make() = 0;
155  virtual ~GeneralPreconditionerMaker() = default;
156 };
157 
162 template <class OriginalPreconditioner, class... Args>
163 struct PreconditionerMaker : public GeneralPreconditionerMaker<OriginalPreconditioner> {
164  using GenericPreconditioner = Preconditioner<typename OriginalPreconditioner::domain_type, typename OriginalPreconditioner::range_type>;
165 
166  explicit PreconditionerMaker(Args... args)
167  : args_(args...)
168  {
169  }
170 
171  std::unique_ptr<GenericPreconditioner>
172  make() override
173  {
174  // return std::unique_ptr<GenericPreconditioner> {new auto(std::make_from_tuple<OriginalPreconditioner>(args_))};
175  return std::apply(
176  [](auto&&... args) {
177  return std::make_unique<OriginalPreconditioner>(std::forward<Args>(args)...);
178  }, args_);
179  }
180 
181  std::tuple<Args...> args_;
182 };
183 
186 template <class OriginalPreconditioner>
187 class RebuildOnUpdatePreconditioner : public PreconditionerWithUpdate<typename OriginalPreconditioner::domain_type,
188  typename OriginalPreconditioner::range_type>
189 {
190 public:
191  template<class... Args>
192  explicit RebuildOnUpdatePreconditioner(Args... args)
193  : preconditioner_maker_(std::make_unique<PreconditionerMaker<OriginalPreconditioner, Args...>>(args...))
194  {
195  update();
196  }
197 
198  using X = typename OriginalPreconditioner::domain_type;
199  using Y = typename OriginalPreconditioner::range_type;
200 
201  void pre(X& x, Y& b) override
202  {
203  orig_precond_->pre(x, b);
204  }
205 
206  void apply(X& v, const Y& d) override
207  {
208  orig_precond_->apply(v, d);
209  }
210 
211  void post(X& x) override
212  {
213  orig_precond_->post(x);
214  }
215 
216  SolverCategory::Category category() const override
217  {
218  return orig_precond_->category();
219  }
220 
221  // Rebuild the preconditioner on update
222  void update() override
223  {
224  orig_precond_ = preconditioner_maker_->make();
225  }
226 
227  bool hasPerfectUpdate() const override
228  {
229  return true;
230  }
231 
232 private:
234  using GenericPreconditioner = Preconditioner<typename OriginalPreconditioner::domain_type, typename OriginalPreconditioner::range_type>;
235 
236  std::unique_ptr<AbstractMakerType> preconditioner_maker_;
237  std::unique_ptr<GenericPreconditioner> orig_precond_;
238 };
239 
245 template <class OriginalPreconditioner, class... Args>
246 auto
247 getRebuildOnUpdateWrapper(Args... args)
248 {
249  return std::make_shared<RebuildOnUpdatePreconditioner<OriginalPreconditioner>>(args...);
250 }
251 
252 } // namespace Dune
253 
254 #endif // OPM_PRECONDITIONERWITHUPDATE_HEADER_INCLUDED
Interface class ensuring make function is overriden.
Definition: PreconditionerWithUpdate.hpp:151
Definition: fvbaseprimaryvariables.hh:161
Struct implementing a make function which creates a preconditioner Can create arbitrary preconditione...
Definition: PreconditionerWithUpdate.hpp:163
Interface class adding the update() method to the preconditioner interface.
Definition: PreconditionerWithUpdate.hpp:33
Definition: PreconditionerWithUpdate.hpp:97
Wrapper class of preconditioners that should be reconstructed on update.
Definition: PreconditionerWithUpdate.hpp:187
Definition: PreconditionerWithUpdate.hpp:43