GenericThresholdPressure_impl.hpp
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
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 2 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 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
23#ifndef OPM_GENERIC_THRESHOLD_PRESSURE_IMPL_HPP
24#define OPM_GENERIC_THRESHOLD_PRESSURE_IMPL_HPP
25
27
28#include <dune/grid/common/mcmgmapper.hh>
29#include <dune/grid/common/rangegenerators.hh>
30
31#include <opm/common/ErrorMacros.hpp>
32
33#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
34#include <opm/input/eclipse/EclipseState/Grid/FieldPropsManager.hpp>
35#include <opm/input/eclipse/EclipseState/Tables/Eqldims.hpp>
36#include <opm/input/eclipse/EclipseState/SimulationConfig/SimulationConfig.hpp>
37#include <opm/input/eclipse/EclipseState/SimulationConfig/ThresholdPressure.hpp>
38
39#include <fmt/format.h>
40
41#include <algorithm>
42#include <cstddef>
43#include <limits>
44#include <stdexcept>
45
46namespace Opm {
47
48template<class Grid, class GridView, class ElementMapper, class Scalar>
51 const GridView& gridView,
52 const ElementMapper& elementMapper,
53 const EclipseState& eclState)
54 : cartMapper_(cartMapper)
55 , gridView_(gridView)
56 , elementMapper_(elementMapper)
57 , lookUpData_(gridView)
58 , lookUpCartesianData_(gridView, cartMapper_)
59 , eclState_(eclState)
60{
61}
63template<class Grid, class GridView, class ElementMapper,class Scalar>
65thresholdPressure(int elem1Idx, int elem2Idx) const
66{
67 if (!enableThresholdPressure_)
68 return 0.0;
69
70 // threshold pressure accross faults
71 if (!thpresftValues_.empty()) {
72
73 int fault1Idx = lookUpCartesianData_(elem1Idx, cartElemFaultIdx_);
74 int fault2Idx = lookUpCartesianData_(elem2Idx, cartElemFaultIdx_);
75
76 if (fault1Idx != -1 && fault1Idx == fault2Idx) {
77 // inside a fault there's no threshold pressure, even accross EQUIL
78 // regions.
79 return 0.0;
80 }
81 if (fault1Idx != fault2Idx) {
82 // TODO: which value if a cell is part of multiple faults? we take
83 // the maximum here.
84 Scalar val1 = (fault1Idx >= 0) ? thpresftValues_[fault1Idx] : 0.0;
85 Scalar val2 = (fault2Idx >= 0) ? thpresftValues_[fault2Idx] : 0.0;
86 return std::max(val1, val2);
87 }
88 }
89
90 // threshold pressure accross EQUIL regions
91 auto equilRegion1Idx = elemEquilRegion_[elem1Idx];
92 auto equilRegion2Idx = elemEquilRegion_[elem2Idx];
93
94 if (equilRegion1Idx == equilRegion2Idx) {
95 return 0.0;
96 }
97
98 return thpres_[equilRegion1Idx*numEquilRegions_ + equilRegion2Idx];
99}
101template<class Grid, class GridView, class ElementMapper, class Scalar>
104{
105 const auto& simConfig = eclState_.getSimulationConfig();
106
107 enableThresholdPressure_ = simConfig.useThresholdPressure();
108 if (!enableThresholdPressure_) {
109 return;
110 }
111
112 numEquilRegions_ = eclState_.getTableManager().getEqldims().getNumEquilRegions();
113 const decltype(numEquilRegions_) maxRegions =
114 std::numeric_limits<std::decay_t<decltype(elemEquilRegion_[0])>>::max();
115
116 if (numEquilRegions_ > maxRegions) {
117 // make sure that the index of an equilibration region can be stored
118 // in the vector
119 OPM_THROW(std::invalid_argument,
120 (fmt::format("The maximum number of supported "
121 "equilibration regions by OPM flow is {}, but "
122 "{} are used!",
123 maxRegions, numEquilRegions_)));
124 }
125
126 if (numEquilRegions_ > 2048) {
127 // warn about performance
128 OpmLog::warning(fmt::format("Number of equilibration regions is {}, which is "
129 "rather large. Note, that this might "
130 "have a negative impact on performance "
131 "and memory consumption.", numEquilRegions_));
132 }
133
134 // internalize the data specified using the EQLNUM keyword
135 elemEquilRegion_ = lookUpData_.
136 template assignFieldPropsIntOnLeaf<short unsigned int>(eclState_.fieldProps(),
137 "EQLNUM", true);
138
139 /*
140 If this is a restart run the ThresholdPressure object will be active,
141 and already properly initialized with numerical values from the restart.
142 Done using GenericThresholdPressure::setFromRestart() in EclWriter::beginRestart().
143 */
144 if (simConfig.getThresholdPressure().restart()) {
145 return;
146 }
147
148 // allocate the array which specifies the threshold pressures
149 thpres_.resize(numEquilRegions_*numEquilRegions_, 0.0);
150 thpresDefault_.resize(numEquilRegions_*numEquilRegions_, 0.0);
151}
152
153template<class Grid, class GridView, class ElementMapper, class Scalar>
156{
157 const SimulationConfig& simConfig = eclState_.getSimulationConfig();
158 const auto& thpres = simConfig.getThresholdPressure();
159
160 // set the threshold pressures for all EQUIL region boundaries which have a
161 // intersection in the grid
162 for (const auto& elem : elements(gridView_, Dune::Partitions::interior)) {
163 for (const auto& intersection : intersections(gridView_, elem)) {
164 if (intersection.boundary()) {
165 continue; // ignore boundary intersections for now (TODO?)
166 }
167 else if (!intersection.neighbor()) { // processor boundary but not domain boundary
168 continue;
169 }
170
171 const auto& inside = intersection.inside();
172 const auto& outside = intersection.outside();
173
174 auto equilRegionInside = elemEquilRegion_[elementMapper_.index(inside)];
175 auto equilRegionOutside = elemEquilRegion_[elementMapper_.index(outside)];
176
177 if (thpres.hasRegionBarrier(equilRegionInside + 1, equilRegionOutside + 1)) {
178 Scalar pth = 0.0;
179 if (thpres.hasThresholdPressure(equilRegionInside + 1, equilRegionOutside + 1)) {
180 // threshold pressure explicitly specified
181 pth = thpres.getThresholdPressure(equilRegionInside + 1, equilRegionOutside + 1);
182 }
183 else {
184 // take the threshold pressure from the initial condition
185 unsigned offset = equilRegionInside*numEquilRegions_ + equilRegionOutside;
186 pth = thpresDefault_[offset];
187 }
188
189 unsigned offset1 = equilRegionInside*numEquilRegions_ + equilRegionOutside;
190 unsigned offset2 = equilRegionOutside*numEquilRegions_ + equilRegionInside;
191
192 thpres_[offset1] = pth;
193 if (!thpres.irreversible()) {
194 thpres_[offset2] = pth;
195 }
196 }
197 }
198 }
199
200 // apply threshold pressures across faults
201 if (thpres.ftSize() > 0) {
202 configureThpresft_();
203 }
204}
205
206template<class Grid, class GridView, class ElementMapper, class Scalar>
209{
210 // retrieve the faults collection.
211 const FaultCollection& faults = eclState_.getFaults();
212 const SimulationConfig& simConfig = eclState_.getSimulationConfig();
213 const auto& thpres = simConfig.getThresholdPressure();
214
215 // extract the multipliers
216 int numFaults = faults.size();
217 int numCartesianElem = eclState_.getInputGrid().getCartesianSize();
218 thpresftValues_.resize(numFaults, -1.0);
219 cartElemFaultIdx_.resize(numCartesianElem, -1);
220 for (std::size_t faultIdx = 0; faultIdx < faults.size(); ++faultIdx) {
221 const auto& fault = faults.getFault(faultIdx);
222 thpresftValues_[faultIdx] = thpres.getThresholdPressureFault(faultIdx);
223 for (const FaultFace& face : fault) {
224 // "face" is a misnomer because the object describes a set of cell
225 // indices, but we go with the conventions of the parser here...
226 for (std::size_t cartElemIdx : face) {
227 cartElemFaultIdx_[cartElemIdx] = faultIdx;
228 }
229 }
230 }
231}
232
233template<class Grid, class GridView, class ElementMapper, class Scalar>
234std::vector<Scalar>
236getRestartVector() const
237{
238 if (!enableThresholdPressure_) {
239 return {};
240 }
241
242 return this->thpres_;
243}
244
245template<class Grid, class GridView, class ElementMapper, class Scalar>
246bool
249{
250 return this->enableThresholdPressure_;
251}
252
253
254template<class Grid, class GridView, class ElementMapper, class Scalar>
255void
258{
259 if (!enableThresholdPressure_) {
260 return;
261 }
262
263 auto lineFormat = [this](unsigned i, unsigned j, double val)
264 {
265 const auto& units = eclState_.getUnits();
266 return fmt::format("{:4}{:>6}{:23}{:>6}{:24}{:>11.07}{:7}{}\n",
267 " ", i,
268 " ", j,
269 " ", units.from_si(UnitSystem::measure::pressure, val),
270 " ", units.name(UnitSystem::measure::pressure));
271 };
272 auto lineFormatS = [](auto s1, auto s2, auto s3)
273 {
274 return fmt::format("{:4}{:^16}{:13}{:^9}{:21}{:^18}\n",
275 " ", s1, " ", s2, " ", s3);
276 };
277
278 std::string str = "\nLIST OF ALL NON-ZERO THRESHOLD PRESSURES\n"
279 "----------------------------------------\n"
280 "\n";
281 str += lineFormatS("FLOW FROM REGION", "TO REGION", "THRESHOLD PRESSURE");
282 str += lineFormatS(std::string(16, '-'), std::string(9, '-'), std::string(18, '-'));
283 const auto& simConfig = eclState_.getSimulationConfig();
284 const auto& thpres = simConfig.getThresholdPressure();
285
286 for (unsigned i = 1; i <= numEquilRegions_; ++i) {
287 for (unsigned j = (thpres.irreversible() ? 1 : i); j <= numEquilRegions_; ++j) {
288 if (thpres.hasRegionBarrier(i, j)) {
289 if (thpres.hasThresholdPressure(i, j)) {
290 str += lineFormat(i, j, thpres.getThresholdPressure(i, j));
291 }
292 else {
293 std::size_t idx = (i - 1) * numEquilRegions_ + (j - 1);
294 str += lineFormat(i, j, this->thpresDefault_[idx]);
295 }
296 }
297 }
298 }
299 str += lineFormatS(std::string(16, '-'), std::string(9, '-'), std::string(18, '-'));
300 OpmLog::note(str);
301}
302
303} // namespace Opm
304
305#endif // OPM_GENERIC_THRESHOLD_PRESSURE_IMPL_HPP
Definition: CollectDataOnIORank.hpp:49
void configureThpresft_()
Definition: GenericThresholdPressure_impl.hpp:208
void logPressures()
Definition: GenericThresholdPressure_impl.hpp:257
void finishInit()
Actually compute the threshold pressures over a face as a pre-compute step.
Definition: GenericThresholdPressure_impl.hpp:103
GenericThresholdPressure(const CartesianIndexMapper &cartMapper, const GridView &gridView, const ElementMapper &elementMapper, const EclipseState &eclState)
Definition: GenericThresholdPressure_impl.hpp:50
bool enableThresholdPressure() const
Definition: GenericThresholdPressure_impl.hpp:248
Scalar thresholdPressure(int elem1Idx, int elem2Idx) const
Returns the theshold pressure [Pa] for the intersection between two elements.
Definition: GenericThresholdPressure_impl.hpp:65
std::vector< Scalar > getRestartVector() const
Returns a fully expanded vector for restart file writing.
Definition: GenericThresholdPressure_impl.hpp:236
void applyExplicitThresholdPressures_()
Definition: GenericThresholdPressure_impl.hpp:155
Definition: blackoilbioeffectsmodules.hh:45