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