PressureBhpTransferPolicy.hpp
Go to the documentation of this file.
1/*
2 Copyright 2019 SINTEF Digital, Mathematics and Cybernetics.
3 Copyright 2019 Dr. Blatt - HPC-Simulation-Software & Services.
4
5 This file is part of the Open Porous Media project (OPM).
6
7 OPM is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 OPM is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with OPM. If not, see <http://www.gnu.org/licenses/>.
19*/
20
21#pragma once
22
23#include <opm/common/ErrorMacros.hpp>
24#include <opm/common/TimingMacros.hpp>
25
29
30#include <dune/istl/paamg/pinfo.hh>
32
33#include <cstddef>
34
35namespace Opm
36{
37 template <class Communication>
39 std::shared_ptr<Communication>& commRW,
40 const int nw)
41 {
42 OPM_TIMEBLOCK(extendCommunicatorWithWells);
43 // used for extending the coarse communicator pattern
44 using IndexSet = typename Communication::ParallelIndexSet;
45 using LocalIndex = typename IndexSet::LocalIndex;
46 const IndexSet& indset = comm.indexSet();
47 IndexSet& indset_rw = commRW->indexSet();
48 const int max_nw = comm.communicator().max(nw);
49 const int rank = comm.communicator().rank();
50 int glo_max = 0;
51 std::size_t loc_max = 0;
52 indset_rw.beginResize();
53 for (auto ind = indset.begin(), indend = indset.end(); ind != indend; ++ind) {
54 indset_rw.add(ind->global(), LocalIndex(ind->local(), ind->local().attribute(), true));
55 const int glo = ind->global();
56 const std::size_t loc = ind->local().local();
57 glo_max = std::max(glo_max, glo);
58 loc_max = std::max(loc_max, loc);
59 }
60 const int global_max = comm.communicator().max(glo_max);
61 // used append the welldofs at the end
62 assert(loc_max + 1 == indset.size());
63 std::size_t local_ind = loc_max + 1;
64 for (int i = 0; i < nw; ++i) {
65 // need to set unique global number
66 const std::size_t v = global_max + max_nw * rank + i + 1;
67 // set to true to not have problems with higher levels if growing of domains is used
68 indset_rw.add(v, LocalIndex(local_ind, Dune::OwnerOverlapCopyAttributeSet::owner, true));
69 ++local_ind;
70 }
71 indset_rw.endResize();
72 assert(indset_rw.size() == indset.size() + nw);
73 // assume same communication pattern
74 commRW->remoteIndices().setNeighbours(comm.remoteIndices().getNeighbours());
75 commRW->remoteIndices().template rebuild<true>();
76 //commRW->clearInterfaces(); may need this for correct rebuild
77 }
78
79 namespace Details
80 {
81 template<class Scalar> using PressureMatrixType = Dune::BCRSMatrix<MatrixBlock<Scalar, 1, 1>>;
82 template<class Scalar> using PressureVectorType = Dune::BlockVector<Dune::FieldVector<Scalar, 1>>;
83 template<class Scalar> using SeqCoarseOperatorType = Dune::MatrixAdapter<PressureMatrixType<Scalar>,
86 template<class Scalar, class Comm>
91 Comm>;
92 template<class Scalar, class Comm>
93 using CoarseOperatorType = std::conditional_t<std::is_same<Comm, Dune::Amg::SequentialInformation>::value,
96 } // namespace Details
97
98 template<class FineOperator, class Communication, class Scalar, bool transpose = false>
99 class PressureBhpTransferPolicy : public Dune::Amg::LevelTransferPolicyCpr<FineOperator, Details::CoarseOperatorType<Scalar,Communication>>
100 {
101 public:
105 using FineVectorType= typename FineOperator::domain_type;
106
107 public:
109 const FineVectorType& weights,
110 const PropertyTree& prm,
111 const std::size_t pressureIndex)
112 : communication_(&const_cast<Communication&>(comm))
113 , weights_(weights)
114 , prm_(prm)
115 , pressure_var_index_(pressureIndex)
116 {
117 }
118
119 void createCoarseLevelSystem(const FineOperator& fineOperator) override
120 {
121 OPM_TIMEBLOCK(createCoarseLevelSystem);
122 using CoarseMatrix = typename CoarseOperator::matrix_type;
123 const auto& fineLevelMatrix = fineOperator.getmat();
124 const auto& nw = fineOperator.getNumberOfExtraEquations();
125 if (prm_.get<bool>("add_wells")) {
126 const std::size_t average_elements_per_row
127 = static_cast<std::size_t>(std::ceil(fineLevelMatrix.nonzeroes() / fineLevelMatrix.N()));
128 const double overflow_fraction = 1.2;
129 coarseLevelMatrix_.reset(new CoarseMatrix(fineLevelMatrix.N() + nw,
130 fineLevelMatrix.M() + nw,
131 average_elements_per_row,
132 overflow_fraction,
133 CoarseMatrix::implicit));
134 int rownum = 0;
135 for (const auto& row : fineLevelMatrix) {
136 for (auto col = row.begin(), cend = row.end(); col != cend; ++col) {
137 coarseLevelMatrix_->entry(rownum, col.index()) = 0.0;
138 }
139 ++rownum;
140 }
141 } else {
142 coarseLevelMatrix_.reset(
143 new CoarseMatrix(fineLevelMatrix.N(), fineLevelMatrix.M(), fineLevelMatrix.nonzeroes(), CoarseMatrix::row_wise));
144 auto createIter = coarseLevelMatrix_->createbegin();
145 for (const auto& row : fineLevelMatrix) {
146 for (auto col = row.begin(), cend = row.end(); col != cend; ++col) {
147 createIter.insert(col.index());
148 }
149 ++createIter;
150 }
151 }
152 if constexpr (std::is_same_v<Communication, Dune::Amg::SequentialInformation>) {
153 coarseLevelCommunication_ = std::make_shared<Communication>();
154 } else {
155 coarseLevelCommunication_ = std::make_shared<Communication>(
156 communication_->communicator(), communication_->category(), false);
157 }
158 if (prm_.get<bool>("add_wells")) {
159 fineOperator.addWellPressureEquationsStruct(*coarseLevelMatrix_);
160 coarseLevelMatrix_->compress(); // all elemenst should be set
161 if constexpr (!std::is_same_v<Communication, Dune::Amg::SequentialInformation>) {
162 extendCommunicatorWithWells(*communication_, coarseLevelCommunication_, nw);
163 }
164 }
165 calculateCoarseEntries(fineOperator);
166
167 this->lhs_.resize(this->coarseLevelMatrix_->M());
168 this->rhs_.resize(this->coarseLevelMatrix_->N());
169 using OperatorArgs = typename Dune::Amg::ConstructionTraits<CoarseOperator>::Arguments;
170 OperatorArgs oargs(coarseLevelMatrix_, *coarseLevelCommunication_);
171 this->operator_ = Dune::Amg::ConstructionTraits<CoarseOperator>::construct(oargs);
172 }
173
174 void calculateCoarseEntries(const FineOperator& fineOperator) override
175 {
176 OPM_TIMEBLOCK(calculateCoarseEntries);
177 const auto& fineMatrix = fineOperator.getmat();
178 *coarseLevelMatrix_ = 0;
179 auto rowCoarse = coarseLevelMatrix_->begin();
180 for (auto row = fineMatrix.begin(), rowEnd = fineMatrix.end(); row != rowEnd; ++row, ++rowCoarse) {
181 assert(row.index() == rowCoarse.index());
182 auto entryCoarse = rowCoarse->begin();
183 for (auto entry = row->begin(), entryEnd = row->end(); entry != entryEnd; ++entry, ++entryCoarse) {
184 assert(entry.index() == entryCoarse.index());
185 Scalar matrix_el = 0;
186 if (transpose) {
187 const auto& bw = weights_[entry.index()];
188 for (std::size_t i = 0; i < bw.size(); ++i) {
189 matrix_el += (*entry)[pressure_var_index_][i] * bw[i];
190 }
191 } else {
192 const auto& bw = weights_[row.index()];
193 for (std::size_t i = 0; i < bw.size(); ++i) {
194 matrix_el += (*entry)[i][pressure_var_index_] * bw[i];
195 }
196 }
197 (*entryCoarse) = matrix_el;
198 }
199 }
200 if (prm_.get<bool>("add_wells")) {
201 OPM_TIMEBLOCK(cprwAddWellEquation);
202 assert(transpose == false); // not implemented
203 const bool use_well_weights = prm_.get<bool>("use_well_weights");
204 // How a multisegment well's coarse diagonal is formed: "row_sum"
205 // (the default) keeps the historical minus-the-row-sum diagonal,
206 // "contract_d" takes it from lambda' D(:,bhp) as standard wells
207 // have always done. Standard wells contract D either way, so this
208 // only changes non-pressure-controlled multisegment wells;
209 // pressure-controlled multisegment wells retain a unit diagonal.
210 // Named after the operation
211 // rather than "auto" so a configuration says which it wants, and
212 // to match the vocabulary of the system solver's own key.
213 const auto diagonal = prm_.get<std::string>("well_coarse_diagonal", "row_sum");
214 if (diagonal != "row_sum" && diagonal != "contract_d") {
215 OPM_THROW(std::invalid_argument,
216 "Unknown well_coarse_diagonal '" + diagonal +
217 "'. Valid values are 'row_sum' and 'contract_d'.");
218 }
219 const bool contract_d_diagonal = (diagonal == "contract_d");
220 fineOperator.addWellPressureEquations(*coarseLevelMatrix_, weights_,
221 use_well_weights, contract_d_diagonal);
222#ifndef NDEBUG
223 std::advance(rowCoarse, fineOperator.getNumberOfExtraEquations());
224 assert(rowCoarse == coarseLevelMatrix_->end());
225#endif
226
227 }
228 }
229
230 void moveToCoarseLevel(const typename ParentType::FineRangeType& fine) override
231 {
232 OPM_TIMEBLOCK(moveToCoarseLevel);
233 //NB we iterate over fine assumming welldofs is at the end
234 // Set coarse vector to zero
235 this->rhs_ = 0;
236
237 auto end = fine.end(), begin = fine.begin();
238
239 for (auto block = begin; block != end; ++block) {
240 const auto& bw = weights_[block.index()];
241 Scalar rhs_el = 0.0;
242 if (transpose) {
243 rhs_el = (*block)[pressure_var_index_];
244 } else {
245 for (std::size_t i = 0; i < block->size(); ++i) {
246 rhs_el += (*block)[i] * bw[i];
247 }
248 }
249 this->rhs_[block - begin] = rhs_el;
250 }
251
252 this->lhs_ = 0;
253 }
254
255 void moveToFineLevel(typename ParentType::FineDomainType& fine) override
256 {
257 OPM_TIMEBLOCK(moveToFineLevel);
258 //NB we iterate over fine assumming welldofs is at the end
259 auto end = fine.end(), begin = fine.begin();
260
261 for (auto block = begin; block != end; ++block) {
262 if (transpose) {
263 const auto& bw = weights_[block.index()];
264 for (std::size_t i = 0; i < block->size(); ++i) {
265 (*block)[i] = this->lhs_[block - begin][0] * bw[i];
266 }
267 } else {
268 (*block)[pressure_var_index_] = this->lhs_[block - begin][0];
269 }
270 }
271 }
272
274 {
275 return new PressureBhpTransferPolicy(*this);
276 }
277
279 {
280 return *coarseLevelCommunication_;
281 }
282
283private:
284 Communication* communication_;
285 const FineVectorType& weights_;
286 PropertyTree prm_;
287 const int pressure_var_index_;
288 std::shared_ptr<Communication> coarseLevelCommunication_;
289 std::shared_ptr<typename CoarseOperator::matrix_type> coarseLevelMatrix_;
290};
291
292} // namespace Opm
Dune::OwnerOverlapCopyCommunication< int, int > Comm
Definition: FlexibleSolver_impl.hpp:404
Abstract base class for transfer between levels and creation of the coarse level system.
Definition: twolevelmethodcpr.hh:49
FineOperatorType::range_type FineRangeType
The type of the range of the fine level operator.
Definition: twolevelmethodcpr.hh:59
CoarseDomainType lhs_
The coarse level lhs.
Definition: twolevelmethodcpr.hh:146
CoarseRangeType rhs_
The coarse level rhs.
Definition: twolevelmethodcpr.hh:144
FineOperatorType::domain_type FineDomainType
The type of the domain of the fine level operator.
Definition: twolevelmethodcpr.hh:63
std::shared_ptr< CoarseOperatorType > operator_
the coarse level linear operator.
Definition: twolevelmethodcpr.hh:148
Dune linear operator that assumes ghost rows are ordered after interior rows. Avoids some computation...
Definition: WellOperators.hpp:412
Definition: PressureBhpTransferPolicy.hpp:100
typename Details::CoarseOperatorType< Scalar, Communication > CoarseOperator
Definition: PressureBhpTransferPolicy.hpp:102
typename FineOperator::domain_type FineVectorType
Definition: PressureBhpTransferPolicy.hpp:105
Communication ParallelInformation
Definition: PressureBhpTransferPolicy.hpp:104
PressureBhpTransferPolicy * clone() const override
Clone the current object.
Definition: PressureBhpTransferPolicy.hpp:273
void moveToFineLevel(typename ParentType::FineDomainType &fine) override
Updates the fine level linear system after the correction of the coarse levels system.
Definition: PressureBhpTransferPolicy.hpp:255
void createCoarseLevelSystem(const FineOperator &fineOperator) override
Algebraically creates the coarse level system.
Definition: PressureBhpTransferPolicy.hpp:119
PressureBhpTransferPolicy(const Communication &comm, const FineVectorType &weights, const PropertyTree &prm, const std::size_t pressureIndex)
Definition: PressureBhpTransferPolicy.hpp:108
const Communication & getCoarseLevelCommunication() const
Definition: PressureBhpTransferPolicy.hpp:278
void calculateCoarseEntries(const FineOperator &fineOperator) override
???.
Definition: PressureBhpTransferPolicy.hpp:174
void moveToCoarseLevel(const typename ParentType::FineRangeType &fine) override
Definition: PressureBhpTransferPolicy.hpp:230
Hierarchical collection of key/value pairs.
Definition: PropertyTree.hpp:39
T get(const std::string &key) const
Dune::BCRSMatrix< MatrixBlock< Scalar, 1, 1 > > PressureMatrixType
Definition: PressureBhpTransferPolicy.hpp:81
std::conditional_t< std::is_same< Comm, Dune::Amg::SequentialInformation >::value, SeqCoarseOperatorType< Scalar >, ParCoarseOperatorType< Scalar, Comm > > CoarseOperatorType
Definition: PressureBhpTransferPolicy.hpp:95
Dune::BlockVector< Dune::FieldVector< Scalar, 1 > > PressureVectorType
Definition: PressureBhpTransferPolicy.hpp:82
Dune::MatrixAdapter< PressureMatrixType< Scalar >, PressureVectorType< Scalar >, PressureVectorType< Scalar > > SeqCoarseOperatorType
Definition: PressureBhpTransferPolicy.hpp:85
Dune::Communication< MPIComm > Communication
Definition: ParallelCommunication.hpp:30
Definition: blackoilbioeffectsmodules.hh:45
void extendCommunicatorWithWells(const Communication &comm, std::shared_ptr< Communication > &commRW, const int nw)
Definition: PressureBhpTransferPolicy.hpp:38
Algebraic twolevel methods.