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 thpres_[offset2] = pth;
194 }
195 }
196 }
197
198 // apply threshold pressures across faults
199 if (thpres.ftSize() > 0) {
200 configureThpresft_();
201 }
202}
203
204template<class Grid, class GridView, class ElementMapper, class Scalar>
207{
208 // retrieve the faults collection.
209 const FaultCollection& faults = eclState_.getFaults();
210 const SimulationConfig& simConfig = eclState_.getSimulationConfig();
211 const auto& thpres = simConfig.getThresholdPressure();
212
213 // extract the multipliers
214 int numFaults = faults.size();
215 int numCartesianElem = eclState_.getInputGrid().getCartesianSize();
216 thpresftValues_.resize(numFaults, -1.0);
217 cartElemFaultIdx_.resize(numCartesianElem, -1);
218 for (std::size_t faultIdx = 0; faultIdx < faults.size(); ++faultIdx) {
219 const auto& fault = faults.getFault(faultIdx);
220 thpresftValues_[faultIdx] = thpres.getThresholdPressureFault(faultIdx);
221 for (const FaultFace& face : fault) {
222 // "face" is a misnomer because the object describes a set of cell
223 // indices, but we go with the conventions of the parser here...
224 for (std::size_t cartElemIdx : face) {
225 cartElemFaultIdx_[cartElemIdx] = faultIdx;
226 }
227 }
228 }
229}
230
231template<class Grid, class GridView, class ElementMapper, class Scalar>
232std::vector<Scalar>
234getRestartVector() const
235{
236 if (!enableThresholdPressure_) {
237 return {};
238 }
239
240 return this->thpres_;
241}
242
243template<class Grid, class GridView, class ElementMapper, class Scalar>
244bool
247{
248 return this->enableThresholdPressure_;
249}
250
251
252template<class Grid, class GridView, class ElementMapper, class Scalar>
253void
256{
257 if (!enableThresholdPressure_) {
258 return;
259 }
260
261 auto lineFormat = [this](unsigned i, unsigned j, double val)
262 {
263 const auto& units = eclState_.getUnits();
264 return fmt::format("{:4}{:>6}{:23}{:>6}{:24}{:>11.07}{:7}{}\n",
265 " ", i,
266 " ", j,
267 " ", units.from_si(UnitSystem::measure::pressure, val),
268 " ", units.name(UnitSystem::measure::pressure));
269 };
270 auto lineFormatS = [](auto s1, auto s2, auto s3)
271 {
272 return fmt::format("{:4}{:^16}{:13}{:^9}{:21}{:^18}\n",
273 " ", s1, " ", s2, " ", s3);
274 };
275
276 std::string str = "\nLIST OF ALL NON-ZERO THRESHOLD PRESSURES\n"
277 "----------------------------------------\n"
278 "\n";
279 str += lineFormatS("FLOW FROM REGION", "TO REGION", "THRESHOLD PRESSURE");
280 str += lineFormatS(std::string(16, '-'), std::string(9, '-'), std::string(18, '-'));
281 const auto& simConfig = eclState_.getSimulationConfig();
282 const auto& thpres = simConfig.getThresholdPressure();
283
284 for (unsigned i = 1; i <= numEquilRegions_; ++i) {
285 for (unsigned j = (thpres.irreversible() ? 1 : i); j <= numEquilRegions_; ++j) {
286 if (thpres.hasRegionBarrier(i, j)) {
287 if (thpres.hasThresholdPressure(i, j)) {
288 str += lineFormat(i, j, thpres.getThresholdPressure(j, i));
289 }
290 else {
291 std::size_t idx = (j - 1) * numEquilRegions_ + (i - 1);
292 str += lineFormat(i, j, this->thpresDefault_[idx]);
293 }
294 }
295 }
296 }
297 str += lineFormatS(std::string(16, '-'), std::string(9, '-'), std::string(18, '-'));
298 OpmLog::note(str);
299}
300
301} // namespace Opm
302
303#endif // OPM_GENERIC_THRESHOLD_PRESSURE_IMPL_HPP
Definition: CollectDataOnIORank.hpp:49
void configureThpresft_()
Definition: GenericThresholdPressure_impl.hpp:206
void logPressures()
Definition: GenericThresholdPressure_impl.hpp:255
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:246
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:234
void applyExplicitThresholdPressures_()
Definition: GenericThresholdPressure_impl.hpp:155
Definition: blackoilboundaryratevector.hh:39