opm-simulators
GenericThresholdPressure_impl.hpp
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 
46 namespace Opm {
47 
48 template<class Grid, class GridView, class ElementMapper, class Scalar>
49 GenericThresholdPressure<Grid,GridView,ElementMapper,Scalar>::
50 GenericThresholdPressure(const CartesianIndexMapper& cartMapper,
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 }
62 
63 template<class Grid, class GridView, class ElementMapper,class Scalar>
64 Scalar GenericThresholdPressure<Grid,GridView,ElementMapper,Scalar>::
65 thresholdPressure(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 }
100 
101 template<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 
153 template<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 
204 template<class Grid, class GridView, class ElementMapper, class Scalar>
205 void GenericThresholdPressure<Grid,GridView,ElementMapper,Scalar>::
206 configureThpresft_()
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 
231 template<class Grid, class GridView, class ElementMapper, class Scalar>
232 std::vector<Scalar>
233 GenericThresholdPressure<Grid,GridView,ElementMapper,Scalar>::
234 getRestartVector() const
235 {
236  if (!enableThresholdPressure_) {
237  return {};
238  }
239 
240  return this->thpres_;
241 }
242 
243 template<class Grid, class GridView, class ElementMapper, class Scalar>
244 bool
247 {
248  return this->enableThresholdPressure_;
249 }
250 
251 
252 template<class Grid, class GridView, class ElementMapper, class Scalar>
253 void
254 GenericThresholdPressure<Grid,GridView,ElementMapper,Scalar>::
255 logPressures()
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
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
Definition: GenericThresholdPressure.hpp:43