81 using Toolbox = MathToolbox<Evaluation>;
82 using SolventPvt =
typename BlackOilSolventParams<Scalar>::SolventPvt;
83 using Co2GasPvt =
typename BlackOilSolventParams<Scalar>::Co2GasPvt;
84 using H2GasPvt =
typename BlackOilSolventParams<Scalar>::H2GasPvt;
85 using BrineCo2Pvt =
typename BlackOilSolventParams<Scalar>::BrineCo2Pvt;
86 using BrineH2Pvt =
typename BlackOilSolventParams<Scalar>::BrineH2Pvt;
88 using TabulatedFunction =
typename BlackOilSolventParams<Scalar>::TabulatedFunction;
90 static constexpr unsigned solventSaturationIdx = Indices::solventSaturationIdx;
91 static constexpr unsigned contiSolventEqIdx = Indices::contiSolventEqIdx;
92 static constexpr unsigned enableSolvent = enableSolventV;
94 static constexpr bool blackoilConserveSurfaceVolume =
96 static constexpr int waterPhaseIdx = FluidSystem::waterPhaseIdx;
99 static constexpr double cutOff = 1e-12;
102 { params_ = params; }
108 { params_.solventPvt_ = value; }
110 static void setIsMiscible(
const bool isMiscible)
111 { params_.isMiscible_ = isMiscible; }
118 if constexpr (enableSolvent) {
127 Simulator& simulator)
129 if constexpr (enableSolvent) {
134 static bool primaryVarApplies(
unsigned pvIdx)
136 if constexpr (enableSolvent) {
137 return pvIdx == solventSaturationIdx;
144 static std::string primaryVarName([[maybe_unused]]
unsigned pvIdx)
146 assert(primaryVarApplies(pvIdx));
148 return "saturation_solvent";
151 static Scalar primaryVarWeight([[maybe_unused]]
unsigned pvIdx)
153 assert(primaryVarApplies(pvIdx));
156 return static_cast<Scalar
>(1.0);
159 static bool eqApplies(
unsigned eqIdx)
161 if constexpr (enableSolvent) {
162 return eqIdx == contiSolventEqIdx;
169 static std::string eqName([[maybe_unused]]
unsigned eqIdx)
171 assert(eqApplies(eqIdx));
173 return "conti^solvent";
176 static Scalar eqWeight([[maybe_unused]]
unsigned eqIdx)
178 assert(eqApplies(eqIdx));
181 return static_cast<Scalar
>(1.0);
184 template <
class StorageType>
185 OPM_HOST_DEVICE
static void addStorage(StorageType& storage,
186 const IntensiveQuantities& intQuants)
188 using LhsEval =
typename StorageType::value_type;
190 if constexpr (enableSolvent) {
191 if constexpr (blackoilConserveSurfaceVolume) {
192 storage[contiSolventEqIdx] +=
193 Toolbox::template decay<LhsEval>(intQuants.porosity()) *
194 Toolbox::template decay<LhsEval>(intQuants.solventSaturation()) *
195 Toolbox::template decay<LhsEval>(intQuants.solventInverseFormationVolumeFactor());
196 if (isSolubleInWater()) {
197 storage[contiSolventEqIdx] +=
198 Toolbox::template decay<LhsEval>(intQuants.porosity()) *
199 Toolbox::template decay<LhsEval>(intQuants.fluidState().saturation(waterPhaseIdx)) *
200 Toolbox::template decay<LhsEval>(intQuants.fluidState().invB(waterPhaseIdx)) *
201 Toolbox::template decay<LhsEval>(intQuants.rsSolw());
205 storage[contiSolventEqIdx] +=
206 Toolbox::template decay<LhsEval>(intQuants.porosity()) *
207 Toolbox::template decay<LhsEval>(intQuants.solventSaturation()) *
208 Toolbox::template decay<LhsEval>(intQuants.solventDensity());
209 if (isSolubleInWater()) {
210 storage[contiSolventEqIdx] +=
211 Toolbox::template decay<LhsEval>(intQuants.porosity()) *
212 Toolbox::template decay<LhsEval>(intQuants.fluidState().saturation(waterPhaseIdx)) *
213 Toolbox::template decay<LhsEval>(intQuants.fluidState().density(waterPhaseIdx)) *
214 Toolbox::template decay<LhsEval>(intQuants.rsSolw());
220 static void computeFlux([[maybe_unused]] RateVector& flux,
221 [[maybe_unused]]
const ElementContext& elemCtx,
222 [[maybe_unused]]
unsigned scvfIdx,
223 [[maybe_unused]]
unsigned timeIdx)
226 if constexpr (enableSolvent) {
227 const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, timeIdx);
229 const unsigned upIdx = extQuants.solventUpstreamIndex();
230 const unsigned inIdx = extQuants.interiorIndex();
231 const auto& up = elemCtx.intensiveQuantities(upIdx, timeIdx);
233 if constexpr (blackoilConserveSurfaceVolume) {
234 if (upIdx == inIdx) {
235 flux[contiSolventEqIdx] = extQuants.solventVolumeFlux() *
236 up.solventInverseFormationVolumeFactor();
239 flux[contiSolventEqIdx] = extQuants.solventVolumeFlux() *
240 decay<Scalar>(up.solventInverseFormationVolumeFactor());
244 if (isSolubleInWater()) {
245 if (upIdx == inIdx) {
246 flux[contiSolventEqIdx] +=
247 extQuants.volumeFlux(waterPhaseIdx) *
248 up.fluidState().invB(waterPhaseIdx) *
252 flux[contiSolventEqIdx] +=
253 extQuants.volumeFlux(waterPhaseIdx) *
254 decay<Scalar>(up.fluidState().invB(waterPhaseIdx)) *
255 decay<Scalar>(up.rsSolw());
260 if (upIdx == inIdx) {
261 flux[contiSolventEqIdx] = extQuants.solventVolumeFlux() * up.solventDensity();
264 flux[contiSolventEqIdx] = extQuants.solventVolumeFlux() * decay<Scalar>(up.solventDensity());
267 if (isSolubleInWater()) {
268 if (upIdx == inIdx) {
269 flux[contiSolventEqIdx] +=
270 extQuants.volumeFlux(waterPhaseIdx) *
271 up.fluidState().density(waterPhaseIdx) *
275 flux[contiSolventEqIdx] +=
276 extQuants.volumeFlux(waterPhaseIdx) *
277 decay<Scalar>(up.fluidState().density(waterPhaseIdx)) *
278 decay<Scalar>(up.rsSolw());
289 Scalar solventSaturation,
292 if constexpr (!enableSolvent) {
293 priVars.setPrimaryVarsMeaningSolvent(PrimaryVariables::SolventMeaning::Disabled);
297 if (solventSaturation > 0 || !isSolubleInWater()) {
298 priVars.setPrimaryVarsMeaningSolvent(PrimaryVariables::SolventMeaning::Ss);
299 priVars[solventSaturationIdx] = solventSaturation;
301 priVars.setPrimaryVarsMeaningSolvent(PrimaryVariables::SolventMeaning::Rsolw);
302 priVars[solventSaturationIdx] = solventRsw;
310 const PrimaryVariables& oldPv,
311 const EqVector& delta)
313 if constexpr (enableSolvent) {
315 newPv[solventSaturationIdx] = oldPv[solventSaturationIdx] - delta[solventSaturationIdx];
328 return static_cast<Scalar
>(0.0);
337 return std::abs(Toolbox::scalarValue(resid[contiSolventEqIdx]));
340 template <
class DofEntity>
341 static void serializeEntity(
const Model& model, std::ostream& outstream,
const DofEntity& dof)
343 if constexpr (enableSolvent) {
344 const unsigned dofIdx = model.dofMapper().index(dof);
346 const PrimaryVariables& priVars = model.solution(0)[dofIdx];
347 outstream << priVars[solventSaturationIdx];
351 template <
class DofEntity>
352 static void deserializeEntity(Model& model, std::istream& instream,
const DofEntity& dof)
354 if constexpr (enableSolvent) {
355 const unsigned dofIdx = model.dofMapper().index(dof);
357 PrimaryVariables& priVars0 = model.solution(0)[dofIdx];
358 PrimaryVariables& priVars1 = model.solution(1)[dofIdx];
360 instream >> priVars0[solventSaturationIdx];
363 priVars1 = priVars0[solventSaturationIdx];
367 static const SolventPvt& solventPvt()
368 {
return params_.solventPvt_; }
370 static const Co2GasPvt& co2GasPvt()
371 {
return params_.co2GasPvt_; }
373 static const H2GasPvt& h2GasPvt()
374 {
return params_.h2GasPvt_; }
376 static const BrineCo2Pvt& brineCo2Pvt()
377 {
return params_.brineCo2Pvt_; }
379 static const BrineH2Pvt& brineH2Pvt()
380 {
return params_.brineH2Pvt_; }
382 template <
class ElemContext>
383 static const TabulatedFunction& ssfnKrg(
const ElemContext& elemCtx,
387 const unsigned satnumRegionIdx =
388 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
389 return params_.ssfnKrg_[satnumRegionIdx];
392 template <
class ElemContext>
393 static const TabulatedFunction& ssfnKrs(
const ElemContext& elemCtx,
397 const unsigned satnumRegionIdx =
398 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
399 return params_.ssfnKrs_[satnumRegionIdx];
402 static const TabulatedFunction& ssfnKrg(
const unsigned satnumRegionIdx)
404 return params_.ssfnKrg_[satnumRegionIdx];
407 static const TabulatedFunction& ssfnKrs(
const unsigned satnumRegionIdx)
409 return params_.ssfnKrs_[satnumRegionIdx];
412 template <
class ElemContext>
413 static const TabulatedFunction& sof2Krn(
const ElemContext& elemCtx,
417 const unsigned satnumRegionIdx =
418 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
419 return params_.sof2Krn_[satnumRegionIdx];
422 template <
class ElemContext>
423 static const TabulatedFunction& misc(
const ElemContext& elemCtx,
427 const unsigned miscnumRegionIdx =
428 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
429 return params_.misc_[miscnumRegionIdx];
432 template <
class ElemContext>
433 static const TabulatedFunction& pmisc(
const ElemContext& elemCtx,
437 const unsigned miscnumRegionIdx =
438 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
439 return params_.pmisc_[miscnumRegionIdx];
442 template <
class ElemContext>
443 static const TabulatedFunction& msfnKrsg(
const ElemContext& elemCtx,
447 const unsigned satnumRegionIdx =
448 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
449 return params_.msfnKrsg_[satnumRegionIdx];
452 template <
class ElemContext>
453 static const TabulatedFunction& msfnKro(
const ElemContext& elemCtx,
457 const unsigned satnumRegionIdx =
458 elemCtx.problem().satnumRegionIndex(elemCtx, scvIdx, timeIdx);
459 return params_.msfnKro_[satnumRegionIdx];
462 template <
class ElemContext>
463 static const TabulatedFunction& sorwmis(
const ElemContext& elemCtx,
467 const unsigned miscnumRegionIdx =
468 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
469 return params_.sorwmis_[miscnumRegionIdx];
472 template <
class ElemContext>
473 static const TabulatedFunction& sgcwmis(
const ElemContext& elemCtx,
477 const unsigned miscnumRegionIdx =
478 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
479 return params_.sgcwmis_[miscnumRegionIdx];
482 template <
class ElemContext>
483 static const TabulatedFunction& tlPMixTable(
const ElemContext& elemCtx,
487 const unsigned miscnumRegionIdx =
488 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
489 return params_.tlPMixTable_[miscnumRegionIdx];
492 template <
class ElemContext>
493 static Scalar tlMixParamViscosity(
const ElemContext& elemCtx,
497 const unsigned miscnumRegionIdx =
498 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
499 return params_.tlMixParamViscosity_[miscnumRegionIdx];
503 template <
class ElemContext>
504 static Scalar tlMixParamDensity(
const ElemContext& elemCtx,
508 const unsigned miscnumRegionIdx =
509 elemCtx.problem().miscnumRegionIndex(elemCtx, scvIdx, timeIdx);
510 return params_.tlMixParamDensity_[miscnumRegionIdx];
513 static bool isMiscible()
514 {
return params_.isMiscible_; }
516 template <
class Value>
517 static Value solubilityLimit(
unsigned pvtIdx,
const Value& temperature,
518 const Value& pressure,
const Value& saltConcentration)
520 if (!isSolubleInWater()) {
524 assert(isCO2Sol() || isH2Sol());
526 return brineCo2Pvt().saturatedGasDissolutionFactor(pvtIdx, temperature,
527 pressure, saltConcentration);
530 return brineH2Pvt().saturatedGasDissolutionFactor(pvtIdx, temperature,
531 pressure, saltConcentration);
535 static bool isSolubleInWater()
536 {
return params_.rsSolw_active_; }
538 static bool isCO2Sol()
539 {
return params_.co2sol_; }
541 static bool isH2Sol()
542 {
return params_.h2sol_; }
545 static BlackOilSolventParams<Scalar> params_;
579 static constexpr int solventSaturationIdx = Indices::solventSaturationIdx;
580 static constexpr int oilPhaseIdx = FluidSystem::oilPhaseIdx;
581 static constexpr int gasPhaseIdx = FluidSystem::gasPhaseIdx;
582 static constexpr int waterPhaseIdx = FluidSystem::waterPhaseIdx;
583 static constexpr double cutOff = SolventModule::cutOff;
597 const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
601 void solventPreSatFuncUpdate_(
const PrimaryVariables& priVars,
602 const unsigned timeIdx,
605 auto& fs = asImp_().fluidState_;
606 Evaluation solventSat{0.0};
607 if (priVars.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
608 solventSat = priVars.makeEvaluation(solventSaturationIdx, timeIdx, linearizationType);
611 fs.setSolventSaturation(solventSat);
613 hydrocarbonSaturation_ = fs.saturation(gasPhaseIdx);
616 if (solventSaturation().value() < cutOff) {
622 fs.setSaturation(gasPhaseIdx, hydrocarbonSaturation_ + solventSat);
636 const PrimaryVariables& priVars = elemCtx.primaryVars(dofIdx, timeIdx);
637 this->
solventPostSatFuncUpdate_(elemCtx.problem(), priVars, elemCtx.globalSpaceIndex(dofIdx, timeIdx), timeIdx, elemCtx.linearizationType());
642 template <
class Problem>
643 struct ProblemAndCellIndexOnlyContext
645 const Problem& problem_;
647 const Problem& problem()
const {
return problem_; }
648 unsigned int globalSpaceIndex([[maybe_unused]]
const unsigned int spaceIdx,
649 [[maybe_unused]]
const unsigned int timeIdx)
const
656 void solventPostSatFuncUpdate_(
const Problem& problem,
657 const PrimaryVariables& priVars,
658 const unsigned globalSpaceIdx,
659 const unsigned timeIdx,
660 const LinearizationType linearizationType)
664 auto& fs = asImp_().fluidState_;
665 fs.setSaturation(gasPhaseIdx, hydrocarbonSaturation_);
668 Evaluation rsSolw{0.0};
669 if (priVars.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Ss) {
670 rsSolw = SolventModule::solubilityLimit(asImp_().pvtRegionIndex(),
671 fs.temperature(waterPhaseIdx),
672 fs.pressure(waterPhaseIdx),
673 fs.saltConcentration());
674 }
else if (priVars.primaryVarsMeaningSolvent() == PrimaryVariables::SolventMeaning::Rsolw) {
675 rsSolw = priVars.makeEvaluation(solventSaturationIdx, timeIdx, linearizationType);
678 fs.setRsSolw(rsSolw);
680 solventMobility_ = 0.0;
683 if (solventSaturation().value() < cutOff) {
687 ProblemAndCellIndexOnlyContext<Problem> elemCtx{problem, globalSpaceIdx};
691 if (SolventModule::isMiscible()) {
692 const Evaluation& p =
693 FluidSystem::phaseIsActive(oilPhaseIdx)
694 ? fs.pressure(oilPhaseIdx)
695 : fs.pressure(gasPhaseIdx);
696 const Evaluation pmisc =
697 SolventModule::pmisc(elemCtx, dofIdx, timeIdx).eval(p,
true);
698 const Evaluation& pgImisc = fs.pressure(gasPhaseIdx);
701 Evaluation pgMisc = 0.0;
702 std::array<Evaluation, numPhases> pC;
703 const auto& materialParams = problem.materialLawParams(elemCtx, dofIdx, timeIdx);
704 MaterialLaw::capillaryPressures(pC, materialParams, fs);
707 if (priVars.primaryVarsMeaningPressure() == PrimaryVariables::PressureMeaning::Pg) {
708 pgMisc = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx,
712 const Evaluation& po =
713 priVars.makeEvaluation(Indices::pressureSwitchIdx,
714 timeIdx, linearizationType);
715 pgMisc = po + (pC[gasPhaseIdx] - pC[oilPhaseIdx]);
718 fs.setPressure(gasPhaseIdx, pmisc * pgMisc + (1.0 - pmisc) * pgImisc);
721 const Evaluation gasSolventSat = hydrocarbonSaturation_ + solventSaturation();
723 if (gasSolventSat.value() < cutOff) {
727 const Evaluation Fhydgas = hydrocarbonSaturation_ / gasSolventSat;
728 const Evaluation Fsolgas = solventSaturation() / gasSolventSat;
731 if (SolventModule::isMiscible() && FluidSystem::phaseIsActive(oilPhaseIdx)) {
732 const auto& misc = SolventModule::misc(elemCtx, dofIdx, timeIdx);
733 const auto& pmisc = SolventModule::pmisc(elemCtx, dofIdx, timeIdx);
734 const Evaluation& p =
735 FluidSystem::phaseIsActive(oilPhaseIdx)
736 ? fs.pressure(oilPhaseIdx)
737 : fs.pressure(gasPhaseIdx);
738 const Evaluation miscibility =
739 misc.eval(Fsolgas,
true) *
743 const unsigned cellIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx);
744 const auto& materialLawManager = elemCtx.problem().materialLawManager();
745 const auto& scaledDrainageInfo =
746 materialLawManager->oilWaterScaledEpsInfoDrainage(cellIdx);
748 const Scalar sogcr = scaledDrainageInfo.Sogcr;
749 Evaluation sor = sogcr;
750 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
751 const Evaluation& sw = fs.saturation(waterPhaseIdx);
752 const auto& sorwmis = SolventModule::sorwmis(elemCtx, dofIdx, timeIdx);
754 sorwmis.eval(sw,
true) + (1.0 - miscibility) * sogcr;
756 const Scalar sgcr = scaledDrainageInfo.Sgcr;
757 Evaluation sgc = sgcr;
758 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
759 const Evaluation& sw = fs.saturation(waterPhaseIdx);
760 const auto& sgcwmis = SolventModule::sgcwmis(elemCtx, dofIdx, timeIdx);
761 sgc = miscibility * sgcwmis.eval(sw,
true) + (1.0 - miscibility) * sgcr;
764 Evaluation oilGasSolventSat = gasSolventSat;
765 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
766 oilGasSolventSat += fs.saturation(oilPhaseIdx);
768 const Evaluation zero = 0.0;
769 const Evaluation oilGasSolventEffSat = std::max(oilGasSolventSat - sor - sgc, zero);
771 Evaluation F_totalGas = 0.0;
772 if (oilGasSolventEffSat.value() > cutOff) {
773 const Evaluation gasSolventEffSat = std::max(gasSolventSat - sgc, zero);
774 F_totalGas = gasSolventEffSat / oilGasSolventEffSat;
776 const auto& msfnKro = SolventModule::msfnKro(elemCtx, dofIdx, timeIdx);
777 const auto& msfnKrsg = SolventModule::msfnKrsg(elemCtx, dofIdx, timeIdx);
778 const auto& sof2Krn = SolventModule::sof2Krn(elemCtx, dofIdx, timeIdx);
780 const Evaluation mkrgt = msfnKrsg.eval(F_totalGas,
true) *
781 sof2Krn.eval(oilGasSolventSat,
true);
782 const Evaluation mkro = msfnKro.eval(F_totalGas,
true) *
783 sof2Krn.eval(oilGasSolventSat,
true);
785 Evaluation& kro = asImp_().mobility_[oilPhaseIdx];
786 Evaluation& krg = asImp_().mobility_[gasPhaseIdx];
789 krg *= 1.0 - miscibility;
790 krg += miscibility * mkrgt;
791 kro *= 1.0 - miscibility;
792 kro += miscibility * mkro;
796 const auto& ssfnKrg = SolventModule::ssfnKrg(elemCtx, dofIdx, timeIdx);
797 const auto& ssfnKrs = SolventModule::ssfnKrs(elemCtx, dofIdx, timeIdx);
799 Evaluation& krg = asImp_().mobility_[gasPhaseIdx];
800 solventMobility_ = krg * ssfnKrs.eval(Fsolgas,
true);
801 krg *= ssfnKrg.eval(Fhydgas,
true);
814 const auto& iq = asImp_();
815 auto& fs = asImp_().fluidState_;
816 const unsigned pvtRegionIdx = iq.pvtRegionIndex();
817 const Evaluation& T = iq.fluidState().temperature(gasPhaseIdx);
818 const Evaluation& p = iq.fluidState().pressure(gasPhaseIdx);
820 Evaluation solventInvB;
821 const Evaluation rv = 0.0;
822 const Evaluation rvw = 0.0;
823 if (SolventModule::isCO2Sol() || SolventModule::isH2Sol() ){
824 if (SolventModule::isCO2Sol()) {
825 const auto& co2gasPvt = SolventModule::co2GasPvt();
827 co2gasPvt.inverseFormationVolumeFactor(pvtRegionIdx, T, p, rv, rvw);
828 solventRefDensity_ = co2gasPvt.gasReferenceDensity(pvtRegionIdx);
829 solventViscosity_ = co2gasPvt.viscosity(pvtRegionIdx, T, p, rv, rvw);
831 const auto& brineCo2Pvt = SolventModule::brineCo2Pvt();
832 const auto& bw = brineCo2Pvt.inverseFormationVolumeFactor(pvtRegionIdx, T, p, rsSolw());
834 const auto denw = bw * brineCo2Pvt.waterReferenceDensity(pvtRegionIdx) +
835 rsSolw() * bw * brineCo2Pvt.gasReferenceDensity(pvtRegionIdx);
836 fs.setDensity(waterPhaseIdx, denw);
837 fs.setInvB(waterPhaseIdx, bw);
838 Evaluation& mobw = asImp_().mobility_[waterPhaseIdx];
839 const auto& muWat = fs.viscosity(waterPhaseIdx);
840 const auto& muWatEff = brineCo2Pvt.viscosity(pvtRegionIdx, T, p, rsSolw());
841 mobw *= muWat / muWatEff;
843 const auto& h2gasPvt = SolventModule::h2GasPvt();
845 h2gasPvt.inverseFormationVolumeFactor(pvtRegionIdx, T, p, rv, rvw);
846 solventRefDensity_ = h2gasPvt.gasReferenceDensity(pvtRegionIdx);
847 solventViscosity_ = h2gasPvt.viscosity(pvtRegionIdx, T, p, rv, rvw);
849 const auto& brineH2Pvt = SolventModule::brineH2Pvt();
850 const auto& bw = brineH2Pvt.inverseFormationVolumeFactor(pvtRegionIdx, T, p, rsSolw());
852 const auto denw = bw * brineH2Pvt.waterReferenceDensity(pvtRegionIdx) +
853 rsSolw() * bw * brineH2Pvt.gasReferenceDensity(pvtRegionIdx);
854 fs.setDensity(waterPhaseIdx, denw);
855 fs.setInvB(waterPhaseIdx, bw);
856 Evaluation& mobw = asImp_().mobility_[waterPhaseIdx];
857 const auto& muWat = fs.viscosity(waterPhaseIdx);
858 const auto& muWatEff = brineH2Pvt.viscosity(pvtRegionIdx, T, p, rsSolw());
859 mobw *= muWat / muWatEff;
862 const auto& solventPvt = SolventModule::solventPvt();
863 solventInvB = solventPvt.inverseFormationVolumeFactor(pvtRegionIdx, T, p);
864 solventRefDensity_ = solventPvt.referenceDensity(pvtRegionIdx);
865 solventViscosity_ = solventPvt.viscosity(pvtRegionIdx, T, p);
869 fs.setSolventInvB(solventInvB);
870 fs.setSolventDensity(solventInvB * solventRefDensity_);
872 effectiveProperties(elemCtx, scvIdx, timeIdx);
874 solventMobility_ /= solventViscosity_;
877 Evaluation solventSaturation()
const
878 {
return asImp_().fluidState_.solventSaturation(); }
880 Evaluation rsSolw()
const
881 {
return asImp_().fluidState_.rsSolw(); }
883 Evaluation solventDensity()
const
884 {
return asImp_().fluidState_.solventDensity(); }
886 const Evaluation& solventViscosity()
const
887 {
return solventViscosity_; }
889 const Evaluation& solventMobility()
const
890 {
return solventMobility_; }
892 Evaluation solventInverseFormationVolumeFactor()
const
893 {
return asImp_().fluidState_.solventInvB(); }
896 Scalar solventRefDensity()
const
897 {
return solventRefDensity_; }
902 void effectiveProperties(
const ElementContext& elemCtx,
906 if (!SolventModule::isMiscible()) {
912 if (solventSaturation() < cutOff) {
918 auto& fs = asImp_().fluidState_;
921 Evaluation oilEffSat = 0.0;
922 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
923 oilEffSat = fs.saturation(oilPhaseIdx);
925 Evaluation gasEffSat = fs.saturation(gasPhaseIdx);
926 Evaluation solventEffSat = solventSaturation();
927 if (FluidSystem::phaseIsActive(waterPhaseIdx)) {
928 const auto& sorwmis = SolventModule::sorwmis(elemCtx, scvIdx, timeIdx);
929 const auto& sgcwmis = SolventModule::sgcwmis(elemCtx, scvIdx, timeIdx);
930 const Evaluation zero = 0.0;
931 const Evaluation& sw = fs.saturation(waterPhaseIdx);
932 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
933 oilEffSat = std::max(oilEffSat - sorwmis.eval(sw,
true), zero);
935 gasEffSat = std::max(gasEffSat - sgcwmis.eval(sw,
true), zero);
936 solventEffSat = std::max(solventEffSat - sgcwmis.eval(sw,
true), zero);
938 const Evaluation oilGasSolventEffSat = oilEffSat + gasEffSat + solventEffSat;
939 const Evaluation oilSolventEffSat = oilEffSat + solventEffSat;
940 const Evaluation solventGasEffSat = solventEffSat + gasEffSat;
947 const Evaluation& p =
948 FluidSystem::phaseIsActive(oilPhaseIdx)
949 ? fs.pressure(oilPhaseIdx)
950 : fs.pressure(gasPhaseIdx);
952 const auto& pmiscTable = SolventModule::pmisc(elemCtx, scvIdx, timeIdx);
953 const Evaluation pmisc = pmiscTable.eval(p,
true);
954 const auto& tlPMixTable = SolventModule::tlPMixTable(elemCtx, scvIdx, timeIdx);
955 const Evaluation tlMixParamMu = SolventModule::tlMixParamViscosity(elemCtx, scvIdx, timeIdx) *
956 tlPMixTable.eval(p,
true);
958 const Evaluation& muGas = fs.viscosity(gasPhaseIdx);
959 const Evaluation& muSolvent = solventViscosity_;
961 assert(muGas.value() > 0);
962 assert(muSolvent.value() > 0);
963 const Evaluation muGasPow = pow(muGas, 0.25);
964 const Evaluation muSolventPow = pow(muSolvent, 0.25);
966 Evaluation muMixSolventGas = muGas;
967 if (solventGasEffSat > cutOff) {
968 muMixSolventGas *= muSolvent / pow(((gasEffSat / solventGasEffSat) * muSolventPow) +
969 ((solventEffSat / solventGasEffSat) * muGasPow), 4.0);
972 Evaluation muOil = 1.0;
973 Evaluation muOilPow = 1.0;
974 Evaluation muMixOilSolvent = 1.0;
975 Evaluation muOilEff = 1.0;
976 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
977 muOil = fs.viscosity(oilPhaseIdx);
978 assert(muOil.value() > 0);
979 muOilPow = pow(muOil, 0.25);
980 muMixOilSolvent = muOil;
981 if (oilSolventEffSat > cutOff) {
982 muMixOilSolvent *= muSolvent / pow(((oilEffSat / oilSolventEffSat) * muSolventPow) +
983 ((solventEffSat / oilSolventEffSat) * muOilPow), 4.0);
986 muOilEff = pow(muOil,1.0 - tlMixParamMu) * pow(muMixOilSolvent, tlMixParamMu);
988 Evaluation muMixSolventGasOil = muOil;
989 if (oilGasSolventEffSat > cutOff) {
990 muMixSolventGasOil *= muSolvent * muGas / pow(((oilEffSat / oilGasSolventEffSat) *
991 muSolventPow * muGasPow) +
992 ((solventEffSat / oilGasSolventEffSat) *
993 muOilPow * muGasPow) +
994 ((gasEffSat / oilGasSolventEffSat) *
995 muSolventPow * muOilPow), 4.0);
998 Evaluation muGasEff = pow(muGas,1.0 - tlMixParamMu) * pow(muMixSolventGas, tlMixParamMu);
999 const Evaluation muSolventEff = pow(muSolvent,1.0 - tlMixParamMu) * pow(muMixSolventGasOil, tlMixParamMu);
1002 const Evaluation& rhoGas = fs.density(gasPhaseIdx);
1003 Evaluation rhoOil = 0.0;
1004 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1005 rhoOil = fs.density(oilPhaseIdx);
1008 Evaluation rhoSolvent = solventDensity();
1014 const Evaluation tlMixParamRho = SolventModule::tlMixParamDensity(elemCtx, scvIdx, timeIdx) *
1015 tlPMixTable.eval(p,
true);
1019 const Evaluation muOilEffPow = pow(pow(muOil, 1.0 - tlMixParamRho) *
1020 pow(muMixOilSolvent, tlMixParamRho), 0.25);
1021 const Evaluation muGasEffPow = pow(pow(muGas, 1.0 - tlMixParamRho) *
1022 pow(muMixSolventGas, tlMixParamRho), 0.25);
1023 const Evaluation muSolventEffPow = pow(pow(muSolvent, 1.0 - tlMixParamRho) *
1024 pow(muMixSolventGasOil, tlMixParamRho), 0.25);
1026 const Evaluation oilGasEffSaturation = oilEffSat + gasEffSat;
1027 Evaluation sof = 0.0;
1028 Evaluation sgf = 0.0;
1029 if (oilGasEffSaturation.value() > cutOff) {
1030 sof = oilEffSat / oilGasEffSaturation;
1031 sgf = gasEffSat / oilGasEffSaturation;
1034 const Evaluation muSolventOilGasPow = muSolventPow * ((sgf * muOilPow) + (sof * muGasPow));
1036 Evaluation rhoMixSolventGasOil = 0.0;
1037 if (oilGasSolventEffSat.value() > cutOff) {
1038 rhoMixSolventGasOil = (rhoOil * oilEffSat / oilGasSolventEffSat) +
1039 (rhoGas * gasEffSat / oilGasSolventEffSat) +
1040 (rhoSolvent * solventEffSat / oilGasSolventEffSat);
1043 Evaluation rhoGasEff = 0.0;
1044 if (std::abs(muSolventPow.value() - muGasPow.value()) < cutOff) {
1045 rhoGasEff = ((1.0 - tlMixParamRho) * rhoGas) +
1046 (tlMixParamRho * rhoMixSolventGasOil);
1049 const Evaluation solventGasEffFraction = (muGasPow * (muSolventPow - muGasEffPow)) /
1050 (muGasEffPow * (muSolventPow - muGasPow));
1051 rhoGasEff = (rhoGas * solventGasEffFraction) + (rhoSolvent * (1.0 - solventGasEffFraction));
1054 Evaluation rhoSolventEff = 0.0;
1055 if (std::abs((muSolventOilGasPow.value() - (muOilPow.value() * muGasPow.value()))) < cutOff) {
1056 rhoSolventEff = ((1.0 - tlMixParamRho) * rhoSolvent) + (tlMixParamRho * rhoMixSolventGasOil);
1059 const Evaluation sfraction_se = (muSolventOilGasPow -
1060 muOilPow * muGasPow * muSolventPow / muSolventEffPow) /
1061 (muSolventOilGasPow - (muOilPow * muGasPow));
1062 rhoSolventEff = (rhoSolvent * sfraction_se) +
1063 (rhoGas * sgf * (1.0 - sfraction_se)) +
1064 (rhoOil * sof * (1.0 - sfraction_se));
1068 const unsigned pvtRegionIdx = asImp_().pvtRegionIndex();
1069 Evaluation bGasEff = rhoGasEff;
1070 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1071 bGasEff /= (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) +
1072 FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) * fs.Rv());
1074 bGasEff /= (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx));
1076 const Evaluation bSolventEff = rhoSolventEff / solventRefDensity();
1079 const Evaluation bg = fs.invB(gasPhaseIdx);
1080 const Evaluation bs = solventInverseFormationVolumeFactor();
1081 const Evaluation bg_eff = pmisc * bGasEff + (1.0 - pmisc) * bg;
1082 const Evaluation bs_eff = pmisc * bSolventEff + (1.0 - pmisc) * bs;
1085 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1086 fs.setDensity(gasPhaseIdx,
1088 (FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) +
1089 FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx)*fs.Rv()));
1091 fs.setDensity(gasPhaseIdx,
1092 bg_eff * FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx));
1094 rhoSolvent = bs_eff * solventRefDensity();
1095 fs.setSolventDensity(rhoSolvent);
1098 Evaluation& mobg = asImp_().mobility_[gasPhaseIdx];
1099 muGasEff = bg_eff / (pmisc * bGasEff / muGasEff + (1.0 - pmisc) * bg / muGas);
1100 mobg *= muGas / muGasEff;
1103 solventViscosity_ = bs_eff / (pmisc * bSolventEff / muSolventEff +
1104 (1.0 - pmisc) * bs / muSolvent);
1106 if (FluidSystem::phaseIsActive(oilPhaseIdx)) {
1107 Evaluation rhoOilEff = 0.0;
1108 if (std::abs(muOilPow.value() - muSolventPow.value()) < cutOff) {
1109 rhoOilEff = ((1.0 - tlMixParamRho) * rhoOil) + (tlMixParamRho * rhoMixSolventGasOil);
1112 const Evaluation solventOilEffFraction = (muOilPow * (muOilEffPow - muSolventPow)) /
1113 (muOilEffPow * (muOilPow - muSolventPow));
1114 rhoOilEff = (rhoOil * solventOilEffFraction) + (rhoSolvent * (1.0 - solventOilEffFraction));
1116 const Evaluation bOilEff =
1117 rhoOilEff / (FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) +
1118 FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) * fs.Rs());
1119 const Evaluation bo = fs.invB(oilPhaseIdx);
1120 const Evaluation bo_eff = pmisc * bOilEff + (1.0 - pmisc) * bo;
1121 fs.setDensity(oilPhaseIdx,
1122 bo_eff * (FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx) +
1123 FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx) * fs.Rs()));
1126 Evaluation& mobo = asImp_().mobility_[oilPhaseIdx];
1127 muOilEff = bo_eff / (pmisc * bOilEff / muOilEff + (1.0 - pmisc) * bo / muOil);
1128 mobo *= muOil / muOilEff;
1133 Implementation& asImp_()
1134 {
return *
static_cast<Implementation*
>(
this); }
1136 const Implementation& asImp_()
const
1137 {
return *
static_cast<const Implementation*
>(
this); }
1139 Evaluation hydrocarbonSaturation_;
1140 Evaluation solventViscosity_;
1141 Evaluation solventMobility_;
1143 Scalar solventRefDensity_;