static Evaluation krn(const Params ¶ms, const FluidState &fluidState) { typedef MathToolbox<Evaluation> Toolbox; typedef MathToolbox<typename FluidState::Scalar> FsToolbox; Scalar Swco = params.Swl(); Evaluation Sw = Toolbox::max(Evaluation(Swco), FsToolbox::template decay<Evaluation>(fluidState.saturation(waterPhaseIdx))); Evaluation Sg = FsToolbox::template decay<Evaluation>(fluidState.saturation(gasPhaseIdx)); Evaluation Sw_ow = Sg + Sw; Evaluation So_go = 1.0 - Sw_ow; const Evaluation& kro_ow = OilWaterMaterialLaw::twoPhaseSatKrn(params.oilWaterParams(), Sw_ow); const Evaluation& kro_go = GasOilMaterialLaw::twoPhaseSatKrw(params.gasOilParams(), So_go); // avoid the division by zero: chose a regularized kro which is used if Sw - Swco // < epsilon/2 and interpolate between the oridinary and the regularized kro between // epsilon and epsilon/2 const Scalar epsilon = 1e-5; if (Toolbox::scalarValue(Sw_ow) - Swco < epsilon) { Evaluation kro2 = (kro_ow + kro_go)/2;; if (Toolbox::scalarValue(Sw_ow) - Swco > epsilon/2) { Evaluation kro1 = (Sg*kro_go + (Sw - Swco)*kro_ow)/(Sw_ow - Swco); Evaluation alpha = (epsilon - (Sw_ow - Swco))/(epsilon/2); return kro2*alpha + kro1*(1 - alpha); } return kro2; } else return (Sg*kro_go + (Sw - Swco)*kro_ow)/(Sw_ow - Swco); }
static void updateHysteresis(Params ¶ms, const FluidState &fluidState) { typedef MathToolbox<typename FluidState::Scalar> FsToolbox; Scalar Sw = FsToolbox::scalarValue(fluidState.saturation(waterPhaseIdx)); Scalar So = FsToolbox::scalarValue(fluidState.saturation(oilPhaseIdx)); Scalar Sg = FsToolbox::scalarValue(fluidState.saturation(gasPhaseIdx)); if (params.inconsistentHysteresisUpdate()) { Sg = std::min(Scalar(1.0), std::max(Scalar(0.0), Sg)); // NOTE: the saturations which are passed to update the hysteresis curves are // inconsistent with the ones used to calculate the relative permabilities. We do // it like this anyway because (a) the saturation functions of opm-core do it // this way (b) the simulations seem to converge better (which is not too much // surprising actually, because the time step does not start on a kink in the // solution) and (c) the Eclipse 100 simulator may do the same. // // Though be aware that from a physical perspective this is definitively // incorrect! params.oilWaterParams().update(/*pcSw=*/1 - So, /*krwSw=*/1 - So, /*krn_Sw=*/1 - So); params.gasOilParams().update(/*pcSw=*/1 - Sg, /*krwSw=*/1 - Sg, /*krn_Sw=*/1 - Sg); } else { Scalar Swco = params.Swl(); Sw = std::min(Scalar(1.0), std::max(Scalar(0.0), Sw)); Sg = std::min(Scalar(1.0), std::max(Scalar(0.0), Sg)); Scalar Sw_ow = Sg + std::max(Swco, Sw); Scalar So_go = 1 + Sw_ow; params.oilWaterParams().update(/*pcSw=*/Sw, /*krwSw=*/1 - Sg, /*krnSw=*/Sw_ow); params.gasOilParams().update(/*pcSw=*/1 - Sg, /*krwSw=*/So_go, /*krnSw=*/1 - Sg); } }
static Evaluation krn(const Params ¶ms, const FluidState &fluidState) { typedef MathToolbox<typename FluidState::Scalar> FsToolbox; Scalar Swco = params.Swl(); const Evaluation& Sw = FsToolbox::template toLhs<Evaluation>(fluidState.saturation(waterPhaseIdx)); const Evaluation& Sg = FsToolbox::template toLhs<Evaluation>(fluidState.saturation(gasPhaseIdx)); Scalar krocw = OilWaterMaterialLaw::twoPhaseSatKrn(params.oilWaterParams(), Swco); Evaluation krow = OilWaterMaterialLaw::twoPhaseSatKrn(params.oilWaterParams(), Sw); Evaluation krw = OilWaterMaterialLaw::twoPhaseSatKrw(params.oilWaterParams(), Sw); Evaluation krg = GasOilMaterialLaw::twoPhaseSatKrn(params.gasOilParams(), 1 - Sg); Evaluation krog = GasOilMaterialLaw::twoPhaseSatKrw(params.gasOilParams(), 1 - Sg); return krocw*((krow/krocw + krw)*(krog/krocw + krg) - krw - krg); }
static Evaluation krn(const Params ¶ms, const FluidState &fluidState) { typedef MathToolbox<Evaluation> Toolbox; typedef MathToolbox<typename FluidState::Scalar> FsToolbox; // the Eclipse docu is inconsistent here: In some places the connate water // saturation is represented by "Swl", in others "Swco" is used. Scalar Swco = params.Swl(); Scalar Sowcr = params.Sowcr(); Scalar Sogcr = params.Sogcr(); Scalar Som = std::min(Sowcr, Sogcr); // minimum residual oil saturation Scalar eta = params.eta(); // exponent of the beta term const Evaluation& Sw = FsToolbox::template toLhs<Evaluation>(fluidState.saturation(waterPhaseIdx)); const Evaluation& So = FsToolbox::template toLhs<Evaluation>(fluidState.saturation(oilPhaseIdx)); const Evaluation& Sg = FsToolbox::template toLhs<Evaluation>(fluidState.saturation(gasPhaseIdx)); Evaluation SSw; if (Sw > Swco) SSw = (Sw - Swco)/(1 - Swco - Som); else SSw = 0.0; Evaluation SSo; if (So > Som) SSo = (So - Som)/(1 - Swco - Som); else SSo = 0.0; Evaluation SSg = Sg/(1 - Swco - Som); Scalar krocw = OilWaterMaterialLaw::twoPhaseSatKrn(params.oilWaterParams(), Swco); Evaluation krow = OilWaterMaterialLaw::twoPhaseSatKrn(params.oilWaterParams(), Sw); Evaluation krog = GasOilMaterialLaw::twoPhaseSatKrw(params.gasOilParams(), 1 - Sg); Evaluation beta = Toolbox::pow(SSo/((1 - SSw)*(1 - SSg)), eta); return beta*krow*krog/krocw; }