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