ISTLSolverSystem.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_ISTLSOLVERSYSTEM_HEADER_INCLUDED
20#define OPM_ISTLSOLVERSYSTEM_HEADER_INCLUDED
21
26
29
30namespace Opm
31{
32
33template <class TypeTag>
34class ISTLSolverSystem : public ISTLSolver<TypeTag>
35{
36protected:
40 using Matrix = typename SparseMatrixAdapter::IstlMatrix;
43
44 // Compile-time validation: SystemPreconditionerFactory and related types
45 // are hardcoded for standard 3-phase blackoil (3 reservoir equations, 4 well equations).
46 // See SystemTypes.hpp for details.
47 static_assert(Indices::numEq == 3,
48 "ISTLSolverSystem (with system_cpr preconditioner) only supports "
49 "3-equation blackoil models. This model has different equation count.");
50
51 constexpr static std::size_t pressureIndex
52 = Indices::pressureSwitchIdx;
53
54 enum { enablePolymerMolarWeight = getPropValue<TypeTag, Properties::EnablePolymerMW>() };
56
57#if HAVE_MPI
58 using CommunicationType = Dune::OwnerOverlapCopyCommunication<int, int>;
59#else
60 using CommunicationType = Dune::Communication<int>;
61#endif
63
64 static constexpr auto _0 = Dune::Indices::_0;
65 static constexpr auto _1 = Dune::Indices::_1;
66
67public:
68 ISTLSolverSystem(const Simulator& simulator,
69 const FlowLinearSolverParameters& parameters,
70 bool forceSerial = false)
71 : Parent(simulator, parameters, forceSerial)
72 {
73 }
74
75 explicit ISTLSolverSystem(const Simulator& simulator)
76 : Parent(simulator)
77 {
78 }
79
80 void prepare(const SparseMatrixAdapter& M, Vector& b) override
81 {
82 OPM_TIMEBLOCK(istlSolverPrepare);
83 this->initPrepare(M.istlMatrix(), b);
84 prepareSystemSolver();
85 }
86
87 void prepare(const Matrix& M, Vector& b) override
88 {
89 OPM_TIMEBLOCK(istlSolverPrepare);
90 this->initPrepare(M, b);
91 prepareSystemSolver();
92 }
93
94 bool solve(Vector& x) override
95 {
96 OPM_TIMEBLOCK(istlSolverSolve);
97 ++this->solveCount_;
98
99 const std::size_t numRes = Parent::matrix_->N();
100 const std::size_t numWell = cachedWellStructure_.totalWellBlocks;
101
102 sysX_[_0].resize(numRes);
103 sysX_[_0] = 0.0;
104 sysX_[_1].resize(numWell);
105 sysX_[_1] = 0.0;
106
107 sysRhs_[_0].resize(numRes);
108 sysRhs_[_0] = *Parent::rhs_;
109 sysRhs_[_1].resize(numWell);
110 sysRhs_[_1] = 0.0;
111
113 sysSolver_->apply(sysX_, sysRhs_, result);
114 this->iterations_ = result.iterations;
115
116 x = sysX_[_0];
117
118 return this->checkConvergence(result);
119 }
120
121private:
122 bool sysInitialized_ = false;
123 WellMatrixStructure cachedWellStructure_;
124
125 // Current per-well B/C/D blocks for the explicit 2x2 system matrix.
126 std::vector<WRMatrix<Scalar>> wellBMatrices_;
127 std::vector<RWMatrix<Scalar>> wellCMatrices_;
128 std::vector<WWMatrix<Scalar>> wellDMatrices_;
129 Opm::SparseTable<int> wellCells_;
130
131 // Owned storage for merged well matrices; SystemMatrix points into these.
132 WRMatrix<Scalar> mergedB_;
133 RWMatrix<Scalar> mergedC_;
134 WWMatrix<Scalar> mergedD_;
135
136 SystemMatrix<Scalar> sysMatrix_;
138 SystemVector<Scalar> sysRhs_;
139
140 // Serial solver components
141 std::unique_ptr<SystemSeqOp<Scalar>> sysOp_;
142 std::unique_ptr<Dune::FlexibleSolver<SystemSeqOp<Scalar>>> sysFlexSolverSeq_;
143
144 // Parallel solver components
145#if HAVE_MPI
146 using WellComm = Dune::JacComm;
147 std::unique_ptr<WellComm> wellComm_;
148 std::unique_ptr<SystemComm> systemComm_;
149 std::unique_ptr<SystemParOp<Scalar>> sysOpPar_;
150 std::unique_ptr<Dune::FlexibleSolver<SystemParOp<Scalar>>> sysFlexSolverPar_;
151#endif
152
153 using SysSolverType = Dune::InverseOperator<SystemVector<Scalar>, SystemVector<Scalar>>;
156#if HAVE_MPI
158#endif
159 SysSolverType* sysSolver_ = nullptr;
160 SysPrecondType* sysPrecond_ = nullptr;
161
162 void prepareSystemSolver()
163 {
164 OPM_TIMEBLOCK(flexibleSolverPrepare);
165
166 wellBMatrices_.clear();
167 wellCMatrices_.clear();
168 wellDMatrices_.clear();
169 wellCells_.clear();
170
171 this->simulator_.problem().wellModel().addBCDMatrix(
172 wellBMatrices_, wellCMatrices_, wellDMatrices_, wellCells_);
173
175 Parent::matrix_->N(), wellBMatrices_, wellCMatrices_, wellDMatrices_, wellCells_);
176
177 const bool localStructureChanged = !sysInitialized_
178 || !merger.hasSameStructure(cachedWellStructure_);
179
180 // All ranks must agree on whether to take the structure-change path,
181 // because the distributed solver create and update paths use different
182 // MPI-collective sequences.
183#if HAVE_MPI
184 const bool globalStructureChanged = this->comm_->communicator().max(
185 static_cast<int>(localStructureChanged)) > 0;
186#else
187 const bool globalStructureChanged = localStructureChanged;
188#endif
189 const bool needStructureRefresh = !sysInitialized_ || globalStructureChanged;
190
191 const auto& prm = this->prm_[this->activeSolverNum_];
192
193 if (needStructureRefresh) {
194 OPM_TIMEBLOCK(flexibleSolverCreate);
195 merger.buildMatrices(mergedB_, mergedC_, mergedD_);
196 sysMatrix_.A = Parent::matrix_;
197 sysMatrix_.B = &mergedB_;
198 sysMatrix_.C = &mergedC_;
199 sysMatrix_.D = &mergedD_;
200 cachedWellStructure_ = merger.buildStructure();
201
202 refreshSystemSolverForChangedWellStructure(prm);
203 sysInitialized_ = true;
204 } else {
205 OPM_TIMEBLOCK(flexibleSolverUpdate);
206 // Pattern unchanged: write fresh values into the existing merged
207 // matrices without any (de)allocation.
208 merger.updateValues(mergedB_, mergedC_, mergedD_);
209
210 // Refresh A pointer in case the reservoir matrix was reallocated.
211 sysMatrix_.A = Parent::matrix_;
212 sysMatrix_.B = &mergedB_;
213 sysMatrix_.C = &mergedC_;
214 sysMatrix_.D = &mergedD_;
215 sysPrecond_->update();
216 }
217 }
218
219 void refreshSystemSolverForChangedWellStructure(const Opm::PropertyTree& prm)
220 {
221 if (!sysInitialized_ || !sysPrecond_) {
222 createSystemSolver(prm);
223 return;
224 }
225
226#if HAVE_MPI
227 if (this->comm_->communicator().size() > 1) {
228 if (auto* precond = dynamic_cast<ParSysPrecondType*>(sysPrecond_)) {
229 precond->updateForChangedWellStructure();
230 } else
231 { // Rebuild the parallel solver if the parallel preconditioner cannot be updated in-place.
232 createSystemSolver(prm);
233 }
234 return;
235 }
236#endif
237
238 if (auto* precond = dynamic_cast<SeqSysPrecondType*>(sysPrecond_)) {
239 precond->updateForChangedWellStructure();
240 } else
241 { // Rebuild the solver if the sequential preconditioner cannot be updated in-place
242 createSystemSolver(prm);
243 }
244 }
245
246 void createSystemSolver(const Opm::PropertyTree& prm)
247 {
248 // Derive weights from the reservoir sub-block config (which uses CPR internally)
249 auto resSolverPrm = prm.get_child("preconditioner.reservoir_solver");
250 std::function<ResVector<Scalar>()> resWeightCalc
251 = this->getWeightsCalculator(resSolverPrm, this->getMatrix(), pressureIndex);
252
253 std::function<SystemVector<Scalar>()> sysWeightCalc;
254 if (resWeightCalc) {
255 sysWeightCalc = [resWeightCalc]() {
256 SystemVector<Scalar> w;
257 w[_0] = resWeightCalc();
258 return w;
259 };
260 }
261
262#if HAVE_MPI
263 const bool is_parallel = this->comm_->communicator().size() > 1;
264 if (is_parallel) {
265 wellComm_ = std::make_unique<WellComm>();
266 systemComm_ = std::make_unique<SystemComm>(*(this->comm_), *wellComm_);
267
268 sysOpPar_ = std::make_unique<SystemParOp<Scalar>>(sysMatrix_, *systemComm_);
269
270 sysFlexSolverPar_ = std::make_unique<Dune::FlexibleSolver<SystemParOp<Scalar>>>(
271 *sysOpPar_, *systemComm_, prm, sysWeightCalc, pressureIndex);
272
273 sysSolver_ = sysFlexSolverPar_.get();
274 sysPrecond_ = &sysFlexSolverPar_->preconditioner();
275 }
276 else
277#endif
278 {
279 sysOp_ = std::make_unique<SystemSeqOp<Scalar>>(sysMatrix_);
280
281 sysFlexSolverSeq_ = std::make_unique<Dune::FlexibleSolver<SystemSeqOp<Scalar>>>(
282 *sysOp_, prm, sysWeightCalc, pressureIndex);
283
284 sysSolver_ = sysFlexSolverSeq_.get();
285 sysPrecond_ = &sysFlexSolverSeq_->preconditioner();
286 }
287 }
288};
289
290} // namespace Opm
291
292#endif // OPM_ISTLSOLVERSYSTEM_HEADER_INCLUDED
Definition: MultiComm.hpp:75
Interface class adding the update() method to the preconditioner interface.
Definition: PreconditionerWithUpdate.hpp:34
Definition: ISTLSolver.hpp:152
std::shared_ptr< CommunicationType > comm_
Definition: ISTLSolver.hpp:686
typename SparseMatrixAdapter::IstlMatrix Matrix
Definition: ISTLSolver.hpp:161
int solveCount_
Definition: ISTLSolver.hpp:666
Matrix & getMatrix()
Definition: ISTLSolver.hpp:654
GetPropType< TypeTag, Properties::SparseMatrixAdapter > SparseMatrixAdapter
Definition: ISTLSolver.hpp:156
Dune::OwnerOverlapCopyCommunication< int, int > CommunicationType
Definition: ISTLSolver.hpp:177
Matrix * matrix_
Definition: ISTLSolver.hpp:670
bool checkConvergence(const Dune::InverseOperatorResult &result) const
Definition: ISTLSolver.hpp:484
GetPropType< TypeTag, Properties::GlobalEqVector > Vector
Definition: ISTLSolver.hpp:157
void initPrepare(const Matrix &M, Vector &b)
Definition: ISTLSolver.hpp:348
std::function< Vector()> getWeightsCalculator(const PropertyTree &prm, const Matrix &matrix, std::size_t pressIndex) const
Definition: ISTLSolver.hpp:587
int iterations_
Definition: ISTLSolver.hpp:665
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: ISTLSolver.hpp:160
Vector * rhs_
Definition: ISTLSolver.hpp:671
int activeSolverNum_
Definition: ISTLSolver.hpp:673
GetPropType< TypeTag, Properties::Indices > Indices
Definition: ISTLSolver.hpp:158
const Simulator & simulator_
Definition: ISTLSolver.hpp:664
std::vector< PropertyTree > prm_
Definition: ISTLSolver.hpp:684
Definition: ISTLSolverSystem.hpp:35
void prepare(const SparseMatrixAdapter &M, Vector &b) override
Definition: ISTLSolverSystem.hpp:80
@ enablePolymerMolarWeight
Definition: ISTLSolverSystem.hpp:54
static constexpr auto _1
Definition: ISTLSolverSystem.hpp:65
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: ISTLSolverSystem.hpp:37
static constexpr std::size_t pressureIndex
Definition: ISTLSolverSystem.hpp:52
ISTLSolverSystem(const Simulator &simulator, const FlowLinearSolverParameters &parameters, bool forceSerial=false)
Definition: ISTLSolverSystem.hpp:68
static constexpr bool isIncompatibleWithCprw
Definition: ISTLSolverSystem.hpp:55
static constexpr auto _0
Definition: ISTLSolverSystem.hpp:64
ISTLSolverSystem(const Simulator &simulator)
Definition: ISTLSolverSystem.hpp:75
void prepare(const Matrix &M, Vector &b) override
Definition: ISTLSolverSystem.hpp:87
bool solve(Vector &x) override
Definition: ISTLSolverSystem.hpp:94
Hierarchical collection of key/value pairs.
Definition: PropertyTree.hpp:39
PropertyTree get_child(const std::string &key) const
Definition: SystemTypes.hpp:77
const WRMatrix< Scalar > * B
Definition: SystemTypes.hpp:88
const RWMatrix< Scalar > * C
Definition: SystemTypes.hpp:87
const RRMatrix< Scalar > * A
Definition: SystemTypes.hpp:86
const WWMatrix< Scalar > * D
Definition: SystemTypes.hpp:89
Definition: SystemPreconditioner.hpp:55
Definition: WellMatrixMerger.hpp:124
Definition: blackoilbioeffectsmodules.hh:45
Dune::MultiTypeBlockVector< ResVector< Scalar >, WellVector< Scalar > > SystemVector
Definition: SystemTypes.hpp:59
Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, numWellDofs, numWellDofs > > WWMatrix
Definition: SystemTypes.hpp:52
Dune::InverseOperatorResult InverseOperatorResult
Definition: GpuBridge.hpp:32
Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, numResDofs, numWellDofs > > RWMatrix
Definition: SystemTypes.hpp:48
Dune::OwnerOverlapCopyCommunication< int, int > ParResComm
Definition: SystemPreconditioner.hpp:38
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233
Dune::BCRSMatrix< Dune::FieldMatrix< Scalar, numWellDofs, numResDofs > > WRMatrix
Definition: SystemTypes.hpp:50
This class carries all parameters for the NewtonIterationBlackoilInterleaved class.
Definition: FlowLinearSolverParameters.hpp:98
Definition: WellMatrixMerger.hpp:63
std::size_t totalWellBlocks
Definition: WellMatrixMerger.hpp:65