51 using EffLawParams =
typename EffLawT::Params;
52 using Scalar =
typename EffLawParams::Traits::Scalar;
55 using Traits =
typename EffLawParams::Traits;
60 result.deltaSwImbKrn_ = 1.0;
64 result.initialImb_ =
true;
65 result.pcSwMic_ = 3.0;
66 result.krnSwMdc_ = 4.0;
67 result.krwSwMdc_ = 4.5;
80 if (
config().enableHysteresis()) {
81 if (
config().krHysteresisModel() == 2 ||
config().krHysteresisModel() == 3 ||
config().krHysteresisModel() == 4 ||
config().pcHysteresisModel() == 0) {
82 C_ = 1.0/(Sncri_ - Sncrd_ + 1.0e-12) - 1.0/(Snmaxd_ - Sncrd_);
85 if (
config().krHysteresisModel() == 4) {
86 Cw_ = 1.0/(Swcri_ - Swcrd_ + 1.0e-12) - 1.0/(Swmaxd_ - Swcrd_);
87 Krwd_sncri_ = EffLawT::twoPhaseSatKrw(
drainageParams(), 1 - Sncri());
89 updateDynamicParams_();
91 EnsureFinalized :: finalize();
109 void setWagConfig(std::shared_ptr<WagHysteresisConfig::WagHysteresisConfigRecord> value)
119 {
return *wagConfig_; }
128 drainageParams_ = value;
130 oilWaterSystem_ = (twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
131 gasWaterSystem_ = (twoPhaseSystem == EclTwoPhaseSystemType::GasWater);
132 gasOilSystem_ = (twoPhaseSystem == EclTwoPhaseSystemType::GasOil);
134 if (!
config().enableHysteresis())
136 if (
config().krHysteresisModel() == 2 ||
config().krHysteresisModel() == 3 ||
config().krHysteresisModel() == 4 ||
config().pcHysteresisModel() == 0 || gasOilHysteresisWAG()) {
138 if (twoPhaseSystem == EclTwoPhaseSystemType::GasOil) {
139 Sncrd_ = info.Sgcr + info.Swl;
141 Snmaxd_ = info.Sgu + info.Swl;
142 KrndMax_ = EffLawT::twoPhaseSatKrn(
drainageParams(), 1.0-Snmaxd_);
144 else if (twoPhaseSystem == EclTwoPhaseSystemType::GasWater) {
148 KrndMax_ = EffLawT::twoPhaseSatKrn(
drainageParams(), 1.0-Snmaxd_);
151 assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
154 Snmaxd_ = 1.0 - info.Swl - info.Sgl;
155 KrndMax_ = EffLawT::twoPhaseSatKrn(
drainageParams(), 1.0-Snmaxd_);
159 if (
config().krHysteresisModel() == 4) {
161 if (twoPhaseSystem == EclTwoPhaseSystemType::GasOil) {
162 Swmaxd_ = 1.0 - info.Sgl - info.Swl;
165 else if (twoPhaseSystem == EclTwoPhaseSystemType::GasWater) {
170 assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
177 if (
config().pcHysteresisModel() == 0) {
178 if (twoPhaseSystem == EclTwoPhaseSystemType::GasOil) {
179 pcmaxd_ = info.maxPcgo;
180 }
else if (twoPhaseSystem == EclTwoPhaseSystemType::GasWater) {
181 pcmaxd_ = info.maxPcgo + info.maxPcow;
184 assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
190 if (gasOilHysteresisWAG()) {
191 swatImbStart_ = Swco_;
192 swatImbStartNxt_ = -1.0;
194 krnSwDrainStart_ = Sncrd_;
195 krnSwDrainStartNxt_ = Sncrd_;
197 krnImbStartNxt_ = 0.0;
198 krnDrainStart_ = 0.0;
199 krnDrainStartNxt_ = 0.0;
202 krnSwImbStart_ = Sncrd_;
212 {
return drainageParams_; }
215 {
return drainageParams_; }
224 imbibitionParams_ = value;
226 if (!
config().enableHysteresis())
230 if (twoPhaseSystem == EclTwoPhaseSystemType::GasOil) {
231 Sncri_ = info.Sgcr + info.Swl;
234 else if (twoPhaseSystem == EclTwoPhaseSystemType::GasWater) {
239 assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
245 if (
config().pcHysteresisModel() == 0) {
246 if (twoPhaseSystem == EclTwoPhaseSystemType::GasOil) {
247 Swmaxi_ = 1.0 - info.Sgl - info.Swl;
248 pcmaxi_ = info.maxPcgo;
249 }
else if (twoPhaseSystem == EclTwoPhaseSystemType::GasWater) {
251 pcmaxi_ = info.maxPcgo + info.maxPcow;
254 assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
256 pcmaxi_ = info.maxPcow;
260 if (
config().krHysteresisModel() == 4) {
270 {
return imbibitionParams_; }
273 {
return imbibitionParams_; }
282 Scalar pcSwMic()
const
289 {
return initialImb_; }
297 { krwSwMdc_ = value; };
305 {
return krwSwMdc_; };
313 { krnSwMdc_ = value; }
321 {
return krnSwMdc_; }
351 { deltaSwImbKrn_ = value; }
361 {
return deltaSwImbKrn_; }
370 Scalar Swmaxi()
const
385 Scalar SnTrapped(
bool maximumTrapping)
const
387 if(!maximumTrapping && isDrain_)
391 if(
config().krHysteresisModel() > 1 )
394 return Sncri_ + deltaSwImbKrn_;
397 Scalar SnStranded(Scalar sg, Scalar krg)
const {
398 const Scalar sn = EffLawT::twoPhaseSatKrnInv(drainageParams_, krg);
399 return sg - (1.0 - sn) + Sncrd_;
402 Scalar SwTrapped()
const
404 if(
config().krHysteresisModel() == 0 ||
config().krHysteresisModel() == 2)
407 if(
config().krHysteresisModel() == 1 ||
config().krHysteresisModel() == 3)
411 if(
config().krHysteresisModel() == 4 )
419 Scalar SncrtWAG()
const
420 {
return SncrtWAG_; }
422 Scalar Snmaxd()
const
425 Scalar Swmaxd()
const
429 {
return 1.0 - krnSwMdc_; }
432 {
return krwSwMdc_; }
437 Scalar krnWght()
const
438 {
return KrndHy_/KrndMax_; }
440 template <
class Evaluation>
441 Evaluation krwWght(
const Evaluation& Krwd)
const
444 Scalar deltaKrw = Krwi_snrmax() - Krwd_sncri();
445 Scalar Krwi_snr = Krwd_sncrt() + deltaKrw * (Sncrt() / max(1e-12, Sncri()));
446 return (Krwi_snr - Krwd) / ( Krwi_snrmax() - Krwi_snmax());
449 Scalar krwdMax()
const
453 Scalar KrwdHy()
const
459 Scalar Krwd_sncri()
const
464 Scalar Krwi_snmax()
const
469 Scalar Krwi_snrmax()
const
474 Scalar Krwd_sncrt()
const
479 Scalar pcWght() const
482 return EffLawT::twoPhaseSatPcnw(
drainageParams(), 0.0)/(pcmaxi_+1e-6);
484 return pcmaxd_/(pcmaxi_+1e-6);
487 Scalar curvatureCapPrs()
const
488 {
return curvatureCapPrs_;}
490 bool gasOilHysteresisWAG()
const
491 {
return (
config().enableWagHysteresis() && gasOilSystem_ &&
wagConfig().wagGasFlag()) ; }
493 Scalar reductionDrain()
const
494 {
return std::pow(Swco_/(swatImbStart_+tolWAG_*
wagConfig().wagWaterThresholdSaturation()),
wagConfig().wagSecondaryDrainageReduction());}
496 Scalar reductionDrainNxt()
const
497 {
return std::pow(Swco_/(swatImbStartNxt_+tolWAG_*
wagConfig().wagWaterThresholdSaturation()),
wagConfig().wagSecondaryDrainageReduction());}
499 bool threePhaseState()
const
500 {
return (swatImbStart_ > (Swco_ +
wagConfig().wagWaterThresholdSaturation()) ); }
502 Scalar nState()
const
505 Scalar krnSwDrainRevert()
const
506 {
return krnSwDrainRevert_;}
508 Scalar krnDrainStart()
const
509 {
return krnDrainStart_;}
511 Scalar krnDrainStartNxt()
const
512 {
return krnDrainStartNxt_;}
514 Scalar krnImbStart()
const
515 {
return krnImbStart_;}
517 Scalar krnImbStartNxt()
const
518 {
return krnImbStartNxt_;}
520 Scalar krnSwWAG()
const
523 Scalar krnSwDrainStart()
const
524 {
return krnSwDrainStart_;}
526 Scalar krnSwDrainStartNxt()
const
527 {
return krnSwDrainStartNxt_;}
529 Scalar krnSwImbStart()
const
530 {
return krnSwImbStart_;}
532 Scalar tolWAG()
const
535 template <
class Evaluation>
536 Evaluation computeSwf(
const Evaluation& Sw)
const
538 Evaluation SgT = 1.0 - Sw - SncrtWAG();
539 Scalar SgCut =
wagConfig().wagImbCurveLinearFraction()*(Snhy()- SncrtWAG());
540 Evaluation Swf = 1.0;
545 Swf -= (Sncrd() + 0.5*( SgT + Opm::sqrt( SgT*SgT + 4.0/C*SgT)));
548 SgCut = std::max(Scalar(0.000001), SgCut);
549 Scalar SgCutValue = 0.5*( SgCut + Opm::sqrt( SgCut*SgCut + 4.0/C*SgCut));
550 Scalar SgCutSlope = SgCutValue/SgCut;
552 Swf -= (Sncrd() + SgT);
558 template <
class Evaluation>
559 Evaluation computeKrImbWAG(
const Evaluation& Sw)
const
563 Swf = computeSwf(Sw);
564 if (Swf <= krnSwDrainStart_) {
565 Evaluation Krg = EffLawT::twoPhaseSatKrn(drainageParams_, Swf);
566 Evaluation KrgImb2 = (Krg-krnDrainStart_)*reductionDrain() + krnImbStart_;
570 Evaluation Sn = Sncrd_;
571 if (Swf < 1.0-SncrtWAG_) {
573 Evaluation dd = (1.0-krnSwImbStart_ - Sncrd_) / (1.0-krnSwDrainStart_ - SncrtWAG_);
574 Sn += (1.0-Swf-SncrtWAG_)*dd;
576 Evaluation KrgDrn1 = EffLawT::twoPhaseSatKrn(drainageParams_, 1.0 - Sn);
587 bool update(Scalar pcSw, Scalar krwSw, Scalar krnSw)
589 bool updateParams =
false;
591 if (
config().pcHysteresisModel() == 0 && pcSw < pcSwMdc_) {
592 if (pcSwMdc_ == 2.0 && pcSw+1.0e-6 < Swcrd_ && (oilWaterSystem_ || gasWaterSystem_)) {
599 if (initialImb_ && pcSw > pcSwMic_) {
604 if (krnSw < krnSwMdc_) {
607 if (
config().krHysteresisModel() == 4) {
612 if (krwSw > krwSwMdc_) {
618 if (!gasOilHysteresisWAG()) {
619 this->isDrain_ = (krnSw <= this->krnSwMdc_);
621 wasDrain_ = isDrain_;
623 if (swatImbStartNxt_ < 0.0) {
624 swatImbStartNxt_ = std::max(Swco_, Swco_ + krnSw - krwSw);
627 if ( (swatImbStartNxt_ > Swco_ + tolWAG_) && krwSw > tolWAG_) {
628 swatImbStart_ = swatImbStartNxt_;
630 krnSwDrainStartNxt_ = krnSwWAG_;
631 krnSwDrainStart_ = krnSwDrainStartNxt_;
637 if (krnSw <= krnSwWAG_+tolWAG_) {
638 krnSwWAG_ = std::min(krnSw, krnSwWAG_);
639 krnSwDrainRevert_ = krnSwWAG_;
649 if (krnSw >= krnSwWAG_-tolWAG_) {
650 krnSwWAG_ = std::max(krnSw, krnSwWAG_);
651 krnSwDrainStartNxt_ = krnSwWAG_;
652 swatImbStartNxt_ = std::max(swatImbStartNxt_, Swco_ + krnSw - krwSw);
657 krnSwDrainStart_ = krnSwDrainStartNxt_;
658 swatImbStart_ = swatImbStartNxt_;
667 updateDynamicParams_();
672 template<
class Serializer>
676 serializer(deltaSwImbKrn_);
680 serializer(initialImb_);
681 serializer(pcSwMic_);
682 serializer(krnSwMdc_);
683 serializer(krwSwMdc_);
688 bool operator==(
const EclHysteresisTwoPhaseLawParams& rhs)
const
690 return this->deltaSwImbKrn_ == rhs.deltaSwImbKrn_ &&
692 this->Sncrt_ == rhs.Sncrt_ &&
693 this->Swcrt_ == rhs.Swcrt_ &&
694 this->initialImb_ == rhs.initialImb_ &&
695 this->pcSwMic_ == rhs.pcSwMic_ &&
696 this->krnSwMdc_ == rhs.krnSwMdc_ &&
697 this->krwSwMdc_ == rhs.krwSwMdc_ &&
698 this->KrndHy_ == rhs.KrndHy_ &&
699 this->KrwdHy_ == rhs.KrwdHy_;
703 void updateDynamicParams_()
712 if (
config().krHysteresisModel() == 0 ||
config().krHysteresisModel() == 1) {
713 Scalar krnMdcDrainage = EffLawT::twoPhaseSatKrn(
drainageParams(), krnSwMdc_);
714 Scalar SwKrnMdcImbibition = EffLawT::twoPhaseSatKrnInv(
imbibitionParams(), krnMdcDrainage);
715 deltaSwImbKrn_ = SwKrnMdcImbibition - krnSwMdc_;
722 if (
config().krHysteresisModel() == 2 ||
723 config().krHysteresisModel() == 3 ||
724 config().krHysteresisModel() == 4 ||
725 config().pcHysteresisModel() == 0)
727 const Scalar snhy = 1.0 - krnSwMdc_;
729 Sncrt_ = Sncrd_ + (snhy - Sncrd_) /
730 ((1.0 +
config().modParamTrapped()*(Snmaxd_ - snhy)) + C_ * (snhy - Sncrd_));
737 if (
config().krHysteresisModel() == 4) {
738 Scalar swhy = krnSwMdc_;
739 if (swhy >= Swcrd_) {
740 Swcrt_ = Swcrd_ + (swhy - Swcrd_) /
741 ((1.0 +
config().modParamTrapped() * (Swmaxd_ - swhy)) + Cw_ * (swhy - Swcrd_));
745 Krwd_sncrt_ = EffLawT::twoPhaseSatKrw(
drainageParams(), 1 - Sncrt());
749 if (gasOilHysteresisWAG()) {
750 if (isDrain_ && krnSwMdc_ == krnSwWAG_) {
751 Scalar snhy = 1.0 - krnSwMdc_;
754 SncrtWAG_ += (snhy - Sncrd_) /
755 (1.0 +
config().modParamTrapped() * (Snmaxd_ - snhy) +
756 wagConfig().wagLandsParam() * (snhy - Sncrd_));
760 if (isDrain_ && (1.0 - krnSwDrainRevert_) > SncrtWAG_) {
761 cTransf_ = 1.0 / (SncrtWAG_ - Sncrd_ + 1.0e-12) - 1.0 / (1.0 - krnSwDrainRevert_ - Sncrd_);
764 if (!wasDrain_ && isDrain_) {
765 if (threePhaseState() || nState_ > 1) {
767 krnDrainStart_ = EffLawT::twoPhaseSatKrn(
drainageParams(), krnSwDrainStart_);
768 krnImbStart_ = krnImbStartNxt_;
770 krnSwImbStart_ = EffLawT::twoPhaseSatKrnInv(
drainageParams(), krnImbStart_);
774 if (!wasDrain_ && !isDrain_) {
775 krnDrainStartNxt_ = EffLawT::twoPhaseSatKrn(
drainageParams(), krnSwWAG_);
776 if (threePhaseState()) {
777 krnImbStartNxt_ = computeKrImbWAG(krnSwWAG_);
780 Scalar swf = computeSwf(krnSwWAG_);
789 EclHysteresisConfig config_{};
790 std::shared_ptr<WagHysteresisConfig::WagHysteresisConfigRecord> wagConfig_{};
791 EffLawParams imbibitionParams_{};
792 EffLawParams drainageParams_{};
797 Scalar krwSwMdc_{-2.0};
798 Scalar krnSwMdc_{2.0};
799 Scalar pcSwMdc_{2.0};
802 Scalar pcSwMic_{1.0};
804 bool initialImb_{
false};
806 bool oilWaterSystem_{
false};
807 bool gasOilSystem_{
false};
808 bool gasWaterSystem_{
false};
815 Scalar deltaSwImbKrn_{};
849 Scalar Krwd_sncri_{};
850 Scalar Krwi_snmax_{};
851 Scalar Krwi_snrmax_{};
852 Scalar Krwd_sncrt_{};
858 Scalar curvatureCapPrs_{};
864 Scalar swatImbStart_{};
865 Scalar swatImbStartNxt_{};
866 Scalar krnSwWAG_{2.0};
867 Scalar krnSwDrainRevert_{2.0};
870 Scalar krnSwDrainStart_{-2.0};
871 Scalar krnSwDrainStartNxt_{};
872 Scalar krnImbStart_{};
873 Scalar krnImbStartNxt_{};
874 Scalar krnDrainStart_{};
875 Scalar krnDrainStartNxt_{};
878 Scalar krnSwImbStart_{};
883 Scalar tolWAG_{0.001};