EclMaterialLawManager.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  Copyright (C) 2015 by Andreas Lauser
5  Copyright (C) 2015 by IRIS AS
6 
7  This file is part of the Open Porous Media project (OPM).
8 
9  OPM is free software: you can redistribute it and/or modify
10  it under the terms of the GNU General Public License as published by
11  the Free Software Foundation, either version 2 of the License, or
12  (at your option) any later version.
13 
14  OPM is distributed in the hope that it will be useful,
15  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  GNU General Public License for more details.
18 
19  You should have received a copy of the GNU General Public License
20  along with OPM. If not, see <http://www.gnu.org/licenses/>.
21 */
26 #if ! HAVE_OPM_PARSER
27 #error "The opm-parser module is required to use the ECL material manager!"
28 #endif
29 
30 #ifndef OPM_ECL_MATERIAL_LAW_MANAGER_HPP
31 #define OPM_ECL_MATERIAL_LAW_MANAGER_HPP
32 
43 
44 #include <opm/common/Exceptions.hpp>
45 #include <opm/common/ErrorMacros.hpp>
46 
47 #include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
48 #include <opm/parser/eclipse/Deck/Deck.hpp>
49 
50 #include <algorithm>
51 
52 
53 namespace Opm {
54 
61 template <class TraitsT>
63 {
64 private:
65  typedef TraitsT Traits;
66  typedef typename Traits::Scalar Scalar;
67  enum { waterPhaseIdx = Traits::wettingPhaseIdx };
68  enum { oilPhaseIdx = Traits::nonWettingPhaseIdx };
69  enum { gasPhaseIdx = Traits::gasPhaseIdx };
70  enum { numPhases = Traits::numPhases };
71 
74 
75  // the two-phase material law which is defined on effective (unscaled) saturations
78  typedef typename GasOilEffectiveTwoPhaseLaw::Params GasOilEffectiveTwoPhaseParams;
79  typedef typename OilWaterEffectiveTwoPhaseLaw::Params OilWaterEffectiveTwoPhaseParams;
80 
81  // the two-phase material law which is defined on absolute (scaled) saturations
84  typedef typename GasOilEpsTwoPhaseLaw::Params GasOilEpsTwoPhaseParams;
85  typedef typename OilWaterEpsTwoPhaseLaw::Params OilWaterEpsTwoPhaseParams;
86 
87  // the scaled two-phase material laws with hystersis
90  typedef typename GasOilTwoPhaseLaw::Params GasOilTwoPhaseHystParams;
91  typedef typename OilWaterTwoPhaseLaw::Params OilWaterTwoPhaseHystParams;
92 
93 public:
94  // the three-phase material law used by the simulation
96  typedef typename MaterialLaw::Params MaterialLawParams;
97 
98 private:
99  // internal typedefs
100  typedef std::vector<std::shared_ptr<GasOilEffectiveTwoPhaseParams> > GasOilEffectiveParamVector;
101  typedef std::vector<std::shared_ptr<OilWaterEffectiveTwoPhaseParams> > OilWaterEffectiveParamVector;
102  typedef std::vector<std::shared_ptr<EclEpsScalingPoints<Scalar> > > GasOilScalingPointsVector;
103  typedef std::vector<std::shared_ptr<EclEpsScalingPoints<Scalar> > > OilWaterScalingPointsVector;
104  typedef std::vector<std::shared_ptr<EclEpsScalingPointsInfo<Scalar> > > GasOilScalingInfoVector;
105  typedef std::vector<std::shared_ptr<EclEpsScalingPointsInfo<Scalar> > > OilWaterScalingInfoVector;
106  typedef std::vector<std::shared_ptr<GasOilTwoPhaseHystParams> > GasOilParamVector;
107  typedef std::vector<std::shared_ptr<OilWaterTwoPhaseHystParams> > OilWaterParamVector;
108  typedef std::vector<std::shared_ptr<MaterialLawParams> > MaterialLawParamsVector;
109 
110 public:
112  {}
113 
114  void initFromDeck(Opm::DeckConstPtr deck,
115  Opm::EclipseStateConstPtr eclState,
116  const std::vector<int>& compressedToCartesianElemIdx)
117  {
118  // get the number of saturation regions and the number of cells in the deck
119  unsigned numSatRegions = static_cast<unsigned>(deck->getKeyword("TABDIMS")->getRecord(0)->getItem("NTSFUN")->getInt(0));
120  size_t numCompressedElems = compressedToCartesianElemIdx.size();
121 
122  // copy the SATNUM grid property. in some cases this is not necessary, but it
123  // should not require much memory anyway...
124  std::vector<int> satnumRegionArray(numCompressedElems);
125  if (eclState->hasIntGridProperty("SATNUM")) {
126  const auto& satnumRawData = eclState->getIntGridProperty("SATNUM")->getData();
127  for (unsigned elemIdx = 0; elemIdx < numCompressedElems; ++elemIdx) {
128  unsigned cartesianElemIdx = static_cast<unsigned>(compressedToCartesianElemIdx[elemIdx]);
129  satnumRegionArray[elemIdx] = satnumRawData[cartesianElemIdx] - 1;
130  }
131  }
132  else
133  std::fill(satnumRegionArray.begin(), satnumRegionArray.end(), 0);
134 
135  readGlobalEpsOptions_(deck, eclState);
136  readGlobalHysteresisOptions_(deck);
137  readGlobalThreePhaseOptions_(deck);
138 
139  unscaledEpsInfo_.resize(numSatRegions);
140  for (unsigned satnumIdx = 0; satnumIdx < numSatRegions; ++satnumIdx)
141  unscaledEpsInfo_[satnumIdx].extractUnscaled(deck, eclState, satnumIdx);
142 
143  initParamsForElements_(deck, eclState, compressedToCartesianElemIdx, satnumRegionArray);
144  }
145 
154  Scalar applySwatinit(unsigned elemIdx,
155  Scalar pcow,
156  Scalar Sw)
157  {
158  auto& elemScaledEpsInfo = *oilWaterScaledEpsInfoDrainage_[elemIdx];
159 
160  // TODO: Mixed wettability systems - see ecl kw OPTIONS switch 74
161  if (Sw <= elemScaledEpsInfo.Swl)
162  Sw = elemScaledEpsInfo.Swl;
163  else if (pcow < 0.0)
164  Sw = elemScaledEpsInfo.Swu;
165  else {
166  // specify a fluid state which only stores the saturations
167  typedef Opm::SimpleModularFluidState<Scalar,
168  numPhases,
169  /*numComponents=*/0,
170  /*FluidSystem=*/void, /* -> don't care */
171  /*storePressure=*/false,
172  /*storeTemperature=*/false,
173  /*storeComposition=*/false,
174  /*storeFugacity=*/false,
175  /*storeSaturation=*/true,
176  /*storeDensity=*/false,
177  /*storeViscosity=*/false,
178  /*storeEnthalpy=*/false> FluidState;
179  FluidState fs;
180  fs.setSaturation(waterPhaseIdx, Sw);
181  fs.setSaturation(gasPhaseIdx, 0);
182  fs.setSaturation(oilPhaseIdx, 0);
183  Scalar pc[numPhases];
184  MaterialLaw::capillaryPressures(pc, materialLawParams(elemIdx), fs);
185 
186  Scalar pcowAtSw = pc[oilPhaseIdx] - pc[waterPhaseIdx];
187  if (pcowAtSw > 0.0) {
188  elemScaledEpsInfo.maxPcow *= pcow/pcowAtSw;
189  auto& elemEclEpsScalingPoints = getOilWaterScaledEpsPointsDrainage_(elemIdx);
190  elemEclEpsScalingPoints.init(elemScaledEpsInfo, *oilWaterEclEpsConfig_, Opm::EclOilWaterSystem);
191  }
192  }
193 
194  return Sw;
195  }
196 
198  { return enableEndPointScaling_; }
199 
200  bool enableHysteresis() const
201  { return hysteresisConfig_->enableHysteresis(); }
202 
203  MaterialLawParams& materialLawParams(unsigned elemIdx)
204  {
205  assert(0 <= elemIdx && elemIdx < materialLawParams_.size());
206  return *materialLawParams_[elemIdx];
207  }
208 
209  const MaterialLawParams& materialLawParams(unsigned elemIdx) const
210  {
211  assert(0 <= elemIdx && elemIdx < (int) materialLawParams_.size());
212  return *materialLawParams_[elemIdx];
213  }
214 
215  template <class FluidState>
216  void updateHysteresis(const FluidState& fluidState, unsigned elemIdx)
217  {
218  if (!enableHysteresis())
219  return;
220 
221  auto threePhaseParams = materialLawParams_[elemIdx];
222  MaterialLaw::updateHysteresis(*threePhaseParams, fluidState);
223  }
224 
226  {
227  return *oilWaterScaledEpsInfoDrainage_[elemIdx];
228  }
229 
230 private:
231  void readGlobalEpsOptions_(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclState)
232  {
233  oilWaterEclEpsConfig_ = std::make_shared<Opm::EclEpsConfig>();
234  oilWaterEclEpsConfig_-> initFromDeck(deck, eclState, Opm::EclOilWaterSystem);
235 
236  enableEndPointScaling_ = deck->hasKeyword("ENDSCALE");
237 
238  if (enableEndPointScaling()) {
239  // sift through the options of the ENDSCALE keyword
240  Opm::DeckKeywordConstPtr endscaleKeyword = deck->getKeyword("ENDSCALE");
241  Opm::DeckRecordConstPtr endscaleRecord = endscaleKeyword->getRecord(0);
242  for (unsigned itemIdx = 0; itemIdx < endscaleRecord->size() && itemIdx < 2; ++ itemIdx) {
243  std::string optionValue = endscaleRecord->getItem(itemIdx)->getTrimmedString(0);
244 
245  // convert the value of the option to upper case, just to be sure
246  std::transform(optionValue.begin(),
247  optionValue.end(),
248  optionValue.begin(),
249  ::toupper);
250 
251  if (optionValue == "DIRECT") {
252  OPM_THROW(std::runtime_error,
253  "Directional end-point scaling (indicated by the 'DIRECT' option"
254  " of the 'ENDSCALE' keyword) is not yet supported");
255  }
256  if (optionValue == "IRREVERS") {
257  OPM_THROW(std::runtime_error,
258  "Irreversible end-point scaling (indicated by the 'IRREVERS' option"
259  " of the 'ENDSCALE' keyword) is not yet supported");
260  }
261  }
262  }
263  }
264 
265  void readGlobalHysteresisOptions_(Opm::DeckConstPtr deck)
266  {
267  hysteresisConfig_ = std::make_shared<Opm::EclHysteresisConfig>();
268  hysteresisConfig_->initFromDeck(deck);
269  }
270 
271  void readGlobalThreePhaseOptions_(Opm::DeckConstPtr deck)
272  {
273  bool gasEnabled = deck->hasKeyword("GAS");
274  bool oilEnabled = deck->hasKeyword("OIL");
275  bool waterEnabled = deck->hasKeyword("WATER");
276 
277  int numEnabled =
278  (gasEnabled?1:0)
279  + (oilEnabled?1:0)
280  + (waterEnabled?1:0);
281 
282  if (numEnabled < 2)
283  OPM_THROW(std::runtime_error,
284  "At least two fluid phases must be enabled. (Is: " << numEnabled << ")");
285 
286  if (numEnabled == 2) {
287  threePhaseApproach_ = Opm::EclTwoPhaseApproach;
288  if (!gasEnabled)
289  twoPhaseApproach_ = Opm::EclTwoPhaseOilWater;
290  else if (!oilEnabled)
291  twoPhaseApproach_ = Opm::EclTwoPhaseGasWater;
292  else if (!waterEnabled)
293  twoPhaseApproach_ = Opm::EclTwoPhaseGasOil;
294  }
295  else {
296  assert(numEnabled == 3);
297 
298  threePhaseApproach_ = Opm::EclDefaultApproach;
299  if (deck->hasKeyword("STONE") || deck->hasKeyword("STONE2"))
300  threePhaseApproach_ = Opm::EclStone2Approach;
301  else if (deck->hasKeyword("STONE1"))
302  threePhaseApproach_ = Opm::EclStone1Approach;
303  }
304  }
305 
306  void initParamsForElements_(DeckConstPtr deck, EclipseStateConstPtr eclState,
307  const std::vector<int>& compressedToCartesianElemIdx,
308  const std::vector<int>& satnumRegionArray)
309  {
310  unsigned numSatRegions = static_cast<unsigned>(deck->getKeyword("TABDIMS")->getRecord(0)->getItem("NTSFUN")->getInt(0));
311  unsigned numCompressedElems = static_cast<unsigned>(compressedToCartesianElemIdx.size());
312 
313  // read the end point scaling configuration. this needs to be done only once per
314  // deck.
315  auto gasOilConfig = std::make_shared<Opm::EclEpsConfig>();
316  auto oilWaterConfig = std::make_shared<Opm::EclEpsConfig>();
317  gasOilConfig->initFromDeck(deck, eclState, Opm::EclGasOilSystem);
318  oilWaterConfig->initFromDeck(deck, eclState, Opm::EclOilWaterSystem);
319 
320  // read the saturation region specific parameters from the deck
321  GasOilScalingPointsVector gasOilUnscaledPointsVector(numSatRegions);
322  OilWaterScalingPointsVector oilWaterUnscaledPointsVector(numSatRegions);
323  GasOilEffectiveParamVector gasOilEffectiveParamVector(numSatRegions);
324  OilWaterEffectiveParamVector oilWaterEffectiveParamVector(numSatRegions);
325  for (unsigned satnumIdx = 0; satnumIdx < numSatRegions; ++satnumIdx) {
326  // unscaled points for end-point scaling
327  readGasOilUnscaledPoints_(gasOilUnscaledPointsVector, gasOilConfig, deck, eclState, satnumIdx);
328  readOilWaterUnscaledPoints_(oilWaterUnscaledPointsVector, oilWaterConfig, deck, eclState, satnumIdx);
329 
330  // the parameters for the effective two-phase matererial laws
331  readGasOilEffectiveParameters_(gasOilEffectiveParamVector, deck, eclState, satnumIdx);
332  readOilWaterEffectiveParameters_(oilWaterEffectiveParamVector, deck, eclState, satnumIdx);
333 
334  // read the end point scaling info for the saturation region
335  unscaledEpsInfo_[satnumIdx].extractUnscaled(deck, eclState, satnumIdx);
336 
337  }
338 
339  // read the scaled end point scaling parameters which are specific for each
340  // element
341  GasOilScalingInfoVector gasOilScaledInfoVector(numCompressedElems);
342  oilWaterScaledEpsInfoDrainage_.resize(numCompressedElems);
343  GasOilScalingInfoVector gasOilScaledImbInfoVector;
344  OilWaterScalingInfoVector oilWaterScaledImbInfoVector;
345 
346  GasOilScalingPointsVector gasOilScaledPointsVector(numCompressedElems);
347  GasOilScalingPointsVector oilWaterScaledEpsPointsDrainage(numCompressedElems);
348  GasOilScalingPointsVector gasOilScaledImbPointsVector;
349  OilWaterScalingPointsVector oilWaterScaledImbPointsVector;
350 
351  if (enableHysteresis()) {
352  gasOilScaledImbInfoVector.resize(numCompressedElems);
353  gasOilScaledImbPointsVector.resize(numCompressedElems);
354  oilWaterScaledImbInfoVector.resize(numCompressedElems);
355  oilWaterScaledImbPointsVector.resize(numCompressedElems);
356  }
357 
358  EclEpsGridProperties epsGridProperties, epsImbGridProperties;
359  epsGridProperties.initFromDeck(deck, eclState, /*imbibition=*/false);
360  if (enableHysteresis())
361  epsImbGridProperties.initFromDeck(deck, eclState, /*imbibition=*/true);
362  for (unsigned elemIdx = 0; elemIdx < numCompressedElems; ++elemIdx) {
363  unsigned cartElemIdx = static_cast<unsigned>(compressedToCartesianElemIdx[elemIdx]);
364  readGasOilScaledPoints_(gasOilScaledInfoVector,
365  gasOilScaledPointsVector,
366  gasOilConfig,
367  epsGridProperties,
368  elemIdx,
369  cartElemIdx);
370  readOilWaterScaledPoints_(oilWaterScaledEpsInfoDrainage_,
371  oilWaterScaledEpsPointsDrainage,
372  oilWaterConfig,
373  epsGridProperties,
374  elemIdx,
375  cartElemIdx);
376 
377  if (enableHysteresis()) {
378  readGasOilScaledPoints_(gasOilScaledImbInfoVector,
379  gasOilScaledImbPointsVector,
380  gasOilConfig,
381  epsImbGridProperties,
382  elemIdx,
383  cartElemIdx);
384  readOilWaterScaledPoints_(oilWaterScaledImbInfoVector,
385  oilWaterScaledImbPointsVector,
386  oilWaterConfig,
387  epsImbGridProperties,
388  elemIdx,
389  cartElemIdx);
390  }
391  }
392 
393  // create the parameter objects for the two-phase laws
394  GasOilParamVector gasOilParams(numCompressedElems);
395  OilWaterParamVector oilWaterParams(numCompressedElems);
396  GasOilParamVector gasOilImbParams;
397  OilWaterParamVector oilWaterImbParams;
398 
399  if (enableHysteresis()) {
400  gasOilImbParams.resize(numCompressedElems);
401  oilWaterImbParams.resize(numCompressedElems);
402  }
403 
404  const auto& imbnumData = eclState->getIntGridProperty("IMBNUM")->getData();
405  assert(numCompressedElems == satnumRegionArray.size());
406  for (unsigned elemIdx = 0; elemIdx < numCompressedElems; ++elemIdx) {
407  unsigned satnumIdx = static_cast<unsigned>(satnumRegionArray[elemIdx]);
408 
409  gasOilParams[elemIdx] = std::make_shared<GasOilTwoPhaseHystParams>();
410  oilWaterParams[elemIdx] = std::make_shared<OilWaterTwoPhaseHystParams>();
411 
412  gasOilParams[elemIdx]->setConfig(hysteresisConfig_);
413  oilWaterParams[elemIdx]->setConfig(hysteresisConfig_);
414 
415  auto gasOilDrainParams = std::make_shared<GasOilEpsTwoPhaseParams>();
416  gasOilDrainParams->setConfig(gasOilConfig);
417  gasOilDrainParams->setUnscaledPoints(gasOilUnscaledPointsVector[satnumIdx]);
418  gasOilDrainParams->setScaledPoints(gasOilScaledPointsVector[elemIdx]);
419  gasOilDrainParams->setEffectiveLawParams(gasOilEffectiveParamVector[satnumIdx]);
420  gasOilDrainParams->finalize();
421 
422  auto oilWaterDrainParams = std::make_shared<OilWaterEpsTwoPhaseParams>();
423  oilWaterDrainParams->setConfig(oilWaterConfig);
424  oilWaterDrainParams->setUnscaledPoints(oilWaterUnscaledPointsVector[satnumIdx]);
425  oilWaterDrainParams->setScaledPoints(oilWaterScaledEpsPointsDrainage[elemIdx]);
426  oilWaterDrainParams->setEffectiveLawParams(oilWaterEffectiveParamVector[satnumIdx]);
427  oilWaterDrainParams->finalize();
428 
429  gasOilParams[elemIdx]->setDrainageParams(gasOilDrainParams,
430  *gasOilScaledInfoVector[elemIdx],
432  oilWaterParams[elemIdx]->setDrainageParams(oilWaterDrainParams,
433  *oilWaterScaledEpsInfoDrainage_[elemIdx],
435 
436  if (enableHysteresis()) {
437  unsigned imbRegionIdx = static_cast<unsigned>(imbnumData[elemIdx]) - 1;
438 
439  auto gasOilImbParamsHyst = std::make_shared<GasOilEpsTwoPhaseParams>();
440  gasOilImbParamsHyst->setConfig(gasOilConfig);
441  gasOilImbParamsHyst->setUnscaledPoints(gasOilUnscaledPointsVector[imbRegionIdx]);
442  gasOilImbParamsHyst->setScaledPoints(gasOilScaledImbPointsVector[elemIdx]);
443  gasOilImbParamsHyst->setEffectiveLawParams(gasOilEffectiveParamVector[imbRegionIdx]);
444  gasOilImbParamsHyst->finalize();
445 
446  auto oilWaterImbParamsHyst = std::make_shared<OilWaterEpsTwoPhaseParams>();
447  oilWaterImbParamsHyst->setConfig(oilWaterConfig);
448  oilWaterImbParamsHyst->setUnscaledPoints(oilWaterUnscaledPointsVector[imbRegionIdx]);
449  oilWaterImbParamsHyst->setScaledPoints(oilWaterScaledImbPointsVector[elemIdx]);
450  oilWaterImbParamsHyst->setEffectiveLawParams(oilWaterEffectiveParamVector[imbRegionIdx]);
451  oilWaterImbParamsHyst->finalize();
452 
453  gasOilParams[elemIdx]->setImbibitionParams(gasOilImbParamsHyst,
454  *gasOilScaledImbInfoVector[elemIdx],
456  oilWaterParams[elemIdx]->setImbibitionParams(oilWaterImbParamsHyst,
457  *gasOilScaledImbInfoVector[elemIdx],
459  }
460 
461  gasOilParams[elemIdx]->finalize();
462  oilWaterParams[elemIdx]->finalize();
463  }
464 
465  // create the parameter objects for the three-phase law
466  materialLawParams_.resize(numCompressedElems);
467  for (unsigned elemIdx = 0; elemIdx < numCompressedElems; ++elemIdx) {
468  materialLawParams_[elemIdx] = std::make_shared<MaterialLawParams>();
469  unsigned satnumIdx = static_cast<unsigned>(satnumRegionArray[elemIdx]);
470 
471  initThreePhaseParams_(deck,
472  eclState,
473  *materialLawParams_[elemIdx],
474  satnumIdx,
475  *oilWaterScaledEpsInfoDrainage_[elemIdx],
476  oilWaterParams[elemIdx],
477  gasOilParams[elemIdx]);
478 
479  materialLawParams_[elemIdx]->finalize();
480  }
481  }
482 
483  // The saturation function family.
484  // If SWOF and SGOF are specified in the deck it return FamilyI
485  // If SWFN, SGFN and SOF3 are specified in the deck it return FamilyII
486  // If keywords are missing or mixed, an error is given.
487  enum SaturationFunctionFamily {
488  noFamily,
489  FamilyI,
490  FamilyII
491  };
492 
493  SaturationFunctionFamily getSaturationFunctionFamily(Opm::EclipseStateConstPtr eclState) const
494  {
495  const auto& tableManager = eclState->getTableManager();
496  const TableContainer& swofTables = tableManager->getSwofTables();
497  const TableContainer& slgofTables= tableManager->getSlgofTables();
498  const TableContainer& sgofTables = tableManager->getSgofTables();
499  const TableContainer& swfnTables = tableManager->getSwfnTables();
500  const TableContainer& sgfnTables = tableManager->getSgfnTables();
501  const TableContainer& sof3Tables = tableManager->getSof3Tables();
502 
503  bool family1 = (!sgofTables.empty() || !slgofTables.empty()) && !swofTables.empty();
504  bool family2 = !swfnTables.empty() && !sgfnTables.empty() && !sof3Tables.empty();
505 
506  if (family1 && family2) {
507  throw std::invalid_argument("Saturation families should not be mixed \n"
508  "Use either SGOF and SWOF or SGFN, SWFN and SOF3");
509  }
510 
511  if (!family1 && !family2) {
512  throw std::invalid_argument("Saturations function must be specified using either "
513  "family 1 or family 2 keywords \n"
514  "Use either SGOF and SWOF or SGFN, SWFN and SOF3" );
515  }
516 
517  if (family1 && !family2)
518  return SaturationFunctionFamily::FamilyI;
519  else if (family2 && !family1)
520  return SaturationFunctionFamily::FamilyII;
521  return SaturationFunctionFamily::noFamily; // no family or two families
522  }
523 
524  template <class Container>
525  void readGasOilEffectiveParameters_(Container& dest,
526  Opm::DeckConstPtr deck,
527  Opm::EclipseStateConstPtr eclState,
528  unsigned satnumIdx)
529  {
530  dest[satnumIdx] = std::make_shared<GasOilEffectiveTwoPhaseParams>();
531 
532  bool hasWater = deck->hasKeyword("WATER");
533  bool hasGas = deck->hasKeyword("GAS");
534  bool hasOil = deck->hasKeyword("OIL");
535 
536  auto& effParams = *dest[satnumIdx];
537 
538  // the situation for the gas phase is complicated that all saturations are
539  // shifted by the connate water saturation.
540  Scalar Swco = unscaledEpsInfo_[satnumIdx].Swl;
541 
542  // handle the twophase case
543  const auto& tableManager = eclState->getTableManager();
544  if (!hasWater) {
545  const TableContainer& sgofTables = tableManager->getSgofTables();
546  const TableContainer& slgofTables = tableManager->getSlgofTables();
547  if (!sgofTables.empty())
548  readGasOilEffectiveParametersSgof_(effParams,
549  Swco,
550  sgofTables.getTable<SgofTable>(satnumIdx));
551  else {
552  assert(!slgofTables.empty());
553  readGasOilEffectiveParametersSlgof_(effParams,
554  Swco,
555  slgofTables.getTable<SlgofTable>(satnumIdx));
556  }
557 
558  // Todo (?): support for twophase simulations using family2?
559  return;
560  }
561  else if (!hasGas) {
562  return;
563  }
564 
565  // so far, only water-oil and oil-gas simulations are supported, i.e.,
566  // there's no gas-water yet.
567  if (!hasWater || !hasGas || !hasOil)
568  throw std::domain_error("The specified phase configuration is not suppored");
569 
570  switch (getSaturationFunctionFamily(eclState)) {
571  case FamilyI:
572  {
573  const TableContainer& sgofTables = tableManager->getSgofTables();
574  const TableContainer& slgofTables = tableManager->getSlgofTables();
575  if (!sgofTables.empty())
576  readGasOilEffectiveParametersSgof_(effParams,
577  Swco,
578  sgofTables.getTable<SgofTable>(satnumIdx));
579  else if (!slgofTables.empty())
580  readGasOilEffectiveParametersSlgof_(effParams,
581  Swco,
582  slgofTables.getTable<SlgofTable>(satnumIdx));
583  break;
584  }
585 
586  case FamilyII:
587  {
588  const Sof3Table& sof3Table = tableManager->getSof3Tables().getTable<Sof3Table>( satnumIdx );
589  const SgfnTable& sgfnTable = tableManager->getSgfnTables().getTable<SgfnTable>( satnumIdx );
590  readGasOilEffectiveParametersFamily2_(effParams,
591  Swco,
592  sof3Table,
593  sgfnTable);
594  break;
595  }
596 
597  //default:
598  case noFamily:
599  throw std::domain_error("No valid saturation keyword family specified");
600 
601  }
602  }
603 
604  void readGasOilEffectiveParametersSgof_(GasOilEffectiveTwoPhaseParams& effParams,
605  Scalar Swco,
606  const Opm::SgofTable& sgofTable)
607  {
608  // convert the saturations of the SGOF keyword from gas to oil saturations
609  std::vector<double> SoSamples(sgofTable.numRows());
610  std::vector<double> SoKroSamples(sgofTable.numRows());
611  for (size_t sampleIdx = 0; sampleIdx < sgofTable.numRows(); ++ sampleIdx) {
612  SoSamples[sampleIdx] = 1 - sgofTable.getSgColumn()[sampleIdx];
613  SoKroSamples[sampleIdx] = SoSamples[sampleIdx] - Swco;
614  }
615 
616  effParams.setKrwSamples(SoKroSamples, sgofTable.getKrogColumn());
617  effParams.setKrnSamples(SoSamples, sgofTable.getKrgColumn());
618  effParams.setPcnwSamples(SoSamples, sgofTable.getPcogColumn());
619  effParams.finalize();
620  }
621 
622  void readGasOilEffectiveParametersSlgof_(GasOilEffectiveTwoPhaseParams& effParams,
623  Scalar Swco,
624  const Opm::SlgofTable& slgofTable)
625  {
626  // convert the saturations of the SLGOF keyword from "liquid" to oil saturations
627  std::vector<double> SoSamples(slgofTable.numRows());
628  std::vector<double> SoKroSamples(slgofTable.numRows());
629  for (size_t sampleIdx = 0; sampleIdx < slgofTable.numRows(); ++ sampleIdx) {
630  SoSamples[sampleIdx] = slgofTable.getSlColumn()[sampleIdx];
631  SoKroSamples[sampleIdx] = slgofTable.getSlColumn()[sampleIdx] - Swco;
632  }
633 
634  effParams.setKrwSamples(SoKroSamples, slgofTable.getKrogColumn());
635  effParams.setKrnSamples(SoSamples, slgofTable.getKrgColumn());
636  effParams.setPcnwSamples(SoSamples, slgofTable.getPcogColumn());
637  effParams.finalize();
638  }
639 
640  void readGasOilEffectiveParametersFamily2_(GasOilEffectiveTwoPhaseParams& effParams,
641  Scalar /* Swco */,
642  const Opm::Sof3Table& sof3Table,
643  const Opm::SgfnTable& sgfnTable)
644  {
645  // convert the saturations of the SGFN keyword from gas to oil saturations
646  std::vector<double> SoSamples(sgfnTable.numRows());
647  const auto &SoColumn = sof3Table.getSoColumn();
648  for (size_t sampleIdx = 0; sampleIdx < sgfnTable.numRows(); ++ sampleIdx) {
649  SoSamples[sampleIdx] = 1 - sgfnTable.getSgColumn()[sampleIdx];
650  }
651 
652  effParams.setKrwSamples(SoColumn, sof3Table.getKrogColumn());
653  effParams.setKrnSamples(SoSamples, sgfnTable.getKrgColumn());
654  effParams.setPcnwSamples(SoSamples, sgfnTable.getPcogColumn());
655  effParams.finalize();
656  }
657 
658  template <class Container>
659  void readOilWaterEffectiveParameters_(Container& dest,
660  Opm::DeckConstPtr deck,
661  Opm::EclipseStateConstPtr eclState,
662  unsigned satnumIdx)
663  {
664  dest[satnumIdx] = std::make_shared<OilWaterEffectiveTwoPhaseParams>();
665 
666  bool hasWater = deck->hasKeyword("WATER");
667  bool hasGas = deck->hasKeyword("GAS");
668  bool hasOil = deck->hasKeyword("OIL");
669 
670  const auto tableManager = eclState->getTableManager();
671  auto& effParams = *dest[satnumIdx];
672 
673  // handle the twophase case
674  if (!hasWater) {
675  return;
676  }
677  else if (!hasGas) {
678  const auto& swofTable = tableManager->getSwofTables().getTable<SwofTable>(satnumIdx);
679  const auto &SwColumn = swofTable.getSwColumn();
680 
681  effParams.setKrwSamples(SwColumn, swofTable.getKrwColumn());
682  effParams.setKrnSamples(SwColumn, swofTable.getKrowColumn());
683  effParams.setPcnwSamples(SwColumn, swofTable.getPcowColumn());
684  effParams.finalize();
685 
686  // Todo (?): support for twophase simulations using family2?
687  return;
688  }
689 
690  // so far, only water-oil and oil-gas simulations are supported, i.e.,
691  // there's no gas-water yet.
692  if (!hasWater || !hasGas || !hasOil)
693  throw std::domain_error("The specified phase configuration is not suppored");
694 
695  switch (getSaturationFunctionFamily(eclState)) {
696  case FamilyI: {
697  const auto& swofTable = tableManager->getSwofTables().getTable<SwofTable>(satnumIdx);
698  const auto &SwColumn = swofTable.getSwColumn();
699 
700  effParams.setKrwSamples(SwColumn, swofTable.getKrwColumn());
701  effParams.setKrnSamples(SwColumn, swofTable.getKrowColumn());
702  effParams.setPcnwSamples(SwColumn, swofTable.getPcowColumn());
703  effParams.finalize();
704  break;
705  }
706  case FamilyII:
707  {
708  const auto& swfnTable = tableManager->getSwfnTables().getTable<SwfnTable>(satnumIdx);
709  const auto& sof3Table = tableManager->getSof3Tables().getTable<Sof3Table>(satnumIdx);
710  const auto &SwColumn = swfnTable.getSwColumn();
711 
712  // convert the saturations of the SOF3 keyword from oil to water saturations
713  std::vector<double> SwSamples(sof3Table.numRows());
714  for (size_t sampleIdx = 0; sampleIdx < sof3Table.numRows(); ++ sampleIdx)
715  SwSamples[sampleIdx] = 1 - sof3Table.getSoColumn()[sampleIdx];
716 
717  effParams.setKrwSamples(SwColumn, swfnTable.getKrwColumn());
718  effParams.setKrnSamples(SwSamples, sof3Table.getKrowColumn());
719  effParams.setPcnwSamples(SwColumn, swfnTable.getPcowColumn());
720  effParams.finalize();
721  break;
722  }
723 
724  case noFamily:
725  //default:
726  throw std::domain_error("No valid saturation keyword family specified");
727 
728  }
729  }
730 
731 
732  template <class Container>
733  void readGasOilUnscaledPoints_(Container &dest,
734  std::shared_ptr<EclEpsConfig> config,
735  Opm::DeckConstPtr /* deck */,
736  Opm::EclipseStateConstPtr /* eclState */,
737  unsigned satnumIdx)
738  {
739  dest[satnumIdx] = std::make_shared<EclEpsScalingPoints<Scalar> >();
740  dest[satnumIdx]->init(unscaledEpsInfo_[satnumIdx], *config, EclGasOilSystem);
741  }
742 
743  template <class Container>
744  void readOilWaterUnscaledPoints_(Container &dest,
745  std::shared_ptr<EclEpsConfig> config,
746  Opm::DeckConstPtr /* deck */,
747  Opm::EclipseStateConstPtr /* eclState */,
748  unsigned satnumIdx)
749  {
750  dest[satnumIdx] = std::make_shared<EclEpsScalingPoints<Scalar> >();
751  dest[satnumIdx]->init(unscaledEpsInfo_[satnumIdx], *config, EclOilWaterSystem);
752  }
753 
754  template <class InfoContainer, class PointsContainer>
755  void readGasOilScaledPoints_(InfoContainer& destInfo,
756  PointsContainer& destPoints,
757  std::shared_ptr<EclEpsConfig> config,
758  const EclEpsGridProperties& epsGridProperties,
759  unsigned elemIdx,
760  unsigned cartElemIdx)
761  {
762  unsigned satnumIdx = static_cast<unsigned>((*epsGridProperties.satnum)[cartElemIdx]) - 1; // ECL uses Fortran indices!
763 
764  destInfo[elemIdx] = std::make_shared<EclEpsScalingPointsInfo<Scalar> >(unscaledEpsInfo_[satnumIdx]);
765  destInfo[elemIdx]->extractScaled(epsGridProperties, cartElemIdx);
766 
767  destPoints[elemIdx] = std::make_shared<EclEpsScalingPoints<Scalar> >();
768  destPoints[elemIdx]->init(*destInfo[elemIdx], *config, EclGasOilSystem);
769  }
770 
771  template <class InfoContainer, class PointsContainer>
772  void readOilWaterScaledPoints_(InfoContainer& destInfo,
773  PointsContainer& destPoints,
774  std::shared_ptr<EclEpsConfig> config,
775  const EclEpsGridProperties& epsGridProperties,
776  unsigned elemIdx,
777  unsigned cartElemIdx)
778  {
779  unsigned satnumIdx = static_cast<unsigned>((*epsGridProperties.satnum)[cartElemIdx]) - 1; // ECL uses Fortran indices!
780 
781  destInfo[elemIdx] = std::make_shared<EclEpsScalingPointsInfo<Scalar> >(unscaledEpsInfo_[satnumIdx]);
782  destInfo[elemIdx]->extractScaled(epsGridProperties, cartElemIdx);
783 
784  destPoints[elemIdx] = std::make_shared<EclEpsScalingPoints<Scalar> >();
785  destPoints[elemIdx]->init(*destInfo[elemIdx], *config, EclOilWaterSystem);
786  }
787 
788  void initThreePhaseParams_(Opm::DeckConstPtr deck,
789  Opm::EclipseStateConstPtr /* eclState */,
790  MaterialLawParams& materialParams,
791  unsigned satnumIdx,
792  const EclEpsScalingPointsInfo<Scalar>& epsInfo,
793  std::shared_ptr<OilWaterTwoPhaseHystParams> oilWaterParams,
794  std::shared_ptr<GasOilTwoPhaseHystParams> gasOilParams)
795  {
796  materialParams.setApproach(threePhaseApproach_);
797 
798  switch (materialParams.approach()) {
799  case EclStone1Approach: {
800  auto& realParams = materialParams.template getRealParams<Opm::EclStone1Approach>();
801  realParams.setGasOilParams(gasOilParams);
802  realParams.setOilWaterParams(oilWaterParams);
803  realParams.setSwl(epsInfo.Swl);
804  realParams.setSowcr(epsInfo.Sowcr);
805 
806  if (deck->hasKeyword("STONE1EX")) {
807  Scalar eta =
808  deck->getKeyword("STONE1EX")->getRecord(satnumIdx)->getItem(0)->getSIDouble(0);
809  realParams.setSogcr(eta);
810  }
811  else
812  realParams.setSogcr(1.0);
813  realParams.finalize();
814  break;
815  }
816 
817  case EclStone2Approach: {
818  auto& realParams = materialParams.template getRealParams<Opm::EclStone2Approach>();
819  realParams.setGasOilParams(gasOilParams);
820  realParams.setOilWaterParams(oilWaterParams);
821  realParams.setSwl(epsInfo.Swl);
822  realParams.finalize();
823  break;
824  }
825 
826  case EclDefaultApproach: {
827  auto& realParams = materialParams.template getRealParams<Opm::EclDefaultApproach>();
828  realParams.setGasOilParams(gasOilParams);
829  realParams.setOilWaterParams(oilWaterParams);
830  realParams.setSwl(epsInfo.Swl);
831  realParams.finalize();
832  break;
833  }
834 
835  case EclTwoPhaseApproach: {
836  auto& realParams = materialParams.template getRealParams<Opm::EclTwoPhaseApproach>();
837  realParams.setGasOilParams(gasOilParams);
838  realParams.setOilWaterParams(oilWaterParams);
839  realParams.setApproach(twoPhaseApproach_);
840  realParams.finalize();
841  break;
842  }
843  }
844  }
845 
846  EclEpsScalingPoints<Scalar>& getOilWaterScaledEpsPointsDrainage_(unsigned elemIdx)
847  {
848  auto& materialParams = *materialLawParams_[elemIdx];
849  switch (materialParams.approach()) {
850  case EclStone1Approach: {
851  auto& realParams = materialParams.template getRealParams<Opm::EclStone1Approach>();
852  return realParams.oilWaterParams().drainageParams().scaledPoints();
853  }
854 
855  case EclStone2Approach: {
856  auto& realParams = materialParams.template getRealParams<Opm::EclStone2Approach>();
857  return realParams.oilWaterParams().drainageParams().scaledPoints();
858  }
859 
860  case EclDefaultApproach: {
861  auto& realParams = materialParams.template getRealParams<Opm::EclDefaultApproach>();
862  return realParams.oilWaterParams().drainageParams().scaledPoints();
863  }
864 
865  case EclTwoPhaseApproach: {
866  auto& realParams = materialParams.template getRealParams<Opm::EclTwoPhaseApproach>();
867  return realParams.oilWaterParams().drainageParams().scaledPoints();
868  }
869  default:
870  OPM_THROW(std::logic_error, "Enum value for material approach unknown!");
871  }
872  }
873 
874  bool enableEndPointScaling_;
875  std::shared_ptr<EclHysteresisConfig> hysteresisConfig_;
876 
877  std::shared_ptr<EclEpsConfig> oilWaterEclEpsConfig_;
878  std::vector<Opm::EclEpsScalingPointsInfo<Scalar>> unscaledEpsInfo_;
879  OilWaterScalingInfoVector oilWaterScaledEpsInfoDrainage_;
880 
881  Opm::EclMultiplexerApproach threePhaseApproach_;
882 
883  // this attribute only makes sense for twophase simulations!
884  enum EclTwoPhaseApproach twoPhaseApproach_;
885 
886  std::vector<std::shared_ptr<MaterialLawParams> > materialLawParams_;
887 };
888 } // namespace Opm
889 
890 #endif
ParamsT Params
The type of the parameter objects for this law.
Definition: PiecewiseLinearTwoPhaseMaterial.hpp:60
This material law implements the hysteresis model of the ECL file format.
Specifies the configuration used by the ECL kr/pC hysteresis code.
Definition: EclTwoPhaseMaterialParams.hpp:35
Definition: Air_Mesitylene.hpp:31
Definition: EclMultiplexerMaterialParams.hpp:42
void updateHysteresis(const FluidState &fluidState, unsigned elemIdx)
Definition: EclMaterialLawManager.hpp:216
bool enableHysteresis() const
Definition: EclMaterialLawManager.hpp:200
Implementation for the parameters required by the material law for two-phase simulations.
Provides an simple way to create and manage the material law objects for a complete ECL deck...
Definition: EclMaterialLawManager.hpp:62
MaterialLaw::Params MaterialLawParams
Definition: EclMaterialLawManager.hpp:96
bool enableEndPointScaling() const
Definition: EclMaterialLawManager.hpp:197
EclTwoPhaseApproach
Definition: EclTwoPhaseMaterialParams.hpp:33
Definition: EclTwoPhaseMaterialParams.hpp:34
Implements a multiplexer class that provides all three phase capillary pressure laws used by the ECLi...
Definition: EclMultiplexerMaterial.hpp:55
MaterialLawParams & materialLawParams(unsigned elemIdx)
Definition: EclMaterialLawManager.hpp:203
This structure represents all values which can be possibly used as scaling points in the endpoint sca...
Definition: EclEpsScalingPoints.hpp:122
ParamsT Params
Definition: EclHysteresisTwoPhaseLaw.hpp:45
EclMultiplexerMaterial< Traits, GasOilTwoPhaseLaw, OilWaterTwoPhaseLaw > MaterialLaw
Definition: EclMaterialLawManager.hpp:95
Definition: EclMultiplexerMaterialParams.hpp:41
EclMultiplexerApproach
Definition: EclMultiplexerMaterialParams.hpp:39
EclMaterialLawManager()
Definition: EclMaterialLawManager.hpp:111
void initFromDeck(Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclState, const std::vector< int > &compressedToCartesianElemIdx)
Definition: EclMaterialLawManager.hpp:114
This file contains helper classes for the material laws.
const Opm::EclEpsScalingPointsInfo< Scalar > & oilWaterScaledEpsInfoDrainage(size_t elemIdx) const
Definition: EclMaterialLawManager.hpp:225
Scalar applySwatinit(unsigned elemIdx, Scalar pcow, Scalar Sw)
Modify the initial condition according to the SWATINIT keyword.
Definition: EclMaterialLawManager.hpp:154
A generic traits class for two-phase material laws.
Definition: MaterialTraits.hpp:57
Definition: EclEpsConfig.hpp:44
ParamsT Params
Definition: EclEpsTwoPhaseLaw.hpp:54
This material law takes a material law defined for unscaled saturation and converts it to a material ...
Implements a multiplexer class that provides all three phase capillary pressure laws used by the ECLi...
This material law implements the hysteresis model of the ECL file format.
Definition: EclHysteresisTwoPhaseLaw.hpp:38
This material law takes a material law defined for unscaled saturation and converts it to a material ...
Definition: EclEpsTwoPhaseLaw.hpp:48
Specifies the configuration used by the endpoint scaling code.
const MaterialLawParams & materialLawParams(unsigned elemIdx) const
Definition: EclMaterialLawManager.hpp:209
Definition: EclEpsConfig.hpp:43
Represents all relevant thermodynamic quantities of a multi-phase, multi-component fluid system assum...
Definition: EclTwoPhaseMaterialParams.hpp:36
Implementation of a tabulated, piecewise linear capillary pressure law.
Definition: PiecewiseLinearTwoPhaseMaterial.hpp:51
Implementation of a tabulated, piecewise linear capillary pressure law.
Definition: EclMultiplexerMaterialParams.hpp:40
Represents all relevant thermodynamic quantities of a multi-phase, multi-component fluid system assum...
Definition: SimpleModularFluidState.hpp:75