23#ifndef OPM_INIT_STATE_EQUIL_IMPL_HPP
24#define OPM_INIT_STATE_EQUIL_IMPL_HPP
26#include <dune/grid/common/mcmgmapper.hh>
28#include <opm/common/OpmLog/OpmLog.hpp>
30#include <opm/grid/utility/RegionMapping.hpp>
31#include <opm/grid/LookUpData.hh>
33#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
34#include <opm/input/eclipse/EclipseState/Tables/PbvdTable.hpp>
35#include <opm/input/eclipse/EclipseState/Tables/PdvdTable.hpp>
36#include <opm/input/eclipse/EclipseState/Tables/RsconstTable.hpp>
37#include <opm/input/eclipse/EclipseState/Tables/RsvdTable.hpp>
38#include <opm/input/eclipse/EclipseState/Tables/RtempvdTable.hpp>
39#include <opm/input/eclipse/EclipseState/Tables/RvvdTable.hpp>
40#include <opm/input/eclipse/EclipseState/Tables/RvwvdTable.hpp>
41#include <opm/input/eclipse/EclipseState/Tables/SaltvdTable.hpp>
42#include <opm/input/eclipse/EclipseState/Tables/SaltpvdTable.hpp>
44#include <opm/input/eclipse/Units/UnitSystem.hpp>
46#include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp>
47#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
54#include <fmt/format.h>
69template <
typename CellRange,
class Scalar>
71 const std::vector<std::pair<Scalar, Scalar>>&
cellZMinMax,
73 std::array<Scalar,2>& span)
75 span[0] = std::numeric_limits<Scalar>::max();
76 span[1] = std::numeric_limits<Scalar>::lowest();
86 for (
const auto& cell : cells) {
90 span[0] = comm.min(span[0]);
91 span[1] = comm.max(span[1]);
97 const int numIntervals,
98 std::vector<std::pair<Scalar, Scalar>>& subdiv)
100 const auto h = (right - left) / numIntervals;
103 for (
auto i = 0*numIntervals; i < numIntervals; ++i) {
104 const auto start = end;
105 end = left + (i + 1)*h;
107 subdiv.emplace_back((start + end) / 2, h);
111template <
typename CellID,
typename Scalar>
112std::vector<std::pair<Scalar, Scalar>>
114 const std::pair<Scalar, Scalar> topbot,
115 const int numIntervals)
117 auto subdiv = std::vector<std::pair<Scalar, Scalar>>{};
118 subdiv.reserve(2 * numIntervals);
120 if (topbot.first > topbot.second) {
121 throw std::out_of_range {
122 "Negative thickness (inverted top/bottom faces) in cell "
128 2*numIntervals, subdiv);
133template <
class Scalar,
class Element>
136 typedef typename Element::Geometry Geometry;
137 static constexpr int zCoord = Element::dimension - 1;
140 const Geometry& geometry = element.geometry();
141 const int corners = geometry.corners();
142 for (
int i=0; i < corners; ++i)
143 zz += geometry.corner(i)[zCoord];
148template <
class Scalar,
class Element>
151 typedef typename Element::Geometry Geometry;
152 static constexpr int xCoord = Element::dimension - 3;
153 static constexpr int yCoord = Element::dimension - 2;
158 const Geometry& geometry = element.geometry();
159 const int corners = geometry.corners();
160 for (
int i=0; i < corners; ++i) {
161 xx += geometry.corner(i)[xCoord];
162 yy += geometry.corner(i)[yCoord];
164 return std::make_pair(xx/corners, yy/corners);
167template <
class Scalar,
class Element>
168std::pair<Scalar,Scalar>
cellZSpan(
const Element& element)
170 typedef typename Element::Geometry Geometry;
171 static constexpr int zCoord = Element::dimension - 1;
175 const Geometry& geometry = element.geometry();
176 const int corners = geometry.corners();
177 assert(corners == 8);
178 for (
int i=0; i < 4; ++i)
179 bot += geometry.corner(i)[zCoord];
180 for (
int i=4; i < corners; ++i)
181 top += geometry.corner(i)[zCoord];
183 return std::make_pair(bot/4, top/4);
186template <
class Scalar,
class Element>
189 typedef typename Element::Geometry Geometry;
190 static constexpr int zCoord = Element::dimension - 1;
191 const Geometry& geometry = element.geometry();
192 const int corners = geometry.corners();
193 assert(corners == 8);
194 auto min = std::numeric_limits<Scalar>::max();
195 auto max = std::numeric_limits<Scalar>::lowest();
198 for (
int i=0; i < corners; ++i) {
199 min = std::min(min,
static_cast<Scalar
>(geometry.corner(i)[zCoord]));
200 max = std::max(max,
static_cast<Scalar
>(geometry.corner(i)[zCoord]));
202 return std::make_pair(min, max);
205template<
class Scalar>
207 Scalar& dipAngle, Scalar& dipAzimuth)
209 const auto& Xc = cellCorners.
X;
210 const auto& Yc = cellCorners.
Y;
211 const auto& Zc = cellCorners.
Z;
213 Scalar v1x = Xc[1] - Xc[0];
214 Scalar v1y = Yc[1] - Yc[0];
215 Scalar v1z = Zc[1] - Zc[0];
217 Scalar v2x = Xc[2] - Xc[0];
218 Scalar v2y = Yc[2] - Yc[0];
219 Scalar v2z = Zc[2] - Zc[0];
222 Scalar nx = v1y * v2z - v1z * v2y;
223 Scalar ny = v1z * v2x - v1x * v2z;
224 Scalar nz = v1x * v2y - v1y * v2x;
227 Scalar norm = std::hypot(nx, ny, nz);
235 dipAngle = std::acos(std::abs(nz));
238 if (std::abs(nx) > 1e-10 || std::abs(ny) > 1e-10) {
239 dipAzimuth = std::atan2(ny, nx);
241 dipAzimuth = std::fmod(dipAzimuth + 2*std::numbers::pi_v<Scalar>, 2*std::numbers::pi_v<Scalar>);
247 const Scalar maxDip = std::numbers::pi_v<Scalar>/2 -
static_cast<Scalar
>(1e-6);
248 dipAngle = std::min(dipAngle, maxDip);
256template <
class Scalar,
class Element>
259 typedef typename Element::Geometry Geometry;
260 const Geometry& geometry = element.geometry();
261 static constexpr int zCoord = Element::dimension - 1;
262 static constexpr int yCoord = Element::dimension - 2;
263 static constexpr int xCoord = Element::dimension - 3;
264 const int corners = geometry.corners();
265 assert(corners == 8);
266 std::array<Scalar, 8> X {};
267 std::array<Scalar, 8> Y {};
268 std::array<Scalar, 8> Z {};
270 for (
int i = 0; i < corners; ++i) {
271 auto corner = geometry.corner(i);
272 X[i] = corner[xCoord];
273 Y[i] = corner[yCoord];
274 Z[i] = corner[zCoord];
280template<
class Scalar>
282 Scalar dipAngle, Scalar dipAzimuth,
283 const std::array<Scalar, 3>& referencePoint)
290 Scalar dx = x - referencePoint[0];
291 Scalar dy = y - referencePoint[1];
292 Scalar dz = z - referencePoint[2];
295 if (std::abs(dipAngle) < 1e-10) {
296 return referencePoint[2] + dz;
300 Scalar pointAzimuth = std::atan2(dy, dx);
303 Scalar azimuthDiff = pointAzimuth - dipAzimuth;
306 Scalar lateralDist = std::hypot(dx, dy);
309 Scalar lateralInDipDir = lateralDist * std::cos(azimuthDiff);
314 Scalar tvd = referencePoint[2] + dz * std::cos(dipAngle) + lateralInDipDir * std::sin(dipAngle);
319namespace PhasePressODE {
321template<
class Flu
idSystem>
323Water(
const TabulatedFunction& tempVdTable,
324 const TabulatedFunction& saltVdTable,
325 const int pvtRegionIdx,
326 const Scalar normGrav)
327 : tempVdTable_(tempVdTable)
328 , saltVdTable_(saltVdTable)
329 , pvtRegionIdx_(pvtRegionIdx)
334template<
class Flu
idSystem>
335typename Water<FluidSystem>::Scalar
338 const Scalar press)
const
340 return this->density(depth, press) * g_;
343template<
class Flu
idSystem>
344typename Water<FluidSystem>::Scalar
347 const Scalar press)
const
350 Scalar saltConcentration = saltVdTable_.eval(depth,
true);
351 Scalar temp = tempVdTable_.eval(depth,
true);
352 Scalar rho = FluidSystem::waterPvt().inverseFormationVolumeFactor(pvtRegionIdx_,
357 rho *= FluidSystem::referenceDensity(FluidSystem::waterPhaseIdx, pvtRegionIdx_);
361template<
class Flu
idSystem,
class RS>
363Oil(
const TabulatedFunction& tempVdTable,
365 const int pvtRegionIdx,
366 const Scalar normGrav)
367 : tempVdTable_(tempVdTable)
369 , pvtRegionIdx_(pvtRegionIdx)
374template<
class Flu
idSystem,
class RS>
375typename Oil<FluidSystem,RS>::Scalar
378 const Scalar press)
const
380 return this->density(depth, press) * g_;
383template<
class Flu
idSystem,
class RS>
384typename Oil<FluidSystem,RS>::Scalar
387 const Scalar press)
const
389 const Scalar temp = tempVdTable_.eval(depth,
true);
391 if (FluidSystem::enableDissolvedGas() || FluidSystem::enableConstantRs())
392 rs = rs_(depth, press, temp);
395 if (rs >= FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_, temp, press)) {
396 bOil = FluidSystem::oilPvt().saturatedInverseFormationVolumeFactor(pvtRegionIdx_, temp, press);
399 bOil = FluidSystem::oilPvt().inverseFormationVolumeFactor(pvtRegionIdx_, temp, press, rs);
401 Scalar rho = bOil * FluidSystem::referenceDensity(FluidSystem::oilPhaseIdx, pvtRegionIdx_);
402 if (FluidSystem::enableDissolvedGas() || FluidSystem::enableConstantRs()) {
403 rho += rs * bOil * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, pvtRegionIdx_);
409template<
class Flu
idSystem,
class RV,
class RVW>
411Gas(
const TabulatedFunction& tempVdTable,
414 const int pvtRegionIdx,
415 const Scalar normGrav)
416 : tempVdTable_(tempVdTable)
419 , pvtRegionIdx_(pvtRegionIdx)
424template<
class Flu
idSystem,
class RV,
class RVW>
425typename Gas<FluidSystem,RV,RVW>::Scalar
428 const Scalar press)
const
430 return this->density(depth, press) * g_;
433template<
class Flu
idSystem,
class RV,
class RVW>
434typename Gas<FluidSystem,RV,RVW>::Scalar
437 const Scalar press)
const
439 const Scalar temp = tempVdTable_.eval(depth,
true);
441 if (FluidSystem::enableVaporizedOil())
442 rv = rv_(depth, press, temp);
445 if (FluidSystem::enableVaporizedWater())
446 rvw = rvw_(depth, press, temp);
450 if (FluidSystem::enableVaporizedOil() && FluidSystem::enableVaporizedWater()) {
451 if (rv >= FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_, temp, press)
452 && rvw >= FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_, temp, press))
454 bGas = FluidSystem::gasPvt().saturatedInverseFormationVolumeFactor(pvtRegionIdx_, temp, press);
456 bGas = FluidSystem::gasPvt().inverseFormationVolumeFactor(pvtRegionIdx_, temp, press, rv, rvw);
458 Scalar rho = bGas * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, pvtRegionIdx_);
459 rho += rv * bGas * FluidSystem::referenceDensity(FluidSystem::oilPhaseIdx, pvtRegionIdx_)
460 + rvw * bGas * FluidSystem::referenceDensity(FluidSystem::waterPhaseIdx, pvtRegionIdx_);
464 if (FluidSystem::enableVaporizedOil()){
465 if (rv >= FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_, temp, press)) {
466 bGas = FluidSystem::gasPvt().saturatedInverseFormationVolumeFactor(pvtRegionIdx_, temp, press);
468 bGas = FluidSystem::gasPvt().inverseFormationVolumeFactor(pvtRegionIdx_,
474 Scalar rho = bGas * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, pvtRegionIdx_);
475 rho += rv * bGas * FluidSystem::referenceDensity(FluidSystem::oilPhaseIdx, pvtRegionIdx_);
479 if (FluidSystem::enableVaporizedWater()){
480 if (rvw >= FluidSystem::gasPvt().saturatedWaterVaporizationFactor(pvtRegionIdx_, temp, press)) {
481 bGas = FluidSystem::gasPvt().saturatedInverseFormationVolumeFactor(pvtRegionIdx_, temp, press);
484 bGas = FluidSystem::gasPvt().inverseFormationVolumeFactor(pvtRegionIdx_,
490 Scalar rho = bGas * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, pvtRegionIdx_);
491 rho += rvw * bGas * FluidSystem::referenceDensity(FluidSystem::waterPhaseIdx, pvtRegionIdx_);
496 bGas = FluidSystem::gasPvt().inverseFormationVolumeFactor(pvtRegionIdx_, temp,
500 Scalar rho = bGas * FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx, pvtRegionIdx_);
507template<
class Flu
idSystem,
class Region>
508template<
typename PressFunc>
509void PressureTable<FluidSystem,Region>::
510checkPtr(
const PressFunc* phasePress,
511 const std::string& phaseName)
const
513 if (phasePress !=
nullptr) {
return; }
515 throw std::invalid_argument {
516 "Phase pressure function for \"" + phaseName
517 +
"\" most not be null"
521template<
class Flu
idSystem,
class Region>
522typename PressureTable<FluidSystem,Region>::Strategy
523PressureTable<FluidSystem,Region>::
524selectEquilibrationStrategy(
const Region& reg)
const
526 if (!this->oilActive()) {
527 if (reg.datum() > reg.zwoc()) {
528 return &PressureTable::equil_WOG;
530 return &PressureTable::equil_GOW;
533 if (reg.datum() > reg.zwoc()) {
534 return &PressureTable::equil_WOG;
536 else if (reg.datum() < reg.zgoc()) {
537 return &PressureTable::equil_GOW;
540 return &PressureTable::equil_OWG;
544template<
class Flu
idSystem,
class Region>
545void PressureTable<FluidSystem,Region>::
546copyInPointers(
const PressureTable& rhs)
548 if (rhs.oil_ !=
nullptr) {
549 this->oil_ = std::make_unique<OPress>(*rhs.oil_);
552 if (rhs.gas_ !=
nullptr) {
553 this->gas_ = std::make_unique<GPress>(*rhs.gas_);
556 if (rhs.wat_ !=
nullptr) {
557 this->wat_ = std::make_unique<WPress>(*rhs.wat_);
561template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
564 const std::vector<Scalar>& swatInit)
565 : matLawMgr_(matLawMgr)
566 , swatInit_ (swatInit)
570template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
573 : matLawMgr_(rhs.matLawMgr_)
574 , swatInit_ (rhs.swatInit_)
576 , press_ (rhs.press_)
579 this->setEvaluationPoint(*rhs.evalPt_.position,
581 *rhs.evalPt_.ptable);
584template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
591 this->setEvaluationPoint(x, reg, ptable);
592 this->initializePhaseQuantities();
594 if (ptable.
gasActive()) { this->deriveGasSat(); }
596 if (ptable.
waterActive()) { this->deriveWaterSat(); }
599 if (this->isOverlappingTransition()) {
600 this->fixUnphysicalTransition();
603 if (ptable.
oilActive()) { this->deriveOilSat(); }
605 this->accountForScaledSaturations();
610template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
614 const PTable& ptable)
616 this->evalPt_.position = &x;
617 this->evalPt_.region = ®
618 this->evalPt_.ptable = &ptable;
621template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
622void PhaseSaturations<MaterialLawManager,FluidSystem,Region,CellID>::
623initializePhaseQuantities()
626 this->press_.reset();
628 const auto depth = this->evalPt_.position->depth;
629 const auto& ptable = *this->evalPt_.ptable;
631 if (ptable.oilActive()) {
632 this->press_.oil = ptable.oil(depth);
635 if (ptable.gasActive()) {
636 this->press_.gas = ptable.gas(depth);
639 if (ptable.waterActive()) {
640 this->press_.water = ptable.water(depth);
644template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
645void PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::deriveOilSat()
647 this->sat_.oil = 1.0 - this->sat_.water - this->sat_.gas;
650template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
651void PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::deriveGasSat()
653 auto& sg = this->sat_.gas;
655 const auto isIncr =
true;
656 const auto oilActive = this->evalPt_.ptable->oilActive();
658 if (this->isConstCapPress(this->gasPos())) {
662 const auto gas_contact = oilActive? this->evalPt_.region->zgoc() : this->evalPt_.region->zwoc();
663 sg = this->fromDepthTable(gas_contact,
664 this->gasPos(), isIncr);
674 const auto pw = oilActive? this->press_.oil : this->press_.water;
675 const auto pcgo = this->press_.gas - pw;
676 sg = this->invertCapPress(pcgo, this->gasPos(), isIncr);
680template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
681void PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::deriveWaterSat()
683 auto& sw = this->sat_.water;
685 const auto oilActive = this->evalPt_.ptable->oilActive();
688 sw = 1.0 - this->sat_.gas;
693 if (! this->swatInit_.empty() && ! this->isConstCapPress(this->gasPos())) {
694 const auto pcgw = this->press_.gas - this->press_.water;
696 auto [swout, newSwatInit] = this->applySwatInit(pcgw);
699 const auto isIncr =
true;
700 this->sat_.gas = this->invertCapPress(pcgw, this->gasPos(), isIncr);
701 sw = 1.0 - this->sat_.gas;
705 this->sat_.gas = 1.0 - sw;
710 const auto isIncr =
false;
712 if (this->isConstCapPress(this->waterPos())) {
716 sw = this->fromDepthTable(this->evalPt_.region->zwoc(),
717 this->waterPos(), isIncr);
729 const auto pcow = this->press_.oil - this->press_.water;
731 if (this->swatInit_.empty()) {
732 sw = this->invertCapPress(pcow, this->waterPos(), isIncr);
735 auto [swout, newSwatInit] = this->applySwatInit(pcow);
737 sw = this->invertCapPress(pcow, this->waterPos(), isIncr);
746template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
747void PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
748fixUnphysicalTransition()
750 auto& sg = this->sat_.gas;
751 auto& sw = this->sat_.water;
759 const auto pcgw = this->press_.gas - this->press_.water;
760 if (! this->swatInit_.empty()) {
764 auto [swout, newSwatInit] = this->applySwatInit(pcgw, sw);
766 const auto isIncr =
false;
767 sw = this->invertCapPress(pcgw, this->waterPos(), isIncr);
774 sw = satFromSumOfPcs<FluidSystem>
775 (this->matLawMgr_, this->waterPos(), this->gasPos(),
776 this->evalPt_.position->cell, pcgw);
779 this->fluidState_.setSaturation(this->oilPos(), 1.0 - sw - sg);
780 this->fluidState_.setSaturation(this->gasPos(), sg);
781 this->fluidState_.setSaturation(this->waterPos(), this->evalPt_
782 .ptable->waterActive() ? sw : 0.0);
785 this->computeMaterialLawCapPress();
786 this->press_.oil = this->press_.gas - this->materialLawCapPressGasOil();
789template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
790void PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
791accountForScaledSaturations()
793 const auto gasActive = this->evalPt_.ptable->gasActive();
794 const auto watActive = this->evalPt_.ptable->waterActive();
795 const auto oilActive = this->evalPt_.ptable->oilActive();
797 auto sg = gasActive? this->sat_.gas : 0.0;
798 auto sw = watActive? this->sat_.water : 0.0;
799 auto so = oilActive? this->sat_.oil : 0.0;
801 this->fluidState_.setSaturation(this->waterPos(), sw);
802 this->fluidState_.setSaturation(this->oilPos(), so);
803 this->fluidState_.setSaturation(this->gasPos(), sg);
805 const auto& scaledDrainageInfo = this->matLawMgr_
806 .oilWaterScaledEpsInfoDrainage(this->evalPt_.position->cell);
808 const auto thresholdSat = 1.0e-6;
809 if (watActive && ((sw + thresholdSat) > scaledDrainageInfo.Swu)) {
813 this->fluidState_.setSaturation(this->waterPos(), scaledDrainageInfo.Swu);
815 this->fluidState_.setSaturation(this->oilPos(), so + sw - scaledDrainageInfo.Swu);
816 }
else if (gasActive) {
817 this->fluidState_.setSaturation(this->gasPos(), sg + sw - scaledDrainageInfo.Swu);
819 sw = scaledDrainageInfo.Swu;
820 this->computeMaterialLawCapPress();
824 this->press_.oil = this->press_.water + this->materialLawCapPressOilWater();
827 this->press_.gas = this->press_.water + this->materialLawCapPressGasWater();
831 if (gasActive && ((sg + thresholdSat) > scaledDrainageInfo.Sgu)) {
835 this->fluidState_.setSaturation(this->gasPos(), scaledDrainageInfo.Sgu);
837 this->fluidState_.setSaturation(this->oilPos(), so + sg - scaledDrainageInfo.Sgu);
838 }
else if (watActive) {
839 this->fluidState_.setSaturation(this->waterPos(), sw + sg - scaledDrainageInfo.Sgu);
841 sg = scaledDrainageInfo.Sgu;
842 this->computeMaterialLawCapPress();
846 this->press_.oil = this->press_.gas - this->materialLawCapPressGasOil();
849 this->press_.water = this->press_.gas - this->materialLawCapPressGasWater();
853 if (watActive && ((sw - thresholdSat) < scaledDrainageInfo.Swl)) {
857 this->fluidState_.setSaturation(this->waterPos(), scaledDrainageInfo.Swl);
859 this->fluidState_.setSaturation(this->oilPos(), so + sw - scaledDrainageInfo.Swl);
860 }
else if (gasActive) {
861 this->fluidState_.setSaturation(this->gasPos(), sg + sw - scaledDrainageInfo.Swl);
863 sw = scaledDrainageInfo.Swl;
864 this->computeMaterialLawCapPress();
868 this->press_.water = this->press_.oil - this->materialLawCapPressOilWater();
871 this->press_.water = this->press_.gas - this->materialLawCapPressGasWater();
875 if (gasActive && ((sg - thresholdSat) < scaledDrainageInfo.Sgl)) {
879 this->fluidState_.setSaturation(this->gasPos(), scaledDrainageInfo.Sgl);
881 this->fluidState_.setSaturation(this->oilPos(), so + sg - scaledDrainageInfo.Sgl);
882 }
else if (watActive) {
883 this->fluidState_.setSaturation(this->waterPos(), sw + sg - scaledDrainageInfo.Sgl);
885 sg = scaledDrainageInfo.Sgl;
886 this->computeMaterialLawCapPress();
890 this->press_.gas = this->press_.oil + this->materialLawCapPressGasOil();
893 this->press_.gas = this->press_.water + this->materialLawCapPressGasWater();
898template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
899std::pair<typename FluidSystem::Scalar, bool>
900PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
901applySwatInit(
const Scalar pcow)
903 return this->applySwatInit(pcow, this->swatInit_[this->evalPt_.position->cell]);
906template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
907std::pair<typename FluidSystem::Scalar, bool>
908PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
909applySwatInit(
const Scalar pcow,
const Scalar sw)
911 return this->matLawMgr_.applySwatinit(this->evalPt_.position->cell, pcow, sw);
914template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
915void PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
916computeMaterialLawCapPress()
918 const auto& matParams = this->matLawMgr_
919 .materialLawParams(this->evalPt_.position->cell);
921 this->matLawCapPress_.fill(0.0);
922 MaterialLaw::capillaryPressures(this->matLawCapPress_,
923 matParams, this->fluidState_);
926template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
927typename FluidSystem::Scalar
928PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
929materialLawCapPressGasOil()
const
931 return this->matLawCapPress_[this->oilPos()]
932 + this->matLawCapPress_[this->gasPos()];
935template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
936typename FluidSystem::Scalar
937PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
938materialLawCapPressOilWater()
const
940 return this->matLawCapPress_[this->oilPos()]
941 - this->matLawCapPress_[this->waterPos()];
944template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
945typename FluidSystem::Scalar
946PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
947materialLawCapPressGasWater()
const
949 return this->matLawCapPress_[this->gasPos()]
950 - this->matLawCapPress_[this->waterPos()];
953template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
954bool PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
955isConstCapPress(
const PhaseIdx phaseIdx)
const
957 return isConstPc<FluidSystem>
958 (this->matLawMgr_, phaseIdx, this->evalPt_.position->cell);
961template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
962bool PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
963isOverlappingTransition()
const
965 return this->evalPt_.ptable->gasActive()
966 && this->evalPt_.ptable->waterActive()
967 && ((this->sat_.gas + this->sat_.water) > 1.0);
970template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
971typename FluidSystem::Scalar
972PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
973fromDepthTable(
const Scalar contactdepth,
974 const PhaseIdx phasePos,
975 const bool isincr)
const
977 return satFromDepth<FluidSystem>
978 (this->matLawMgr_, this->evalPt_.position->depth,
979 contactdepth,
static_cast<int>(phasePos),
980 this->evalPt_.position->cell, isincr);
983template <
class MaterialLawManager,
class Flu
idSystem,
class Region,
typename CellID>
984typename FluidSystem::Scalar
985PhaseSaturations<MaterialLawManager, FluidSystem, Region, CellID>::
986invertCapPress(
const Scalar pc,
987 const PhaseIdx phasePos,
988 const bool isincr)
const
990 return satFromPc<FluidSystem>
991 (this->matLawMgr_,
static_cast<int>(phasePos),
992 this->evalPt_.position->cell, pc, isincr);
995template<
class Flu
idSystem,
class Region>
998 const int samplePoints)
1000 , nsample_(samplePoints)
1004template <
class Flu
idSystem,
class Region>
1007 : gravity_(rhs.gravity_)
1008 , nsample_(rhs.nsample_)
1010 this->copyInPointers(rhs);
1013template <
class Flu
idSystem,
class Region>
1016 : gravity_(rhs.gravity_)
1017 , nsample_(rhs.nsample_)
1018 , oil_ (std::move(rhs.oil_))
1019 , gas_ (std::move(rhs.gas_))
1020 , wat_ (std::move(rhs.wat_))
1024template <
class Flu
idSystem,
class Region>
1029 this->gravity_ = rhs.gravity_;
1030 this->nsample_ = rhs.nsample_;
1031 this->copyInPointers(rhs);
1036template <
class Flu
idSystem,
class Region>
1041 this->gravity_ = rhs.gravity_;
1042 this->nsample_ = rhs.nsample_;
1044 this->oil_ = std::move(rhs.oil_);
1045 this->gas_ = std::move(rhs.gas_);
1046 this->wat_ = std::move(rhs.wat_);
1051template <
class Flu
idSystem,
class Region>
1057 auto equil = this->selectEquilibrationStrategy(reg);
1059 (this->*equil)(reg, span);
1062template <
class Flu
idSystem,
class Region>
1066 return FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
1069template <
class Flu
idSystem,
class Region>
1073 return FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx);
1076template <
class Flu
idSystem,
class Region>
1080 return FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
1083template <
class Flu
idSystem,
class Region>
1084typename FluidSystem::Scalar
1088 this->checkPtr(this->oil_.get(),
"OIL");
1090 return this->oil_->value(depth);
1093template <
class Flu
idSystem,
class Region>
1094typename FluidSystem::Scalar
1098 this->checkPtr(this->gas_.get(),
"GAS");
1100 return this->gas_->value(depth);
1104template <
class Flu
idSystem,
class Region>
1105typename FluidSystem::Scalar
1109 this->checkPtr(this->wat_.get(),
"WATER");
1111 return this->wat_->value(depth);
1114template <
class Flu
idSystem,
class Region>
1116equil_WOG(
const Region& reg,
const VSpan& span)
1121 if (! this->waterActive()) {
1122 throw std::invalid_argument {
1123 "Don't know how to interpret EQUIL datum depth in "
1124 "WATER zone in model without active water phase"
1129 const auto ic =
typename WPress::InitCond {
1130 reg.datum(), reg.pressure()
1133 this->makeWatPressure(ic, reg, span);
1136 if (this->oilActive()) {
1138 const auto ic =
typename OPress::InitCond {
1140 this->water(reg.zwoc()) + reg.pcowWoc()
1143 this->makeOilPressure(ic, reg, span);
1146 if (this->gasActive() && this->oilActive()) {
1148 const auto ic =
typename GPress::InitCond {
1150 this->oil(reg.zgoc()) + reg.pcgoGoc()
1153 this->makeGasPressure(ic, reg, span);
1154 }
else if (this->gasActive() && !this->oilActive()) {
1156 const auto ic =
typename GPress::InitCond {
1158 this->water(reg.zwoc()) + reg.pcowWoc()
1160 this->makeGasPressure(ic, reg, span);
1164template <
class Flu
idSystem,
class Region>
1165void PressureTable<FluidSystem, Region>::
1166equil_GOW(
const Region& reg,
const VSpan& span)
1171 if (! this->gasActive()) {
1172 throw std::invalid_argument {
1173 "Don't know how to interpret EQUIL datum depth in "
1174 "GAS zone in model without active gas phase"
1179 const auto ic =
typename GPress::InitCond {
1180 reg.datum(), reg.pressure()
1183 this->makeGasPressure(ic, reg, span);
1186 if (this->oilActive()) {
1188 const auto ic =
typename OPress::InitCond {
1190 this->gas(reg.zgoc()) - reg.pcgoGoc()
1192 this->makeOilPressure(ic, reg, span);
1195 if (this->waterActive() && this->oilActive()) {
1197 const auto ic =
typename WPress::InitCond {
1199 this->oil(reg.zwoc()) - reg.pcowWoc()
1202 this->makeWatPressure(ic, reg, span);
1203 }
else if (this->waterActive() && !this->oilActive()) {
1205 const auto ic =
typename WPress::InitCond {
1207 this->gas(reg.zwoc()) - reg.pcowWoc()
1209 this->makeWatPressure(ic, reg, span);
1213template <
class Flu
idSystem,
class Region>
1214void PressureTable<FluidSystem, Region>::
1215equil_OWG(
const Region& reg,
const VSpan& span)
1220 if (! this->oilActive()) {
1221 throw std::invalid_argument {
1222 "Don't know how to interpret EQUIL datum depth in "
1223 "OIL zone in model without active oil phase"
1228 const auto ic =
typename OPress::InitCond {
1229 reg.datum(), reg.pressure()
1232 this->makeOilPressure(ic, reg, span);
1235 if (this->waterActive()) {
1237 const auto ic =
typename WPress::InitCond {
1239 this->oil(reg.zwoc()) - reg.pcowWoc()
1242 this->makeWatPressure(ic, reg, span);
1245 if (this->gasActive()) {
1247 const auto ic =
typename GPress::InitCond {
1249 this->oil(reg.zgoc()) + reg.pcgoGoc()
1251 this->makeGasPressure(ic, reg, span);
1255template <
class Flu
idSystem,
class Region>
1256void PressureTable<FluidSystem, Region>::
1257makeOilPressure(
const typename OPress::InitCond& ic,
1261 const auto drho = OilPressODE {
1262 reg.tempVdTable(), reg.dissolutionCalculator(),
1263 reg.pvtIdx(), this->gravity_
1266 this->oil_ = std::make_unique<OPress>(drho, ic, this->nsample_, span);
1269template <
class Flu
idSystem,
class Region>
1270void PressureTable<FluidSystem, Region>::
1271makeGasPressure(
const typename GPress::InitCond& ic,
1275 const auto drho = GasPressODE {
1276 reg.tempVdTable(), reg.evaporationCalculator(), reg.waterEvaporationCalculator(),
1277 reg.pvtIdx(), this->gravity_
1280 this->gas_ = std::make_unique<GPress>(drho, ic, this->nsample_, span);
1283template <
class Flu
idSystem,
class Region>
1284void PressureTable<FluidSystem, Region>::
1285makeWatPressure(
const typename WPress::InitCond& ic,
1289 const auto drho = WatPressODE {
1290 reg.tempVdTable(), reg.saltVdTable(), reg.pvtIdx(), this->gravity_
1293 this->wat_ = std::make_unique<WPress>(drho, ic, this->nsample_, span);
1298namespace DeckDependent {
1300std::vector<EquilRecord>
1303 const auto& init = state.getInitConfig();
1305 if(!init.hasEquil()) {
1306 throw std::domain_error(
"Deck does not provide equilibration data.");
1309 const auto& equil = init.getEquil();
1310 return { equil.begin(), equil.end() };
1313template<
class Gr
idView>
1316 const GridView& gridview)
1318 std::vector<int> eqlnum(gridview.size(0), 0);
1320 if (eclipseState.fieldProps().has_int(
"EQLNUM")) {
1331 eqlnum = lookUpData.template assignFieldPropsIntOnLeaf<int>(
1332 eclipseState.fieldProps(),
"EQLNUM",
true);
1335 const int num_regions = eclipseState.getTableManager().getEqldims().getNumEquilRegions();
1336 if (std::ranges::any_of(eqlnum, [num_regions](
int n){
return n >= num_regions;})) {
1337 throw std::runtime_error(
"Values larger than maximum Equil regions " +
1340 if (std::ranges::any_of(eqlnum, [](
int n){
return n < 0;})) {
1341 throw std::runtime_error(
"zero or negative values provided in EQLNUM");
1348template<
class FluidSystem,
1351 class ElementMapper,
1352 class CartesianIndexMapper>
1353template<
class MaterialLawManager>
1354InitialStateComputer<FluidSystem,
1358 CartesianIndexMapper>::
1359InitialStateComputer(MaterialLawManager& materialLawManager,
1360 const EclipseState& eclipseState,
1362 const GridView& gridView,
1363 const CartesianIndexMapper& cartMapper,
1365 const int num_pressure_points,
1366 const bool applySwatInit)
1367 : temperature_(grid.size(0), eclipseState.getTableManager().rtemp()),
1368 saltConcentration_(grid.size(0)),
1369 saltSaturation_(grid.size(0)),
1370 pp_(FluidSystem::numPhases,
1371 std::vector<Scalar>(grid.size(0))),
1372 sat_(FluidSystem::numPhases,
1373 std::vector<Scalar>(grid.size(0))),
1377 cartesianIndexMapper_(cartMapper),
1378 num_pressure_points_(num_pressure_points)
1381 if (applySwatInit) {
1382 if (eclipseState.fieldProps().has_double(
"SWATINIT")) {
1389 lookUpData.assignFieldPropsDoubleOnLeaf(eclipseState.fieldProps(),
"SWATINIT");
1390 if constexpr (std::is_same_v<Scalar, double>) {
1391 swatInit_ = std::move(input);
1393 swatInit_.assign(input.begin(), input.end());
1400 const auto& num_aquifers = eclipseState.aquifer().numericalAquifers();
1401 updateCellProps_(gridView, num_aquifers);
1404 const std::vector<EquilRecord> rec =
getEquil(eclipseState);
1405 const auto& tables = eclipseState.getTableManager();
1407 const RegionMapping<> eqlmap(
equilnum(eclipseState, gridView));
1408 const int invalidRegion = -1;
1409 regionPvtIdx_.resize(rec.size(), invalidRegion);
1410 setRegionPvtIdx(eclipseState, gridView, eqlmap);
1413 rsFunc_.reserve(rec.size());
1415 auto getArray = [](
const std::vector<double>& input)
1417 if constexpr (std::is_same_v<Scalar,double>) {
1420 std::vector<Scalar> output;
1421 output.resize(input.size());
1422 std::ranges::copy(input, output.begin());
1427 if (FluidSystem::enableDissolvedGas()) {
1428 for (std::size_t i = 0; i < rec.size(); ++i) {
1429 if (eqlmap.cells(i).empty()) {
1433 const int pvtIdx = regionPvtIdx_[i];
1434 if (!rec[i].liveOilInitConstantRs()) {
1435 const TableContainer& rsvdTables = tables.getRsvdTables();
1436 const TableContainer& pbvdTables = tables.getPbvdTables();
1437 if (rsvdTables.size() > 0) {
1438 const RsvdTable& rsvdTable = rsvdTables.getTable<RsvdTable>(i);
1439 auto depthColumn = getArray(rsvdTable.getColumn(
"DEPTH").vectorCopy());
1440 auto rsColumn = getArray(rsvdTable.getColumn(
"RS").vectorCopy());
1442 depthColumn, rsColumn));
1443 }
else if (pbvdTables.size() > 0) {
1444 const PbvdTable& pbvdTable = pbvdTables.getTable<PbvdTable>(i);
1445 auto depthColumn = getArray(pbvdTable.getColumn(
"DEPTH").vectorCopy());
1446 auto pbubColumn = getArray(pbvdTable.getColumn(
"PBUB").vectorCopy());
1448 depthColumn, pbubColumn));
1451 throw std::runtime_error(
"Cannot initialise: RSVD or PBVD table not available.");
1456 if (rec[i].gasOilContactDepth() != rec[i].datumDepth()) {
1457 throw std::runtime_error(
"Cannot initialise: when no explicit RSVD table is given, \n"
1458 "datum depth must be at the gas-oil-contact. "
1459 "In EQUIL region "+
std::to_string(i + 1)+
" (counting from 1), this does not hold.");
1461 const Scalar pContact = rec[i].datumDepthPressure();
1462 const Scalar TContact = 273.15 + 20;
1467 else if (FluidSystem::enableConstantRs() && tables.hasTables(
"RSCONST")) {
1468 const auto& rsconstTables = tables.getRsconstTables();
1470 if (rsconstTables.empty()) {
1471 for (std::size_t i = 0; i < rec.size(); ++i) {
1477 const auto& rsconstTable = rsconstTables.getTable<RsconstTable>(0);
1479 const auto rsConst = rsconstTable.getRsColumn().front();
1480 const auto pBub = rsconstTable.getPbubColumn().front();
1482 const auto& units = eclipseState.getUnits();
1484 OpmLog::info(fmt::format(
"Using RSCONST keyword: Rs = {:.2} [{}], Pb = {:.2} [{}]",
1485 units.from_si(UnitSystem::measure::gas_oil_ratio, rsConst),
1486 units.name (UnitSystem::measure::gas_oil_ratio),
1487 units.from_si(UnitSystem::measure::pressure, pBub),
1488 units.name (UnitSystem::measure::pressure)));
1490 for (std::size_t i = 0; i < rec.size(); ++i) {
1496 for (std::size_t i = 0; i < rec.size(); ++i) {
1502 rvFunc_.reserve(rec.size());
1503 if (FluidSystem::enableVaporizedOil()) {
1504 for (std::size_t i = 0; i < rec.size(); ++i) {
1505 if (eqlmap.cells(i).empty()) {
1509 const int pvtIdx = regionPvtIdx_[i];
1510 if (!rec[i].wetGasInitConstantRv()) {
1511 const TableContainer& rvvdTables = tables.getRvvdTables();
1512 const TableContainer& pdvdTables = tables.getPdvdTables();
1514 if (rvvdTables.size() > 0) {
1515 const RvvdTable& rvvdTable = rvvdTables.getTable<RvvdTable>(i);
1516 auto depthColumn = getArray(rvvdTable.getColumn(
"DEPTH").vectorCopy());
1517 auto rvColumn = getArray(rvvdTable.getColumn(
"RV").vectorCopy());
1519 depthColumn, rvColumn));
1520 }
else if (pdvdTables.size() > 0) {
1521 const PdvdTable& pdvdTable = pdvdTables.getTable<PdvdTable>(i);
1522 auto depthColumn = getArray(pdvdTable.getColumn(
"DEPTH").vectorCopy());
1523 auto pdewColumn = getArray(pdvdTable.getColumn(
"PDEW").vectorCopy());
1525 depthColumn, pdewColumn));
1527 throw std::runtime_error(
"Cannot initialise: RVVD or PDCD table not available.");
1531 if (rec[i].gasOilContactDepth() != rec[i].datumDepth()) {
1532 throw std::runtime_error(
1533 "Cannot initialise: when no explicit RVVD table is given, \n"
1534 "datum depth must be at the gas-oil-contact. "
1535 "In EQUIL region "+
std::to_string(i + 1)+
" (counting from 1), this does not hold.");
1537 const Scalar pContact = rec[i].datumDepthPressure() + rec[i].gasOilContactCapillaryPressure();
1538 const Scalar TContact = 273.15 + 20;
1544 for (std::size_t i = 0; i < rec.size(); ++i) {
1549 rvwFunc_.reserve(rec.size());
1550 if (FluidSystem::enableVaporizedWater()) {
1551 for (std::size_t i = 0; i < rec.size(); ++i) {
1552 if (eqlmap.cells(i).empty()) {
1556 const int pvtIdx = regionPvtIdx_[i];
1557 if (!rec[i].humidGasInitConstantRvw()) {
1558 const TableContainer& rvwvdTables = tables.getRvwvdTables();
1560 if (rvwvdTables.size() > 0) {
1561 const RvwvdTable& rvwvdTable = rvwvdTables.getTable<RvwvdTable>(i);
1562 auto depthColumn = getArray(rvwvdTable.getColumn(
"DEPTH").vectorCopy());
1563 auto rvwvdColumn = getArray(rvwvdTable.getColumn(
"RVWVD").vectorCopy());
1565 depthColumn, rvwvdColumn));
1567 throw std::runtime_error(
"Cannot initialise: RVWVD table not available.");
1571 const auto oilActive = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
1573 if (rec[i].gasOilContactDepth() != rec[i].datumDepth()) {
1575 const auto msg =
"No explicit RVWVD table is given for EQUIL region " +
std::to_string(i + 1) +
". \n"
1576 "and datum depth is not at the gas-oil-contact. \n"
1577 "Rvw is set to 0.0 in all cells. \n";
1578 OpmLog::warning(msg);
1582 const Scalar pContact = rec[i].datumDepthPressure() + rec[i].gasOilContactCapillaryPressure();
1583 const Scalar TContact = 273.15 + 20;
1590 if (rec[i].waterOilContactDepth() != rec[i].datumDepth()) {
1592 const auto msg =
"No explicit RVWVD table is given for EQUIL region " +
std::to_string(i + 1) +
". \n"
1593 "and datum depth is not at the gas-water-contact. \n"
1594 "Rvw is set to 0.0 in all cells. \n";
1595 OpmLog::warning(msg);
1598 const Scalar pContact = rec[i].datumDepthPressure() + rec[i].waterOilContactCapillaryPressure();
1599 const Scalar TContact = 273.15 + 20;
1607 for (std::size_t i = 0; i < rec.size(); ++i) {
1613 updateInitialTemperature_(eclipseState, eqlmap);
1616 updateInitialSaltConcentration_(eclipseState, eqlmap);
1619 updateInitialSaltSaturation_(eclipseState, eqlmap);
1622 const auto& comm = grid.comm();
1623 calcPressSatRsRv(eqlmap, rec, materialLawManager, gridView, comm, grav);
1626 applyNumericalAquifers_(gridView, num_aquifers,
1627 eclipseState.runspec().co2Storage() ||
1628 eclipseState.runspec().h2Storage());
1634template<
class FluidSystem,
1637 class ElementMapper,
1638 class CartesianIndexMapper>
1644 CartesianIndexMapper>::
1645updateInitialTemperature_(
const EclipseState& eclState,
const RMap& reg)
1647 const int numEquilReg = rsFunc_.size();
1648 tempVdTable_.resize(numEquilReg);
1649 const auto& tables = eclState.getTableManager();
1650 if (!tables.hasTables(
"RTEMPVD")) {
1651 std::vector<Scalar> x = {0.0,1.0};
1652 std::vector<Scalar> y = {
static_cast<Scalar
>(tables.rtemp()),
1653 static_cast<Scalar
>(tables.rtemp())};
1654 for (
auto& table : this->tempVdTable_) {
1655 table.setXYContainers(x, y);
1658 const TableContainer& tempvdTables = tables.getRtempvdTables();
1659 for (std::size_t i = 0; i < tempvdTables.size(); ++i) {
1660 const RtempvdTable& tempvdTable = tempvdTables.getTable<RtempvdTable>(i);
1661 tempVdTable_[i].setXYContainers(tempvdTable.getDepthColumn(), tempvdTable.getTemperatureColumn());
1662 const auto& cells = reg.cells(i);
1663 for (
const auto& cell : cells) {
1664 const Scalar depth = cellCenterDepth_[cell];
1665 this->temperature_[cell] = tempVdTable_[i].eval(depth,
true);
1671template<
class FluidSystem,
1674 class ElementMapper,
1675 class CartesianIndexMapper>
1677void InitialStateComputer<FluidSystem,
1681 CartesianIndexMapper>::
1682updateInitialSaltConcentration_(
const EclipseState& eclState,
const RMap& reg)
1684 const int numEquilReg = rsFunc_.size();
1685 saltVdTable_.resize(numEquilReg);
1686 const auto& tables = eclState.getTableManager();
1687 const TableContainer& saltvdTables = tables.getSaltvdTables();
1690 if (saltvdTables.empty()) {
1691 std::vector<Scalar> x = {0.0,1.0};
1692 std::vector<Scalar> y = {0.0,0.0};
1693 for (
auto& table : this->saltVdTable_) {
1694 table.setXYContainers(x, y);
1697 for (std::size_t i = 0; i < saltvdTables.size(); ++i) {
1698 const SaltvdTable& saltvdTable = saltvdTables.getTable<SaltvdTable>(i);
1699 saltVdTable_[i].setXYContainers(saltvdTable.getDepthColumn(), saltvdTable.getSaltColumn());
1701 const auto& cells = reg.cells(i);
1702 for (
const auto& cell : cells) {
1703 const Scalar depth = cellCenterDepth_[cell];
1704 this->saltConcentration_[cell] = saltVdTable_[i].eval(depth,
true);
1710template<
class FluidSystem,
1713 class ElementMapper,
1714 class CartesianIndexMapper>
1716void InitialStateComputer<FluidSystem,
1720 CartesianIndexMapper>::
1721updateInitialSaltSaturation_(
const EclipseState& eclState,
const RMap& reg)
1723 const int numEquilReg = rsFunc_.size();
1724 saltpVdTable_.resize(numEquilReg);
1725 const auto& tables = eclState.getTableManager();
1726 const TableContainer& saltpvdTables = tables.getSaltpvdTables();
1728 for (std::size_t i = 0; i < saltpvdTables.size(); ++i) {
1729 const SaltpvdTable& saltpvdTable = saltpvdTables.getTable<SaltpvdTable>(i);
1730 saltpVdTable_[i].setXYContainers(saltpvdTable.getDepthColumn(), saltpvdTable.getSaltpColumn());
1732 const auto& cells = reg.cells(i);
1733 for (
const auto& cell : cells) {
1734 const Scalar depth = cellCenterDepth_[cell];
1735 this->saltSaturation_[cell] = saltpVdTable_[i].eval(depth,
true);
1740template<
class FluidSystem,
1743 class ElementMapper,
1744 class CartesianIndexMapper>
1745void InitialStateComputer<FluidSystem,
1749 CartesianIndexMapper>::
1750updateCellProps_(
const GridView& gridView,
1751 const NumericalAquifers& aquifer)
1753 ElementMapper elemMapper(gridView, Dune::mcmgElementLayout());
1754 int numElements = gridView.size(0);
1755 cellCenterDepth_.resize(numElements);
1756 cellCenterXY_.resize(numElements);
1757 cellCorners_.resize(numElements);
1758 cellZSpan_.resize(numElements);
1759 cellZMinMax_.resize(numElements);
1761 auto elemIt = gridView.template begin<0>();
1762 const auto& elemEndIt = gridView.template end<0>();
1763 const auto num_aqu_cells = aquifer.allAquiferCells();
1764 for (; elemIt != elemEndIt; ++elemIt) {
1765 const Element& element = *elemIt;
1766 const unsigned int elemIdx = elemMapper.index(element);
1767 cellCenterDepth_[elemIdx] = Details::cellCenterDepth<Scalar>(element);
1768 cellCenterXY_[elemIdx] = Details::cellCenterXY<Scalar>(element);
1769 cellCorners_[elemIdx] = Details::getCellCornerXY<Scalar>(element);
1770 const auto cartIx = cartesianIndexMapper_.cartesianIndex(elemIdx);
1771 cellZSpan_[elemIdx] = Details::cellZSpan<Scalar>(element);
1772 cellZMinMax_[elemIdx] = Details::cellZMinMax<Scalar>(element);
1773 if (!num_aqu_cells.empty()) {
1774 const auto search = num_aqu_cells.find(cartIx);
1775 if (search != num_aqu_cells.end()) {
1776 const auto* aqu_cell = num_aqu_cells.at(cartIx);
1777 const Scalar depth_change_num_aqu = aqu_cell->depth - cellCenterDepth_[elemIdx];
1778 cellCenterDepth_[elemIdx] += depth_change_num_aqu;
1779 cellZSpan_[elemIdx].first += depth_change_num_aqu;
1780 cellZSpan_[elemIdx].second += depth_change_num_aqu;
1781 cellZMinMax_[elemIdx].first += depth_change_num_aqu;
1782 cellZMinMax_[elemIdx].second += depth_change_num_aqu;
1788template<
class FluidSystem,
1791 class ElementMapper,
1792 class CartesianIndexMapper>
1793void InitialStateComputer<FluidSystem,
1797 CartesianIndexMapper>::
1798applyNumericalAquifers_(
const GridView& gridView,
1799 const NumericalAquifers& aquifer,
1800 const bool co2store_or_h2store)
1802 const auto num_aqu_cells = aquifer.allAquiferCells();
1803 if (num_aqu_cells.empty())
return;
1806 bool oil_as_brine = co2store_or_h2store && FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
1807 const auto watPos = oil_as_brine? FluidSystem::oilPhaseIdx : FluidSystem::waterPhaseIdx;
1808 if (!FluidSystem::phaseIsActive(watPos)){
1809 throw std::logic_error {
"Water phase has to be active for numerical aquifer case" };
1812 ElementMapper elemMapper(gridView, Dune::mcmgElementLayout());
1813 auto elemIt = gridView.template begin<0>();
1814 const auto& elemEndIt = gridView.template end<0>();
1815 const auto oilPos = FluidSystem::oilPhaseIdx;
1816 const auto gasPos = FluidSystem::gasPhaseIdx;
1817 for (; elemIt != elemEndIt; ++elemIt) {
1818 const Element& element = *elemIt;
1819 const unsigned int elemIdx = elemMapper.index(element);
1820 const auto cartIx = cartesianIndexMapper_.cartesianIndex(elemIdx);
1821 const auto search = num_aqu_cells.find(cartIx);
1822 if (search != num_aqu_cells.end()) {
1824 this->sat_[watPos][elemIdx] = 1.;
1826 if (!co2store_or_h2store && FluidSystem::phaseIsActive(oilPos)) {
1827 this->sat_[oilPos][elemIdx] = 0.;
1830 if (FluidSystem::phaseIsActive(gasPos)) {
1831 this->sat_[gasPos][elemIdx] = 0.;
1833 const auto* aqu_cell = num_aqu_cells.at(cartIx);
1834 const auto msg = fmt::format(
"FOR AQUIFER CELL AT ({}, {}, {}) OF NUMERICAL "
1835 "AQUIFER {}, WATER SATURATION IS SET TO BE UNITY",
1836 aqu_cell->I+1, aqu_cell->J+1, aqu_cell->K+1, aqu_cell->aquifer_id);
1841 if (aqu_cell->init_pressure) {
1842 const Scalar pres = *(aqu_cell->init_pressure);
1843 this->pp_[watPos][elemIdx] = pres;
1844 if (FluidSystem::phaseIsActive(gasPos)) {
1845 this->pp_[gasPos][elemIdx] = pres;
1847 if (FluidSystem::phaseIsActive(oilPos)) {
1848 this->pp_[oilPos][elemIdx] = pres;
1855template<
class FluidSystem,
1858 class ElementMapper,
1859 class CartesianIndexMapper>
1861void InitialStateComputer<FluidSystem,
1865 CartesianIndexMapper>::
1866setRegionPvtIdx(
const EclipseState& eclState,
const GridView& gridView,
const RMap& reg)
1875 const LookUpData<typename GridView::Grid, GridView> lookUpData(gridView);
1876 const auto pvtnumData = lookUpData.template assignFieldPropsIntOnLeaf<int>(
1877 eclState.fieldProps(),
"PVTNUM",
true);
1879 for (
const auto& r : reg.activeRegions()) {
1880 const auto& cells = reg.cells(r);
1881 regionPvtIdx_[r] = pvtnumData[*cells.begin()];
1885template<
class FluidSystem,
1888 class ElementMapper,
1889 class CartesianIndexMapper>
1890template<
class RMap,
class MaterialLawManager,
class Comm>
1891void InitialStateComputer<FluidSystem,
1895 CartesianIndexMapper>::
1896calcPressSatRsRv(
const RMap& reg,
1897 const std::vector<EquilRecord>& rec,
1898 MaterialLawManager& materialLawManager,
1899 const GridView& gridView,
1903 using PhaseSat = Details::PhaseSaturations<
1904 MaterialLawManager, FluidSystem, EquilReg<Scalar>,
typename RMap::CellId
1907 auto ptable = Details::PressureTable<FluidSystem, EquilReg<Scalar>>{ grav, this->num_pressure_points_ };
1908 auto psat = PhaseSat { materialLawManager, this->swatInit_ };
1909 auto vspan = std::array<Scalar, 2>{};
1911 std::vector<int> regionIsEmpty(rec.size(), 0);
1912 for (std::size_t r = 0; r < rec.size(); ++r) {
1913 const auto& cells = reg.cells(r);
1917 const auto acc = rec[r].initializationTargetAccuracy();
1921 if (cells.empty()) {
1922 regionIsEmpty[r] = 1;
1925 const auto eqreg = EquilReg {
1926 rec[r], this->rsFunc_[r], this->rvFunc_[r], this->rvwFunc_[r],
1927 this->tempVdTable_[r], this->saltVdTable_[r], this->regionPvtIdx_[r]
1930 vspan[0] = std::min(vspan[0], std::min(eqreg.zgoc(), eqreg.zwoc()));
1931 vspan[1] = std::max(vspan[1], std::max(eqreg.zgoc(), eqreg.zwoc()));
1932 ptable.equilibrate(eqreg, vspan);
1935 this->equilibrateTiltedFaultBlock(cells, eqreg, gridView, acc, ptable, psat);
1937 else if (acc == 0) {
1938 if (cells.empty()) {
1939 regionIsEmpty[r] = 1;
1942 const auto eqreg = EquilReg {
1943 rec[r], this->rsFunc_[r], this->rvFunc_[r], this->rvwFunc_[r],
1944 this->tempVdTable_[r], this->saltVdTable_[r], this->regionPvtIdx_[r]
1946 vspan[0] = std::min(vspan[0], std::min(eqreg.zgoc(), eqreg.zwoc()));
1947 vspan[1] = std::max(vspan[1], std::max(eqreg.zgoc(), eqreg.zwoc()));
1948 ptable.equilibrate(eqreg, vspan);
1950 this->equilibrateCellCentres(cells, eqreg, ptable, psat);
1953 if (cells.empty()) {
1954 regionIsEmpty[r] = 1;
1957 const auto eqreg = EquilReg {
1958 rec[r], this->rsFunc_[r], this->rvFunc_[r], this->rvwFunc_[r],
1959 this->tempVdTable_[r], this->saltVdTable_[r], this->regionPvtIdx_[r]
1961 vspan[0] = std::min(vspan[0], std::min(eqreg.zgoc(), eqreg.zwoc()));
1962 vspan[1] = std::max(vspan[1], std::max(eqreg.zgoc(), eqreg.zwoc()));
1963 ptable.equilibrate(eqreg, vspan);
1965 this->equilibrateHorizontal(cells, eqreg, -acc, ptable, psat);
1968 comm.min(regionIsEmpty.data(),regionIsEmpty.size());
1969 if (comm.rank() == 0) {
1970 for (std::size_t r = 0; r < rec.size(); ++r) {
1971 if (regionIsEmpty[r])
1973 +
" has no active cells");
1978template<
class FluidSystem,
1981 class ElementMapper,
1982 class CartesianIndexMapper>
1983template<
class CellRange,
class EquilibrationMethod>
1984void InitialStateComputer<FluidSystem,
1988 CartesianIndexMapper>::
1989cellLoop(
const CellRange& cells,
1990 EquilibrationMethod&& eqmethod)
1992 const auto oilPos = FluidSystem::oilPhaseIdx;
1993 const auto gasPos = FluidSystem::gasPhaseIdx;
1994 const auto watPos = FluidSystem::waterPhaseIdx;
1996 const auto oilActive = FluidSystem::phaseIsActive(oilPos);
1997 const auto gasActive = FluidSystem::phaseIsActive(gasPos);
1998 const auto watActive = FluidSystem::phaseIsActive(watPos);
2000 auto pressures = Details::PhaseQuantityValue<Scalar>{};
2001 auto saturations = Details::PhaseQuantityValue<Scalar>{};
2006 for (
const auto& cell : cells) {
2007 eqmethod(cell, pressures, saturations, Rs, Rv, Rvw);
2010 this->pp_ [oilPos][cell] = pressures.oil;
2011 this->sat_[oilPos][cell] = saturations.oil;
2015 this->pp_ [gasPos][cell] = pressures.gas;
2016 this->sat_[gasPos][cell] = saturations.gas;
2020 this->pp_ [watPos][cell] = pressures.water;
2021 this->sat_[watPos][cell] = saturations.water;
2024 if (oilActive && gasActive) {
2025 this->rs_[cell] =
Rs;
2026 this->rv_[cell] =
Rv;
2029 if (watActive && gasActive) {
2030 this->rvw_[cell] =
Rvw;
2035template<
class FluidSystem,
2038 class ElementMapper,
2039 class CartesianIndexMapper>
2040template<
class CellRange,
class PressTable,
class PhaseSat>
2041void InitialStateComputer<FluidSystem,
2045 CartesianIndexMapper>::
2046equilibrateCellCentres(
const CellRange& cells,
2047 const EquilReg<Scalar>& eqreg,
2048 const PressTable& ptable,
2051 using CellPos =
typename PhaseSat::Position;
2052 using CellID = std::remove_cv_t<std::remove_reference_t<
2053 decltype(std::declval<CellPos>().cell)>>;
2054 this->cellLoop(cells, [
this, &eqreg, &ptable, &psat]
2056 Details::PhaseQuantityValue<Scalar>& pressures,
2057 Details::PhaseQuantityValue<Scalar>& saturations,
2060 Scalar& Rvw) ->
void
2062 const auto pos = CellPos {
2063 cell, cellCenterDepth_[cell]
2066 saturations = psat.deriveSaturations(pos, eqreg, ptable);
2067 pressures = psat.correctedPhasePressures();
2069 const auto temp = this->temperature_[cell];
2071 Rs = eqreg.dissolutionCalculator()
2072 (pos.depth, pressures.oil, temp, saturations.gas);
2074 Rv = eqreg.evaporationCalculator()
2075 (pos.depth, pressures.gas, temp, saturations.oil);
2077 Rvw = eqreg.waterEvaporationCalculator()
2078 (pos.depth, pressures.gas, temp, saturations.water);
2082template<
class FluidSystem,
2085 class ElementMapper,
2086 class CartesianIndexMapper>
2087template<
class CellRange,
class PressTable,
class PhaseSat>
2088void InitialStateComputer<FluidSystem,
2092 CartesianIndexMapper>::
2093equilibrateHorizontal(
const CellRange& cells,
2094 const EquilReg<Scalar>& eqreg,
2096 const PressTable& ptable,
2099 using CellPos =
typename PhaseSat::Position;
2100 using CellID = std::remove_cv_t<std::remove_reference_t<
2101 decltype(std::declval<CellPos>().cell)>>;
2103 this->cellLoop(cells, [
this, acc, &eqreg, &ptable, &psat]
2105 Details::PhaseQuantityValue<Scalar>& pressures,
2106 Details::PhaseQuantityValue<Scalar>& saturations,
2109 Scalar& Rvw) ->
void
2112 saturations.reset();
2114 Scalar totfrac = 0.0;
2116 const auto pos = CellPos { cell, depth };
2118 saturations.axpy(psat.deriveSaturations(pos, eqreg, ptable), frac);
2119 pressures .axpy(psat.correctedPhasePressures(), frac);
2125 saturations /= totfrac;
2126 pressures /= totfrac;
2129 const auto pos = CellPos {
2130 cell, cellCenterDepth_[cell]
2133 saturations = psat.deriveSaturations(pos, eqreg, ptable);
2134 pressures = psat.correctedPhasePressures();
2137 const auto temp = this->temperature_[cell];
2138 const auto cz = cellCenterDepth_[cell];
2140 Rs = eqreg.dissolutionCalculator()
2141 (cz, pressures.oil, temp, saturations.gas);
2143 Rv = eqreg.evaporationCalculator()
2144 (cz, pressures.gas, temp, saturations.oil);
2146 Rvw = eqreg.waterEvaporationCalculator()
2147 (cz, pressures.gas, temp, saturations.water);
2151template<
class Flu
idSystem,
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper>
2152template<
class CellRange,
class PressTable,
class PhaseSat>
2153void InitialStateComputer<FluidSystem, Grid, GridView, ElementMapper, CartesianIndexMapper>::
2154equilibrateTiltedFaultBlockSimple(
const CellRange& cells,
2155 const EquilReg<Scalar>& eqreg,
2156 const GridView& gridView,
2158 const PressTable& ptable,
2161 using CellPos =
typename PhaseSat::Position;
2162 using CellID = std::remove_cv_t<std::remove_reference_t<
2163 decltype(std::declval<CellPos>().cell)>>;
2165 this->cellLoop(cells, [
this, acc, &eqreg, &ptable, &psat, &gridView]
2167 Details::PhaseQuantityValue<Scalar>& pressures,
2168 Details::PhaseQuantityValue<Scalar>& saturations,
2171 Scalar& Rvw) ->
void
2174 saturations.reset();
2175 Scalar totalWeight = 0.0;
2178 const auto& [zmin, zmax] = cellZMinMax_[cell];
2179 const Scalar cellThickness = zmax - zmin;
2180 const Scalar halfThickness = cellThickness / 2.0;
2183 Scalar dipAngle, dipAzimuth;
2187 std::array<Scalar, 3> referencePoint = {
2188 cellCenterXY_[cell].first,
2189 cellCenterXY_[cell].second,
2190 cellCenterDepth_[cell]
2194 const int numLevelsPerHalf = std::min(20, acc);
2197 std::vector<std::pair<Scalar, Scalar>> levels;
2200 for (
int side = 0; side < 2; ++side) {
2201 Scalar halfStart = (side == 0) ? zmin : zmin + halfThickness;
2203 for (
int i = 0; i < numLevelsPerHalf; ++i) {
2205 Scalar depth = halfStart + (i + 0.5) * (halfThickness / numLevelsPerHalf);
2209 Scalar crossSectionWeight = (halfThickness / numLevelsPerHalf);
2212 if (std::abs(dipAngle) > 1e-10) {
2213 crossSectionWeight /= std::cos(dipAngle);
2216 levels.emplace_back(depth, crossSectionWeight);
2220 for (
const auto& [depth, weight] : levels) {
2222 const auto& [x, y] = cellCenterXY_[cell];
2224 depth, x, y, dipAngle, dipAzimuth, referencePoint);
2226 const auto pos = CellPos{cell, tvd};
2228 auto localSaturations = psat.deriveSaturations(pos, eqreg, ptable);
2229 auto localPressures = psat.correctedPhasePressures();
2232 saturations.axpy(localSaturations, weight);
2233 pressures.axpy(localPressures, weight);
2234 totalWeight += weight;
2238 if (totalWeight > 1e-10) {
2239 saturations /= totalWeight;
2240 pressures /= totalWeight;
2243 const auto& [x, y] = cellCenterXY_[cell];
2245 cellCenterDepth_[cell], x, y, dipAngle, dipAzimuth, referencePoint);
2246 const auto pos = CellPos{cell, tvdCenter};
2247 saturations = psat.deriveSaturations(pos, eqreg, ptable);
2248 pressures = psat.correctedPhasePressures();
2252 const auto temp = this->temperature_[cell];
2253 const auto& [x, y] = cellCenterXY_[cell];
2255 cellCenterDepth_[cell], x, y, dipAngle, dipAzimuth, referencePoint);
2257 Rs = eqreg.dissolutionCalculator()(tvdCenter, pressures.oil, temp, saturations.gas);
2258 Rv = eqreg.evaporationCalculator()(tvdCenter, pressures.gas, temp, saturations.oil);
2259 Rvw = eqreg.waterEvaporationCalculator()(tvdCenter, pressures.gas, temp, saturations.water);
2263template<
class Flu
idSystem,
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper>
2264template<
class CellRange,
class PressTable,
class PhaseSat>
2265void InitialStateComputer<FluidSystem, Grid, GridView, ElementMapper, CartesianIndexMapper>::
2266equilibrateTiltedFaultBlock(
const CellRange& cells,
2267 const EquilReg<Scalar>& eqreg,
2268 const GridView& gridView,
2270 const PressTable& ptable,
2273 using CellPos =
typename PhaseSat::Position;
2274 using CellID = std::remove_cv_t<std::remove_reference_t<
2275 decltype(std::declval<CellPos>().cell)>>;
2277 std::vector<typename GridView::template Codim<0>::Entity> entityMap(gridView.size(0));
2278 for (
const auto& entity : entities(gridView, Dune::Codim<0>())) {
2279 CellID idx = gridView.indexSet().index(entity);
2280 entityMap[idx] = entity;
2284 auto polygonArea = [](
const std::vector<std::array<Scalar, 2>>& pts) {
2285 if (pts.size() < 3)
return Scalar(0);
2287 for (
size_t i = 0; i < pts.size(); ++i) {
2288 size_t j = (i + 1) % pts.size();
2289 area += pts[i][0] * pts[j][1] - pts[j][0] * pts[i][1];
2291 return std::abs(area) * Scalar(0.5);
2295 auto computeCrossSectionArea = [&](
const CellID cell, Scalar depth) -> Scalar {
2297 const auto& entity = entityMap[cell];
2298 const auto& geometry = entity.geometry();
2299 const int numCorners = geometry.corners();
2301 std::vector<std::array<Scalar, 3>> corners(numCorners);
2302 for (
int i = 0; i < numCorners; ++i) {
2303 const auto& corner = geometry.corner(i);
2304 corners[i] = {
static_cast<Scalar
>(corner[0]),
static_cast<Scalar
>(corner[1]),
static_cast<Scalar
>(corner[2])};
2308 std::vector<std::array<Scalar, 2>> intersectionPoints;
2309 const Scalar tol = 1e-10;
2312 for (
size_t i = 0; i < corners.size(); ++i) {
2313 for (
size_t j = i + 1; j < corners.size(); ++j) {
2314 Scalar za = corners[i][2];
2315 Scalar zb = corners[j][2];
2317 if ((za - depth) * (zb - depth) <= 0.0 && std::abs(za - zb) > tol) {
2319 Scalar t = (depth - za) / (zb - za);
2320 Scalar x = corners[i][0] + t * (corners[j][0] - corners[i][0]);
2321 Scalar y = corners[i][1] + t * (corners[j][1] - corners[i][1]);
2322 intersectionPoints.push_back({x, y});
2328 if (intersectionPoints.size() > 1) {
2329 auto pointsEqual = [tol](
const std::array<Scalar, 2>& a,
const std::array<Scalar, 2>& b) {
2330 return std::abs(a[0] - b[0]) < tol && std::abs(a[1] - b[1]) < tol;
2333 intersectionPoints.erase(
2334 std::unique(intersectionPoints.begin(), intersectionPoints.end(), pointsEqual),
2335 intersectionPoints.end()
2339 if (intersectionPoints.size() < 3) {
2345 Scalar cx = 0, cy = 0;
2346 for (
const auto& p : intersectionPoints) {
2347 cx += p[0]; cy += p[1];
2349 cx /= intersectionPoints.size();
2350 cy /= intersectionPoints.size();
2353 auto angleCompare = [cx, cy](
const std::array<Scalar, 2>& a,
const std::array<Scalar, 2>& b) {
2354 return std::atan2(a[1] - cy, a[0] - cx) < std::atan2(b[1] - cy, b[0] - cx);
2357 std::ranges::sort(intersectionPoints, angleCompare);
2359 return polygonArea(intersectionPoints);
2361 }
catch (
const std::exception& e) {
2366 auto cellProcessor = [
this, acc, &eqreg, &ptable, &psat, &computeCrossSectionArea]
2368 Details::PhaseQuantityValue<Scalar>& pressures,
2369 Details::PhaseQuantityValue<Scalar>& saturations,
2372 Scalar&
Rvw) ->
void
2375 saturations.reset();
2376 Scalar totalWeight = 0.0;
2378 const auto& zmin = this->cellZMinMax_[cell].first;
2379 const auto& zmax = this->cellZMinMax_[cell].second;
2380 const Scalar cellThickness = zmax - zmin;
2381 const Scalar halfThickness = cellThickness / 2.0;
2384 Scalar dipAngle, dipAzimuth;
2388 std::array<Scalar, 3> referencePoint = {
2389 this->cellCenterXY_[cell].first,
2390 this->cellCenterXY_[cell].second,
2391 cellCenterDepth_[cell]
2395 const int numLevelsPerHalf = std::min(20, acc);
2398 std::vector<std::pair<Scalar, Scalar>> levels;
2401 for (
int side = 0; side < 2; ++side) {
2402 Scalar halfStart = (side == 0) ? zmin : zmin + halfThickness;
2404 for (
int i = 0; i < numLevelsPerHalf; ++i) {
2406 Scalar depth = halfStart + (i + 0.5) * (halfThickness / numLevelsPerHalf);
2409 Scalar crossSectionArea = computeCrossSectionArea(cell, depth);
2412 Scalar weight = crossSectionArea * (halfThickness / numLevelsPerHalf);
2414 levels.emplace_back(depth, weight);
2419 bool hasValidAreas =
false;
2420 for (
const auto& level : levels) {
2421 if (level.second > 1e-10) {
2422 hasValidAreas =
true;
2427 if (!hasValidAreas) {
2430 for (
int side = 0; side < 2; ++side) {
2431 Scalar halfStart = (side == 0) ? zmin : zmin + halfThickness;
2432 for (
int i = 0; i < numLevelsPerHalf; ++i) {
2433 Scalar depth = halfStart + (i + 0.5) * (halfThickness / numLevelsPerHalf);
2434 Scalar weight = (halfThickness / numLevelsPerHalf);
2435 if (std::abs(dipAngle) > 1e-10) {
2436 weight /= std::cos(dipAngle);
2438 levels.emplace_back(depth, weight);
2443 for (
const auto& level : levels) {
2444 Scalar depth = level.first;
2445 Scalar weight = level.second;
2448 const auto& xy = this->cellCenterXY_[cell];
2450 depth, xy.first, xy.second, dipAngle, dipAzimuth, referencePoint);
2452 const auto pos = CellPos{cell, tvd};
2454 auto localSaturations = psat.deriveSaturations(pos, eqreg, ptable);
2455 auto localPressures = psat.correctedPhasePressures();
2458 saturations.axpy(localSaturations, weight);
2459 pressures.axpy(localPressures, weight);
2460 totalWeight += weight;
2463 if (totalWeight > 1e-10) {
2464 saturations /= totalWeight;
2465 pressures /= totalWeight;
2468 const auto& xy = this->cellCenterXY_[cell];
2470 this->cellCenterDepth_[cell], xy.first, xy.second, dipAngle, dipAzimuth, referencePoint);
2471 const auto pos = CellPos{cell, tvdCenter};
2472 saturations = psat.deriveSaturations(pos, eqreg, ptable);
2473 pressures = psat.correctedPhasePressures();
2477 const auto temp = this->temperature_[cell];
2478 const auto& xy = this->cellCenterXY_[cell];
2480 this->cellCenterDepth_[cell], xy.first, xy.second, dipAngle, dipAzimuth, referencePoint);
2482 Rs = eqreg.dissolutionCalculator()(tvdCenter, pressures.oil, temp, saturations.gas);
2483 Rv = eqreg.evaporationCalculator()(tvdCenter, pressures.gas, temp, saturations.oil);
2484 Rvw = eqreg.waterEvaporationCalculator()(tvdCenter, pressures.gas, temp, saturations.water);
2487 this->cellLoop(cells, cellProcessor);
#define OPM_END_PARALLEL_TRY_CATCH(prefix, comm)
Catch exception and throw in a parallel try-catch clause.
Definition: DeferredLoggingErrorHelpers.hpp:197
#define OPM_BEGIN_PARALLEL_TRY_CATCH()
Macro to setup the try of a parallel try-catch.
Definition: DeferredLoggingErrorHelpers.hpp:160
Auxiliary routines that to solve the ODEs that emerge from the hydrostatic equilibrium problem.
Dune::OwnerOverlapCopyCommunication< int, int > Comm
Definition: FlexibleSolver_impl.hpp:394
Routines that actually solve the ODEs that emerge from the hydrostatic equilibrium problem.
Definition: InitStateEquil.hpp:655
Definition: InitStateEquil.hpp:133
Gas(const TabulatedFunction &tempVdTable, const RV &rv, const RVW &rvw, const int pvtRegionIdx, const Scalar normGrav)
Definition: InitStateEquil_impl.hpp:411
Scalar operator()(const Scalar depth, const Scalar press) const
Definition: InitStateEquil_impl.hpp:427
Definition: InitStateEquil.hpp:108
Oil(const TabulatedFunction &tempVdTable, const RS &rs, const int pvtRegionIdx, const Scalar normGrav)
Definition: InitStateEquil_impl.hpp:363
Scalar operator()(const Scalar depth, const Scalar press) const
Definition: InitStateEquil_impl.hpp:377
Definition: InitStateEquil.hpp:83
Scalar operator()(const Scalar depth, const Scalar press) const
Definition: InitStateEquil_impl.hpp:337
Water(const TabulatedFunction &tempVdTable, const TabulatedFunction &saltVdTable, const int pvtRegionIdx, const Scalar normGrav)
Definition: InitStateEquil_impl.hpp:323
Definition: InitStateEquil.hpp:350
const PhaseQuantityValue< Scalar > & deriveSaturations(const Position &x, const Region ®, const PTable &ptable)
Definition: InitStateEquil_impl.hpp:587
PhaseSaturations(MaterialLawManager &matLawMgr, const std::vector< Scalar > &swatInit)
Definition: InitStateEquil_impl.hpp:563
Definition: InitStateEquil.hpp:162
PressureTable & operator=(const PressureTable &rhs)
Definition: InitStateEquil_impl.hpp:1027
Scalar water(const Scalar depth) const
Definition: InitStateEquil_impl.hpp:1107
Scalar gas(const Scalar depth) const
Definition: InitStateEquil_impl.hpp:1096
bool waterActive() const
Predicate for whether or not water is an active phase.
Definition: InitStateEquil_impl.hpp:1078
bool gasActive() const
Predicate for whether or not gas is an active phase.
Definition: InitStateEquil_impl.hpp:1071
Scalar oil(const Scalar depth) const
Definition: InitStateEquil_impl.hpp:1086
std::array< Scalar, 2 > VSpan
Definition: InitStateEquil.hpp:165
bool oilActive() const
Predicate for whether or not oil is an active phase.
Definition: InitStateEquil_impl.hpp:1064
typename FluidSystem::Scalar Scalar
Definition: InitStateEquil.hpp:164
void equilibrate(const Region ®, const VSpan &span)
Definition: InitStateEquil_impl.hpp:1053
PressureTable(const Scalar gravity, const int samplePoints=2000)
Definition: InitStateEquil_impl.hpp:997
Definition: EquilibrationHelpers.hpp:135
Definition: EquilibrationHelpers.hpp:216
Definition: EquilibrationHelpers.hpp:269
Definition: EquilibrationHelpers.hpp:612
Definition: EquilibrationHelpers.hpp:162
Definition: EquilibrationHelpers.hpp:322
Definition: EquilibrationHelpers.hpp:376
Definition: FlowGenericProblem.hpp:51
std::vector< EquilRecord > getEquil(const EclipseState &state)
Definition: InitStateEquil_impl.hpp:1301
std::vector< int > equilnum(const EclipseState &eclipseState, const GridView &gridview)
Definition: InitStateEquil_impl.hpp:1315
std::pair< Scalar, Scalar > cellZMinMax(const Element &element)
Definition: InitStateEquil_impl.hpp:187
Scalar cellCenterDepth(const Element &element)
Definition: InitStateEquil_impl.hpp:134
std::pair< Scalar, Scalar > cellZSpan(const Element &element)
Definition: InitStateEquil_impl.hpp:168
CellCornerData< Scalar > getCellCornerXY(const Element &element)
Definition: InitStateEquil_impl.hpp:257
void verticalExtent(const CellRange &cells, const std::vector< std::pair< Scalar, Scalar > > &cellZMinMax, const Parallel::Communication &comm, std::array< Scalar, 2 > &span)
Definition: InitStateEquil_impl.hpp:70
std::pair< Scalar, Scalar > cellCenterXY(const Element &element)
Definition: InitStateEquil_impl.hpp:149
Scalar calculateTrueVerticalDepth(Scalar z, Scalar x, Scalar y, Scalar dipAngle, Scalar dipAzimuth, const std::array< Scalar, 3 > &referencePoint)
Definition: InitStateEquil_impl.hpp:281
void subdivisionCentrePoints(const Scalar left, const Scalar right, const int numIntervals, std::vector< std::pair< Scalar, Scalar > > &subdiv)
Definition: InitStateEquil_impl.hpp:95
std::vector< std::pair< Scalar, Scalar > > horizontalSubdivision(const CellID cell, const std::pair< Scalar, Scalar > topbot, const int numIntervals)
Definition: InitStateEquil_impl.hpp:113
void computeBlockDip(const CellCornerData< Scalar > &cellCorners, Scalar &dipAngle, Scalar &dipAzimuth)
Definition: InitStateEquil_impl.hpp:206
Dune::Communication< MPIComm > Communication
Definition: ParallelCommunication.hpp:30
Definition: blackoilbioeffectsmodules.hh:45
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
Definition: InitStateEquil.hpp:62
std::array< Scalar, 8 > X
Definition: InitStateEquil.hpp:63
std::array< Scalar, 8 > Y
Definition: InitStateEquil.hpp:64
std::array< Scalar, 8 > Z
Definition: InitStateEquil.hpp:65
Simple set of per-phase (named by primary component) quantities.
Definition: InitStateEquil.hpp:302
Definition: InitStateEquil.hpp:356