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 const std::vector<Scalar>* editedCellDepths)
1368 : temperature_(grid.size(0), eclipseState.getTableManager().rtemp()),
1369 saltConcentration_(grid.size(0)),
1370 saltSaturation_(grid.size(0)),
1371 pp_(FluidSystem::numPhases,
1372 std::vector<Scalar>(grid.size(0))),
1373 sat_(FluidSystem::numPhases,
1374 std::vector<Scalar>(grid.size(0))),
1378 cartesianIndexMapper_(cartMapper),
1379 num_pressure_points_(num_pressure_points)
1382 if (applySwatInit) {
1383 if (eclipseState.fieldProps().has_double(
"SWATINIT")) {
1390 lookUpData.assignFieldPropsDoubleOnLeaf(eclipseState.fieldProps(),
"SWATINIT");
1391 if constexpr (std::is_same_v<Scalar, double>) {
1392 swatInit_ = std::move(input);
1394 swatInit_.assign(input.begin(), input.end());
1401 const auto& num_aquifers = eclipseState.aquifer().numericalAquifers();
1402 updateCellProps_(gridView, num_aquifers, editedCellDepths);
1405 const std::vector<EquilRecord> rec =
getEquil(eclipseState);
1406 const auto& tables = eclipseState.getTableManager();
1408 const RegionMapping<> eqlmap(
equilnum(eclipseState, gridView));
1409 const int invalidRegion = -1;
1410 regionPvtIdx_.resize(rec.size(), invalidRegion);
1411 setRegionPvtIdx(eclipseState, gridView, eqlmap);
1414 rsFunc_.reserve(rec.size());
1416 auto getArray = [](
const std::vector<double>& input)
1418 if constexpr (std::is_same_v<Scalar,double>) {
1421 std::vector<Scalar> output;
1422 output.resize(input.size());
1423 std::ranges::copy(input, output.begin());
1428 if (FluidSystem::enableDissolvedGas()) {
1429 for (std::size_t i = 0; i < rec.size(); ++i) {
1430 if (eqlmap.cells(i).empty()) {
1434 const int pvtIdx = regionPvtIdx_[i];
1435 if (!rec[i].liveOilInitConstantRs()) {
1436 const TableContainer& rsvdTables = tables.getRsvdTables();
1437 const TableContainer& pbvdTables = tables.getPbvdTables();
1438 if (rsvdTables.size() > 0) {
1439 const RsvdTable& rsvdTable = rsvdTables.getTable<RsvdTable>(i);
1440 auto depthColumn = getArray(rsvdTable.getColumn(
"DEPTH").vectorCopy());
1441 auto rsColumn = getArray(rsvdTable.getColumn(
"RS").vectorCopy());
1443 depthColumn, rsColumn));
1444 }
else if (pbvdTables.size() > 0) {
1445 const PbvdTable& pbvdTable = pbvdTables.getTable<PbvdTable>(i);
1446 auto depthColumn = getArray(pbvdTable.getColumn(
"DEPTH").vectorCopy());
1447 auto pbubColumn = getArray(pbvdTable.getColumn(
"PBUB").vectorCopy());
1449 depthColumn, pbubColumn));
1452 throw std::runtime_error(
"Cannot initialise: RSVD or PBVD table not available.");
1457 if (rec[i].gasOilContactDepth() != rec[i].datumDepth()) {
1458 throw std::runtime_error(
"Cannot initialise: when no explicit RSVD table is given, \n"
1459 "datum depth must be at the gas-oil-contact. "
1460 "In EQUIL region "+
std::to_string(i + 1)+
" (counting from 1), this does not hold.");
1462 const Scalar pContact = rec[i].datumDepthPressure();
1463 const Scalar TContact = 273.15 + 20;
1468 else if (FluidSystem::enableConstantRs() && tables.hasTables(
"RSCONST")) {
1469 const auto& rsconstTables = tables.getRsconstTables();
1471 if (rsconstTables.empty()) {
1472 for (std::size_t i = 0; i < rec.size(); ++i) {
1478 const auto& rsconstTable = rsconstTables.getTable<RsconstTable>(0);
1480 const auto rsConst = rsconstTable.getRsColumn().front();
1481 const auto pBub = rsconstTable.getPbubColumn().front();
1483 const auto& units = eclipseState.getUnits();
1485 OpmLog::info(fmt::format(
"Using RSCONST keyword: Rs = {:.2} [{}], Pb = {:.2} [{}]",
1486 units.from_si(UnitSystem::measure::gas_oil_ratio, rsConst),
1487 units.name (UnitSystem::measure::gas_oil_ratio),
1488 units.from_si(UnitSystem::measure::pressure, pBub),
1489 units.name (UnitSystem::measure::pressure)));
1491 for (std::size_t i = 0; i < rec.size(); ++i) {
1497 for (std::size_t i = 0; i < rec.size(); ++i) {
1503 rvFunc_.reserve(rec.size());
1504 if (FluidSystem::enableVaporizedOil()) {
1505 for (std::size_t i = 0; i < rec.size(); ++i) {
1506 if (eqlmap.cells(i).empty()) {
1510 const int pvtIdx = regionPvtIdx_[i];
1511 if (!rec[i].wetGasInitConstantRv()) {
1512 const TableContainer& rvvdTables = tables.getRvvdTables();
1513 const TableContainer& pdvdTables = tables.getPdvdTables();
1515 if (rvvdTables.size() > 0) {
1516 const RvvdTable& rvvdTable = rvvdTables.getTable<RvvdTable>(i);
1517 auto depthColumn = getArray(rvvdTable.getColumn(
"DEPTH").vectorCopy());
1518 auto rvColumn = getArray(rvvdTable.getColumn(
"RV").vectorCopy());
1520 depthColumn, rvColumn));
1521 }
else if (pdvdTables.size() > 0) {
1522 const PdvdTable& pdvdTable = pdvdTables.getTable<PdvdTable>(i);
1523 auto depthColumn = getArray(pdvdTable.getColumn(
"DEPTH").vectorCopy());
1524 auto pdewColumn = getArray(pdvdTable.getColumn(
"PDEW").vectorCopy());
1526 depthColumn, pdewColumn));
1528 throw std::runtime_error(
"Cannot initialise: RVVD or PDCD table not available.");
1532 if (rec[i].gasOilContactDepth() != rec[i].datumDepth()) {
1533 throw std::runtime_error(
1534 "Cannot initialise: when no explicit RVVD table is given, \n"
1535 "datum depth must be at the gas-oil-contact. "
1536 "In EQUIL region "+
std::to_string(i + 1)+
" (counting from 1), this does not hold.");
1538 const Scalar pContact = rec[i].datumDepthPressure() + rec[i].gasOilContactCapillaryPressure();
1539 const Scalar TContact = 273.15 + 20;
1545 for (std::size_t i = 0; i < rec.size(); ++i) {
1550 rvwFunc_.reserve(rec.size());
1551 if (FluidSystem::enableVaporizedWater()) {
1552 for (std::size_t i = 0; i < rec.size(); ++i) {
1553 if (eqlmap.cells(i).empty()) {
1557 const int pvtIdx = regionPvtIdx_[i];
1558 if (!rec[i].humidGasInitConstantRvw()) {
1559 const TableContainer& rvwvdTables = tables.getRvwvdTables();
1561 if (rvwvdTables.size() > 0) {
1562 const RvwvdTable& rvwvdTable = rvwvdTables.getTable<RvwvdTable>(i);
1563 auto depthColumn = getArray(rvwvdTable.getColumn(
"DEPTH").vectorCopy());
1564 auto rvwvdColumn = getArray(rvwvdTable.getColumn(
"RVWVD").vectorCopy());
1566 depthColumn, rvwvdColumn));
1568 throw std::runtime_error(
"Cannot initialise: RVWVD table not available.");
1572 const auto oilActive = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
1574 if (rec[i].gasOilContactDepth() != rec[i].datumDepth()) {
1576 const auto msg =
"No explicit RVWVD table is given for EQUIL region " +
std::to_string(i + 1) +
". \n"
1577 "and datum depth is not at the gas-oil-contact. \n"
1578 "Rvw is set to 0.0 in all cells. \n";
1579 OpmLog::warning(msg);
1583 const Scalar pContact = rec[i].datumDepthPressure() + rec[i].gasOilContactCapillaryPressure();
1584 const Scalar TContact = 273.15 + 20;
1591 if (rec[i].waterOilContactDepth() != rec[i].datumDepth()) {
1593 const auto msg =
"No explicit RVWVD table is given for EQUIL region " +
std::to_string(i + 1) +
". \n"
1594 "and datum depth is not at the gas-water-contact. \n"
1595 "Rvw is set to 0.0 in all cells. \n";
1596 OpmLog::warning(msg);
1599 const Scalar pContact = rec[i].datumDepthPressure() + rec[i].waterOilContactCapillaryPressure();
1600 const Scalar TContact = 273.15 + 20;
1608 for (std::size_t i = 0; i < rec.size(); ++i) {
1614 updateInitialTemperature_(eclipseState, eqlmap);
1617 updateInitialSaltConcentration_(eclipseState, eqlmap);
1620 updateInitialSaltSaturation_(eclipseState, eqlmap);
1623 const auto& comm = grid.comm();
1624 calcPressSatRsRv(eqlmap, rec, materialLawManager, gridView, comm, grav);
1627 applyNumericalAquifers_(gridView, num_aquifers,
1628 eclipseState.runspec().co2Storage() ||
1629 eclipseState.runspec().h2Storage());
1635template<
class FluidSystem,
1638 class ElementMapper,
1639 class CartesianIndexMapper>
1645 CartesianIndexMapper>::
1646updateInitialTemperature_(
const EclipseState& eclState,
const RMap& reg)
1648 const int numEquilReg = rsFunc_.size();
1649 tempVdTable_.resize(numEquilReg);
1650 const auto& tables = eclState.getTableManager();
1651 if (!tables.hasTables(
"RTEMPVD")) {
1652 std::vector<Scalar> x = {0.0,1.0};
1653 std::vector<Scalar> y = {
static_cast<Scalar
>(tables.rtemp()),
1654 static_cast<Scalar
>(tables.rtemp())};
1655 for (
auto& table : this->tempVdTable_) {
1656 table.setXYContainers(x, y);
1659 const TableContainer& tempvdTables = tables.getRtempvdTables();
1660 for (std::size_t i = 0; i < tempvdTables.size(); ++i) {
1661 const RtempvdTable& tempvdTable = tempvdTables.getTable<RtempvdTable>(i);
1662 tempVdTable_[i].setXYContainers(tempvdTable.getDepthColumn(), tempvdTable.getTemperatureColumn());
1663 const auto& cells = reg.cells(i);
1664 for (
const auto& cell : cells) {
1665 const Scalar depth = cellCenterDepth_[cell];
1666 this->temperature_[cell] = tempVdTable_[i].eval(depth,
true);
1672template<
class FluidSystem,
1675 class ElementMapper,
1676 class CartesianIndexMapper>
1678void InitialStateComputer<FluidSystem,
1682 CartesianIndexMapper>::
1683updateInitialSaltConcentration_(
const EclipseState& eclState,
const RMap& reg)
1685 const int numEquilReg = rsFunc_.size();
1686 saltVdTable_.resize(numEquilReg);
1687 const auto& tables = eclState.getTableManager();
1688 const TableContainer& saltvdTables = tables.getSaltvdTables();
1691 if (saltvdTables.empty()) {
1692 std::vector<Scalar> x = {0.0,1.0};
1693 std::vector<Scalar> y = {0.0,0.0};
1694 for (
auto& table : this->saltVdTable_) {
1695 table.setXYContainers(x, y);
1698 for (std::size_t i = 0; i < saltvdTables.size(); ++i) {
1699 const SaltvdTable& saltvdTable = saltvdTables.getTable<SaltvdTable>(i);
1700 saltVdTable_[i].setXYContainers(saltvdTable.getDepthColumn(), saltvdTable.getSaltColumn());
1702 const auto& cells = reg.cells(i);
1703 for (
const auto& cell : cells) {
1704 const Scalar depth = cellCenterDepth_[cell];
1705 this->saltConcentration_[cell] = saltVdTable_[i].eval(depth,
true);
1711template<
class FluidSystem,
1714 class ElementMapper,
1715 class CartesianIndexMapper>
1717void InitialStateComputer<FluidSystem,
1721 CartesianIndexMapper>::
1722updateInitialSaltSaturation_(
const EclipseState& eclState,
const RMap& reg)
1724 const int numEquilReg = rsFunc_.size();
1725 saltpVdTable_.resize(numEquilReg);
1726 const auto& tables = eclState.getTableManager();
1727 const TableContainer& saltpvdTables = tables.getSaltpvdTables();
1729 for (std::size_t i = 0; i < saltpvdTables.size(); ++i) {
1730 const SaltpvdTable& saltpvdTable = saltpvdTables.getTable<SaltpvdTable>(i);
1731 saltpVdTable_[i].setXYContainers(saltpvdTable.getDepthColumn(), saltpvdTable.getSaltpColumn());
1733 const auto& cells = reg.cells(i);
1734 for (
const auto& cell : cells) {
1735 const Scalar depth = cellCenterDepth_[cell];
1736 this->saltSaturation_[cell] = saltpVdTable_[i].eval(depth,
true);
1741template<
class FluidSystem,
1744 class ElementMapper,
1745 class CartesianIndexMapper>
1746void InitialStateComputer<FluidSystem,
1750 CartesianIndexMapper>::
1751updateCellProps_(
const GridView& gridView,
1752 const NumericalAquifers& aquifer,
1753 const std::vector<Scalar>* editedCellDepths)
1755 depthEdited_ = (editedCellDepths !=
nullptr);
1756 ElementMapper elemMapper(gridView, Dune::mcmgElementLayout());
1757 int numElements = gridView.size(0);
1758 cellCenterDepth_.resize(numElements);
1759 cellCenterXY_.resize(numElements);
1760 cellCorners_.resize(numElements);
1761 cellZSpan_.resize(numElements);
1762 cellZMinMax_.resize(numElements);
1764 auto elemIt = gridView.template begin<0>();
1765 const auto& elemEndIt = gridView.template end<0>();
1766 const auto num_aqu_cells = aquifer.allAquiferCells();
1767 for (; elemIt != elemEndIt; ++elemIt) {
1768 const Element& element = *elemIt;
1769 const unsigned int elemIdx = elemMapper.index(element);
1770 cellCenterDepth_[elemIdx] = Details::cellCenterDepth<Scalar>(element);
1771 cellCenterXY_[elemIdx] = Details::cellCenterXY<Scalar>(element);
1772 cellCorners_[elemIdx] = Details::getCellCornerXY<Scalar>(element);
1773 const auto cartIx = cartesianIndexMapper_.cartesianIndex(elemIdx);
1774 cellZSpan_[elemIdx] = Details::cellZSpan<Scalar>(element);
1775 cellZMinMax_[elemIdx] = Details::cellZMinMax<Scalar>(element);
1776 if (editedCellDepths) {
1779 const Scalar shift = (*editedCellDepths)[elemIdx] - cellCenterDepth_[elemIdx];
1780 cellCenterDepth_[elemIdx] += shift;
1781 cellZSpan_[elemIdx].first += shift;
1782 cellZSpan_[elemIdx].second += shift;
1783 cellZMinMax_[elemIdx].first += shift;
1784 cellZMinMax_[elemIdx].second += shift;
1786 if (!num_aqu_cells.empty()) {
1787 const auto search = num_aqu_cells.find(cartIx);
1788 if (search != num_aqu_cells.end()) {
1789 const auto* aqu_cell = num_aqu_cells.at(cartIx);
1790 const Scalar depth_change_num_aqu = aqu_cell->depth - cellCenterDepth_[elemIdx];
1791 cellCenterDepth_[elemIdx] += depth_change_num_aqu;
1792 cellZSpan_[elemIdx].first += depth_change_num_aqu;
1793 cellZSpan_[elemIdx].second += depth_change_num_aqu;
1794 cellZMinMax_[elemIdx].first += depth_change_num_aqu;
1795 cellZMinMax_[elemIdx].second += depth_change_num_aqu;
1801template<
class FluidSystem,
1804 class ElementMapper,
1805 class CartesianIndexMapper>
1806void InitialStateComputer<FluidSystem,
1810 CartesianIndexMapper>::
1811applyNumericalAquifers_(
const GridView& gridView,
1812 const NumericalAquifers& aquifer,
1813 const bool co2store_or_h2store)
1815 const auto num_aqu_cells = aquifer.allAquiferCells();
1816 if (num_aqu_cells.empty())
return;
1819 bool oil_as_brine = co2store_or_h2store && FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
1820 const auto watPos = oil_as_brine? FluidSystem::oilPhaseIdx : FluidSystem::waterPhaseIdx;
1821 if (!FluidSystem::phaseIsActive(watPos)){
1822 throw std::logic_error {
"Water phase has to be active for numerical aquifer case" };
1825 ElementMapper elemMapper(gridView, Dune::mcmgElementLayout());
1826 auto elemIt = gridView.template begin<0>();
1827 const auto& elemEndIt = gridView.template end<0>();
1828 const auto oilPos = FluidSystem::oilPhaseIdx;
1829 const auto gasPos = FluidSystem::gasPhaseIdx;
1830 for (; elemIt != elemEndIt; ++elemIt) {
1831 const Element& element = *elemIt;
1832 const unsigned int elemIdx = elemMapper.index(element);
1833 const auto cartIx = cartesianIndexMapper_.cartesianIndex(elemIdx);
1834 const auto search = num_aqu_cells.find(cartIx);
1835 if (search != num_aqu_cells.end()) {
1837 this->sat_[watPos][elemIdx] = 1.;
1839 if (!co2store_or_h2store && FluidSystem::phaseIsActive(oilPos)) {
1840 this->sat_[oilPos][elemIdx] = 0.;
1843 if (FluidSystem::phaseIsActive(gasPos)) {
1844 this->sat_[gasPos][elemIdx] = 0.;
1846 const auto* aqu_cell = num_aqu_cells.at(cartIx);
1847 const auto msg = fmt::format(
"FOR AQUIFER CELL AT ({}, {}, {}) OF NUMERICAL "
1848 "AQUIFER {}, WATER SATURATION IS SET TO BE UNITY",
1849 aqu_cell->I+1, aqu_cell->J+1, aqu_cell->K+1, aqu_cell->aquifer_id);
1854 if (aqu_cell->init_pressure) {
1855 const Scalar pres = *(aqu_cell->init_pressure);
1856 this->pp_[watPos][elemIdx] = pres;
1857 if (FluidSystem::phaseIsActive(gasPos)) {
1858 this->pp_[gasPos][elemIdx] = pres;
1860 if (FluidSystem::phaseIsActive(oilPos)) {
1861 this->pp_[oilPos][elemIdx] = pres;
1868template<
class FluidSystem,
1871 class ElementMapper,
1872 class CartesianIndexMapper>
1874void InitialStateComputer<FluidSystem,
1878 CartesianIndexMapper>::
1879setRegionPvtIdx(
const EclipseState& eclState,
const GridView& gridView,
const RMap& reg)
1888 const LookUpData<typename GridView::Grid, GridView> lookUpData(gridView);
1889 const auto pvtnumData = lookUpData.template assignFieldPropsIntOnLeaf<int>(
1890 eclState.fieldProps(),
"PVTNUM",
true);
1892 for (
const auto& r : reg.activeRegions()) {
1893 const auto& cells = reg.cells(r);
1894 regionPvtIdx_[r] = pvtnumData[*cells.begin()];
1898template<
class FluidSystem,
1901 class ElementMapper,
1902 class CartesianIndexMapper>
1903template<
class RMap,
class MaterialLawManager,
class Comm>
1904void InitialStateComputer<FluidSystem,
1908 CartesianIndexMapper>::
1909calcPressSatRsRv(
const RMap& reg,
1910 const std::vector<EquilRecord>& rec,
1911 MaterialLawManager& materialLawManager,
1912 const GridView& gridView,
1916 using PhaseSat = Details::PhaseSaturations<
1917 MaterialLawManager, FluidSystem, EquilReg<Scalar>,
typename RMap::CellId
1920 auto ptable = Details::PressureTable<FluidSystem, EquilReg<Scalar>>{ grav, this->num_pressure_points_ };
1921 auto psat = PhaseSat { materialLawManager, this->swatInit_ };
1922 auto vspan = std::array<Scalar, 2>{};
1924 std::vector<int> regionIsEmpty(rec.size(), 0);
1925 for (std::size_t r = 0; r < rec.size(); ++r) {
1926 const auto& cells = reg.cells(r);
1930 const auto acc = rec[r].initializationTargetAccuracy();
1932 if (this->depthEdited_) {
1933 OpmLog::warning(
"DEPTH has been edited in the EDIT section, but equilibration "
1935 "accuracy (EQUIL item 9 > 0). The cells are shifted rigidly "
1936 "to the edited depths, but the block geometry used for the "
1937 "tilted cross-sections is not, so the result may be wrong. "
1938 "Use item 9 = 0 or < 0.");
1942 if (cells.empty()) {
1943 regionIsEmpty[r] = 1;
1946 const auto eqreg = EquilReg {
1947 rec[r], this->rsFunc_[r], this->rvFunc_[r], this->rvwFunc_[r],
1948 this->tempVdTable_[r], this->saltVdTable_[r], this->regionPvtIdx_[r]
1951 vspan[0] = std::min(vspan[0], std::min(eqreg.zgoc(), eqreg.zwoc()));
1952 vspan[1] = std::max(vspan[1], std::max(eqreg.zgoc(), eqreg.zwoc()));
1953 ptable.equilibrate(eqreg, vspan);
1956 this->equilibrateTiltedFaultBlock(cells, eqreg, gridView, acc, ptable, psat);
1958 else if (acc == 0) {
1959 if (cells.empty()) {
1960 regionIsEmpty[r] = 1;
1963 const auto eqreg = EquilReg {
1964 rec[r], this->rsFunc_[r], this->rvFunc_[r], this->rvwFunc_[r],
1965 this->tempVdTable_[r], this->saltVdTable_[r], this->regionPvtIdx_[r]
1967 vspan[0] = std::min(vspan[0], std::min(eqreg.zgoc(), eqreg.zwoc()));
1968 vspan[1] = std::max(vspan[1], std::max(eqreg.zgoc(), eqreg.zwoc()));
1969 ptable.equilibrate(eqreg, vspan);
1971 this->equilibrateCellCentres(cells, eqreg, ptable, psat);
1974 if (cells.empty()) {
1975 regionIsEmpty[r] = 1;
1978 const auto eqreg = EquilReg {
1979 rec[r], this->rsFunc_[r], this->rvFunc_[r], this->rvwFunc_[r],
1980 this->tempVdTable_[r], this->saltVdTable_[r], this->regionPvtIdx_[r]
1982 vspan[0] = std::min(vspan[0], std::min(eqreg.zgoc(), eqreg.zwoc()));
1983 vspan[1] = std::max(vspan[1], std::max(eqreg.zgoc(), eqreg.zwoc()));
1984 ptable.equilibrate(eqreg, vspan);
1986 this->equilibrateHorizontal(cells, eqreg, -acc, ptable, psat);
1989 comm.min(regionIsEmpty.data(),regionIsEmpty.size());
1990 if (comm.rank() == 0) {
1991 for (std::size_t r = 0; r < rec.size(); ++r) {
1992 if (regionIsEmpty[r])
1994 +
" has no active cells");
1999template<
class FluidSystem,
2002 class ElementMapper,
2003 class CartesianIndexMapper>
2004template<
class CellRange,
class EquilibrationMethod>
2005void InitialStateComputer<FluidSystem,
2009 CartesianIndexMapper>::
2010cellLoop(
const CellRange& cells,
2011 EquilibrationMethod&& eqmethod)
2013 const auto oilPos = FluidSystem::oilPhaseIdx;
2014 const auto gasPos = FluidSystem::gasPhaseIdx;
2015 const auto watPos = FluidSystem::waterPhaseIdx;
2017 const auto oilActive = FluidSystem::phaseIsActive(oilPos);
2018 const auto gasActive = FluidSystem::phaseIsActive(gasPos);
2019 const auto watActive = FluidSystem::phaseIsActive(watPos);
2021 auto pressures = Details::PhaseQuantityValue<Scalar>{};
2022 auto saturations = Details::PhaseQuantityValue<Scalar>{};
2027 for (
const auto& cell : cells) {
2028 eqmethod(cell, pressures, saturations, Rs, Rv, Rvw);
2031 this->pp_ [oilPos][cell] = pressures.oil;
2032 this->sat_[oilPos][cell] = saturations.oil;
2036 this->pp_ [gasPos][cell] = pressures.gas;
2037 this->sat_[gasPos][cell] = saturations.gas;
2041 this->pp_ [watPos][cell] = pressures.water;
2042 this->sat_[watPos][cell] = saturations.water;
2045 if (oilActive && gasActive) {
2046 this->rs_[cell] =
Rs;
2047 this->rv_[cell] =
Rv;
2050 if (watActive && gasActive) {
2051 this->rvw_[cell] =
Rvw;
2056template<
class FluidSystem,
2059 class ElementMapper,
2060 class CartesianIndexMapper>
2061template<
class CellRange,
class PressTable,
class PhaseSat>
2062void InitialStateComputer<FluidSystem,
2066 CartesianIndexMapper>::
2067equilibrateCellCentres(
const CellRange& cells,
2068 const EquilReg<Scalar>& eqreg,
2069 const PressTable& ptable,
2072 using CellPos =
typename PhaseSat::Position;
2073 using CellID = std::remove_cv_t<std::remove_reference_t<
2074 decltype(std::declval<CellPos>().cell)>>;
2075 this->cellLoop(cells, [
this, &eqreg, &ptable, &psat]
2077 Details::PhaseQuantityValue<Scalar>& pressures,
2078 Details::PhaseQuantityValue<Scalar>& saturations,
2081 Scalar& Rvw) ->
void
2083 const auto pos = CellPos {
2084 cell, cellCenterDepth_[cell]
2087 saturations = psat.deriveSaturations(pos, eqreg, ptable);
2088 pressures = psat.correctedPhasePressures();
2090 const auto temp = this->temperature_[cell];
2092 Rs = eqreg.dissolutionCalculator()
2093 (pos.depth, pressures.oil, temp, saturations.gas);
2095 Rv = eqreg.evaporationCalculator()
2096 (pos.depth, pressures.gas, temp, saturations.oil);
2098 Rvw = eqreg.waterEvaporationCalculator()
2099 (pos.depth, pressures.gas, temp, saturations.water);
2103template<
class FluidSystem,
2106 class ElementMapper,
2107 class CartesianIndexMapper>
2108template<
class CellRange,
class PressTable,
class PhaseSat>
2109void InitialStateComputer<FluidSystem,
2113 CartesianIndexMapper>::
2114equilibrateHorizontal(
const CellRange& cells,
2115 const EquilReg<Scalar>& eqreg,
2117 const PressTable& ptable,
2120 using CellPos =
typename PhaseSat::Position;
2121 using CellID = std::remove_cv_t<std::remove_reference_t<
2122 decltype(std::declval<CellPos>().cell)>>;
2124 this->cellLoop(cells, [
this, acc, &eqreg, &ptable, &psat]
2126 Details::PhaseQuantityValue<Scalar>& pressures,
2127 Details::PhaseQuantityValue<Scalar>& saturations,
2130 Scalar& Rvw) ->
void
2133 saturations.reset();
2135 Scalar totfrac = 0.0;
2137 const auto pos = CellPos { cell, depth };
2139 saturations.axpy(psat.deriveSaturations(pos, eqreg, ptable), frac);
2140 pressures .axpy(psat.correctedPhasePressures(), frac);
2146 saturations /= totfrac;
2147 pressures /= totfrac;
2150 const auto pos = CellPos {
2151 cell, cellCenterDepth_[cell]
2154 saturations = psat.deriveSaturations(pos, eqreg, ptable);
2155 pressures = psat.correctedPhasePressures();
2158 const auto temp = this->temperature_[cell];
2159 const auto cz = cellCenterDepth_[cell];
2161 Rs = eqreg.dissolutionCalculator()
2162 (cz, pressures.oil, temp, saturations.gas);
2164 Rv = eqreg.evaporationCalculator()
2165 (cz, pressures.gas, temp, saturations.oil);
2167 Rvw = eqreg.waterEvaporationCalculator()
2168 (cz, pressures.gas, temp, saturations.water);
2172template<
class Flu
idSystem,
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper>
2173template<
class CellRange,
class PressTable,
class PhaseSat>
2174void InitialStateComputer<FluidSystem, Grid, GridView, ElementMapper, CartesianIndexMapper>::
2175equilibrateTiltedFaultBlockSimple(
const CellRange& cells,
2176 const EquilReg<Scalar>& eqreg,
2177 const GridView& gridView,
2179 const PressTable& ptable,
2182 using CellPos =
typename PhaseSat::Position;
2183 using CellID = std::remove_cv_t<std::remove_reference_t<
2184 decltype(std::declval<CellPos>().cell)>>;
2186 this->cellLoop(cells, [
this, acc, &eqreg, &ptable, &psat, &gridView]
2188 Details::PhaseQuantityValue<Scalar>& pressures,
2189 Details::PhaseQuantityValue<Scalar>& saturations,
2192 Scalar& Rvw) ->
void
2195 saturations.reset();
2196 Scalar totalWeight = 0.0;
2199 const auto& [zmin, zmax] = cellZMinMax_[cell];
2200 const Scalar cellThickness = zmax - zmin;
2201 const Scalar halfThickness = cellThickness / 2.0;
2204 Scalar dipAngle, dipAzimuth;
2208 std::array<Scalar, 3> referencePoint = {
2209 cellCenterXY_[cell].first,
2210 cellCenterXY_[cell].second,
2211 cellCenterDepth_[cell]
2215 const int numLevelsPerHalf = std::min(20, acc);
2218 std::vector<std::pair<Scalar, Scalar>> levels;
2221 for (
int side = 0; side < 2; ++side) {
2222 Scalar halfStart = (side == 0) ? zmin : zmin + halfThickness;
2224 for (
int i = 0; i < numLevelsPerHalf; ++i) {
2226 Scalar depth = halfStart + (i + 0.5) * (halfThickness / numLevelsPerHalf);
2230 Scalar crossSectionWeight = (halfThickness / numLevelsPerHalf);
2233 if (std::abs(dipAngle) > 1e-10) {
2234 crossSectionWeight /= std::cos(dipAngle);
2237 levels.emplace_back(depth, crossSectionWeight);
2241 for (
const auto& [depth, weight] : levels) {
2243 const auto& [x, y] = cellCenterXY_[cell];
2245 depth, x, y, dipAngle, dipAzimuth, referencePoint);
2247 const auto pos = CellPos{cell, tvd};
2249 auto localSaturations = psat.deriveSaturations(pos, eqreg, ptable);
2250 auto localPressures = psat.correctedPhasePressures();
2253 saturations.axpy(localSaturations, weight);
2254 pressures.axpy(localPressures, weight);
2255 totalWeight += weight;
2259 if (totalWeight > 1e-10) {
2260 saturations /= totalWeight;
2261 pressures /= totalWeight;
2264 const auto& [x, y] = cellCenterXY_[cell];
2266 cellCenterDepth_[cell], x, y, dipAngle, dipAzimuth, referencePoint);
2267 const auto pos = CellPos{cell, tvdCenter};
2268 saturations = psat.deriveSaturations(pos, eqreg, ptable);
2269 pressures = psat.correctedPhasePressures();
2273 const auto temp = this->temperature_[cell];
2274 const auto& [x, y] = cellCenterXY_[cell];
2276 cellCenterDepth_[cell], x, y, dipAngle, dipAzimuth, referencePoint);
2278 Rs = eqreg.dissolutionCalculator()(tvdCenter, pressures.oil, temp, saturations.gas);
2279 Rv = eqreg.evaporationCalculator()(tvdCenter, pressures.gas, temp, saturations.oil);
2280 Rvw = eqreg.waterEvaporationCalculator()(tvdCenter, pressures.gas, temp, saturations.water);
2284template<
class Flu
idSystem,
class Gr
id,
class Gr
idView,
class ElementMapper,
class CartesianIndexMapper>
2285template<
class CellRange,
class PressTable,
class PhaseSat>
2286void InitialStateComputer<FluidSystem, Grid, GridView, ElementMapper, CartesianIndexMapper>::
2287equilibrateTiltedFaultBlock(
const CellRange& cells,
2288 const EquilReg<Scalar>& eqreg,
2289 const GridView& gridView,
2291 const PressTable& ptable,
2294 using CellPos =
typename PhaseSat::Position;
2295 using CellID = std::remove_cv_t<std::remove_reference_t<
2296 decltype(std::declval<CellPos>().cell)>>;
2298 std::vector<typename GridView::template Codim<0>::Entity> entityMap(gridView.size(0));
2299 for (
const auto& entity : entities(gridView, Dune::Codim<0>())) {
2300 CellID idx = gridView.indexSet().index(entity);
2301 entityMap[idx] = entity;
2305 auto polygonArea = [](
const std::vector<std::array<Scalar, 2>>& pts) {
2306 if (pts.size() < 3)
return Scalar(0);
2308 for (
size_t i = 0; i < pts.size(); ++i) {
2309 size_t j = (i + 1) % pts.size();
2310 area += pts[i][0] * pts[j][1] - pts[j][0] * pts[i][1];
2312 return std::abs(area) * Scalar(0.5);
2316 auto computeCrossSectionArea = [&](
const CellID cell, Scalar depth) -> Scalar {
2318 const auto& entity = entityMap[cell];
2319 const auto& geometry = entity.geometry();
2320 const int numCorners = geometry.corners();
2322 std::vector<std::array<Scalar, 3>> corners(numCorners);
2323 for (
int i = 0; i < numCorners; ++i) {
2324 const auto& corner = geometry.corner(i);
2325 corners[i] = {
static_cast<Scalar
>(corner[0]),
static_cast<Scalar
>(corner[1]),
static_cast<Scalar
>(corner[2])};
2329 std::vector<std::array<Scalar, 2>> intersectionPoints;
2330 const Scalar tol = 1e-10;
2333 for (
size_t i = 0; i < corners.size(); ++i) {
2334 for (
size_t j = i + 1; j < corners.size(); ++j) {
2335 Scalar za = corners[i][2];
2336 Scalar zb = corners[j][2];
2338 if ((za - depth) * (zb - depth) <= 0.0 && std::abs(za - zb) > tol) {
2340 Scalar t = (depth - za) / (zb - za);
2341 Scalar x = corners[i][0] + t * (corners[j][0] - corners[i][0]);
2342 Scalar y = corners[i][1] + t * (corners[j][1] - corners[i][1]);
2343 intersectionPoints.push_back({x, y});
2349 if (intersectionPoints.size() > 1) {
2350 auto pointsEqual = [tol](
const std::array<Scalar, 2>& a,
const std::array<Scalar, 2>& b) {
2351 return std::abs(a[0] - b[0]) < tol && std::abs(a[1] - b[1]) < tol;
2354 intersectionPoints.erase(
2355 std::unique(intersectionPoints.begin(), intersectionPoints.end(), pointsEqual),
2356 intersectionPoints.end()
2360 if (intersectionPoints.size() < 3) {
2366 Scalar cx = 0, cy = 0;
2367 for (
const auto& p : intersectionPoints) {
2368 cx += p[0]; cy += p[1];
2370 cx /= intersectionPoints.size();
2371 cy /= intersectionPoints.size();
2374 auto angleCompare = [cx, cy](
const std::array<Scalar, 2>& a,
const std::array<Scalar, 2>& b) {
2375 return std::atan2(a[1] - cy, a[0] - cx) < std::atan2(b[1] - cy, b[0] - cx);
2378 std::ranges::sort(intersectionPoints, angleCompare);
2380 return polygonArea(intersectionPoints);
2382 }
catch (
const std::exception& e) {
2387 auto cellProcessor = [
this, acc, &eqreg, &ptable, &psat, &computeCrossSectionArea]
2389 Details::PhaseQuantityValue<Scalar>& pressures,
2390 Details::PhaseQuantityValue<Scalar>& saturations,
2393 Scalar&
Rvw) ->
void
2396 saturations.reset();
2397 Scalar totalWeight = 0.0;
2399 const auto& zmin = this->cellZMinMax_[cell].first;
2400 const auto& zmax = this->cellZMinMax_[cell].second;
2401 const Scalar cellThickness = zmax - zmin;
2402 const Scalar halfThickness = cellThickness / 2.0;
2405 Scalar dipAngle, dipAzimuth;
2409 std::array<Scalar, 3> referencePoint = {
2410 this->cellCenterXY_[cell].first,
2411 this->cellCenterXY_[cell].second,
2412 cellCenterDepth_[cell]
2416 const int numLevelsPerHalf = std::min(20, acc);
2419 std::vector<std::pair<Scalar, Scalar>> levels;
2422 for (
int side = 0; side < 2; ++side) {
2423 Scalar halfStart = (side == 0) ? zmin : zmin + halfThickness;
2425 for (
int i = 0; i < numLevelsPerHalf; ++i) {
2427 Scalar depth = halfStart + (i + 0.5) * (halfThickness / numLevelsPerHalf);
2430 Scalar crossSectionArea = computeCrossSectionArea(cell, depth);
2433 Scalar weight = crossSectionArea * (halfThickness / numLevelsPerHalf);
2435 levels.emplace_back(depth, weight);
2440 bool hasValidAreas =
false;
2441 for (
const auto& level : levels) {
2442 if (level.second > 1e-10) {
2443 hasValidAreas =
true;
2448 if (!hasValidAreas) {
2451 for (
int side = 0; side < 2; ++side) {
2452 Scalar halfStart = (side == 0) ? zmin : zmin + halfThickness;
2453 for (
int i = 0; i < numLevelsPerHalf; ++i) {
2454 Scalar depth = halfStart + (i + 0.5) * (halfThickness / numLevelsPerHalf);
2455 Scalar weight = (halfThickness / numLevelsPerHalf);
2456 if (std::abs(dipAngle) > 1e-10) {
2457 weight /= std::cos(dipAngle);
2459 levels.emplace_back(depth, weight);
2464 for (
const auto& level : levels) {
2465 Scalar depth = level.first;
2466 Scalar weight = level.second;
2469 const auto& xy = this->cellCenterXY_[cell];
2471 depth, xy.first, xy.second, dipAngle, dipAzimuth, referencePoint);
2473 const auto pos = CellPos{cell, tvd};
2475 auto localSaturations = psat.deriveSaturations(pos, eqreg, ptable);
2476 auto localPressures = psat.correctedPhasePressures();
2479 saturations.axpy(localSaturations, weight);
2480 pressures.axpy(localPressures, weight);
2481 totalWeight += weight;
2484 if (totalWeight > 1e-10) {
2485 saturations /= totalWeight;
2486 pressures /= totalWeight;
2489 const auto& xy = this->cellCenterXY_[cell];
2491 this->cellCenterDepth_[cell], xy.first, xy.second, dipAngle, dipAzimuth, referencePoint);
2492 const auto pos = CellPos{cell, tvdCenter};
2493 saturations = psat.deriveSaturations(pos, eqreg, ptable);
2494 pressures = psat.correctedPhasePressures();
2498 const auto temp = this->temperature_[cell];
2499 const auto& xy = this->cellCenterXY_[cell];
2501 this->cellCenterDepth_[cell], xy.first, xy.second, dipAngle, dipAzimuth, referencePoint);
2503 Rs = eqreg.dissolutionCalculator()(tvdCenter, pressures.oil, temp, saturations.gas);
2504 Rv = eqreg.evaporationCalculator()(tvdCenter, pressures.gas, temp, saturations.oil);
2505 Rvw = eqreg.waterEvaporationCalculator()(tvdCenter, pressures.gas, temp, saturations.water);
2508 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:404
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:52
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