SystemPreconditioner.hpp
Go to the documentation of this file.
1/*
2 Copyright Equinor ASA 2026
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#ifndef OPM_SYSTEMPRECONDITIONER_HEADER_INCLUDED
20#define OPM_SYSTEMPRECONDITIONER_HEADER_INCLUDED
21
27
28#include <dune/istl/operators.hh>
29#include <dune/istl/paamg/pinfo.hh>
30
31
32namespace Opm
33{
34
35// Reservoir operator/comm types used as template arguments.
36template<typename Scalar>
37using SeqResOperator = Dune::MatrixAdapter<RRMatrix<Scalar>, ResVector<Scalar>, ResVector<Scalar>>;
38
39#if HAVE_MPI
40using ParResComm = Dune::OwnerOverlapCopyCommunication<int, int>;
41template<typename Scalar>
42using ParResOperator = Dune::OverlappingSchwarzOperator<RRMatrix<Scalar>, ResVector<Scalar>, ResVector<Scalar>, ParResComm>;
43#endif
44
45// Preconditioner for the coupled reservoir-well system.
46//
47// Templated on scalar type, reservoir operator and communication types to
48// unify sequential and parallel implementations. The 3-stage algorithm:
49// 1. Reservoir CPR solve
50// 2. Well solve + reservoir smoothing
51// 3. Final well solve
52//
53// For parallel runs, copyOwnerToAll synchronises overlap DOFs before
54// each reservoir sub-solve.
55template <class Scalar, class ResOp, class ResComm = Dune::Amg::SequentialInformation>
56class SystemPreconditioner : public Dune::PreconditionerWithUpdate<SystemVector<Scalar>, SystemVector<Scalar>>
57{
58public:
59 static constexpr bool isParallel = !std::is_same_v<ResComm, Dune::Amg::SequentialInformation>;
60
62 using WellOperator = Dune::MatrixAdapter<WWMatrix<Scalar>, WellVector<Scalar>, WellVector<Scalar>>;
64
65 static constexpr auto _0 = Dune::Indices::_0;
66 static constexpr auto _1 = Dune::Indices::_1;
67
68 // Sequential constructor (enabled only for non-parallel specializations).
70 const std::function<ResVector<Scalar>()>& weightsCalculator,
71 int pressureIndex,
72 const Opm::PropertyTree& prm)
73 requires (!isParallel)
74 : S_(S)
75 , pressureIndex_(pressureIndex)
76 {
77 initSubSolvers(prm, weightsCalculator);
78 initWorkVectors();
79 }
80
81 // Parallel constructor (enabled only for parallel specializations).
83 const std::function<ResVector<Scalar>()>& weightsCalculator,
84 int pressureIndex,
85 const Opm::PropertyTree& prm,
86 const ResComm& resComm)
87 requires (isParallel)
88 : S_(S)
89 , resComm_(&resComm)
90 , pressureIndex_(pressureIndex)
91 {
92 initSubSolvers(prm, weightsCalculator);
93 initWorkVectors();
94 }
95
97 {
98 }
99
101 {
102 }
103
104 Dune::SolverCategory::Category category() const override
105 {
106 if constexpr (isParallel)
107 return Dune::SolverCategory::overlapping;
108 else
109 return Dune::SolverCategory::sequential;
110 }
111
112 void update() override
113 {
114 resSolver_->preconditioner().update();
115 resSmoother_->preconditioner().update();
116 wellSolver_->preconditioner().update();
117 }
118
120 {
121 resSolver_->preconditioner().update();
122 resSmoother_->preconditioner().update();
123 initWellSolver();
124 resizeWellWorkVectors();
125 }
126
127 bool hasPerfectUpdate() const override
128 {
129 return true;
130 }
131
132// System matrix block structure:
133//
134// [ A C ] [ x_res ] [ resRes ]
135// S = [ B D ] [ x_well ] = [ wRes ]
136//
137// A = reservoir-reservoir (top-left)
138// C = reservoir-well coupling (top-right)
139// B = well-reservoir coupling (bottom-left)
140// D = well-well (bottom-right)
142 {
143 // Extract blocks using the agreed convention
144 const auto& A = S_[_0][_0];
145 const auto& C = S_[_0][_1];
146 const auto& B = S_[_1][_0];
147 const auto& D = S_[_1][_1];
148
149 resRes_ = d[_0];
150 wRes_ = d[_1];
151 resSol_ = 0.0;
152 wSol_ = 0.0;
153
154 // Stage 1: Reservoir CPR solve
155 {
157 dresSol_ = 0.0;
158 tmp_resRes_ = resRes_;
159 syncResVector(tmp_resRes_);
160 resSolver_->apply(dresSol_, tmp_resRes_, res_result);
161 resSol_ += dresSol_;
162 // resRes_ -= A * dresSol_
163 A.mmv(dresSol_, resRes_);
164 // wRes_ -= B * dresSol_
165 B.mmv(dresSol_, wRes_);
166 }
167
168 // Stage 2: Well solve + reservoir system smoothing
169 {
170 Dune::InverseOperatorResult well_result;
171 dwSol_ = 0.0;
172 tmp_wRes_ = wRes_;
173 wellSolver_->apply(dwSol_, tmp_wRes_, well_result);
174 wSol_ += dwSol_;
175 // resRes_ -= C * dwSol_
176 C.mmv(dwSol_, resRes_);
177 // resRes_ -= D * dwSol_
178 D.mmv(dwSol_, wRes_);
179
181 dresSol_ = 0.0;
182 tmp_resRes_ = resRes_;
183 syncResVector(tmp_resRes_);
184 resSmoother_->apply(dresSol_, tmp_resRes_, res_result);
185 resSol_ += dresSol_;
186 // wRes_ -= B * dresSol_
187 B.mmv(dresSol_, wRes_);
188 }
189
190 // Stage 3: Final well solve
191 {
192 Dune::InverseOperatorResult well_result;
193 dwSol_ = 0.0;
194 tmp_wRes_ = wRes_;
195 wellSolver_->apply(dwSol_, tmp_wRes_, well_result);
196 wSol_ += dwSol_;
197 }
198
199 syncResVector(resSol_);
200 v[_0] = resSol_;
201 v[_1] = wSol_;
202 }
203
204private:
205 const SystemMatrix<Scalar>& S_;
206 const ResComm* resComm_ = nullptr;
207 int pressureIndex_ = 0;
208 static constexpr int dummyWellPressureIndex = std::numeric_limits<int>::min();
209 Opm::PropertyTree wellprm_;
210
211 std::unique_ptr<ResOp> rop_;
212 std::unique_ptr<WellOperator> wop_;
213 std::unique_ptr<ResFlexibleSolverType> resSolver_;
214 std::unique_ptr<ResFlexibleSolverType> resSmoother_;
215 std::unique_ptr<WellFlexibleSolverType> wellSolver_;
216
217 WellVector<Scalar> wSol_;
218 ResVector<Scalar> resSol_;
219 ResVector<Scalar> dresSol_;
220 WellVector<Scalar> dwSol_;
221 ResVector<Scalar> tmp_resRes_;
222 WellVector<Scalar> tmp_wRes_;
223 ResVector<Scalar> resRes_;
224 WellVector<Scalar> wRes_;
225
226 void syncResVector(ResVector<Scalar>& v)
227 {
228 if constexpr (isParallel) {
229 resComm_->copyOwnerToAll(v, v);
230 }
231 }
232
233 void initWellSolver()
234 {
235 wop_ = std::make_unique<WellOperator>(S_[_1][_1]);
236 std::function<WellVector<Scalar>()> weightsCalculatorWell;
237 wellSolver_ = std::make_unique<WellFlexibleSolverType>(
238 *wop_, wellprm_, weightsCalculatorWell, dummyWellPressureIndex);
239 }
240
241 void initSubSolvers(const Opm::PropertyTree& prm,
242 const std::function<ResVector<Scalar>()>& weightsCalculator)
243 {
244 auto resprm = prm.get_child("reservoir_solver");
245 auto resprmsmoother = prm.get_child("reservoir_smoother");
246 wellprm_ = prm.get_child("well_solver");
247
248 if constexpr (isParallel) {
249 rop_ = std::make_unique<ResOp>(S_[_0][_0], *resComm_);
250 resSolver_ = std::make_unique<ResFlexibleSolverType>(
251 *rop_, *resComm_, resprm, weightsCalculator, pressureIndex_);
252 resSmoother_ = std::make_unique<ResFlexibleSolverType>(
253 *rop_, *resComm_, resprmsmoother, weightsCalculator, pressureIndex_);
254 } else {
255 rop_ = std::make_unique<ResOp>(S_[_0][_0]);
256 resSolver_ = std::make_unique<ResFlexibleSolverType>(
257 *rop_, resprm, weightsCalculator, pressureIndex_);
258 resSmoother_ = std::make_unique<ResFlexibleSolverType>(
259 *rop_, resprmsmoother, weightsCalculator, pressureIndex_);
260 }
261
262 initWellSolver();
263 }
264
265 void initWorkVectors()
266 {
267 resizeReservoirWorkVectors();
268 resizeWellWorkVectors();
269 }
270
271 void resizeReservoirWorkVectors()
272 {
273 const auto numRes = S_[_0][_0].N();
274 resSol_.resize(numRes);
275 dresSol_.resize(numRes);
276 tmp_resRes_.resize(numRes);
277 resRes_.resize(numRes);
278 }
279
280 void resizeWellWorkVectors()
281 {
282 const auto numWell = S_[_1][_1].N();
283 wSol_.resize(numWell);
284 dwSol_.resize(numWell);
285 tmp_wRes_.resize(numWell);
286 wRes_.resize(numWell);
287 }
288};
289
290} // namespace Opm
291
292#endif // OPM_SYSTEMPRECONDITIONER_HEADER_INCLUDED
Definition: FlexibleSolver.hpp:45
Interface class adding the update() method to the preconditioner interface.
Definition: PreconditionerWithUpdate.hpp:34
Hierarchical collection of key/value pairs.
Definition: PropertyTree.hpp:39
PropertyTree get_child(const std::string &key) const
Definition: SystemTypes.hpp:77
static constexpr size_type N()
Definition: SystemTypes.hpp:82
Definition: SystemPreconditioner.hpp:57
bool hasPerfectUpdate() const override
Definition: SystemPreconditioner.hpp:127
SystemPreconditioner(const SystemMatrix< Scalar > &S, const std::function< ResVector< Scalar >()> &weightsCalculator, int pressureIndex, const Opm::PropertyTree &prm)
Definition: SystemPreconditioner.hpp:69
void post(SystemVector< Scalar > &) override
Definition: SystemPreconditioner.hpp:100
void pre(SystemVector< Scalar > &, SystemVector< Scalar > &) override
Definition: SystemPreconditioner.hpp:96
Dune::SolverCategory::Category category() const override
Definition: SystemPreconditioner.hpp:104
void updateForChangedWellStructure()
Definition: SystemPreconditioner.hpp:119
static constexpr auto _0
Definition: SystemPreconditioner.hpp:65
static constexpr auto _1
Definition: SystemPreconditioner.hpp:66
Dune::MatrixAdapter< WWMatrix< Scalar >, WellVector< Scalar >, WellVector< Scalar > > WellOperator
Definition: SystemPreconditioner.hpp:62
static constexpr bool isParallel
Definition: SystemPreconditioner.hpp:59
SystemPreconditioner(const SystemMatrix< Scalar > &S, const std::function< ResVector< Scalar >()> &weightsCalculator, int pressureIndex, const Opm::PropertyTree &prm, const ResComm &resComm)
Definition: SystemPreconditioner.hpp:82
void update() override
Definition: SystemPreconditioner.hpp:112
void apply(SystemVector< Scalar > &v, const SystemVector< Scalar > &d) override
Definition: SystemPreconditioner.hpp:141
Definition: blackoilbioeffectsmodules.hh:45
Dune::MultiTypeBlockVector< ResVector< Scalar >, WellVector< Scalar > > SystemVector
Definition: SystemTypes.hpp:59
Dune::InverseOperatorResult InverseOperatorResult
Definition: GpuBridge.hpp:32
Dune::OverlappingSchwarzOperator< RRMatrix< Scalar >, ResVector< Scalar >, ResVector< Scalar >, ParResComm > ParResOperator
Definition: SystemPreconditioner.hpp:42
Dune::OwnerOverlapCopyCommunication< int, int > ParResComm
Definition: SystemPreconditioner.hpp:40
Dune::MatrixAdapter< RRMatrix< Scalar >, ResVector< Scalar >, ResVector< Scalar > > SeqResOperator
Definition: SystemPreconditioner.hpp:37
Dune::BlockVector< Dune::FieldVector< Scalar, numResDofs > > ResVector
Definition: SystemTypes.hpp:55
Dune::BlockVector< Dune::FieldVector< Scalar, numWellDofs > > WellVector
Definition: SystemTypes.hpp:57