80 using Toolbox = MathToolbox<Evaluation>;
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;
91 static constexpr unsigned enableSolvent = enableSolventV;
93 static constexpr bool blackoilConserveSurfaceVolume =
95 static constexpr int waterPhaseIdx = FluidSystem::waterPhaseIdx;
100 { params_ = params; }
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;
142 static std::string primaryVarName([[maybe_unused]]
unsigned pvIdx)
144 assert(primaryVarApplies(pvIdx));
146 return "saturation_solvent";
149 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
151 assert(primaryVarApplies(pvIdx));
154 return static_cast<Scalar
>(1.0);
157 static bool eqApplies(
unsigned eqIdx)
159 if constexpr (enableSolvent) {
160 return eqIdx == contiSolventEqIdx;
167 static std::string eqName([[maybe_unused]]
unsigned eqIdx)
169 assert(eqApplies(eqIdx));
171 return "conti^solvent";
174 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
176 assert(eqApplies(eqIdx));
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) {
188 storage[contiSolventEqIdx] +=
189 Toolbox::template decay<LhsEval>(intQuants.porosity()) *
190 Toolbox::template decay<LhsEval>(intQuants.solventSaturation()) *
191 Toolbox::template decay<LhsEval>(intQuants.solventInverseFormationVolumeFactor());
192 if (isSolubleInWater()) {
193 storage[contiSolventEqIdx] +=
194 Toolbox::template decay<LhsEval>(intQuants.porosity()) *
195 Toolbox::template decay<LhsEval>(intQuants.fluidState().saturation(waterPhaseIdx)) *
196 Toolbox::template decay<LhsEval>(intQuants.fluidState().invB(waterPhaseIdx)) *
197 Toolbox::template decay<LhsEval>(intQuants.rsSolw());
201 storage[contiSolventEqIdx] +=
202 Toolbox::template decay<LhsEval>(intQuants.porosity()) *
203 Toolbox::template decay<LhsEval>(intQuants.solventSaturation()) *
204 Toolbox::template decay<LhsEval>(intQuants.solventDensity());
205 if (isSolubleInWater()) {
206 storage[contiSolventEqIdx] +=
207 Toolbox::template decay<LhsEval>(intQuants.porosity()) *
208 Toolbox::template decay<LhsEval>(intQuants.fluidState().saturation(waterPhaseIdx)) *
209 Toolbox::template decay<LhsEval>(intQuants.fluidState().density(waterPhaseIdx)) *
210 Toolbox::template decay<LhsEval>(intQuants.rsSolw());
216 static void computeFlux([[maybe_unused]] RateVector& flux,
217 [[maybe_unused]]
const ElementContext& elemCtx,
218 [[maybe_unused]]
unsigned scvfIdx,
219 [[maybe_unused]]
unsigned timeIdx)
222 if constexpr (enableSolvent) {
223 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
225 const unsigned upIdx = extQuants.solventUpstreamIndex();
226 const unsigned inIdx = extQuants.interiorIndex();
227 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
229 if constexpr (blackoilConserveSurfaceVolume) {
230 if (upIdx == inIdx) {
231 flux[contiSolventEqIdx] = extQuants.solventVolumeFlux() *
232 up.solventInverseFormationVolumeFactor();
235 flux[contiSolventEqIdx] = extQuants.solventVolumeFlux() *
236 decay<Scalar>(up.solventInverseFormationVolumeFactor());
240 if (isSolubleInWater()) {
241 if (upIdx == inIdx) {
242 flux[contiSolventEqIdx] +=
243 extQuants.volumeFlux(waterPhaseIdx) *
244 up.fluidState().invB(waterPhaseIdx) *
248 flux[contiSolventEqIdx] +=
249 extQuants.volumeFlux(waterPhaseIdx) *
250 decay<Scalar>(up.fluidState().invB(waterPhaseIdx)) *
251 decay<Scalar>(up.rsSolw());
256 if (upIdx == inIdx) {
257 flux[contiSolventEqIdx] = extQuants.solventVolumeFlux() * up.solventDensity();
260 flux[contiSolventEqIdx] = extQuants.solventVolumeFlux() * decay<Scalar>(up.solventDensity());
263 if (isSolubleInWater()) {
264 if (upIdx == inIdx) {
265 flux[contiSolventEqIdx] +=
266 extQuants.volumeFlux(waterPhaseIdx) *
267 up.fluidState().density(waterPhaseIdx) *
271 flux[contiSolventEqIdx] +=
272 extQuants.volumeFlux(waterPhaseIdx) *
273 decay<Scalar>(up.fluidState().density(waterPhaseIdx)) *
274 decay<Scalar>(up.rsSolw());
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>
337 static void serializeEntity(
const Model& model, std::ostream& outstream,
const DofEntity& dof)
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>
348 static void deserializeEntity(Model& model, std::istream& instream,
const DofEntity& dof)
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];
356 instream >> priVars0[solventSaturationIdx];
359 priVars1 = priVars0[solventSaturationIdx];
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,
383 const unsigned satnumRegionIdx =
384 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
385 return params_.ssfnKrg_[satnumRegionIdx];
388 template <
class ElemContext>
389 static const TabulatedFunction& ssfnKrs(
const ElemContext& elemCtx,
393 const unsigned satnumRegionIdx =
394 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
395 return params_.ssfnKrs_[satnumRegionIdx];
398 template <
class ElemContext>
399 static const TabulatedFunction& sof2Krn(
const ElemContext& elemCtx,
403 const unsigned satnumRegionIdx =
404 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
405 return params_.sof2Krn_[satnumRegionIdx];
408 template <
class ElemContext>
409 static const TabulatedFunction& misc(
const ElemContext& elemCtx,
413 const unsigned miscnumRegionIdx =
414 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
415 return params_.misc_[miscnumRegionIdx];
418 template <
class ElemContext>
419 static const TabulatedFunction& pmisc(
const ElemContext& elemCtx,
423 const unsigned miscnumRegionIdx =
424 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
425 return params_.pmisc_[miscnumRegionIdx];
428 template <
class ElemContext>
429 static const TabulatedFunction& msfnKrsg(
const ElemContext& elemCtx,
433 const unsigned satnumRegionIdx =
434 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
435 return params_.msfnKrsg_[satnumRegionIdx];
438 template <
class ElemContext>
439 static const TabulatedFunction& msfnKro(
const ElemContext& elemCtx,
443 const unsigned satnumRegionIdx =
444 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
445 return params_.msfnKro_[satnumRegionIdx];
448 template <
class ElemContext>
449 static const TabulatedFunction& sorwmis(
const ElemContext& elemCtx,
453 const unsigned miscnumRegionIdx =
454 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
455 return params_.sorwmis_[miscnumRegionIdx];
458 template <
class ElemContext>
459 static const TabulatedFunction& sgcwmis(
const ElemContext& elemCtx,
463 const unsigned miscnumRegionIdx =
464 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
465 return params_.sgcwmis_[miscnumRegionIdx];
468 template <
class ElemContext>
469 static const TabulatedFunction& tlPMixTable(
const ElemContext& elemCtx,
473 const unsigned miscnumRegionIdx =
474 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
475 return params_.tlPMixTable_[miscnumRegionIdx];
478 template <
class ElemContext>
479 static Scalar tlMixParamViscosity(
const ElemContext& elemCtx,
483 const unsigned miscnumRegionIdx =
484 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
485 return params_.tlMixParamViscosity_[miscnumRegionIdx];
489 template <
class ElemContext>
490 static Scalar tlMixParamDensity(
const ElemContext& elemCtx,
494 const unsigned miscnumRegionIdx =
495 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
496 return params_.tlMixParamDensity_[miscnumRegionIdx];
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_; }
531 static BlackOilSolventParams<Scalar> params_;
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 = 1e-12;
582 const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
586 void solventPreSatFuncUpdate_(
const PrimaryVariables& priVars,
587 const unsigned timeIdx,
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>
626 struct ProblemAndCellIndexOnlyContext
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,
641 const unsigned globalSpaceIdx,
642 const unsigned timeIdx,
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) {
668 ProblemAndCellIndexOnlyContext<Problem> elemCtx{problem, globalSpaceIdx};
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);
682 Evaluation pgMisc = 0.0;
683 std::array<Evaluation, numPhases> pC;
684 const auto& materialParams = problem.materialLawParams(elemCtx, dofIdx, timeIdx);
685 MaterialLaw::capillaryPressures(pC, materialParams, fs);
688 if (priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Pg) {
689 pgMisc = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx,
693 const Evaluation& po =
694 priVars.makeEvaluation(Indices::pressureSwitchIdx,
695 timeIdx, linearizationType);
696 pgMisc = po + (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
699 fs.setPressure(gasPhaseIdx, pmisc * pgMisc + (1.0 - pmisc) * pgImisc);
702 const Evaluation gasSolventSat = hydrocarbonSaturation_ + solventSaturation_;
704 if (gasSolventSat.value() < cutOff) {
708 const Evaluation Fhydgas = hydrocarbonSaturation_ / gasSolventSat;
709 const Evaluation Fsolgas = solventSaturation_ / gasSolventSat;
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);
719 const Evaluation miscibility =
720 misc.eval(Fsolgas,
true) *
724 const unsigned cellIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
725 const auto& materialLawManager = elemCtx.problem().materialLawManager();
726 const auto& scaledDrainageInfo =
727 materialLawManager->oilWaterScaledEpsInfoDrainage(cellIdx);
729 const Scalar sogcr = scaledDrainageInfo.Sogcr;
730 Evaluation sor = sogcr;
731 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
732 const Evaluation& sw = fs.saturation(waterPhaseIdx);
733 const auto& sorwmis = SolventModule::sorwmis(elemCtx, dofIdx, timeIdx);
735 sorwmis.eval(sw,
true) + (1.0 - miscibility) * sogcr;
737 const Scalar sgcr = scaledDrainageInfo.Sgcr;
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);
742 sgc = miscibility * sgcwmis.eval(sw,
true) + (1.0 - miscibility) * sgcr;
745 Evaluation oilGasSolventSat = gasSolventSat;
746 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
747 oilGasSolventSat += fs.saturation(oilPhaseIdx);
749 const Evaluation zero = 0.0;
750 const Evaluation oilGasSolventEffSat = std::max(oilGasSolventSat - sor - sgc, zero);
752 Evaluation F_totalGas = 0.0;
753 if (oilGasSolventEffSat.value() > cutOff) {
754 const Evaluation gasSolventEffSat = std::max(gasSolventSat - sgc, zero);
755 F_totalGas = gasSolventEffSat / oilGasSolventEffSat;
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);
761 const Evaluation mkrgt = msfnKrsg.eval(F_totalGas,
true) *
762 sof2Krn.eval(oilGasSolventSat,
true);
763 const Evaluation mkro = msfnKro.eval(F_totalGas,
true) *
764 sof2Krn.eval(oilGasSolventSat,
true);
766 Evaluation& kro = asImp_().mobility_[oilPhaseIdx];
767 Evaluation& krg = asImp_().mobility_[gasPhaseIdx];
770 krg *= 1.0 - miscibility;
771 krg += miscibility * mkrgt;
772 kro *= 1.0 - miscibility;
773 kro += miscibility * mkro;
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);
782 krg *= ssfnKrg.eval(Fhydgas,
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());
821 mobw *= muWat / muWatEff;
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());
840 mobw *= muWat / muWatEff;
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_;
850 effectiveProperties(elemCtx, scvIdx, timeIdx);
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_;
899 Evaluation oilEffSat = 0.0;
900 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
901 oilEffSat = fs.saturation(oilPhaseIdx);
903 Evaluation gasEffSat = fs.saturation(gasPhaseIdx);
904 Evaluation solventEffSat = solventSaturation();
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)) {
911 oilEffSat = std::max(oilEffSat - sorwmis.eval(sw,
true), zero);
913 gasEffSat = std::max(gasEffSat - sgcwmis.eval(sw,
true), zero);
914 solventEffSat = std::max(solventEffSat - sgcwmis.eval(sw,
true), zero);
916 const Evaluation oilGasSolventEffSat = oilEffSat + gasEffSat + solventEffSat;
917 const Evaluation oilSolventEffSat = oilEffSat + solventEffSat;
918 const Evaluation solventGasEffSat = solventEffSat + gasEffSat;
925 const Evaluation& p =
926 FluidSystem::phaseIsActive(oilPhaseIdx)
927 ? fs.pressure(oilPhaseIdx)
928 : fs.pressure(gasPhaseIdx);
930 const auto& pmiscTable = SolventModule::pmisc(elemCtx, scvIdx, timeIdx);
931 const Evaluation pmisc = pmiscTable.eval(p,
true);
932 const auto& tlPMixTable = SolventModule::tlPMixTable(elemCtx, scvIdx, timeIdx);
933 const Evaluation tlMixParamMu = SolventModule::tlMixParamViscosity(elemCtx, scvIdx, timeIdx) *
934 tlPMixTable.eval(p,
true);
936 const Evaluation& muGas = fs.viscosity(gasPhaseIdx);
937 const Evaluation& muSolvent = solventViscosity_;
939 assert(muGas.value() > 0);
940 assert(muSolvent.value() > 0);
941 const Evaluation muGasPow = pow(muGas, 0.25);
942 const Evaluation muSolventPow = pow(muSolvent, 0.25);
944 Evaluation muMixSolventGas = muGas;
945 if (solventGasEffSat > cutOff) {
946 muMixSolventGas *= muSolvent / pow(((gasEffSat / solventGasEffSat) * muSolventPow) +
947 ((solventEffSat / solventGasEffSat) * muGasPow), 4.0);
950 Evaluation muOil = 1.0;
951 Evaluation muOilPow = 1.0;
952 Evaluation muMixOilSolvent = 1.0;
953 Evaluation muOilEff = 1.0;
954 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
955 muOil = fs.viscosity(oilPhaseIdx);
956 assert(muOil.value() > 0);
957 muOilPow = pow(muOil, 0.25);
958 muMixOilSolvent = muOil;
959 if (oilSolventEffSat > cutOff) {
960 muMixOilSolvent *= muSolvent / pow(((oilEffSat / oilSolventEffSat) * muSolventPow) +
961 ((solventEffSat / oilSolventEffSat) * muOilPow), 4.0);
964 muOilEff = pow(muOil,1.0 - tlMixParamMu) * pow(muMixOilSolvent, tlMixParamMu);
966 Evaluation muMixSolventGasOil = muOil;
967 if (oilGasSolventEffSat > cutOff) {
968 muMixSolventGasOil *= muSolvent * muGas / pow(((oilEffSat / oilGasSolventEffSat) *
969 muSolventPow * muGasPow) +
970 ((solventEffSat / oilGasSolventEffSat) *
971 muOilPow * muGasPow) +
972 ((gasEffSat / oilGasSolventEffSat) *
973 muSolventPow * muOilPow), 4.0);
976 Evaluation muGasEff = pow(muGas,1.0 - tlMixParamMu) * pow(muMixSolventGas, tlMixParamMu);
977 const Evaluation muSolventEff = pow(muSolvent,1.0 - tlMixParamMu) * pow(muMixSolventGasOil, tlMixParamMu);
980 const Evaluation& rhoGas = fs.density(gasPhaseIdx);
981 Evaluation rhoOil = 0.0;
982 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
983 rhoOil = fs.density(oilPhaseIdx);
986 const Evaluation& rhoSolvent = solventDensity_;
992 const Evaluation tlMixParamRho = SolventModule::tlMixParamDensity(elemCtx, scvIdx, timeIdx) *
993 tlPMixTable.eval(p,
true);
997 const Evaluation muOilEffPow = pow(pow(muOil, 1.0 - tlMixParamRho) *
998 pow(muMixOilSolvent, tlMixParamRho), 0.25);
999 const Evaluation muGasEffPow = pow(pow(muGas, 1.0 - tlMixParamRho) *
1000 pow(muMixSolventGas, tlMixParamRho), 0.25);
1001 const Evaluation muSolventEffPow = pow(pow(muSolvent, 1.0 - tlMixParamRho) *
1002 pow(muMixSolventGasOil, tlMixParamRho), 0.25);
1004 const Evaluation oilGasEffSaturation = oilEffSat + gasEffSat;
1005 Evaluation sof = 0.0;
1006 Evaluation sgf = 0.0;
1007 if (oilGasEffSaturation.value() > cutOff) {
1008 sof = oilEffSat / oilGasEffSaturation;
1009 sgf = gasEffSat / oilGasEffSaturation;
1012 const Evaluation muSolventOilGasPow = muSolventPow * ((sgf * muOilPow) + (sof * muGasPow));
1014 Evaluation rhoMixSolventGasOil = 0.0;
1015 if (oilGasSolventEffSat.value() > cutOff) {
1016 rhoMixSolventGasOil = (rhoOil * oilEffSat / oilGasSolventEffSat) +
1017 (rhoGas * gasEffSat / oilGasSolventEffSat) +
1018 (rhoSolvent * solventEffSat / oilGasSolventEffSat);
1021 Evaluation rhoGasEff = 0.0;
1022 if (std::abs(muSolventPow.value() - muGasPow.value()) < cutOff) {
1023 rhoGasEff = ((1.0 - tlMixParamRho) * rhoGas) +
1024 (tlMixParamRho * rhoMixSolventGasOil);
1027 const Evaluation solventGasEffFraction = (muGasPow * (muSolventPow - muGasEffPow)) /
1028 (muGasEffPow * (muSolventPow - muGasPow));
1029 rhoGasEff = (rhoGas * solventGasEffFraction) + (rhoSolvent * (1.0 - solventGasEffFraction));
1032 Evaluation rhoSolventEff = 0.0;
1033 if (std::abs((muSolventOilGasPow.value() - (muOilPow.value() * muGasPow.value()))) < cutOff) {
1034 rhoSolventEff = ((1.0 - tlMixParamRho) * rhoSolvent) + (tlMixParamRho * rhoMixSolventGasOil);
1037 const Evaluation sfraction_se = (muSolventOilGasPow -
1038 muOilPow * muGasPow * muSolventPow / muSolventEffPow) /
1039 (muSolventOilGasPow - (muOilPow * muGasPow));
1040 rhoSolventEff = (rhoSolvent * sfraction_se) +
1041 (rhoGas * sgf * (1.0 - sfraction_se)) +
1042 (rhoOil * sof * (1.0 - sfraction_se));
1046 const unsigned pvtRegionIdx = asImp_().pvtRegionIndex();
1047 Evaluation bGasEff = rhoGasEff;
1048 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1049 bGasEff /= (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) +
1050 FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) * fs.Rv());
1052 bGasEff /= (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx));
1054 const Evaluation bSolventEff = rhoSolventEff / solventRefDensity();
1057 const Evaluation bg = fs.invB(gasPhaseIdx);
1058 const Evaluation bs = solventInverseFormationVolumeFactor();
1059 const Evaluation bg_eff = pmisc * bGasEff + (1.0 - pmisc) * bg;
1060 const Evaluation bs_eff = pmisc * bSolventEff + (1.0 - pmisc) * bs;
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];
1076 muGasEff = bg_eff / (pmisc * bGasEff / muGasEff + (1.0 - pmisc) * bg / muGas);
1077 mobg *= muGas / muGasEff;
1080 solventViscosity_ = bs_eff / (pmisc * bSolventEff / muSolventEff +
1081 (1.0 - pmisc) * bs / muSolvent);
1083 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1084 Evaluation rhoOilEff = 0.0;
1085 if (std::abs(muOilPow.value() - muSolventPow.value()) < cutOff) {
1086 rhoOilEff = ((1.0 - tlMixParamRho) * rhoOil) + (tlMixParamRho * rhoMixSolventGasOil);
1089 const Evaluation solventOilEffFraction = (muOilPow * (muOilEffPow - muSolventPow)) /
1090 (muOilEffPow * (muOilPow - muSolventPow));
1091 rhoOilEff = (rhoOil * solventOilEffFraction) + (rhoSolvent * (1.0 - solventOilEffFraction));
1093 const Evaluation bOilEff =
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];
1104 muOilEff = bo_eff / (pmisc * bOilEff / muOilEff + (1.0 - pmisc) * bo / muOil);
1105 mobo *= muOil / muOilEff;
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_;