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