74class BlackOilIntensiveQuantities
75 :
public GetPropType<TypeTag, Properties::DiscIntensiveQuantities>
76 ,
public GetPropType<TypeTag, Properties::FluxModule>::FluxIntensiveQuantities
113 enum { enableMICP = Indices::enableMICP };
115 enum { waterCompIdx = FluidSystem::waterCompIdx };
116 enum { oilCompIdx = FluidSystem::oilCompIdx };
117 enum { gasCompIdx = FluidSystem::gasCompIdx };
118 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
119 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
120 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
121 enum { compositionSwitchIdx = Indices::compositionSwitchIdx };
123 static constexpr bool compositionSwitchEnabled = Indices::compositionSwitchIdx >= 0;
124 static constexpr bool waterEnabled = Indices::waterEnabled;
125 static constexpr bool gasEnabled = Indices::gasEnabled;
126 static constexpr bool oilEnabled = Indices::oilEnabled;
128 using Toolbox = MathToolbox<Evaluation>;
129 using FluxIntensiveQuantities =
typename FluxModule::FluxIntensiveQuantities;
133 using DirectionalMobilityPtr = Utility::CopyablePtr<DirectionalMobility<TypeTag>>;
140 using FluidState = BlackOilFluidState<Evaluation,
142 energyModuleType != EnergyModules::NoTemperature,
143 energyModuleType == EnergyModules::FullyImplicitThermal,
144 compositionSwitchEnabled,
147 enableSaltPrecipitation,
151 using ScalarFluidState = BlackOilFluidState<Scalar,
153 energyModuleType != EnergyModules::NoTemperature,
154 energyModuleType == EnergyModules::FullyImplicitThermal,
155 compositionSwitchEnabled,
158 enableSaltPrecipitation,
164 OPM_HOST_DEVICE BlackOilIntensiveQuantities()
166 if constexpr (compositionSwitchEnabled) {
167 fluidState_.setRs(0.0);
168 fluidState_.setRv(0.0);
170 if constexpr (enableVapwat) {
171 fluidState_.setRvw(0.0);
173 if constexpr (enableDisgasInWater) {
174 fluidState_.setRsw(0.0);
177 BlackOilIntensiveQuantities(
const BlackOilIntensiveQuantities& other) =
default;
179 BlackOilIntensiveQuantities& operator=(
const BlackOilIntensiveQuantities& other) =
default;
181 template<
class OtherTypeTag>
182 friend class BlackOilIntensiveQuantities;
185 template<
class OtherTypeTag>
186 explicit BlackOilIntensiveQuantities(
187 const BlackOilIntensiveQuantities<OtherTypeTag>& other,
const FluidSystem& fsystem)
188 : fluidState_(other.fluidState_.withOtherFluidSystem(fsystem))
190 other.rockInternalEnergy_, other.totalThermalConductivity_, other.rockFraction_)
192 other.tortuosities(), other.diffusionCoefficients())
193 , referencePorosity_(other.referencePorosity_)
194 , porosity_(other.porosity_)
195 , rockCompTransMultiplier_(other.rockCompTransMultiplier_)
196 , mobility_(other.mobility_)
199 static_assert(!enableSolvent);
200 static_assert(!enableExtbo);
201 static_assert(!enablePolymer);
202 static_assert(!enableFoam);
203 static_assert(!enableMICP);
204 static_assert(!enableBrine);
205 static_assert(!enableDispersion);
216 template <
class OtherTypeTag>
219 BlackOilIntensiveQuantities<OtherTypeTag> newIntQuants(*
this, other);
223 OPM_HOST_DEVICE
void updateTempSalt(
const Problem& problem,
224 const PrimaryVariables& priVars,
225 const unsigned globalSpaceIdx,
226 const unsigned timeIdx,
229 asImp_().updateTemperature_(problem, priVars, globalSpaceIdx, timeIdx, lintype);
230 if constexpr (enableBrine) {
231 asImp_().updateSaltConcentration_(priVars, timeIdx, lintype);
235 OPM_HOST_DEVICE
void updateSaturations(
const PrimaryVariables& priVars,
236 const unsigned timeIdx,
241 if constexpr (waterEnabled) {
242 if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Sw) {
243 assert(Indices::waterSwitchIdx >= 0);
244 if constexpr (Indices::waterSwitchIdx >= 0) {
245 Sw = priVars.makeEvaluation(Indices::waterSwitchIdx, timeIdx);
248 else if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Rsw ||
249 priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Disabled)
257 if constexpr (gasEnabled) {
258 if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Sg) {
259 assert(Indices::compositionSwitchIdx >= 0);
260 if constexpr (compositionSwitchEnabled) {
261 Sg = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx);
264 else if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rv) {
267 else if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Disabled) {
268 if constexpr (waterEnabled) {
276 Valgrind::CheckDefined(Sg);
277 Valgrind::CheckDefined(Sw);
279 Evaluation So = 1.0 - Sw - Sg;
282 if constexpr (enableSolvent) {
283 if (priVars.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
285 So -= priVars.makeEvaluation(Indices::solventSaturationIdx, timeIdx);
288 Sg -= priVars.makeEvaluation(Indices::solventSaturationIdx, timeIdx);
294 fluidState_.setSaturation(waterPhaseIdx, Sw);
298 fluidState_.setSaturation(gasPhaseIdx, Sg);
302 fluidState_.setSaturation(oilPhaseIdx, So);
306 template <
class ...Args>
307 OPM_HOST_DEVICE
void updateRelpermAndPressures(
const Problem& problem,
308 const PrimaryVariables& priVars,
309 const unsigned globalSpaceIdx,
310 const unsigned timeIdx,
318 if constexpr (enableSolvent) {
319 asImp_().solventPreSatFuncUpdate_(priVars, timeIdx, lintype);
323 problem.template updateRelperms<FluidState, Args...>(mobility_, dirMob_, fluidState_, globalSpaceIdx);
326 using EvalArr = std::array<Evaluation, numPhases>;
328 const auto& materialParams = problem.materialLawParams(globalSpaceIdx);
329 MaterialLaw::template capillaryPressures<EvalArr, FluidState, Args...>(pC, materialParams, fluidState_);
332 if constexpr (enableBrine) {
333 if (BrineModule::hasPcfactTables() &&
334 priVars.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp)
336 const unsigned satnumRegionIdx = problem.satnumRegionIndex(globalSpaceIdx);
337 const Evaluation Sp = priVars.makeEvaluation(Indices::saltConcentrationIdx, timeIdx);
338 const Evaluation porosityFactor = min(1.0 - Sp, 1.0);
339 const auto& pcfactTable = BrineModule::pcfactTable(satnumRegionIdx);
340 const Evaluation pcFactor = pcfactTable.eval(porosityFactor,
true);
341 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
343 pC[phaseIdx] *= pcFactor;
348 else if constexpr (enableBioeffects) {
349 if (BioeffectsModule::hasPcfactTables() && referencePorosity_ > 0) {
350 unsigned satnumRegionIdx = problem.satnumRegionIndex(globalSpaceIdx);
351 const Evaluation Sb = priVars.makeEvaluation(Indices::biofilmVolumeFractionIdx, timeIdx);
352 const Evaluation porosityFactor = min(1.0 - Sb/referencePorosity_, 1.0);
353 const auto& pcfactTable = BioeffectsModule::pcfactTable(satnumRegionIdx);
354 const Evaluation pcFactor = pcfactTable.eval(porosityFactor,
true);
355 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
357 pC[phaseIdx] *= pcFactor;
364 if (priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Pg) {
365 const Evaluation& pg = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx);
366 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
368 fluidState_.setPressure(phaseIdx, pg + (pC[phaseIdx] - pC[gasPhaseIdx]));
372 else if (priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Pw) {
373 const Evaluation& pw = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx);
374 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
376 fluidState_.setPressure(phaseIdx, pw + (pC[phaseIdx] - pC[waterPhaseIdx]));
382 const Evaluation& po = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx);
383 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
385 fluidState_.setPressure(phaseIdx, po + (pC[phaseIdx] - pC[oilPhaseIdx]));
394 if constexpr (enableSolvent) {
395 asImp_().solventPostSatFuncUpdate_(problem, priVars, globalSpaceIdx, timeIdx, lintype);
399 OPM_HOST_DEVICE
void updateRsRvRsw(
const Problem& problem,
400 const PrimaryVariables& priVars,
401 const unsigned globalSpaceIdx,
402 const unsigned timeIdx)
404 const unsigned pvtRegionIdx = priVars.pvtRegionIndex();
407 ? problem.maxOilVaporizationFactor(timeIdx, globalSpaceIdx)
410 ? problem.maxGasDissolutionFactor(timeIdx, globalSpaceIdx)
412 const Scalar RswMax =
getFluidSystem().enableDissolvedGasInWater()
413 ? problem.maxGasDissolutionFactor(timeIdx, globalSpaceIdx)
416 Evaluation SoMax = 0.0;
418 SoMax = max(fluidState_.saturation(oilPhaseIdx),
419 problem.maxOilSaturation(globalSpaceIdx));
425 if constexpr (compositionSwitchEnabled) {
426 if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rs) {
427 const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx);
428 fluidState_.setRs(Rs);
432 const Evaluation& RsSat = enableExtbo ? asImp_().rs() :
437 fluidState_.setRs(min(RsMax, RsSat));
440 fluidState_.setRs(0.0);
444 if (priVars.primaryVarsMeaningGas() == PrimaryVariables::GasMeaning::Rv) {
445 const auto& Rv = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx);
446 fluidState_.setRv(Rv);
450 const Evaluation& RvSat = enableExtbo ? asImp_().rv() :
455 fluidState_.setRv(min(RvMax, RvSat));
458 fluidState_.setRv(0.0);
463 if constexpr (enableVapwat) {
464 if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Rvw) {
465 const auto& Rvw = priVars.makeEvaluation(Indices::waterSwitchIdx, timeIdx);
466 fluidState_.setRvw(Rvw);
470 const Evaluation& RvwSat =
getFluidSystem().saturatedVaporizationFactor(fluidState_,
473 fluidState_.setRvw(RvwSat);
478 if constexpr (enableDisgasInWater) {
479 if (priVars.primaryVarsMeaningWater() == PrimaryVariables::WaterMeaning::Rsw) {
480 const auto& Rsw = priVars.makeEvaluation(Indices::waterSwitchIdx, timeIdx);
481 fluidState_.setRsw(Rsw);
485 const Evaluation& RswSat =
getFluidSystem().saturatedDissolutionFactor(fluidState_,
488 fluidState_.setRsw(min(RswMax, RswSat));
494 OPM_HOST_DEVICE
void updateMobilityAndInvB()
496 OPM_TIMEBLOCK_LOCAL(updateMobilityAndInvB, Subsystem::PvtProps);
497 const unsigned pvtRegionIdx = fluidState_.pvtRegionIndex();
501 constexpr int max_nmobilities = 4;
502 std::array<std::array<Evaluation, numPhases>*, max_nmobilities> mobilities = { &mobility_};
504 for (
int i = 0; i < 3; ++i) {
505 mobilities[nmobilities] = &(dirMob_->getArray(i));
509 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
513 const auto [b, mu] =
getFluidSystem().inverseFormationVolumeFactorAndViscosity(fluidState_, phaseIdx, pvtRegionIdx);
514 fluidState_.setInvB(phaseIdx, b);
515 for (
int i = 0; i < nmobilities; ++i) {
516 if (enableExtbo && phaseIdx == oilPhaseIdx) {
517 (*mobilities[i])[phaseIdx] /= asImp_().oilViscosity();
519 else if (enableExtbo && phaseIdx == gasPhaseIdx) {
520 (*mobilities[i])[phaseIdx] /= asImp_().gasViscosity();
523 (*mobilities[i])[phaseIdx] /= mu;
527 Valgrind::CheckDefined(mobility_);
530 OPM_HOST_DEVICE
void updatePhaseDensities()
532 const unsigned pvtRegionIdx = fluidState_.pvtRegionIndex();
537 rho = fluidState_.invB(waterPhaseIdx);
538 rho *=
getFluidSystem().referenceDensity(waterPhaseIdx, pvtRegionIdx);
540 rho += fluidState_.invB(waterPhaseIdx) *
544 fluidState_.setDensity(waterPhaseIdx, rho);
548 rho = fluidState_.invB(gasPhaseIdx);
549 rho *=
getFluidSystem().referenceDensity(gasPhaseIdx, pvtRegionIdx);
551 rho += fluidState_.invB(gasPhaseIdx) *
556 rho += fluidState_.invB(gasPhaseIdx) *
560 fluidState_.setDensity(gasPhaseIdx, rho);
564 rho = fluidState_.invB(oilPhaseIdx);
565 rho *=
getFluidSystem().referenceDensity(oilPhaseIdx, pvtRegionIdx);
567 rho += fluidState_.invB(oilPhaseIdx) *
571 fluidState_.setDensity(oilPhaseIdx, rho);
575 OPM_HOST_DEVICE
void updatePorosity(
const ElementContext& elemCtx,
unsigned dofIdx,
unsigned timeIdx)
577 const auto& problem = elemCtx.problem();
578 const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
579 const unsigned globalSpaceIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
581 referencePorosity_ = problem.porosity(elemCtx, dofIdx, timeIdx);
583 this->updatePorosityImpl(problem, priVars, globalSpaceIdx, timeIdx);
586 OPM_HOST_DEVICE
void updatePorosity(
const Problem& problem,
587 const PrimaryVariables& priVars,
588 const unsigned globalSpaceIdx,
589 const unsigned timeIdx)
592 referencePorosity_ = problem.porosity(globalSpaceIdx, timeIdx);
594 this->updatePorosityImpl(problem, priVars, globalSpaceIdx, timeIdx);
597 OPM_HOST_DEVICE
void updatePorosityImpl(
const Problem& problem,
598 const PrimaryVariables& priVars,
599 const unsigned globalSpaceIdx,
600 const unsigned timeIdx)
602 const auto& linearizationType = problem.model().linearizer().getLinearizationType();
605 porosity_ = referencePorosity_;
609 const Scalar rockCompressibility = problem.rockCompressibility(globalSpaceIdx);
610 if (rockCompressibility > 0.0) {
611 const Scalar rockRefPressure = problem.rockReferencePressure(globalSpaceIdx);
614 x = rockCompressibility * (fluidState_.pressure(oilPhaseIdx) - rockRefPressure);
617 x = rockCompressibility * (fluidState_.pressure(waterPhaseIdx) - rockRefPressure);
620 x = rockCompressibility * (fluidState_.pressure(gasPhaseIdx) - rockRefPressure);
622 porosity_ *= 1.0 + x + 0.5 * x * x;
626 porosity_ *= problem.template rockCompPoroMultiplier<Evaluation>(*
this, globalSpaceIdx);
629 if constexpr (enableBioeffects) {
630 const Evaluation biofilm_ = priVars.makeEvaluation(Indices::biofilmVolumeFractionIdx,
631 timeIdx, linearizationType);
632 Evaluation calcite_ = 0.0;
633 if constexpr (enableMICP) {
634 calcite_ = priVars.makeEvaluation(Indices::calciteVolumeFractionIdx, timeIdx, linearizationType);
636 porosity_ -= min(biofilm_ + calcite_, referencePorosity_ - 1e-8);
640 if (enableSaltPrecipitation && priVars.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp) {
641 const Evaluation Sp = priVars.makeEvaluation(Indices::saltConcentrationIdx, timeIdx);
642 porosity_ *= (1.0 - Sp);
646 OPM_HOST_DEVICE
void assertFiniteMembers()
649 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
654 assert(isfinite(fluidState_.density(phaseIdx)));
655 assert(isfinite(fluidState_.saturation(phaseIdx)));
656 assert(isfinite(fluidState_.temperature(phaseIdx)));
657 assert(isfinite(fluidState_.pressure(phaseIdx)));
658 assert(isfinite(fluidState_.invB(phaseIdx)));
660 assert(isfinite(fluidState_.Rs()));
661 assert(isfinite(fluidState_.Rv()));
667 template <
class ...Args>
668 OPM_HOST_DEVICE
void update(
const ElementContext& elemCtx,
unsigned dofIdx,
unsigned timeIdx)
670 ParentType::update(elemCtx, dofIdx, timeIdx);
671 const auto& problem = elemCtx.problem();
672 const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
673 const unsigned globalSpaceIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
675 updateCommonPart<Args...>(problem, priVars, globalSpaceIdx, timeIdx);
677 updatePorosity(elemCtx, dofIdx, timeIdx);
681 if constexpr (enableSolvent) {
682 asImp_().solventPvtUpdate_(elemCtx, dofIdx, timeIdx);
684 if constexpr (enableExtbo) {
685 asImp_().zPvtUpdate_();
687 if constexpr (enablePolymer) {
688 asImp_().polymerPropertiesUpdate_(elemCtx, dofIdx, timeIdx);
690 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
691 asImp_().updateEnergyQuantities_(elemCtx, dofIdx, timeIdx);
693 if constexpr (enableFoam) {
694 asImp_().foamPropertiesUpdate_(elemCtx, dofIdx, timeIdx);
696 if constexpr (enableBioeffects) {
697 asImp_().bioeffectsPropertiesUpdate_(elemCtx, dofIdx, timeIdx);
699 if constexpr (enableBrine) {
700 asImp_().saltPropertiesUpdate_(elemCtx, dofIdx, timeIdx);
702 if constexpr (enableConvectiveMixing) {
705 if (!problem.simulator().vanguard().eclState().getIOConfig().initOnly()) {
706 if (problem.simulator().vanguard().eclState().runspec().co2Storage()) {
707 if (problem.drsdtconIsActive(globalSpaceIdx, problem.simulator().episodeIndex())) {
708 asImp_().updateSaturatedDissolutionFactor_();
716 FluxIntensiveQuantities::update_(elemCtx, dofIdx, timeIdx);
719 if constexpr (enableDiffusion) {
720 DiffusionIntensiveQuantities::update_(fluidState_, priVars.pvtRegionIndex(), elemCtx, dofIdx, timeIdx);
724 if constexpr (enableDispersion) {
725 DispersionIntensiveQuantities::update_(elemCtx, dofIdx, timeIdx);
729 template <
class ...Args>
730 OPM_HOST_DEVICE
void update(
const Problem& problem,
731 const PrimaryVariables& priVars,
732 const unsigned globalSpaceIdx,
733 const unsigned timeIdx)
737 static_assert(!enableSolvent);
738 static_assert(!enableExtbo);
739 static_assert(!enablePolymer);
740 static_assert(!enableFoam);
741 static_assert(!enableMICP);
742 static_assert(!enableBrine);
743 static_assert(!enableDiffusion);
744 static_assert(!enableDispersion);
746 this->extrusionFactor_ = 1.0;
747 updateCommonPart<Args...>(problem, priVars, globalSpaceIdx, timeIdx);
749 updatePorosity(problem, priVars, globalSpaceIdx, timeIdx);
755 template <
class ...Args>
756 OPM_HOST_DEVICE
void updateCommonPart(
const Problem& problem,
757 const PrimaryVariables& priVars,
758 const unsigned globalSpaceIdx,
759 const unsigned timeIdx)
761 OPM_TIMEBLOCK_LOCAL(blackoilIntensiveQuanititiesUpdate, Subsystem::SatProps | Subsystem::PvtProps);
763 const auto& linearizationType = problem.model().linearizer().getLinearizationType();
764 const unsigned pvtRegionIdx = priVars.pvtRegionIndex();
766 fluidState_.setPvtRegionIndex(pvtRegionIdx);
768 updateTempSalt(problem, priVars, globalSpaceIdx, timeIdx, linearizationType);
769 updateSaturations(priVars, timeIdx, linearizationType);
770 updateRelpermAndPressures<Args...>(problem, priVars, globalSpaceIdx, timeIdx, linearizationType);
773 if constexpr (enableExtbo) {
774 asImp_().zFractionUpdate_(priVars, timeIdx);
777 updateRsRvRsw(problem, priVars, globalSpaceIdx, timeIdx);
778 updateMobilityAndInvB();
779 updatePhaseDensities();
784 assertFiniteMembers();
792 {
return fluidState_; }
796 {
return fluidState_; }
801 OPM_HOST_DEVICE
const Evaluation&
mobility(
unsigned phaseIdx)
const
802 {
return mobility_[phaseIdx]; }
804 OPM_HOST_DEVICE
const Evaluation&
mobility(
unsigned phaseIdx, FaceDir::DirEnum facedir)
const
806 using Dir = FaceDir::DirEnum;
808 bool constexpr usesStaticFluidSystem = std::is_empty_v<FluidSystem>;
809 if constexpr (usesStaticFluidSystem)
814 return dirMob_->getArray(0)[phaseIdx];
817 return dirMob_->getArray(1)[phaseIdx];
820 return dirMob_->getArray(2)[phaseIdx];
822 throw std::runtime_error(
"Unexpected face direction");
826 OPM_THROW(std::logic_error,
"Directional mobility with non-static fluid system is not supported yet");
830 return mobility_[phaseIdx];
838 {
return porosity_; }
844 {
return rockCompTransMultiplier_; }
854 {
return fluidState_.pvtRegionIndex(); }
862 return fluidState_.viscosity(phaseIdx) *
mobility(phaseIdx);
872 {
return referencePorosity_; }
874 OPM_HOST_DEVICE
const Evaluation& permFactor()
const
876 if constexpr (enableBioeffects) {
877 return BioeffectsIntQua::permFactor();
879 else if constexpr (enableSaltPrecipitation) {
880 return BrineIntQua::permFactor();
883 throw std::logic_error(
"permFactor() called but salt precipitation or bioeffects are disabled");
892 return fluidState_.fluidSystem();
904 OPM_HOST_DEVICE Implementation& asImp_()
905 {
return *
static_cast<Implementation*
>(
this); }
907 FluidState fluidState_;
908 Scalar referencePorosity_;
909 Evaluation porosity_;
910 Evaluation rockCompTransMultiplier_;
911 std::array<Evaluation, numPhases> mobility_;
928 DirectionalMobilityPtr dirMob_;