RateConverter.hpp
Go to the documentation of this file.
1 /*
2  Copyright 2014, 2015 SINTEF ICT, Applied Mathematics.
3  Copyright 2014, 2015 Statoil ASA.
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 #ifndef OPM_RATECONVERTER_HPP_HEADER_INCLUDED
22 #define OPM_RATECONVERTER_HPP_HEADER_INCLUDED
23 
25 
26 #include <opm/core/props/BlackoilPhases.hpp>
27 #include <opm/core/simulator/BlackoilState.hpp>
28 #include <opm/core/utility/RegionMapping.hpp>
29 
30 #include <Eigen/Core>
31 
32 #include <algorithm>
33 #include <cmath>
34 #include <memory>
35 #include <stdexcept>
36 #include <type_traits>
37 #include <unordered_map>
38 #include <utility>
39 #include <vector>
40 
51 namespace Opm {
52  namespace RateConverter {
57  namespace Details {
58  namespace Select {
59  template <class RegionID, bool>
61  {
62  using type =
63  typename std::remove_reference<RegionID>::type &;
64  };
65 
66  template <class RegionID>
67  struct RegionIDParameter<RegionID, true>
68  {
69  using type = RegionID;
70  };
71  } // Select
72 
85  template <typename RegionId, class Attributes>
87  {
88  public:
93  using RegionID =
95  <RegionId, std::is_integral<RegionId>::value>::type;
96 
110  template <class RMap>
111  RegionAttributes(const RMap& rmap,
112  const Attributes& attr)
113  {
114  using VT = typename AttributeMap::value_type;
115 
116  for (const auto& r : rmap.activeRegions()) {
117  auto v = std::unique_ptr<Value>(new Value(attr));
118 
119  const auto stat = attr_.insert(VT(r, std::move(v)));
120 
121  if (stat.second) {
122  // New value inserted.
123  const auto& cells = rmap.cells(r);
124 
125  assert (! cells.empty());
126 
127  // Region's representative cell.
128  stat.first->second->cell_ = cells[0];
129  }
130  }
131  }
132 
140  int cell(const RegionID reg) const
141  {
142  return this->find(reg).cell_;
143  }
144 
153  const Attributes& attributes(const RegionID reg) const
154  {
155  return this->find(reg).attr_;
156  }
157 
166  Attributes& attributes(const RegionID reg)
167  {
168  return this->find(reg).attr_;
169  }
170 
171  private:
176  struct Value {
177  Value(const Attributes& attr)
178  : attr_(attr)
179  , cell_(-1)
180  {}
181 
182  Attributes attr_;
183  int cell_;
184  };
185 
186  using ID =
187  typename std::remove_reference<RegionId>::type;
188 
189  using AttributeMap =
190  std::unordered_map<ID, std::unique_ptr<Value>>;
191 
192  AttributeMap attr_;
193 
197  const Value& find(const RegionID reg) const
198  {
199  const auto& i = attr_.find(reg);
200 
201  if (i == attr_.end()) {
202  throw std::invalid_argument("Unknown region ID");
203  }
204 
205  return *i->second;
206  }
207 
211  Value& find(const RegionID reg)
212  {
213  const auto& i = attr_.find(reg);
214 
215  if (i == attr_.end()) {
216  throw std::invalid_argument("Unknown region ID");
217  }
218 
219  return *i->second;
220  }
221  };
222 
227  namespace PhaseUsed {
235  inline bool
236  water(const PhaseUsage& pu)
237  {
238  return pu.phase_used[ BlackoilPhases::Aqua ] != 0;
239  }
240 
248  inline bool
249  oil(const PhaseUsage& pu)
250  {
251  return pu.phase_used[ BlackoilPhases::Liquid ] != 0;
252  }
253 
261  inline bool
262  gas(const PhaseUsage& pu)
263  {
264  return pu.phase_used[ BlackoilPhases::Vapour ] != 0;
265  }
266  } // namespace PhaseUsed
267 
272  namespace PhasePos {
281  inline int
282  water(const PhaseUsage& pu)
283  {
284  int p = -1;
285 
286  if (PhaseUsed::water(pu)) {
287  p = pu.phase_pos[ BlackoilPhases::Aqua ];
288  }
289 
290  return p;
291  }
292 
301  inline int
302  oil(const PhaseUsage& pu)
303  {
304  int p = -1;
305 
306  if (PhaseUsed::oil(pu)) {
307  p = pu.phase_pos[ BlackoilPhases::Liquid ];
308  }
309 
310  return p;
311  }
312 
321  inline int
322  gas(const PhaseUsage& pu)
323  {
324  int p = -1;
325 
326  if (PhaseUsed::gas(pu)) {
327  p = pu.phase_pos[ BlackoilPhases::Vapour ];
328  }
329 
330  return p;
331  }
332  } // namespace PhasePos
333  } // namespace Details
334 
352  template <class Property, class Region>
354  public:
364  SurfaceToReservoirVoidage(const Property& props,
365  const Region& region)
366  : props_(props)
367  , rmap_ (region)
368  , attr_ (rmap_, Attributes(props_.numPhases()))
369  {}
370 
382  void
383  defineState(const BlackoilState& state)
384  {
385  calcAverages(state);
386  calcRmax();
387  }
388 
394  typedef typename RegionMapping<Region>::RegionId RegionId;
395 
419  template <class Input,
420  class Coeff>
421  void
422  calcCoeff(const Input& in, const RegionId r, Coeff& coeff) const
423  {
424  using V = typename Property::V;
425 
426  const auto& pu = props_.phaseUsage();
427  const auto& ra = attr_.attributes(r);
428 
429  const auto p = this->constant(ra.pressure);
430  const auto T = this->constant(ra.temperature);
431  const auto c = this->getRegCell(r);
432 
433  const int iw = Details::PhasePos::water(pu);
434  const int io = Details::PhasePos::oil (pu);
435  const int ig = Details::PhasePos::gas (pu);
436 
437  std::fill(& coeff[0], & coeff[0] + props_.numPhases(), 0.0);
438 
439  if (Details::PhaseUsed::water(pu)) {
440  // q[w]_r = q[w]_s / bw
441 
442  const V bw = props_.bWat(p, T, c).value();
443 
444  coeff[iw] = 1.0 / bw(0);
445  }
446 
447  const Miscibility& m = calcMiscibility(in, r);
448 
449  // Determinant of 'R' matrix
450  const double detR = 1.0 - (m.rs(0) * m.rv(0));
451 
452  if (Details::PhaseUsed::oil(pu)) {
453  // q[o]_r = 1/(bo * (1 - rs*rv)) * (q[o]_s - rv*q[g]_s)
454 
455  const auto rs = this->constant(m.rs);
456  const V bo = props_.bOil(p, T, rs, m.cond, c).value();
457  const double den = bo(0) * detR;
458 
459  coeff[io] += 1.0 / den;
460 
461  if (Details::PhaseUsed::gas(pu)) {
462  coeff[ig] -= m.rv(0) / den;
463  }
464  }
465 
466  if (Details::PhaseUsed::gas(pu)) {
467  // q[g]_r = 1/(bg * (1 - rs*rv)) * (q[g]_s - rs*q[o]_s)
468 
469  const auto rv = this->constant(m.rv);
470  const V bg = props_.bGas(p, T, rv, m.cond, c).value();
471  const double den = bg(0) * detR;
472 
473  coeff[ig] += 1.0 / den;
474 
475  if (Details::PhaseUsed::oil(pu)) {
476  coeff[io] -= m.rs(0) / den;
477  }
478  }
479  }
480 
481  private:
485  const Property& props_;
486 
490  const RegionMapping<Region> rmap_;
491 
495  struct Attributes {
496  Attributes(const int np)
497  : pressure (0.0)
498  , temperature(0.0)
499  , Rmax (Eigen::ArrayXd::Zero(np, 1))
500  {}
501 
502  double pressure;
503  double temperature;
504  Eigen::ArrayXd Rmax;
505  };
506 
507  Details::RegionAttributes<RegionId, Attributes> attr_;
508 
514  struct Miscibility {
515  Miscibility()
516  : rs (1)
517  , rv (1)
518  , cond(1)
519  {
520  rs << 0.0;
521  rv << 0.0;
522  }
523 
531  typename Property::V rs;
532 
540  typename Property::V rv;
541 
547  std::vector<PhasePresence> cond;
548  };
549 
556  void
557  calcAverages(const BlackoilState& state)
558  {
559  const auto& press = state.pressure();
560  const auto& temp = state.temperature();
561 
562  for (const auto& reg : rmap_.activeRegions()) {
563  auto& ra = attr_.attributes(reg);
564  auto& p = ra.pressure;
565  auto& T = ra.temperature;
566 
567  std::size_t n = 0;
568  p = T = 0.0;
569  for (const auto& cell : rmap_.cells(reg)) {
570  p += press[ cell ];
571  T += temp [ cell ];
572 
573  n += 1;
574  }
575 
576  p /= n;
577  T /= n;
578  }
579  }
580 
588  void
589  calcRmax()
590  {
591  const PhaseUsage& pu = props_.phaseUsage();
592 
593  if (Details::PhaseUsed::oil(pu) &&
595  {
596  const Eigen::ArrayXd::Index
597  io = Details::PhasePos::oil(pu),
598  ig = Details::PhasePos::gas(pu);
599 
600  // Note: Intentionally does not take capillary
601  // pressure into account. This facility uses the
602  // average *hydrocarbon* pressure rather than
603  // average phase pressure.
604 
605  for (const auto& reg : rmap_.activeRegions()) {
606  auto& ra = attr_.attributes(reg);
607 
608  const auto c = this->getRegCell(reg);
609  const auto p = this->constant(ra.pressure);
610  const auto T = this->constant(ra.temperature);
611 
612  auto& Rmax = ra.Rmax;
613  Rmax.row(io) = props_.rsSat(p, T, c).value();
614  Rmax.row(ig) = props_.rvSat(p, T, c).value();
615  }
616  }
617  }
618 
636  template <class Input>
637  Miscibility
638  calcMiscibility(const Input& in, const RegionId r) const
639  {
640  const auto& pu = props_.phaseUsage();
641  const auto& attr = attr_.attributes(r);
642 
643  const int io = Details::PhasePos::oil(pu);
644  const int ig = Details::PhasePos::gas(pu);
645 
646  Miscibility m;
647  PhasePresence& cond = m.cond[0];
648 
649  if (Details::PhaseUsed::water(pu)) {
650  cond.setFreeWater();
651  }
652 
653  if (Details::PhaseUsed::oil(pu)) {
654  cond.setFreeOil();
655 
656  if (Details::PhaseUsed::gas(pu)) {
657  const double rsmax = attr.Rmax(io);
658  const double rs =
659  (0.0 < std::abs(in[io]))
660  ? in[ig] / in[io]
661  : (0.0 < std::abs(in[ig])) ? rsmax : 0.0;
662 
663  if (rsmax < rs) {
664  cond.setFreeGas();
665  }
666 
667  m.rs(0) = std::min(rs, rsmax);
668  }
669  }
670 
671  if (Details::PhaseUsed::gas(pu)) {
672  if (! Details::PhaseUsed::oil(pu)) {
673  // Oil *NOT* active -- not really supported.
674  cond.setFreeGas();
675  }
676 
677  if (Details::PhaseUsed::oil(pu)) {
678  const double rvmax = attr.Rmax(ig);
679  const double rv =
680  (0.0 < std::abs(in[ig]))
681  ? (in[io] / in[ig])
682  : (0.0 < std::abs(in[io])) ? rvmax : 0.0;
683 
684  m.rv(0) = std::min(rv, rvmax);
685  }
686  }
687 
688  return m;
689  }
690 
695  typename Property::ADB
696  constant(const typename Property::V& x) const
697  {
698  return Property::ADB::constant(x);
699  }
700 
705  typename Property::ADB
706  constant(const double x) const
707  {
708  typename Property::V y(1);
709  y << x;
710 
711  return this->constant(y);
712  }
713 
721  typename Property::Cells
722  getRegCell(const RegionId r) const
723  {
724  typename Property::Cells c(1, this->attr_.cell(r));
725 
726  return c;
727  }
728  };
729  } // namespace RateConverter
730 } // namespace Opm
731 
732 #endif /* OPM_RATECONVERTER_HPP_HEADER_INCLUDED */
bool oil(const PhaseUsage &pu)
Definition: RateConverter.hpp:249
Attributes & attributes(const RegionID reg)
Definition: RateConverter.hpp:166
void calcCoeff(const Input &in, const RegionId r, Coeff &coeff) const
Definition: RateConverter.hpp:422
typename std::remove_reference< RegionID >::type & type
Definition: RateConverter.hpp:63
AutoDiffBlock< double > ADB
Definition: BlackoilModelBase_impl.hpp:83
Definition: AdditionalObjectDeleter.hpp:22
int water(const PhaseUsage &pu)
Definition: RateConverter.hpp:282
const Attributes & attributes(const RegionID reg) const
Definition: RateConverter.hpp:153
RegionMapping< Region >::RegionId RegionId
Definition: RateConverter.hpp:394
typename Select::RegionIDParameter< RegionId, std::is_integral< RegionId >::value >::type RegionID
Definition: RateConverter.hpp:95
int cell(const RegionID reg) const
Definition: RateConverter.hpp:140
bool water(const PhaseUsage &pu)
Definition: RateConverter.hpp:236
RegionAttributes(const RMap &rmap, const Attributes &attr)
Definition: RateConverter.hpp:111
bool gas(const PhaseUsage &pu)
Definition: RateConverter.hpp:262
ADB::V V
Definition: BlackoilModelBase_impl.hpp:84
Definition: RateConverter.hpp:86
int gas(const PhaseUsage &pu)
Definition: RateConverter.hpp:322
Definition: RateConverter.hpp:353
int oil(const PhaseUsage &pu)
Definition: RateConverter.hpp:302
void defineState(const BlackoilState &state)
Definition: RateConverter.hpp:383
SurfaceToReservoirVoidage(const Property &props, const Region &region)
Definition: RateConverter.hpp:364