opm-common
EclHysteresisTwoPhaseLawParams.hpp
Go to the documentation of this file.
1 // -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 // vi: set et ts=4 sw=4 sts=4:
3 /*
4  This file is part of the Open Porous Media project (OPM).
5 
6  OPM is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 2 of the License, or
9  (at your option) any later version.
10 
11  OPM is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with OPM. If not, see <http://www.gnu.org/licenses/>.
18 
19  Consult the COPYING file in the top-level source directory of this
20  module for the precise wording of the license and the list of
21  copyright holders.
22 */
27 #ifndef OPM_ECL_HYSTERESIS_TWO_PHASE_LAW_PARAMS_HPP
28 #define OPM_ECL_HYSTERESIS_TWO_PHASE_LAW_PARAMS_HPP
29 
30 #include <opm/input/eclipse/EclipseState/WagHysteresisConfig.hpp>
31 
37 
38 #include <cassert>
39 #include <cmath>
40 #include <memory>
41 namespace Opm {
48 template <class EffLawT>
50 {
51  using EffLawParams = typename EffLawT::Params;
52  using Scalar = typename EffLawParams::Traits::Scalar;
53 
54 public:
55  using Traits = typename EffLawParams::Traits;
56 
57  static EclHysteresisTwoPhaseLawParams serializationTestObject()
58  {
60  result.deltaSwImbKrn_ = 1.0;
61  //result.deltaSwImbKrw_ = 1.0;
62  result.Sncrt_ = 2.0;
63  result.Swcrt_ = 2.5;
64  result.initialImb_ = true;
65  result.pcSwMic_ = 3.0;
66  result.krnSwMdc_ = 4.0;
67  result.krwSwMdc_ = 4.5;
68  result.KrndHy_ = 5.0;
69  result.KrwdHy_ = 6.0;
70 
71  return result;
72  }
73 
78  void finalize()
79  {
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_);
83  curvatureCapPrs_ = config().curvatureCapPrs();
84  }
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());
88  }
89  updateDynamicParams_();
90  }
92  }
93 
98  { config_ = value; }
99 
104  { return config_; }
105 
109  void setWagConfig(std::shared_ptr<WagHysteresisConfig::WagHysteresisConfigRecord> value)
110  {
111  wagConfig_ = value;
112  cTransf_ = wagConfig().wagLandsParam();
113  }
114 
119  { return *wagConfig_; }
120 
124  void setDrainageParams(const EffLawParams& value,
126  EclTwoPhaseSystemType twoPhaseSystem)
127  {
128  drainageParams_ = value;
129 
130  oilWaterSystem_ = (twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
131  gasWaterSystem_ = (twoPhaseSystem == EclTwoPhaseSystemType::GasWater);
132  gasOilSystem_ = (twoPhaseSystem == EclTwoPhaseSystemType::GasOil);
133 
134  if (!config().enableHysteresis())
135  return;
136  if (config().krHysteresisModel() == 2 || config().krHysteresisModel() == 3 || config().krHysteresisModel() == 4 || config().pcHysteresisModel() == 0 || gasOilHysteresisWAG()) {
137  Swco_ = info.Swl;
138  if (twoPhaseSystem == EclTwoPhaseSystemType::GasOil) {
139  Sncrd_ = info.Sgcr + info.Swl;
140  Swcrd_ = info.Sogcr;
141  Snmaxd_ = info.Sgu + info.Swl;
142  KrndMax_ = EffLawT::twoPhaseSatKrn(drainageParams(), 1.0-Snmaxd_);
143  }
144  else if (twoPhaseSystem == EclTwoPhaseSystemType::GasWater) {
145  Sncrd_ = info.Sgcr;
146  Swcrd_ = info.Swcr;
147  Snmaxd_ = info.Sgu;
148  KrndMax_ = EffLawT::twoPhaseSatKrn(drainageParams(), 1.0-Snmaxd_);
149  }
150  else {
151  assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
152  Sncrd_ = info.Sowcr;
153  Swcrd_ = info.Swcr;
154  Snmaxd_ = 1.0 - info.Swl - info.Sgl;
155  KrndMax_ = EffLawT::twoPhaseSatKrn(drainageParams(), 1.0-Snmaxd_);
156  }
157  }
158 
159  if (config().krHysteresisModel() == 4) {
160  //Swco_ = info.Swl;
161  if (twoPhaseSystem == EclTwoPhaseSystemType::GasOil) {
162  Swmaxd_ = 1.0 - info.Sgl - info.Swl;
163  KrwdMax_ = EffLawT::twoPhaseSatKrw(drainageParams(), Swmaxd_);
164  }
165  else if (twoPhaseSystem == EclTwoPhaseSystemType::GasWater) {
166  Swmaxd_ = info.Swu;
167  KrwdMax_ = EffLawT::twoPhaseSatKrw(drainageParams(), Swmaxd_);
168  }
169  else {
170  assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
171  Swmaxd_ = info.Swu;
172  KrwdMax_ = EffLawT::twoPhaseSatKrw(drainageParams(), Swmaxd_);
173  }
174  }
175 
176  // Additional Killough hysteresis model for pc
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;
182  }
183  else {
184  assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
185  pcmaxd_ = -17.0; // At this point 'info.maxPcow' holds pre-swatinit value ...;
186  }
187  }
188 
189  // For WAG hysteresis, assume initial state along primary drainage curve.
190  if (gasOilHysteresisWAG()) {
191  swatImbStart_ = Swco_;
192  swatImbStartNxt_ = -1.0; // Trigger check for saturation gt Swco at first update ...
193  cTransf_ = wagConfig().wagLandsParam();
194  krnSwDrainStart_ = Sncrd_;
195  krnSwDrainStartNxt_ = Sncrd_;
196  krnImbStart_ = 0.0;
197  krnImbStartNxt_ = 0.0;
198  krnDrainStart_ = 0.0;
199  krnDrainStartNxt_ = 0.0;
200  isDrain_ = true;
201  wasDrain_ = true;
202  krnSwImbStart_ = Sncrd_;
203  SncrtWAG_ = Sncrd_;
204  nState_ = 1;
205  }
206  }
207 
211  const EffLawParams& drainageParams() const
212  { return drainageParams_; }
213 
214  EffLawParams& drainageParams()
215  { return drainageParams_; }
216 
220  void setImbibitionParams(const EffLawParams& value,
222  EclTwoPhaseSystemType twoPhaseSystem)
223  {
224  imbibitionParams_ = value;
225 
226  if (!config().enableHysteresis())
227  return;
228 
229  // Store critical nonwetting saturation
230  if (twoPhaseSystem == EclTwoPhaseSystemType::GasOil) {
231  Sncri_ = info.Sgcr + info.Swl;
232  Swcri_ = info.Sogcr;
233  }
234  else if (twoPhaseSystem == EclTwoPhaseSystemType::GasWater) {
235  Sncri_ = info.Sgcr;
236  Swcri_ = info.Swcr;
237  }
238  else {
239  assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
240  Sncri_ = info.Sowcr;
241  Swcri_ = info.Swcr;
242  }
243 
244  // Killough hysteresis model for pc
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) {
250  Swmaxi_ = info.Swu;
251  pcmaxi_ = info.maxPcgo + info.maxPcow;
252  }
253  else {
254  assert(twoPhaseSystem == EclTwoPhaseSystemType::OilWater);
255  Swmaxi_ = info.Swu;
256  pcmaxi_ = info.maxPcow;
257  }
258  }
259 
260  if (config().krHysteresisModel() == 4) {
261  Krwi_snmax_ = EffLawT::twoPhaseSatKrw(imbibitionParams(), 1 - Snmaxd());
262  Krwi_snrmax_ = EffLawT::twoPhaseSatKrw(imbibitionParams(), 1 - Sncri());
263  }
264  }
265 
269  const EffLawParams& imbibitionParams() const
270  { return imbibitionParams_; }
271 
272  EffLawParams& imbibitionParams()
273  { return imbibitionParams_; }
274 
279  Scalar pcSwMdc() const
280  { return pcSwMdc_; }
281 
282  Scalar pcSwMic() const
283  { return pcSwMic_; }
284 
288  bool initialImb() const
289  { return initialImb_; }
290 
296  void setKrwSwMdc(Scalar value)
297  { krwSwMdc_ = value; };
298 
304  Scalar krwSwMdc() const
305  { return krwSwMdc_; };
306 
312  void setKrnSwMdc(Scalar value)
313  { krnSwMdc_ = value; }
314 
320  Scalar krnSwMdc() const
321  { return krnSwMdc_; }
322 
330  //void setDeltaSwImbKrw(Scalar value)
331  //{ deltaSwImbKrw_ = value; }
332 
340  //Scalar deltaSwImbKrw() const
341  //{ return deltaSwImbKrw_; }
342 
350  void setDeltaSwImbKrn(Scalar value)
351  { deltaSwImbKrn_ = value; }
352 
360  Scalar deltaSwImbKrn() const
361  { return deltaSwImbKrn_; }
362 
363 
364  Scalar Swcri() const
365  { return Swcri_; }
366 
367  Scalar Swcrd() const
368  { return Swcrd_; }
369 
370  Scalar Swmaxi() const
371  { return Swmaxi_; }
372 
373  Scalar Sncri() const
374  { return Sncri_; }
375 
376  Scalar Sncrd() const
377  { return Sncrd_; }
378 
379  Scalar Sncrt() const
380  { return Sncrt_; }
381 
382  Scalar Swcrt() const
383  { return Swcrt_; }
384 
385  Scalar SnTrapped(bool maximumTrapping) const
386  {
387  if(!maximumTrapping && isDrain_)
388  return 0.0;
389 
390  // For Killough the trapped saturation is already computed
391  if( config().krHysteresisModel() > 1 )
392  return Sncrt_;
393  else // For Carlson we use the shift to compute it from the critial saturation
394  return Sncri_ + deltaSwImbKrn_;
395  }
396 
397  Scalar SnStranded(Scalar sg, Scalar krg) const {
398  const Scalar sn = EffLawT::twoPhaseSatKrnInv(drainageParams_, krg);
399  return sg - (1.0 - sn) + Sncrd_;
400  }
401 
402  Scalar SwTrapped() const
403  {
404  if( config().krHysteresisModel() == 0 || config().krHysteresisModel() == 2)
405  return Swcrd_;
406 
407  if( config().krHysteresisModel() == 1 || config().krHysteresisModel() == 3)
408  return Swcri_;
409 
410  // For Killough the trapped saturation is already computed
411  if( config().krHysteresisModel() == 4 )
412  return Swcrt_;
413 
414  return 0.0;
415  //else // For Carlson we use the shift to compute it from the critial saturation
416  // return Swcri_ + deltaSwImbKrw_;
417  }
418 
419  Scalar SncrtWAG() const
420  { return SncrtWAG_; }
421 
422  Scalar Snmaxd() const
423  { return Snmaxd_; }
424 
425  Scalar Swmaxd() const
426  { return Swmaxd_; }
427 
428  Scalar Snhy() const
429  { return 1.0 - krnSwMdc_; }
430 
431  Scalar Swhy() const
432  { return krwSwMdc_; }
433 
434  Scalar Swco() const
435  { return Swco_; }
436 
437  Scalar krnWght() const
438  { return KrndHy_/KrndMax_; }
439 
440  template <class Evaluation>
441  Evaluation krwWght(const Evaluation& Krwd) const
442  {
443  // a = 1 (deltaKrw)^a Formulation according to KILLOUGH 1976
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());
447  }
448 
449  Scalar krwdMax() const
450  {
451  return KrwdMax_; }
452 
453  Scalar KrwdHy() const
454  {
455  return KrwdHy_;
456  }
457 
458 
459  Scalar Krwd_sncri() const
460  {
461  return Krwd_sncri_;
462  }
463 
464  Scalar Krwi_snmax() const
465  {
466  return Krwi_snmax_;
467  }
468 
469  Scalar Krwi_snrmax() const
470  {
471  return Krwi_snrmax_;
472  }
473 
474  Scalar Krwd_sncrt() const
475  {
476  return Krwd_sncrt_;
477  }
478 
479  Scalar pcWght() const // Aligning pci and pcd at Swir
480  {
481  if (pcmaxd_ < 0.0)
482  return EffLawT::twoPhaseSatPcnw(drainageParams(), 0.0)/(pcmaxi_+1e-6);
483  else
484  return pcmaxd_/(pcmaxi_+1e-6);
485  }
486 
487  Scalar curvatureCapPrs() const
488  { return curvatureCapPrs_;}
489 
490  bool gasOilHysteresisWAG() const
491  { return (config().enableWagHysteresis() && gasOilSystem_ && wagConfig().wagGasFlag()) ; }
492 
493  Scalar reductionDrain() const
494  { return std::pow(Swco_/(swatImbStart_+tolWAG_*wagConfig().wagWaterThresholdSaturation()), wagConfig().wagSecondaryDrainageReduction());}
495 
496  Scalar reductionDrainNxt() const
497  { return std::pow(Swco_/(swatImbStartNxt_+tolWAG_*wagConfig().wagWaterThresholdSaturation()), wagConfig().wagSecondaryDrainageReduction());}
498 
499  bool threePhaseState() const
500  { return (swatImbStart_ > (Swco_ + wagConfig().wagWaterThresholdSaturation()) ); }
501 
502  Scalar nState() const
503  { return nState_;}
504 
505  Scalar krnSwDrainRevert() const
506  { return krnSwDrainRevert_;}
507 
508  Scalar krnDrainStart() const
509  { return krnDrainStart_;}
510 
511  Scalar krnDrainStartNxt() const
512  { return krnDrainStartNxt_;}
513 
514  Scalar krnImbStart() const
515  { return krnImbStart_;}
516 
517  Scalar krnImbStartNxt() const
518  { return krnImbStartNxt_;}
519 
520  Scalar krnSwWAG() const
521  { return krnSwWAG_;}
522 
523  Scalar krnSwDrainStart() const
524  { return krnSwDrainStart_;}
525 
526  Scalar krnSwDrainStartNxt() const
527  { return krnSwDrainStartNxt_;}
528 
529  Scalar krnSwImbStart() const
530  { return krnSwImbStart_;}
531 
532  Scalar tolWAG() const
533  { return tolWAG_;}
534 
535  template <class Evaluation>
536  Evaluation computeSwf(const Evaluation& Sw) const
537  {
538  Evaluation SgT = 1.0 - Sw - SncrtWAG(); // Sg-Sg_crit_trapped
539  Scalar SgCut = wagConfig().wagImbCurveLinearFraction()*(Snhy()- SncrtWAG());
540  Evaluation Swf = 1.0;
541  //Scalar C = wagConfig().wagLandsParam();
542  Scalar C = cTransf_;
543 
544  if (SgT > SgCut) {
545  Swf -= (Sncrd() + 0.5*( SgT + Opm::sqrt( SgT*SgT + 4.0/C*SgT))); // 1-Sgf
546  }
547  else {
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;
551  SgT *= SgCutSlope;
552  Swf -= (Sncrd() + SgT);
553  }
554 
555  return Swf;
556  }
557 
558  template <class Evaluation>
559  Evaluation computeKrImbWAG(const Evaluation& Sw) const
560  {
561  Evaluation Swf = Sw;
562  if (nState_ <= 2) // Skipping for "higher order" curves seems consistent with benchmark, further investigations needed ...
563  Swf = computeSwf(Sw);
564  if (Swf <= krnSwDrainStart_) { // Use secondary drainage curve
565  Evaluation Krg = EffLawT::twoPhaseSatKrn(drainageParams_, Swf);
566  Evaluation KrgImb2 = (Krg-krnDrainStart_)*reductionDrain() + krnImbStart_;
567  return KrgImb2;
568  }
569  else { // Fallback to primary drainage curve
570  Evaluation Sn = Sncrd_;
571  if (Swf < 1.0-SncrtWAG_) {
572  // Notation: Sn.. = Sg.. + Swco
573  Evaluation dd = (1.0-krnSwImbStart_ - Sncrd_) / (1.0-krnSwDrainStart_ - SncrtWAG_);
574  Sn += (1.0-Swf-SncrtWAG_)*dd;
575  }
576  Evaluation KrgDrn1 = EffLawT::twoPhaseSatKrn(drainageParams_, 1.0 - Sn);
577  return KrgDrn1;
578  }
579  }
580 
587  bool update(Scalar pcSw, Scalar krwSw, Scalar krnSw)
588  {
589  bool updateParams = false;
590 
591  if (config().pcHysteresisModel() == 0 && pcSw < pcSwMdc_) {
592  if (pcSwMdc_ == 2.0 && pcSw+1.0e-6 < Swcrd_ && (oilWaterSystem_ || gasWaterSystem_)) {
593  initialImb_ = true;
594  }
595  pcSwMdc_ = pcSw;
596  updateParams = true;
597  }
598 
599  if (initialImb_ && pcSw > pcSwMic_) {
600  pcSwMic_ = pcSw;
601  updateParams = true;
602  }
603 
604  if (krnSw < krnSwMdc_) {
605  krnSwMdc_ = krnSw;
606  KrndHy_ = EffLawT::twoPhaseSatKrn(drainageParams(), krnSwMdc_);
607  if (config().krHysteresisModel() == 4) {
608  KrwdHy_ = EffLawT::twoPhaseSatKrw(drainageParams(), krnSwMdc_);
609  }
610  updateParams = true;
611  }
612  if (krwSw > krwSwMdc_) {
613  krwSwMdc_ = krwSw; // Only used for output at the moment
614  }
615 
616  // for non WAG hysteresis we still keep track of the process
617  // for output purpose.
618  if (!gasOilHysteresisWAG()) {
619  this->isDrain_ = (krnSw <= this->krnSwMdc_);
620  } else {
621  wasDrain_ = isDrain_;
622 
623  if (swatImbStartNxt_ < 0.0) { // Initial check ...
624  swatImbStartNxt_ = std::max(Swco_, Swco_ + krnSw - krwSw);
625  // check if we are in threephase state sw > swco + tolWag and so > tolWag
626  // (sw = swco + krnSw - krwSw and so = krwSw for oil/gas params)
627  if ( (swatImbStartNxt_ > Swco_ + tolWAG_) && krwSw > tolWAG_) {
628  swatImbStart_ = swatImbStartNxt_;
629  krnSwWAG_ = krnSw;
630  krnSwDrainStartNxt_ = krnSwWAG_;
631  krnSwDrainStart_ = krnSwDrainStartNxt_;
632  wasDrain_ = false; // Signal start from threephase state ...
633  }
634  }
635 
636  if (isDrain_) {
637  if (krnSw <= krnSwWAG_+tolWAG_) { // continue along drainage curve
638  krnSwWAG_ = std::min(krnSw, krnSwWAG_);
639  krnSwDrainRevert_ = krnSwWAG_;
640  updateParams = true;
641  }
642  else { // start new imbibition curve
643  isDrain_ = false;
644  krnSwWAG_ = krnSw;
645  updateParams = true;
646  }
647  }
648  else {
649  if (krnSw >= krnSwWAG_-tolWAG_) { // continue along imbibition curve
650  krnSwWAG_ = std::max(krnSw, krnSwWAG_);
651  krnSwDrainStartNxt_ = krnSwWAG_;
652  swatImbStartNxt_ = std::max(swatImbStartNxt_, Swco_ + krnSw - krwSw);
653  updateParams = true;
654  }
655  else { // start new drainage curve
656  isDrain_ = true;
657  krnSwDrainStart_ = krnSwDrainStartNxt_;
658  swatImbStart_ = swatImbStartNxt_;
659  krnSwWAG_ = krnSw;
660  updateParams = true;
661  }
662  }
663 
664  }
665 
666  if (updateParams)
667  updateDynamicParams_();
668 
669  return updateParams;
670  }
671 
672  template<class Serializer>
673  void serializeOp(Serializer& serializer)
674  {
675  // only serializes dynamic state - see update() and updateDynamic_()
676  serializer(deltaSwImbKrn_);
677  //serializer(deltaSwImbKrw_);
678  serializer(Sncrt_);
679  serializer(Swcrt_);
680  serializer(initialImb_);
681  serializer(pcSwMic_);
682  serializer(krnSwMdc_);
683  serializer(krwSwMdc_);
684  serializer(KrndHy_);
685  serializer(KrwdHy_);
686  }
687 
688  bool operator==(const EclHysteresisTwoPhaseLawParams& rhs) const
689  {
690  return this->deltaSwImbKrn_ == rhs.deltaSwImbKrn_ &&
691  //this->deltaSwImbKrw_ == rhs.deltaSwImbKrw_ &&
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_;
700  }
701 
702 private:
703  void updateDynamicParams_()
704  {
705  // calculate the saturation deltas for the relative permeabilities
706  //if (false) { // we dont support Carlson for wetting phase hysteresis
707  //Scalar krwMdcDrainage = EffLawT::twoPhaseSatKrw(drainageParams(), krwSwMdc_);
708  //Scalar SwKrwMdcImbibition = EffLawT::twoPhaseSatKrwInv(imbibitionParams(), krwMdcDrainage);
709  //deltaSwImbKrw_ = SwKrwMdcImbibition - krwSwMdc_;
710  //}
711 
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_;
716  }
717 
718  // Scalar pcMdcDrainage = EffLawT::twoPhaseSatPcnw(drainageParams(), pcSwMdc_);
719  // Scalar SwPcMdcImbibition = EffLawT::twoPhaseSatPcnwInv(imbibitionParams(), pcMdcDrainage);
720  // deltaSwImbPc_ = SwPcMdcImbibition - pcSwMdc_;
721 
722  if (config().krHysteresisModel() == 2 ||
723  config().krHysteresisModel() == 3 ||
724  config().krHysteresisModel() == 4 ||
725  config().pcHysteresisModel() == 0)
726  {
727  const Scalar snhy = 1.0 - krnSwMdc_;
728  if (snhy > Sncrd_) {
729  Sncrt_ = Sncrd_ + (snhy - Sncrd_) /
730  ((1.0 + config().modParamTrapped()*(Snmaxd_ - snhy)) + C_ * (snhy - Sncrd_));
731  }
732  else {
733  Sncrt_ = Sncrd_;
734  }
735  }
736 
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_));
742  } else {
743  Swcrt_ = Swcrd_;
744  }
745  Krwd_sncrt_ = EffLawT::twoPhaseSatKrw(drainageParams(), 1 - Sncrt());
746  }
747 
748 
749  if (gasOilHysteresisWAG()) {
750  if (isDrain_ && krnSwMdc_ == krnSwWAG_) {
751  Scalar snhy = 1.0 - krnSwMdc_;
752  SncrtWAG_ = Sncrd_;
753  if (snhy > Sncrd_) {
754  SncrtWAG_ += (snhy - Sncrd_) /
755  (1.0 + config().modParamTrapped() * (Snmaxd_ - snhy) +
756  wagConfig().wagLandsParam() * (snhy - Sncrd_));
757  }
758  }
759 
760  if (isDrain_ && (1.0 - krnSwDrainRevert_) > SncrtWAG_) { // Reversal from drain to imb
761  cTransf_ = 1.0 / (SncrtWAG_ - Sncrd_ + 1.0e-12) - 1.0 / (1.0 - krnSwDrainRevert_ - Sncrd_);
762  }
763 
764  if (!wasDrain_ && isDrain_) { // Start of new drainage cycle
765  if (threePhaseState() || nState_ > 1) { // Never return to primary (two-phase) state after leaving
766  nState_ += 1;
767  krnDrainStart_ = EffLawT::twoPhaseSatKrn(drainageParams(), krnSwDrainStart_);
768  krnImbStart_ = krnImbStartNxt_;
769  // Scanning shift for primary drainage
770  krnSwImbStart_ = EffLawT::twoPhaseSatKrnInv(drainageParams(), krnImbStart_);
771  }
772  }
773 
774  if (!wasDrain_ && !isDrain_) { //Moving along current imb curve
775  krnDrainStartNxt_ = EffLawT::twoPhaseSatKrn(drainageParams(), krnSwWAG_);
776  if (threePhaseState()) {
777  krnImbStartNxt_ = computeKrImbWAG(krnSwWAG_);
778  }
779  else {
780  Scalar swf = computeSwf(krnSwWAG_);
781  krnImbStartNxt_ = EffLawT::twoPhaseSatKrn(drainageParams(), swf);
782  }
783  }
784 
785  }
786 
787  }
788 
789  EclHysteresisConfig config_{};
790  std::shared_ptr<WagHysteresisConfig::WagHysteresisConfigRecord> wagConfig_{};
791  EffLawParams imbibitionParams_{};
792  EffLawParams drainageParams_{};
793 
794  // largest wettinging phase saturation which is on the main-drainage curve. These are
795  // three different values because the sourounding code can choose to use different
796  // definitions for the saturations for different quantities
797  Scalar krwSwMdc_{-2.0};
798  Scalar krnSwMdc_{2.0};
799  Scalar pcSwMdc_{2.0};
800 
801  // largest wettinging phase saturation along main imbibition curve
802  Scalar pcSwMic_{1.0};
803  // Initial process is imbibition (for initial saturations at or below critical drainage saturation)
804  bool initialImb_{false};
805 
806  bool oilWaterSystem_{false};
807  bool gasOilSystem_{false};
808  bool gasWaterSystem_{false};
809 
810 
811  // offsets added to wetting phase saturation uf using the imbibition curves need to
812  // be used to calculate the wetting phase relperm, the non-wetting phase relperm and
813  // the capillary pressure
814  //Scalar deltaSwImbKrw_{};
815  Scalar deltaSwImbKrn_{};
816  //Scalar deltaSwImbPc_;
817 
818  // the following uses the conventions of the Eclipse technical description:
819  //
820  // Sncrd_: critical non-wetting phase saturation for the drainage curve
821  // Sncri_: critical non-wetting phase saturation for the imbibition curve
822  // Swcri_: critical wetting phase saturation for the imbibition curve
823  // Swcrd_: critical wetting phase saturation for the drainage curve
824  // Swmaxi_; maximum wetting phase saturation for the imbibition curve
825  // Snmaxd_: non-wetting phase saturation where the non-wetting relperm reaches its
826  // maximum on the drainage curve
827  // C_: factor required to calculate the trapped non-wetting phase saturation using
828  // the Killough approach
829  // Cw_: factor required to calculate the trapped wetting phase saturation using
830  // the Killough approach
831  // Swcod_: connate water saturation value used for wag hysteresis (2. drainage)
832  Scalar Sncrd_{};
833  Scalar Sncri_{};
834  Scalar Swcri_{};
835  Scalar Swcrd_{};
836  Scalar Swmaxi_{};
837  Scalar Snmaxd_{};
838  Scalar Swmaxd_{};
839  Scalar C_{};
840 
841  Scalar KrndMax_{}; // Krn_drain(Snmaxd_)
842  Scalar KrwdMax_{}; // Krw_drain(Swmaxd_)
843  Scalar KrndHy_{}; // Krn_drain(1-krnSwMdc_)
844 
845 
846  // For wetting hysterese Killough
847  Scalar Cw_{};
848  Scalar KrwdHy_{};
849  Scalar Krwd_sncri_{};
850  Scalar Krwi_snmax_{};
851  Scalar Krwi_snrmax_{};
852  Scalar Krwd_sncrt_{};
853  Scalar Swcrt_{}; // trapped wetting phase saturation
854 
855  Scalar pcmaxd_{}; // max pc for drain
856  Scalar pcmaxi_{}; // max pc for imb
857 
858  Scalar curvatureCapPrs_{}; // curvature parameter used for capillary pressure hysteresis
859 
860  Scalar Sncrt_{}; // trapped non-wetting phase saturation
861 
862  // Used for WAG hysteresis
863  Scalar Swco_{}; // Connate water.
864  Scalar swatImbStart_{}; // Water saturation at start of current drainage curve (end of previous imb curve).
865  Scalar swatImbStartNxt_{}; // Water saturation at start of next drainage curve (end of current imb curve).
866  Scalar krnSwWAG_{2.0}; // Saturation value after latest completed timestep.
867  Scalar krnSwDrainRevert_{2.0}; // Saturation value at end of current drainage curve.
868  Scalar cTransf_{}; // Modified Lands constant used for free gas calculations to obtain consistent scanning curve
869  // when reversion to imb occurs above historical maximum gas saturation (i.e. Sw > krwSwMdc_).
870  Scalar krnSwDrainStart_{-2.0}; // Saturation value at start of current drainage curve (end of previous imb curve).
871  Scalar krnSwDrainStartNxt_{}; // Saturation value at start of current drainage curve (end of previous imb curve).
872  Scalar krnImbStart_{}; // Relperm at start of current drainage curve (end of previous imb curve).
873  Scalar krnImbStartNxt_{}; // Relperm at start of next drainage curve (end of current imb curve).
874  Scalar krnDrainStart_{}; // Primary (input) relperm evaluated at start of current drainage curve.
875  Scalar krnDrainStartNxt_{}; // Primary (input) relperm evaluated at start of next drainage curve.
876  bool isDrain_{true}; // Status is either drainage or imbibition
877  bool wasDrain_{}; // Previous status.
878  Scalar krnSwImbStart_{}; // Saturation value where primary drainage relperm equals krnImbStart_
879 
880  int nState_{}; // Number of cycles. Primary cycle is nState_=1.
881 
882  Scalar SncrtWAG_{};
883  Scalar tolWAG_{0.001};
884 };
885 
886 } // namespace Opm
887 
888 #endif
double curvatureCapPrs() const
Curvature parameter used for capillary pressure hysteresis.
Definition: EclHysteresisConfig.hpp:120
Scalar krnSwMdc() const
Get the saturation of the wetting phase where the last switch from the main drainage curve to imbibit...
Definition: EclHysteresisTwoPhaseLawParams.hpp:320
void setImbibitionParams(const EffLawParams &value, const EclEpsScalingPointsInfo< Scalar > &info, EclTwoPhaseSystemType twoPhaseSystem)
Sets the parameters used for the imbibition curve.
Definition: EclHysteresisTwoPhaseLawParams.hpp:220
A traits class which provides basic mathematical functions for arbitrary scalar floating point values...
EclTwoPhaseSystemType
Specified which fluids are involved in a given twophase material law for endpoint scaling...
Definition: EclEpsConfig.hpp:40
Scalar krwSwMdc() const
Get the saturation of the wetting phase where the last switch from the main drainage curve to imbibit...
Definition: EclHysteresisTwoPhaseLawParams.hpp:304
const EffLawParams & imbibitionParams() const
Returns the parameters used for the imbibition curve.
Definition: EclHysteresisTwoPhaseLawParams.hpp:269
A default implementation of the parameters for the material law which implements the ECL relative per...
Definition: EclHysteresisTwoPhaseLawParams.hpp:49
void setDrainageParams(const EffLawParams &value, const EclEpsScalingPointsInfo< Scalar > &info, EclTwoPhaseSystemType twoPhaseSystem)
Sets the parameters used for the drainage curve.
Definition: EclHysteresisTwoPhaseLawParams.hpp:124
This class implements a small container which holds the transmissibility mulitpliers for all the face...
Definition: Exceptions.hpp:30
This structure represents all values which can be possibly used as scaling points in the endpoint sca...
Definition: EclEpsScalingPoints.hpp:54
void finalize()
Calculate all dependent quantities once the independent quantities of the parameter object have been ...
Definition: EclHysteresisTwoPhaseLawParams.hpp:78
Scalar pcSwMdc() const
Get the saturation of the wetting phase where the last switch from the main drainage curve to imbibit...
Definition: EclHysteresisTwoPhaseLawParams.hpp:279
const WagHysteresisConfig::WagHysteresisConfigRecord & wagConfig() const
Returns the WAG-hysteresis configuration object.
Definition: EclHysteresisTwoPhaseLawParams.hpp:118
Default implementation for asserting finalization of parameter objects.
Scalar deltaSwImbKrn() const
Returns the saturation value which must be added if krn is calculated using the imbibition curve...
Definition: EclHysteresisTwoPhaseLawParams.hpp:360
void setKrwSwMdc(Scalar value)
Set the saturation of the wetting phase where the last switch from the main drainage curve (MDC) to i...
Definition: EclHysteresisTwoPhaseLawParams.hpp:296
void setWagConfig(std::shared_ptr< WagHysteresisConfig::WagHysteresisConfigRecord > value)
Set the WAG-hysteresis configuration object.
Definition: EclHysteresisTwoPhaseLawParams.hpp:109
bool update(Scalar pcSw, Scalar krwSw, Scalar krnSw)
Notify the hysteresis law that a given wetting-phase saturation has been seen.
Definition: EclHysteresisTwoPhaseLawParams.hpp:587
void setConfig(const EclHysteresisConfig &value)
Set the hysteresis configuration object.
Definition: EclHysteresisTwoPhaseLawParams.hpp:97
Specifies the configuration used by the ECL kr/pC hysteresis code.
Definition: EclHysteresisConfig.hpp:39
Specifies the configuration used by the endpoint scaling code.
const EffLawParams & drainageParams() const
Returns the parameters used for the drainage curve.
Definition: EclHysteresisTwoPhaseLawParams.hpp:211
Definition: WagHysteresisConfig.hpp:33
bool enableHysteresis() const
Returns whether hysteresis is enabled.
Definition: EclHysteresisConfig.hpp:51
OPM_HOST_DEVICE void finalize()
Mark the object as finalized.
Definition: EnsureFinalized.hpp:82
void setDeltaSwImbKrn(Scalar value)
Sets the saturation value which must be added if krw is calculated using the imbibition curve...
Definition: EclHysteresisTwoPhaseLawParams.hpp:350
Default implementation for asserting finalization of parameter objects.
Definition: EnsureFinalized.hpp:48
void setKrnSwMdc(Scalar value)
Set the saturation of the wetting phase where the last switch from the main drainage curve (MDC) to i...
Definition: EclHysteresisTwoPhaseLawParams.hpp:312
double modParamTrapped() const
Regularisation parameter used for Killough model.
Definition: EclHysteresisConfig.hpp:112
Class for (de-)serializing.
Definition: Serializer.hpp:94
bool initialImb() const
Status of initial process.
Definition: EclHysteresisTwoPhaseLawParams.hpp:288
int pcHysteresisModel() const
Return the type of the hysteresis model which is used for capillary pressure.
Definition: EclHysteresisConfig.hpp:69
int krHysteresisModel() const
Return the type of the hysteresis model which is used for relative permeability.
Definition: EclHysteresisConfig.hpp:104
const EclHysteresisConfig & config() const
Returns the hysteresis configuration object.
Definition: EclHysteresisTwoPhaseLawParams.hpp:103
Specifies the configuration used by the ECL kr/pC hysteresis code.