81 using SolventPvt =
typename BlackOilSolventParams<Scalar>::SolventPvt;
82 using Co2GasPvt =
typename BlackOilSolventParams<Scalar>::Co2GasPvt;
83 using H2GasPvt =
typename BlackOilSolventParams<Scalar>::H2GasPvt;
84 using BrineCo2Pvt =
typename BlackOilSolventParams<Scalar>::BrineCo2Pvt;
85 using BrineH2Pvt =
typename BlackOilSolventParams<Scalar>::BrineH2Pvt;
87 using TabulatedFunction =
typename BlackOilSolventParams<Scalar>::TabulatedFunction;
89 static constexpr unsigned solventSaturationIdx = Indices::solventSaturationIdx;
90 static constexpr unsigned contiSolventEqIdx = Indices::contiSolventEqIdx;
93 static constexpr bool blackoilConserveSurfaceVolume =
95 static constexpr int waterPhaseIdx = FluidSystem::waterPhaseIdx;
106 { params_.solventPvt_ = value; }
108 static void setIsMiscible(
const bool isMiscible)
109 { params_.isMiscible_ = isMiscible; }
116 if constexpr (enableSolvent) {
125 Simulator& simulator)
127 if constexpr (enableSolvent) {
132 static bool primaryVarApplies(
unsigned pvIdx)
134 if constexpr (enableSolvent) {
135 return pvIdx == solventSaturationIdx;
146 return "saturation_solvent";
154 return static_cast<Scalar
>(1.0);
157 static bool eqApplies(
unsigned eqIdx)
159 if constexpr (enableSolvent) {
160 return eqIdx == contiSolventEqIdx;
171 return "conti^solvent";
179 return static_cast<Scalar
>(1.0);
182 template <
class LhsEval>
183 static void addStorage(Dune::FieldVector<LhsEval, numEq>&
storage,
184 const IntensiveQuantities& intQuants)
186 if constexpr (enableSolvent) {
187 if constexpr (blackoilConserveSurfaceVolume) {
191 Toolbox::template
decay<LhsEval>(intQuants.solventInverseFormationVolumeFactor());
192 if (isSolubleInWater()) {
195 Toolbox::template
decay<LhsEval>(intQuants.fluidState().saturation(waterPhaseIdx)) *
196 Toolbox::template
decay<LhsEval>(intQuants.fluidState().invB(waterPhaseIdx)) *
205 if (isSolubleInWater()) {
208 Toolbox::template
decay<LhsEval>(intQuants.fluidState().saturation(waterPhaseIdx)) *
209 Toolbox::template
decay<LhsEval>(intQuants.fluidState().density(waterPhaseIdx)) *
222 if constexpr (enableSolvent) {
229 if constexpr (blackoilConserveSurfaceVolume) {
232 up.solventInverseFormationVolumeFactor();
240 if (isSolubleInWater()) {
242 flux[contiSolventEqIdx] +=
244 up.fluidState().invB(waterPhaseIdx) *
248 flux[contiSolventEqIdx] +=
257 flux[contiSolventEqIdx] =
extQuants.solventVolumeFlux() *
up.solventDensity();
263 if (isSolubleInWater()) {
265 flux[contiSolventEqIdx] +=
267 up.fluidState().density(waterPhaseIdx) *
271 flux[contiSolventEqIdx] +=
285 Scalar solventSaturation,
288 if constexpr (!enableSolvent) {
289 priVars.setPrimaryVarsMeaningSolvent(PrimaryVariables::SolventMeaning::Disabled);
293 if (solventSaturation > 0 || !isSolubleInWater()) {
294 priVars.setPrimaryVarsMeaningSolvent(PrimaryVariables::SolventMeaning::Ss);
295 priVars[solventSaturationIdx] = solventSaturation;
297 priVars.setPrimaryVarsMeaningSolvent(PrimaryVariables::SolventMeaning::Rsolw);
298 priVars[solventSaturationIdx] = solventRsw;
306 const PrimaryVariables&
oldPv,
307 const EqVector&
delta)
309 if constexpr (enableSolvent) {
311 newPv[solventSaturationIdx] =
oldPv[solventSaturationIdx] -
delta[solventSaturationIdx];
324 return static_cast<Scalar
>(0.0);
333 return std::abs(Toolbox::scalarValue(
resid[contiSolventEqIdx]));
336 template <
class DofEntity>
339 if constexpr (enableSolvent) {
340 const unsigned dofIdx = model.dofMapper().index(
dof);
342 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
343 outstream << priVars[solventSaturationIdx];
347 template <
class DofEntity>
350 if constexpr (enableSolvent) {
351 const unsigned dofIdx = model.dofMapper().index(
dof);
353 PrimaryVariables&
priVars0 = model.solution(0)[dofIdx];
354 PrimaryVariables&
priVars1 = model.solution(1)[dofIdx];
363 static const SolventPvt& solventPvt()
364 {
return params_.solventPvt_; }
366 static const Co2GasPvt& co2GasPvt()
367 {
return params_.co2GasPvt_; }
369 static const H2GasPvt& h2GasPvt()
370 {
return params_.h2GasPvt_; }
372 static const BrineCo2Pvt& brineCo2Pvt()
373 {
return params_.brineCo2Pvt_; }
375 static const BrineH2Pvt& brineH2Pvt()
376 {
return params_.brineH2Pvt_; }
378 template <
class ElemContext>
379 static const TabulatedFunction& ssfnKrg(
const ElemContext& elemCtx,
384 elemCtx.problem().satnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
388 template <
class ElemContext>
389 static const TabulatedFunction& ssfnKrs(
const ElemContext& elemCtx,
394 elemCtx.problem().satnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
398 template <
class ElemContext>
399 static const TabulatedFunction& sof2Krn(
const ElemContext& elemCtx,
404 elemCtx.problem().satnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
408 template <
class ElemContext>
409 static const TabulatedFunction& misc(
const ElemContext& elemCtx,
414 elemCtx.problem().miscnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
418 template <
class ElemContext>
419 static const TabulatedFunction& pmisc(
const ElemContext& elemCtx,
424 elemCtx.problem().miscnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
428 template <
class ElemContext>
429 static const TabulatedFunction& msfnKrsg(
const ElemContext& elemCtx,
434 elemCtx.problem().satnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
438 template <
class ElemContext>
439 static const TabulatedFunction& msfnKro(
const ElemContext& elemCtx,
444 elemCtx.problem().satnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
448 template <
class ElemContext>
449 static const TabulatedFunction& sorwmis(
const ElemContext& elemCtx,
454 elemCtx.problem().miscnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
458 template <
class ElemContext>
459 static const TabulatedFunction& sgcwmis(
const ElemContext& elemCtx,
464 elemCtx.problem().miscnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
468 template <
class ElemContext>
469 static const TabulatedFunction& tlPMixTable(
const ElemContext& elemCtx,
474 elemCtx.problem().miscnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
478 template <
class ElemContext>
479 static Scalar tlMixParamViscosity(
const ElemContext& elemCtx,
484 elemCtx.problem().miscnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
489 template <
class ElemContext>
490 static Scalar tlMixParamDensity(
const ElemContext& elemCtx,
495 elemCtx.problem().miscnumRegionIndex(elemCtx,
scvIdx,
timeIdx);
499 static bool isMiscible()
500 {
return params_.isMiscible_; }
502 template <
class Value>
503 static Value solubilityLimit(
unsigned pvtIdx,
const Value& temperature,
504 const Value& pressure,
const Value& saltConcentration)
506 if (!isSolubleInWater()) {
510 assert(isCO2Sol() || isH2Sol());
512 return brineCo2Pvt().saturatedGasDissolutionFactor(pvtIdx, temperature,
513 pressure, saltConcentration);
516 return brineH2Pvt().saturatedGasDissolutionFactor(pvtIdx, temperature,
517 pressure, saltConcentration);
521 static bool isSolubleInWater()
522 {
return params_.rsSolw_active_; }
524 static bool isCO2Sol()
525 {
return params_.co2sol_; }
527 static bool isH2Sol()
528 {
return params_.h2sol_; }
565 static constexpr int solventSaturationIdx = Indices::solventSaturationIdx;
566 static constexpr int oilPhaseIdx = FluidSystem::oilPhaseIdx;
567 static constexpr int gasPhaseIdx = FluidSystem::gasPhaseIdx;
568 static constexpr int waterPhaseIdx = FluidSystem::waterPhaseIdx;
569 static constexpr double cutOff = 1
e-12;
582 const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx,
timeIdx);
583 this->solventPreSatFuncUpdate_(priVars,
timeIdx, elemCtx.linearizationType());
586 void solventPreSatFuncUpdate_(
const PrimaryVariables& priVars,
590 auto& fs = asImp_().fluidState_;
591 solventSaturation_ = 0.0;
592 if (priVars.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
593 solventSaturation_ = priVars.makeEvaluation(solventSaturationIdx,
timeIdx, linearizationType);
596 hydrocarbonSaturation_ = fs.saturation(gasPhaseIdx);
599 if (solventSaturation().value() < cutOff) {
605 fs.setSaturation(gasPhaseIdx, hydrocarbonSaturation_ + solventSaturation_);
619 const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx,
timeIdx);
620 this->solventPostSatFuncUpdate_(elemCtx.problem(), priVars, elemCtx.globalSpaceIndex(dofIdx,
timeIdx),
timeIdx, elemCtx.linearizationType());
625 template <
class Problem>
628 const Problem& problem_;
630 const Problem& problem()
const {
return problem_; }
631 unsigned int globalSpaceIndex([[maybe_unused]]
const unsigned int spaceIdx,
632 [[maybe_unused]]
const unsigned int timeIdx)
const
639 void solventPostSatFuncUpdate_(
const Problem& problem,
640 const PrimaryVariables& priVars,
643 const LinearizationType linearizationType)
647 auto& fs = asImp_().fluidState_;
648 fs.setSaturation(gasPhaseIdx, hydrocarbonSaturation_);
652 if (priVars.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
653 rsSolw_ = SolventModule::solubilityLimit(asImp_().pvtRegionIndex(),
654 fs.temperature(waterPhaseIdx),
655 fs.pressure(waterPhaseIdx),
656 fs.saltConcentration());
657 }
else if (priVars.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Rsolw) {
658 rsSolw_ = priVars.makeEvaluation(solventSaturationIdx,
timeIdx, linearizationType);
661 solventMobility_ = 0.0;
664 if (solventSaturation().value() < cutOff) {
672 if (SolventModule::isMiscible()) {
673 const Evaluation&
p =
674 FluidSystem::phaseIsActive(oilPhaseIdx)
675 ? fs.pressure(oilPhaseIdx)
676 : fs.pressure(gasPhaseIdx);
677 const Evaluation pmisc =
678 SolventModule::pmisc(elemCtx, dofIdx,
timeIdx).eval(
p,
true);
679 const Evaluation&
pgImisc = fs.pressure(gasPhaseIdx);
683 std::array<Evaluation, numPhases>
pC;
688 if (priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Pg) {
689 pgMisc = priVars.makeEvaluation(Indices::pressureSwitchIdx,
timeIdx,
693 const Evaluation& po =
694 priVars.makeEvaluation(Indices::pressureSwitchIdx,
696 pgMisc = po + (
pC[gasPhaseIdx] -
pC[oilPhaseIdx]);
699 fs.setPressure(gasPhaseIdx, pmisc *
pgMisc + (1.0 - pmisc) *
pgImisc);
702 const Evaluation
gasSolventSat = hydrocarbonSaturation_ + solventSaturation_;
712 if (SolventModule::isMiscible() && FluidSystem::phaseIsActive(oilPhaseIdx)) {
713 const auto& misc = SolventModule::misc(elemCtx, dofIdx,
timeIdx);
714 const auto& pmisc = SolventModule::pmisc(elemCtx, dofIdx,
timeIdx);
715 const Evaluation&
p =
716 FluidSystem::phaseIsActive(oilPhaseIdx)
717 ? fs.pressure(oilPhaseIdx)
718 : fs.pressure(gasPhaseIdx);
724 const unsigned cellIdx = elemCtx.globalSpaceIndex(dofIdx,
timeIdx);
725 const auto& materialLawManager = elemCtx.problem().materialLawManager();
727 materialLawManager->oilWaterScaledEpsInfoDrainage(
cellIdx);
731 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
732 const Evaluation&
sw = fs.saturation(waterPhaseIdx);
733 const auto& sorwmis = SolventModule::sorwmis(elemCtx, dofIdx,
timeIdx);
738 Evaluation
sgc = sgcr;
739 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
740 const Evaluation&
sw = fs.saturation(waterPhaseIdx);
741 const auto& sgcwmis = SolventModule::sgcwmis(elemCtx, dofIdx,
timeIdx);
746 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
749 const Evaluation
zero = 0.0;
757 const auto& msfnKro = SolventModule::msfnKro(elemCtx, dofIdx,
timeIdx);
758 const auto& msfnKrsg = SolventModule::msfnKrsg(elemCtx, dofIdx,
timeIdx);
759 const auto& sof2Krn = SolventModule::sof2Krn(elemCtx, dofIdx,
timeIdx);
766 Evaluation&
kro = asImp_().mobility_[oilPhaseIdx];
767 Evaluation&
krg = asImp_().mobility_[gasPhaseIdx];
777 const auto& ssfnKrg = SolventModule::ssfnKrg(elemCtx, dofIdx,
timeIdx);
778 const auto& ssfnKrs = SolventModule::ssfnKrs(elemCtx, dofIdx,
timeIdx);
780 Evaluation&
krg = asImp_().mobility_[gasPhaseIdx];
781 solventMobility_ =
krg * ssfnKrs.eval(
Fsolgas,
true);
795 const auto&
iq = asImp_();
796 const unsigned pvtRegionIdx =
iq.pvtRegionIndex();
797 const Evaluation& T =
iq.fluidState().temperature(gasPhaseIdx);
798 const Evaluation&
p =
iq.fluidState().pressure(gasPhaseIdx);
800 const Evaluation rv = 0.0;
801 const Evaluation rvw = 0.0;
802 if (SolventModule::isCO2Sol() || SolventModule::isH2Sol() ){
803 if (SolventModule::isCO2Sol()) {
804 const auto&
co2gasPvt = SolventModule::co2GasPvt();
805 solventInvFormationVolumeFactor_ =
806 co2gasPvt.inverseFormationVolumeFactor(pvtRegionIdx, T,
p, rv, rvw);
807 solventRefDensity_ =
co2gasPvt.gasReferenceDensity(pvtRegionIdx);
808 solventViscosity_ =
co2gasPvt.viscosity(pvtRegionIdx, T,
p, rv, rvw);
810 const auto& brineCo2Pvt = SolventModule::brineCo2Pvt();
811 auto& fs = asImp_().fluidState_;
812 const auto&
bw = brineCo2Pvt.inverseFormationVolumeFactor(pvtRegionIdx, T,
p, rsSolw());
814 const auto denw =
bw * brineCo2Pvt.waterReferenceDensity(pvtRegionIdx) +
815 rsSolw() *
bw * brineCo2Pvt.gasReferenceDensity(pvtRegionIdx);
816 fs.setDensity(waterPhaseIdx,
denw);
817 fs.setInvB(waterPhaseIdx,
bw);
818 Evaluation&
mobw = asImp_().mobility_[waterPhaseIdx];
819 const auto&
muWat = fs.viscosity(waterPhaseIdx);
820 const auto&
muWatEff = brineCo2Pvt.viscosity(pvtRegionIdx, T,
p, rsSolw());
823 const auto&
h2gasPvt = SolventModule::h2GasPvt();
824 solventInvFormationVolumeFactor_ =
825 h2gasPvt.inverseFormationVolumeFactor(pvtRegionIdx, T,
p, rv, rvw);
826 solventRefDensity_ =
h2gasPvt.gasReferenceDensity(pvtRegionIdx);
827 solventViscosity_ =
h2gasPvt.viscosity(pvtRegionIdx, T,
p, rv, rvw);
829 const auto& brineH2Pvt = SolventModule::brineH2Pvt();
830 auto& fs = asImp_().fluidState_;
831 const auto&
bw = brineH2Pvt.inverseFormationVolumeFactor(pvtRegionIdx, T,
p, rsSolw());
833 const auto denw =
bw * brineH2Pvt.waterReferenceDensity(pvtRegionIdx) +
834 rsSolw() *
bw * brineH2Pvt.gasReferenceDensity(pvtRegionIdx);
835 fs.setDensity(waterPhaseIdx,
denw);
836 fs.setInvB(waterPhaseIdx,
bw);
837 Evaluation&
mobw = asImp_().mobility_[waterPhaseIdx];
838 const auto&
muWat = fs.viscosity(waterPhaseIdx);
839 const auto&
muWatEff = brineH2Pvt.viscosity(pvtRegionIdx, T,
p, rsSolw());
843 const auto& solventPvt = SolventModule::solventPvt();
844 solventInvFormationVolumeFactor_ = solventPvt.inverseFormationVolumeFactor(pvtRegionIdx, T,
p);
845 solventRefDensity_ = solventPvt.referenceDensity(pvtRegionIdx);
846 solventViscosity_ = solventPvt.viscosity(pvtRegionIdx, T,
p);
849 solventDensity_ = solventInvFormationVolumeFactor_*solventRefDensity_;
852 solventMobility_ /= solventViscosity_;
855 const Evaluation& solventSaturation()
const
856 {
return solventSaturation_; }
858 const Evaluation& rsSolw()
const
861 const Evaluation& solventDensity()
const
862 {
return solventDensity_; }
864 const Evaluation& solventViscosity()
const
865 {
return solventViscosity_; }
867 const Evaluation& solventMobility()
const
868 {
return solventMobility_; }
870 const Evaluation& solventInverseFormationVolumeFactor()
const
871 {
return solventInvFormationVolumeFactor_; }
874 Scalar solventRefDensity()
const
875 {
return solventRefDensity_; }
880 void effectiveProperties(
const ElementContext& elemCtx,
884 if (!SolventModule::isMiscible()) {
890 if (solventSaturation() < cutOff) {
896 auto& fs = asImp_().fluidState_;
900 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
903 Evaluation
gasEffSat = fs.saturation(gasPhaseIdx);
905 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
906 const auto& sorwmis = SolventModule::sorwmis(elemCtx,
scvIdx,
timeIdx);
907 const auto& sgcwmis = SolventModule::sgcwmis(elemCtx,
scvIdx,
timeIdx);
908 const Evaluation
zero = 0.0;
909 const Evaluation&
sw = fs.saturation(waterPhaseIdx);
910 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
925 const Evaluation&
p =
926 FluidSystem::phaseIsActive(oilPhaseIdx)
927 ? fs.pressure(oilPhaseIdx)
928 : fs.pressure(gasPhaseIdx);
932 const auto& tlPMixTable = SolventModule::tlPMixTable(elemCtx,
scvIdx,
timeIdx);
934 tlPMixTable.eval(
p,
true);
936 const Evaluation&
muGas = fs.viscosity(gasPhaseIdx);
937 const Evaluation&
muSolvent = solventViscosity_;
950 Evaluation
muOil = 1.0;
954 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
955 muOil = fs.viscosity(oilPhaseIdx);
980 const Evaluation&
rhoGas = fs.density(gasPhaseIdx);
982 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
983 rhoOil = fs.density(oilPhaseIdx);
986 const Evaluation&
rhoSolvent = solventDensity_;
993 tlPMixTable.eval(
p,
true);
1005 Evaluation
sof = 0.0;
1006 Evaluation
sgf = 0.0;
1046 const unsigned pvtRegionIdx = asImp_().pvtRegionIndex();
1048 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1049 bGasEff /= (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) +
1050 FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) * fs.Rv());
1052 bGasEff /= (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx));
1057 const Evaluation bg = fs.invB(gasPhaseIdx);
1058 const Evaluation
bs = solventInverseFormationVolumeFactor();
1059 const Evaluation
bg_eff = pmisc *
bGasEff + (1.0 - pmisc) * bg;
1063 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1064 fs.setDensity(gasPhaseIdx,
1066 (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) +
1067 FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx)*fs.Rv()));
1069 fs.setDensity(gasPhaseIdx,
1070 bg_eff * FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx));
1072 solventDensity_ =
bs_eff * solventRefDensity();
1075 Evaluation&
mobg = asImp_().mobility_[gasPhaseIdx];
1083 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1094 rhoOilEff / (FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) +
1095 FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) * fs.Rs());
1096 const Evaluation bo = fs.invB(oilPhaseIdx);
1097 const Evaluation
bo_eff = pmisc *
bOilEff + (1.0 - pmisc) * bo;
1098 fs.setDensity(oilPhaseIdx,
1099 bo_eff * (FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) +
1100 FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) * fs.Rs()));
1103 Evaluation&
mobo = asImp_().mobility_[oilPhaseIdx];
1110 Implementation& asImp_()
1111 {
return *
static_cast<Implementation*
>(
this); }
1113 Evaluation hydrocarbonSaturation_;
1114 Evaluation solventSaturation_;
1116 Evaluation solventDensity_;
1117 Evaluation solventViscosity_;
1118 Evaluation solventMobility_;
1119 Evaluation solventInvFormationVolumeFactor_;
1121 Scalar solventRefDensity_;
void updateVolumeFluxPerm(const ElementContext &elemCtx, unsigned scvfIdx, unsigned timeIdx)
Method which calculates the volume flux of the polymer "phase" using the pressure potential gradient ...
Definition blackoilsolventmodules.hh:1204
void updateVolumeFluxTrans(const ElementContext &elemCtx, unsigned scvfIdx, unsigned timeIdx)
Method which calculates the volume flux of the polymer "phase" using the gas pressure potential diffe...
Definition blackoilsolventmodules.hh:1311