Add support for IMBNUM
First stage in adding support for using imbibition for cell faces (IMBNUMX, IMBNUMY, IMBNUMZ). At the same time, refactors initParamsForElements() in EclMaterialLawManager.hpp into separate files to more easily add support for materal law parameters for cell faces.
This commit is contained in:
@@ -257,6 +257,9 @@ if(ENABLE_ECL_INPUT)
|
||||
src/opm/material/fluidmatrixinteractions/EclEpsGridProperties.cpp
|
||||
src/opm/material/fluidmatrixinteractions/EclHysteresisConfig.cpp
|
||||
src/opm/material/fluidmatrixinteractions/EclMaterialLawManager.cpp
|
||||
src/opm/material/fluidmatrixinteractions/EclMaterialLawManagerReadEffectiveParams.cpp
|
||||
src/opm/material/fluidmatrixinteractions/EclMaterialLawManagerInitParams.cpp
|
||||
src/opm/material/fluidmatrixinteractions/EclMaterialLawManagerHystParams.cpp
|
||||
src/opm/material/fluidsystems/blackoilpvt/BrineCo2Pvt.cpp
|
||||
src/opm/material/fluidsystems/blackoilpvt/Co2GasPvt.cpp
|
||||
src/opm/material/fluidsystems/blackoilpvt/ConstantCompressibilityBrinePvt.cpp
|
||||
@@ -856,6 +859,8 @@ list( APPEND PUBLIC_HEADER_FILES
|
||||
opm/material/fluidmatrixinteractions/EclEpsTwoPhaseLaw.hpp
|
||||
opm/material/fluidmatrixinteractions/TwoPhaseLETCurves.hpp
|
||||
opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp
|
||||
opm/material/fluidmatrixinteractions/DirectionalMaterialLawParams.hpp
|
||||
opm/material/fluidmatrixinteractions/DirectionalMaterialLawParams.hpp
|
||||
opm/material/fluidmatrixinteractions/RegularizedVanGenuchten.hpp
|
||||
opm/material/fluidmatrixinteractions/EclDefaultMaterialParams.hpp
|
||||
opm/material/fluidmatrixinteractions/ThreePhaseParkerVanGenuchten.hpp
|
||||
|
||||
@@ -247,6 +247,9 @@ static const std::unordered_map<std::string, keyword_info<int>> int_keywords = {
|
||||
{"KRNUMX", keyword_info<int>{}},
|
||||
{"KRNUMY", keyword_info<int>{}},
|
||||
{"KRNUMZ", keyword_info<int>{}},
|
||||
{"IMBNUMX", keyword_info<int>{}},
|
||||
{"IMBNUMY", keyword_info<int>{}},
|
||||
{"IMBNUMZ", keyword_info<int>{}},
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Copyright 2022 Equinor ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*!
|
||||
* \file
|
||||
*
|
||||
* \brief This file contains definitions related to directional material law parameters
|
||||
*/
|
||||
#ifndef OPM_DIRECTIONAL_MATERIAL_LAW_PARAMS_HH
|
||||
#define OPM_DIRECTIONAL_MATERIAL_LAW_PARAMS_HH
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
namespace Opm {
|
||||
template <class MaterialLawParams>
|
||||
struct DirectionalMaterialLawParams {
|
||||
using vector_type = std::vector<MaterialLawParams>;
|
||||
DirectionalMaterialLawParams() : materialLawParamsX_{}, materialLawParamsY_{}, materialLawParamsZ_{} {}
|
||||
DirectionalMaterialLawParams(std::size_t size) :
|
||||
materialLawParamsX_(size), materialLawParamsY_(size), materialLawParamsZ_(size) {}
|
||||
vector_type& getArray(int index) {
|
||||
switch(index) {
|
||||
case 0:
|
||||
return materialLawParamsX_;
|
||||
case 1:
|
||||
return materialLawParamsY_;
|
||||
case 2:
|
||||
return materialLawParamsZ_;
|
||||
default:
|
||||
throw std::runtime_error("Unexpected mobility array index");
|
||||
}
|
||||
}
|
||||
vector_type materialLawParamsX_;
|
||||
vector_type materialLawParamsY_;
|
||||
vector_type materialLawParamsZ_;
|
||||
};
|
||||
} // namespace Opm
|
||||
#endif
|
||||
@@ -38,6 +38,9 @@
|
||||
#include <opm/material/fluidmatrixinteractions/EclHysteresisTwoPhaseLaw.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/EclMultiplexerMaterial.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/MaterialTraits.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/DirectionalMaterialLawParams.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableColumn.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
@@ -56,8 +59,6 @@ class Runspec;
|
||||
class SgfnTable;
|
||||
class SgofTable;
|
||||
class SlgofTable;
|
||||
class Sof2Table;
|
||||
class Sof3Table;
|
||||
|
||||
/*!
|
||||
* \ingroup fluidmatrixinteractions
|
||||
@@ -109,6 +110,7 @@ public:
|
||||
// the three-phase material law used by the simulation
|
||||
using MaterialLaw = EclMultiplexerMaterial<Traits, GasOilTwoPhaseLaw, OilWaterTwoPhaseLaw, GasWaterTwoPhaseLaw>;
|
||||
using MaterialLawParams = typename MaterialLaw::Params;
|
||||
using DirectionalMaterialLawParamsPtr = std::unique_ptr<DirectionalMaterialLawParams<MaterialLawParams>>;
|
||||
|
||||
EclMaterialLawManager();
|
||||
~EclMaterialLawManager();
|
||||
@@ -128,6 +130,113 @@ private:
|
||||
using GasWaterParamVector = std::vector<std::shared_ptr<GasWaterTwoPhaseHystParams>>;
|
||||
using MaterialLawParamsVector = std::vector<std::shared_ptr<MaterialLawParams>>;
|
||||
|
||||
// helper classes
|
||||
|
||||
// This class' implementation is defined in "EclMaterialLawManagerInitParams.cpp"
|
||||
class InitParams {
|
||||
public:
|
||||
InitParams(EclMaterialLawManager<TraitsT>& parent, const EclipseState& eclState, size_t numCompressedElems);
|
||||
void run();
|
||||
private:
|
||||
class HystParams;
|
||||
void copySatnumArrays_();
|
||||
void copyIntArray_(std::vector<int>& dest, const std::string keyword);
|
||||
unsigned imbRegion_(std::vector<int>& array, unsigned elemIdx);
|
||||
void initArrays_(
|
||||
std::vector<std::vector<int>*>& satnumArray,
|
||||
std::vector<std::vector<int>*>& imbnumArray,
|
||||
std::vector<std::vector<MaterialLawParams>*>& mlpArray);
|
||||
void initMaterialLawParamVectors_();
|
||||
void initOilWaterScaledEpsInfo_();
|
||||
void initSatnumRegionArray_();
|
||||
void initThreePhaseParams_(
|
||||
HystParams &hystParams,
|
||||
MaterialLawParams& materialParams,
|
||||
unsigned satRegionIdx,
|
||||
unsigned elemIdx);
|
||||
void readEffectiveParameters_();
|
||||
void readUnscaledEpsPointsVectors_();
|
||||
template <class Container>
|
||||
void readUnscaledEpsPoints_(Container& dest, std::shared_ptr<EclEpsConfig> config, EclTwoPhaseSystemType system_type);
|
||||
unsigned satRegion_(std::vector<int>& array, unsigned elemIdx);
|
||||
unsigned satOrImbRegion_(std::vector<int>& array, std::vector<int>& default_vec, unsigned elemIdx);
|
||||
|
||||
// This class' implementation is defined in "EclMaterialLawManagerHystParams.cpp"
|
||||
class HystParams {
|
||||
public:
|
||||
HystParams(EclMaterialLawManager<TraitsT>::InitParams& init_params);
|
||||
void finalize();
|
||||
std::shared_ptr<GasOilTwoPhaseHystParams> getGasOilParams();
|
||||
std::shared_ptr<OilWaterTwoPhaseHystParams> getOilWaterParams();
|
||||
std::shared_ptr<GasWaterTwoPhaseHystParams> getGasWaterParams();
|
||||
void setConfig();
|
||||
void setDrainageParamsOilGas(unsigned elemIdx, unsigned satRegionIdx);
|
||||
void setDrainageParamsOilWater(unsigned elemIdx, unsigned satRegionIdx);
|
||||
void setDrainageParamsGasWater(unsigned elemIdx, unsigned satRegionIdx);
|
||||
void setImbibitionParamsOilGas(unsigned elemIdx, unsigned satRegionIdx);
|
||||
void setImbibitionParamsOilWater(unsigned elemIdx, unsigned satRegionIdx);
|
||||
void setImbibitionParamsGasWater(unsigned elemIdx, unsigned satRegionIdx);
|
||||
private:
|
||||
bool hasGasWater_();
|
||||
bool hasGasOil_();
|
||||
bool hasOilWater_();
|
||||
|
||||
std::tuple<EclEpsScalingPointsInfo<Scalar>, EclEpsScalingPoints<Scalar>> readScaledEpsPoints_(
|
||||
const EclEpsGridProperties& epsGridProperties, unsigned elemIdx, EclTwoPhaseSystemType type);
|
||||
std::tuple<EclEpsScalingPointsInfo<Scalar>, EclEpsScalingPoints<Scalar>>
|
||||
readScaledEpsPointsDrainage_(unsigned elemIdx, EclTwoPhaseSystemType type);
|
||||
std::tuple<EclEpsScalingPointsInfo<Scalar>, EclEpsScalingPoints<Scalar>>
|
||||
readScaledEpsPointsImbibition_(unsigned elemIdx, EclTwoPhaseSystemType type);
|
||||
EclMaterialLawManager<TraitsT>::InitParams& init_params_;
|
||||
EclMaterialLawManager<TraitsT>& parent_;
|
||||
const EclipseState& eclState_;
|
||||
std::shared_ptr<GasOilTwoPhaseHystParams> gasOilParams_;
|
||||
std::shared_ptr<OilWaterTwoPhaseHystParams> oilWaterParams_;
|
||||
std::shared_ptr<GasWaterTwoPhaseHystParams> gasWaterParams_;
|
||||
};
|
||||
|
||||
// This class' implementation is defined in "EclMaterialLawManagerReadEffectiveParams.cpp"
|
||||
class ReadEffectiveParams {
|
||||
public:
|
||||
ReadEffectiveParams(EclMaterialLawManager<TraitsT>::InitParams& init_params);
|
||||
void read();
|
||||
private:
|
||||
std::vector<double> normalizeKrValues_(const double tolcrit, const TableColumn& krValues) const;
|
||||
void readGasOilParameters_(GasOilEffectiveParamVector& dest, unsigned satRegionIdx);
|
||||
template <class TableType>
|
||||
void readGasOilFamily2_(
|
||||
GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const TableType& sofTable,
|
||||
const SgfnTable& sgfnTable,
|
||||
const std::string& columnName);
|
||||
void readGasOilSgof_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const SgofTable& sgofTable);
|
||||
|
||||
void readGasOilSlgof_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const SlgofTable& slgofTable);
|
||||
void readGasWaterParameters_(GasWaterEffectiveParamVector& dest, unsigned satRegionIdx);
|
||||
void readOilWaterParameters_(OilWaterEffectiveParamVector& dest, unsigned satRegionIdx);
|
||||
|
||||
EclMaterialLawManager<TraitsT>::InitParams& init_params_;
|
||||
EclMaterialLawManager<TraitsT>& parent_;
|
||||
const EclipseState& eclState_;
|
||||
}; // end of "class ReadEffectiveParams"
|
||||
|
||||
EclMaterialLawManager<TraitsT>& parent_;
|
||||
const EclipseState& eclState_;
|
||||
size_t numCompressedElems_;
|
||||
|
||||
std::unique_ptr<EclEpsGridProperties> epsImbGridProperties_; //imbibition
|
||||
std::unique_ptr<EclEpsGridProperties> epsGridProperties_; // drainage
|
||||
|
||||
}; // end of "class InitParams"
|
||||
|
||||
public:
|
||||
void initFromState(const EclipseState& eclState);
|
||||
|
||||
@@ -163,6 +272,16 @@ public:
|
||||
return materialLawParams_[elemIdx];
|
||||
}
|
||||
|
||||
const MaterialLawParams& materialLawParams(unsigned elemIdx, FaceDir::DirEnum facedir) const
|
||||
{
|
||||
return materialLawParamsFunc_(elemIdx, facedir);
|
||||
}
|
||||
|
||||
MaterialLawParams& materialLawParams(unsigned elemIdx, FaceDir::DirEnum facedir)
|
||||
{
|
||||
return const_cast<MaterialLawParams&>(materialLawParamsFunc_(elemIdx, facedir));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns a material parameter object for a given element and saturation region.
|
||||
*
|
||||
@@ -183,6 +302,13 @@ public:
|
||||
return !krnumXArray_.empty() || !krnumYArray_.empty() || !krnumZArray_.empty();
|
||||
}
|
||||
|
||||
bool hasDirectionalImbnum() const {
|
||||
if (imbnumXArray_.size() > 0 || imbnumYArray_.size() > 0 || imbnumZArray_.size() > 0) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int imbnumRegionIdx(unsigned elemIdx) const
|
||||
{ return imbnumRegionArray_[elemIdx]; }
|
||||
|
||||
@@ -192,7 +318,15 @@ public:
|
||||
if (!enableHysteresis())
|
||||
return;
|
||||
|
||||
MaterialLaw::updateHysteresis(materialLawParams_[elemIdx], fluidState);
|
||||
MaterialLaw::updateHysteresis(materialLawParams(elemIdx), fluidState);
|
||||
if (hasDirectionalRelperms() || hasDirectionalImbnum()) {
|
||||
using Dir = FaceDir::DirEnum;
|
||||
constexpr int ndim = 3;
|
||||
Dir facedirs[ndim] = {Dir::XPlus, Dir::YPlus, Dir::ZPlus};
|
||||
for (int i = 0; i<ndim; i++) {
|
||||
MaterialLaw::updateHysteresis(materialLawParams(elemIdx, facedirs[i]), fluidState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void oilWaterHysteresisParams(Scalar& pcSwMdc,
|
||||
@@ -217,83 +351,14 @@ public:
|
||||
{ return oilWaterScaledEpsInfoDrainage_[elemIdx]; }
|
||||
|
||||
private:
|
||||
const MaterialLawParams& materialLawParamsFunc_(unsigned elemIdx, FaceDir::DirEnum facedir) const;
|
||||
|
||||
void readGlobalEpsOptions_(const EclipseState& eclState);
|
||||
|
||||
void readGlobalHysteresisOptions_(const EclipseState& state);
|
||||
|
||||
void readGlobalThreePhaseOptions_(const Runspec& runspec);
|
||||
|
||||
template <class Container>
|
||||
void readGasOilEffectiveParameters_(Container& dest,
|
||||
const EclipseState& eclState,
|
||||
unsigned satRegionIdx);
|
||||
|
||||
void readGasOilEffectiveParametersSgof_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const SgofTable& sgofTable);
|
||||
|
||||
void readGasOilEffectiveParametersSlgof_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const SlgofTable& slgofTable);
|
||||
|
||||
void readGasOilEffectiveParametersFamily2_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const Sof3Table& sof3Table,
|
||||
const SgfnTable& sgfnTable);
|
||||
|
||||
void readGasOilEffectiveParametersFamily2_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const Sof2Table& sof2Table,
|
||||
const SgfnTable& sgfnTable);
|
||||
|
||||
template <class Container>
|
||||
void readOilWaterEffectiveParameters_(Container& dest,
|
||||
const EclipseState& eclState,
|
||||
unsigned satRegionIdx);
|
||||
|
||||
template <class Container>
|
||||
void readGasWaterEffectiveParameters_(Container& dest,
|
||||
const EclipseState& eclState,
|
||||
unsigned satRegionIdx);
|
||||
|
||||
template <class Container>
|
||||
void readGasOilUnscaledPoints_(Container& dest,
|
||||
std::shared_ptr<EclEpsConfig> config,
|
||||
const EclipseState& /* eclState */,
|
||||
unsigned satRegionIdx);
|
||||
|
||||
template <class Container>
|
||||
void readOilWaterUnscaledPoints_(Container& dest,
|
||||
std::shared_ptr<EclEpsConfig> config,
|
||||
const EclipseState& /* eclState */,
|
||||
unsigned satRegionIdx);
|
||||
|
||||
template <class Container>
|
||||
void readGasWaterUnscaledPoints_(Container& dest,
|
||||
std::shared_ptr<EclEpsConfig> config,
|
||||
const EclipseState& /* eclState */,
|
||||
unsigned satRegionIdx);
|
||||
|
||||
std::tuple<EclEpsScalingPointsInfo<Scalar>,
|
||||
EclEpsScalingPoints<Scalar>>
|
||||
readScaledPoints_(const EclEpsConfig& config,
|
||||
const EclipseState& eclState,
|
||||
const EclEpsGridProperties& epsGridProperties,
|
||||
unsigned elemIdx,
|
||||
EclTwoPhaseSystemType type);
|
||||
|
||||
void initThreePhaseParams_(const EclipseState& /* eclState */,
|
||||
MaterialLawParams& materialParams,
|
||||
unsigned satRegionIdx,
|
||||
const EclEpsScalingPointsInfo<Scalar>& epsInfo,
|
||||
std::shared_ptr<OilWaterTwoPhaseHystParams> oilWaterParams,
|
||||
std::shared_ptr<GasOilTwoPhaseHystParams> gasOilParams,
|
||||
std::shared_ptr<GasWaterTwoPhaseHystParams> gasWaterParams);
|
||||
|
||||
bool enableEndPointScaling_;
|
||||
std::shared_ptr<EclHysteresisConfig> hysteresisConfig_;
|
||||
|
||||
@@ -316,21 +381,25 @@ private:
|
||||
enum EclTwoPhaseApproach twoPhaseApproach_ = EclTwoPhaseApproach::GasOil;
|
||||
|
||||
std::vector<MaterialLawParams> materialLawParams_;
|
||||
DirectionalMaterialLawParamsPtr dirMaterialLawParams_;
|
||||
|
||||
std::vector<int> satnumRegionArray_;
|
||||
std::vector<int> krnumXArray_;
|
||||
std::vector<int> krnumYArray_;
|
||||
std::vector<int> krnumZArray_;
|
||||
std::vector<int> imbnumXArray_;
|
||||
std::vector<int> imbnumYArray_;
|
||||
std::vector<int> imbnumZArray_;
|
||||
std::vector<int> imbnumRegionArray_;
|
||||
std::vector<Scalar> stoneEtas;
|
||||
std::vector<Scalar> stoneEtas_;
|
||||
|
||||
bool hasGas;
|
||||
bool hasOil;
|
||||
bool hasWater;
|
||||
|
||||
std::shared_ptr<EclEpsConfig> gasOilConfig;
|
||||
std::shared_ptr<EclEpsConfig> oilWaterConfig;
|
||||
std::shared_ptr<EclEpsConfig> gasWaterConfig;
|
||||
std::shared_ptr<EclEpsConfig> gasOilConfig_;
|
||||
std::shared_ptr<EclEpsConfig> oilWaterConfig_;
|
||||
std::shared_ptr<EclEpsConfig> gasWaterConfig_;
|
||||
};
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
"sections": [
|
||||
"REGIONS"
|
||||
],
|
||||
"deck_names": [
|
||||
"IMBNUM",
|
||||
"IMBNUMX",
|
||||
"IMBNUMY",
|
||||
"IMBNUMZ"
|
||||
],
|
||||
"data": {
|
||||
"value_type": "INT"
|
||||
}
|
||||
|
||||
@@ -26,41 +26,13 @@
|
||||
|
||||
#include <opm/common/OpmLog/OpmLog.hpp>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SgfnTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SgofTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SlgofTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/Sof2Table.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/Sof3Table.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SwfnTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SwofTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableColumn.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
|
||||
|
||||
#include <opm/material/fluidmatrixinteractions/EclEpsGridProperties.hpp>
|
||||
#include <opm/material/fluidstates/SimpleModularFluidState.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
// Relative permeability values not strictly greater than 'tolcrit' treated as zero.
|
||||
std::vector<double> normalizeKrValues_(const double tolcrit,
|
||||
const Opm::TableColumn& krValues)
|
||||
{
|
||||
auto kr = krValues.vectorCopy();
|
||||
std::transform(kr.begin(), kr.end(), kr.begin(),
|
||||
[tolcrit](const double kri)
|
||||
{
|
||||
return (kri > tolcrit) ? kri : 0.0;
|
||||
});
|
||||
|
||||
return kr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Opm {
|
||||
|
||||
template<class TraitsT>
|
||||
@@ -87,12 +59,12 @@ initFromState(const EclipseState& eclState)
|
||||
readGlobalThreePhaseOptions_(runspec);
|
||||
|
||||
// Read the end point scaling configuration (once per run).
|
||||
gasOilConfig = std::make_shared<EclEpsConfig>();
|
||||
oilWaterConfig = std::make_shared<EclEpsConfig>();
|
||||
gasWaterConfig = std::make_shared<EclEpsConfig>();
|
||||
gasOilConfig->initFromState(eclState, EclTwoPhaseSystemType::GasOil);
|
||||
oilWaterConfig->initFromState(eclState, EclTwoPhaseSystemType::OilWater);
|
||||
gasWaterConfig->initFromState(eclState, EclTwoPhaseSystemType::GasWater);
|
||||
gasOilConfig_ = std::make_shared<EclEpsConfig>();
|
||||
oilWaterConfig_ = std::make_shared<EclEpsConfig>();
|
||||
gasWaterConfig_ = std::make_shared<EclEpsConfig>();
|
||||
gasOilConfig_->initFromState(eclState, EclTwoPhaseSystemType::GasOil);
|
||||
oilWaterConfig_->initFromState(eclState, EclTwoPhaseSystemType::OilWater);
|
||||
gasWaterConfig_->initFromState(eclState, EclTwoPhaseSystemType::GasWater);
|
||||
|
||||
|
||||
const auto& tables = eclState.getTableManager();
|
||||
@@ -101,11 +73,11 @@ initFromState(const EclipseState& eclState)
|
||||
const auto& stone1exTables = tables.getStone1exTable();
|
||||
|
||||
if (! stone1exTables.empty()) {
|
||||
stoneEtas.clear();
|
||||
stoneEtas.reserve(numSatRegions);
|
||||
stoneEtas_.clear();
|
||||
stoneEtas_.reserve(numSatRegions);
|
||||
|
||||
for (const auto& table : stone1exTables) {
|
||||
stoneEtas.push_back(table.eta);
|
||||
stoneEtas_.push_back(table.eta);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -134,232 +106,8 @@ template<class TraitsT>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
initParamsForElements(const EclipseState& eclState, size_t numCompressedElems)
|
||||
{
|
||||
// get the number of saturation regions
|
||||
const size_t numSatRegions = eclState.runspec().tabdims().getNumSatTables();
|
||||
|
||||
// setup the saturation region specific parameters
|
||||
gasOilUnscaledPointsVector_.resize(numSatRegions);
|
||||
oilWaterUnscaledPointsVector_.resize(numSatRegions);
|
||||
gasWaterUnscaledPointsVector_.resize(numSatRegions);
|
||||
|
||||
gasOilEffectiveParamVector_.resize(numSatRegions);
|
||||
oilWaterEffectiveParamVector_.resize(numSatRegions);
|
||||
gasWaterEffectiveParamVector_.resize(numSatRegions);
|
||||
for (unsigned satRegionIdx = 0; satRegionIdx < numSatRegions; ++satRegionIdx) {
|
||||
// unscaled points for end-point scaling
|
||||
readGasOilUnscaledPoints_(gasOilUnscaledPointsVector_, gasOilConfig, eclState, satRegionIdx);
|
||||
readOilWaterUnscaledPoints_(oilWaterUnscaledPointsVector_, oilWaterConfig, eclState, satRegionIdx);
|
||||
readGasWaterUnscaledPoints_(gasWaterUnscaledPointsVector_, gasWaterConfig, eclState, satRegionIdx);
|
||||
|
||||
// the parameters for the effective two-phase matererial laws
|
||||
readGasOilEffectiveParameters_(gasOilEffectiveParamVector_, eclState, satRegionIdx);
|
||||
readOilWaterEffectiveParameters_(oilWaterEffectiveParamVector_, eclState, satRegionIdx);
|
||||
readGasWaterEffectiveParameters_(gasWaterEffectiveParamVector_, eclState, satRegionIdx);
|
||||
}
|
||||
|
||||
// copy the SATNUM grid property. in some cases this is not necessary, but it
|
||||
// should not require much memory anyway...
|
||||
satnumRegionArray_.resize(numCompressedElems);
|
||||
if (eclState.fieldProps().has_int("SATNUM")) {
|
||||
const auto& satnumRawData = eclState.fieldProps().get_int("SATNUM");
|
||||
for (unsigned elemIdx = 0; elemIdx < numCompressedElems; ++elemIdx) {
|
||||
satnumRegionArray_[elemIdx] = satnumRawData[elemIdx] - 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::fill(satnumRegionArray_.begin(), satnumRegionArray_.end(), 0);
|
||||
}
|
||||
auto copy_krnum = [&eclState, numCompressedElems](std::vector<int>& dest, const std::string keyword) {
|
||||
if (eclState.fieldProps().has_int(keyword)) {
|
||||
dest.resize(numCompressedElems);
|
||||
const auto& satnumRawData = eclState.fieldProps().get_int(keyword);
|
||||
for (unsigned elemIdx = 0; elemIdx < numCompressedElems; ++elemIdx) {
|
||||
dest[elemIdx] = satnumRawData[elemIdx] - 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
copy_krnum(krnumXArray_, "KRNUMX");
|
||||
copy_krnum(krnumYArray_, "KRNUMY");
|
||||
copy_krnum(krnumZArray_, "KRNUMZ");
|
||||
|
||||
// create the information for the imbibition region (IMBNUM). By default this is
|
||||
// the same as the saturation region (SATNUM)
|
||||
imbnumRegionArray_ = satnumRegionArray_;
|
||||
if (eclState.fieldProps().has_int("IMBNUM")) {
|
||||
const auto& imbnumRawData = eclState.fieldProps().get_int("IMBNUM");
|
||||
for (unsigned elemIdx = 0; elemIdx < numCompressedElems; ++elemIdx) {
|
||||
imbnumRegionArray_[elemIdx] = imbnumRawData[elemIdx] - 1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(numCompressedElems == satnumRegionArray_.size());
|
||||
assert(!enableHysteresis() || numCompressedElems == imbnumRegionArray_.size());
|
||||
|
||||
// read the scaled end point scaling parameters which are specific for each
|
||||
// element
|
||||
oilWaterScaledEpsInfoDrainage_.resize(numCompressedElems);
|
||||
|
||||
std::unique_ptr<EclEpsGridProperties> epsImbGridProperties;
|
||||
|
||||
if (enableHysteresis()) {
|
||||
epsImbGridProperties = std::make_unique<EclEpsGridProperties>(eclState, true);
|
||||
}
|
||||
|
||||
EclEpsGridProperties epsGridProperties(eclState, false);
|
||||
materialLawParams_.resize(numCompressedElems);
|
||||
|
||||
for (unsigned elemIdx = 0; elemIdx < numCompressedElems; ++elemIdx) {
|
||||
unsigned satRegionIdx = static_cast<unsigned>(satnumRegionArray_[elemIdx]);
|
||||
auto gasOilParams = std::make_shared<GasOilTwoPhaseHystParams>();
|
||||
auto oilWaterParams = std::make_shared<OilWaterTwoPhaseHystParams>();
|
||||
auto gasWaterParams = std::make_shared<GasWaterTwoPhaseHystParams>();
|
||||
gasOilParams->setConfig(hysteresisConfig_);
|
||||
oilWaterParams->setConfig(hysteresisConfig_);
|
||||
gasWaterParams->setConfig(hysteresisConfig_);
|
||||
|
||||
auto [gasOilScaledInfo, gasOilScaledPoint] =
|
||||
readScaledPoints_(*gasOilConfig,
|
||||
eclState,
|
||||
epsGridProperties,
|
||||
elemIdx,
|
||||
EclTwoPhaseSystemType::GasOil);
|
||||
|
||||
auto [owinfo, oilWaterScaledEpsPointDrainage] =
|
||||
readScaledPoints_(*oilWaterConfig,
|
||||
eclState,
|
||||
epsGridProperties,
|
||||
elemIdx,
|
||||
EclTwoPhaseSystemType::OilWater);
|
||||
oilWaterScaledEpsInfoDrainage_[elemIdx] = owinfo;
|
||||
|
||||
auto [gasWaterScaledInfo, gasWaterScaledPoint] =
|
||||
readScaledPoints_(*gasWaterConfig,
|
||||
eclState,
|
||||
epsGridProperties,
|
||||
elemIdx,
|
||||
EclTwoPhaseSystemType::GasWater);
|
||||
|
||||
if (hasGas && hasOil) {
|
||||
GasOilEpsTwoPhaseParams gasOilDrainParams;
|
||||
gasOilDrainParams.setConfig(gasOilConfig);
|
||||
gasOilDrainParams.setUnscaledPoints(gasOilUnscaledPointsVector_[satRegionIdx]);
|
||||
gasOilDrainParams.setScaledPoints(gasOilScaledPoint);
|
||||
gasOilDrainParams.setEffectiveLawParams(gasOilEffectiveParamVector_[satRegionIdx]);
|
||||
gasOilDrainParams.finalize();
|
||||
|
||||
gasOilParams->setDrainageParams(gasOilDrainParams,
|
||||
gasOilScaledInfo,
|
||||
EclTwoPhaseSystemType::GasOil);
|
||||
}
|
||||
|
||||
if (hasOil && hasWater) {
|
||||
OilWaterEpsTwoPhaseParams oilWaterDrainParams;
|
||||
oilWaterDrainParams.setConfig(oilWaterConfig);
|
||||
oilWaterDrainParams.setUnscaledPoints(oilWaterUnscaledPointsVector_[satRegionIdx]);
|
||||
oilWaterDrainParams.setScaledPoints(oilWaterScaledEpsPointDrainage);
|
||||
oilWaterDrainParams.setEffectiveLawParams(oilWaterEffectiveParamVector_[satRegionIdx]);
|
||||
oilWaterDrainParams.finalize();
|
||||
|
||||
oilWaterParams->setDrainageParams(oilWaterDrainParams,
|
||||
owinfo,
|
||||
EclTwoPhaseSystemType::OilWater);
|
||||
}
|
||||
|
||||
if (hasGas && hasWater && !hasOil) {
|
||||
GasWaterEpsTwoPhaseParams gasWaterDrainParams;
|
||||
gasWaterDrainParams.setConfig(gasWaterConfig);
|
||||
gasWaterDrainParams.setUnscaledPoints(gasWaterUnscaledPointsVector_[satRegionIdx]);
|
||||
gasWaterDrainParams.setScaledPoints(gasWaterScaledPoint);
|
||||
gasWaterDrainParams.setEffectiveLawParams(gasWaterEffectiveParamVector_[satRegionIdx]);
|
||||
gasWaterDrainParams.finalize();
|
||||
|
||||
gasWaterParams->setDrainageParams(gasWaterDrainParams,
|
||||
gasWaterScaledInfo,
|
||||
EclTwoPhaseSystemType::GasWater);
|
||||
}
|
||||
|
||||
if (enableHysteresis()) {
|
||||
auto [gasOilScaledImbInfo, gasOilScaledImbPoint] =
|
||||
readScaledPoints_(*gasOilConfig,
|
||||
eclState,
|
||||
*epsImbGridProperties,
|
||||
elemIdx,
|
||||
EclTwoPhaseSystemType::GasOil);
|
||||
|
||||
auto [oilWaterScaledImbInfo, oilWaterScaledImbPoint] =
|
||||
readScaledPoints_(*oilWaterConfig,
|
||||
eclState,
|
||||
*epsImbGridProperties,
|
||||
elemIdx,
|
||||
EclTwoPhaseSystemType::OilWater);
|
||||
|
||||
auto [gasWaterScaledImbInfo, gasWaterScaledImbPoint] =
|
||||
readScaledPoints_(*gasWaterConfig,
|
||||
eclState,
|
||||
*epsImbGridProperties,
|
||||
elemIdx,
|
||||
EclTwoPhaseSystemType::GasWater);
|
||||
|
||||
unsigned imbRegionIdx = imbnumRegionArray_[elemIdx];
|
||||
if (hasGas && hasOil) {
|
||||
GasOilEpsTwoPhaseParams gasOilImbParamsHyst;
|
||||
gasOilImbParamsHyst.setConfig(gasOilConfig);
|
||||
gasOilImbParamsHyst.setUnscaledPoints(gasOilUnscaledPointsVector_[imbRegionIdx]);
|
||||
gasOilImbParamsHyst.setScaledPoints(gasOilScaledImbPoint);
|
||||
gasOilImbParamsHyst.setEffectiveLawParams(gasOilEffectiveParamVector_[imbRegionIdx]);
|
||||
gasOilImbParamsHyst.finalize();
|
||||
|
||||
gasOilParams->setImbibitionParams(gasOilImbParamsHyst,
|
||||
gasOilScaledImbInfo,
|
||||
EclTwoPhaseSystemType::GasOil);
|
||||
}
|
||||
|
||||
if (hasOil && hasWater) {
|
||||
OilWaterEpsTwoPhaseParams oilWaterImbParamsHyst;
|
||||
oilWaterImbParamsHyst.setConfig(oilWaterConfig);
|
||||
oilWaterImbParamsHyst.setUnscaledPoints(oilWaterUnscaledPointsVector_[imbRegionIdx]);
|
||||
oilWaterImbParamsHyst.setScaledPoints(oilWaterScaledImbPoint);
|
||||
oilWaterImbParamsHyst.setEffectiveLawParams(oilWaterEffectiveParamVector_[imbRegionIdx]);
|
||||
oilWaterImbParamsHyst.finalize();
|
||||
|
||||
oilWaterParams->setImbibitionParams(oilWaterImbParamsHyst,
|
||||
oilWaterScaledImbInfo,
|
||||
EclTwoPhaseSystemType::OilWater);
|
||||
}
|
||||
|
||||
if (hasGas && hasWater && !hasOil) {
|
||||
GasWaterEpsTwoPhaseParams gasWaterImbParamsHyst;
|
||||
gasWaterImbParamsHyst.setConfig(gasWaterConfig);
|
||||
gasWaterImbParamsHyst.setUnscaledPoints(gasWaterUnscaledPointsVector_[imbRegionIdx]);
|
||||
gasWaterImbParamsHyst.setScaledPoints(gasWaterScaledImbPoint);
|
||||
gasWaterImbParamsHyst.setEffectiveLawParams(gasWaterEffectiveParamVector_[imbRegionIdx]);
|
||||
gasWaterImbParamsHyst.finalize();
|
||||
|
||||
gasWaterParams->setImbibitionParams(gasWaterImbParamsHyst,
|
||||
gasWaterScaledImbInfo,
|
||||
EclTwoPhaseSystemType::GasWater);
|
||||
}
|
||||
}
|
||||
|
||||
if (hasGas && hasOil)
|
||||
gasOilParams->finalize();
|
||||
|
||||
if (hasOil && hasWater)
|
||||
oilWaterParams->finalize();
|
||||
|
||||
if (hasGas && hasWater && !hasOil)
|
||||
gasWaterParams->finalize();
|
||||
|
||||
initThreePhaseParams_(eclState,
|
||||
materialLawParams_[elemIdx],
|
||||
satRegionIdx,
|
||||
oilWaterScaledEpsInfoDrainage_[elemIdx],
|
||||
oilWaterParams,
|
||||
gasOilParams,
|
||||
gasWaterParams);
|
||||
|
||||
materialLawParams_[elemIdx].finalize();
|
||||
}
|
||||
InitParams initParams {*this, eclState, numCompressedElems};
|
||||
initParams.run();
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
@@ -606,6 +354,28 @@ oilWaterScaledEpsPointsDrainage(unsigned elemIdx)
|
||||
}
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
const typename EclMaterialLawManager<TraitsT>::MaterialLawParams& EclMaterialLawManager<TraitsT>::
|
||||
materialLawParamsFunc_(unsigned elemIdx, FaceDir::DirEnum facedir) const
|
||||
{
|
||||
using Dir = FaceDir::DirEnum;
|
||||
if (dirMaterialLawParams_) {
|
||||
switch(facedir) {
|
||||
case Dir::XPlus:
|
||||
return dirMaterialLawParams_->materialLawParamsX_[elemIdx];
|
||||
case Dir::YPlus:
|
||||
return dirMaterialLawParams_->materialLawParamsY_[elemIdx];
|
||||
case Dir::ZPlus:
|
||||
return dirMaterialLawParams_->materialLawParamsZ_[elemIdx];
|
||||
default:
|
||||
throw std::runtime_error("Unexpected face direction");
|
||||
}
|
||||
}
|
||||
else {
|
||||
return materialLawParams_[elemIdx];
|
||||
}
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGlobalEpsOptions_(const EclipseState& eclState)
|
||||
@@ -662,499 +432,6 @@ readGlobalThreePhaseOptions_(const Runspec& runspec)
|
||||
}
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
template <class Container>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGasOilEffectiveParameters_(Container& dest,
|
||||
const EclipseState& eclState,
|
||||
unsigned satRegionIdx)
|
||||
{
|
||||
if (!hasGas || !hasOil)
|
||||
// we don't read anything if either the gas or the oil phase is not active
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<GasOilEffectiveTwoPhaseParams>();
|
||||
|
||||
auto& effParams = *dest[satRegionIdx];
|
||||
|
||||
// the situation for the gas phase is complicated that all saturations are
|
||||
// shifted by the connate water saturation.
|
||||
const Scalar Swco = unscaledEpsInfo_[satRegionIdx].Swl;
|
||||
const auto tolcrit = eclState.runspec().saturationFunctionControls()
|
||||
.minimumRelpermMobilityThreshold();
|
||||
|
||||
const auto& tableManager = eclState.getTableManager();
|
||||
|
||||
switch (eclState.runspec().saturationFunctionControls().family()) {
|
||||
case SatFuncControls::KeywordFamily::Family_I:
|
||||
{
|
||||
const TableContainer& sgofTables = tableManager.getSgofTables();
|
||||
const TableContainer& slgofTables = tableManager.getSlgofTables();
|
||||
if (!sgofTables.empty())
|
||||
readGasOilEffectiveParametersSgof_(effParams, Swco, tolcrit,
|
||||
sgofTables.getTable<SgofTable>(satRegionIdx));
|
||||
else if (!slgofTables.empty())
|
||||
readGasOilEffectiveParametersSlgof_(effParams, Swco, tolcrit,
|
||||
slgofTables.getTable<SlgofTable>(satRegionIdx));
|
||||
else if ( !tableManager.getSgofletTable().empty() ) {
|
||||
const auto& letSgofTab = tableManager.getSgofletTable()[satRegionIdx];
|
||||
const std::vector<Scalar> dum; // dummy arg to comform with existing interface
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::LET);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::LET>();
|
||||
|
||||
// S=(So-Sogcr)/(1-Sogcr-Sgcr-Swco), krog = Krt*S^L/[S^L+E*(1.0-S)^T]
|
||||
const Scalar s_min_w = letSgofTab.s2_critical;
|
||||
const Scalar s_max_w = 1.0-letSgofTab.s1_critical-Swco;
|
||||
const std::vector<Scalar>& letCoeffsOil = {s_min_w, s_max_w,
|
||||
static_cast<Scalar>(letSgofTab.l2_relperm),
|
||||
static_cast<Scalar>(letSgofTab.e2_relperm),
|
||||
static_cast<Scalar>(letSgofTab.t2_relperm),
|
||||
static_cast<Scalar>(letSgofTab.krt2_relperm)};
|
||||
realParams.setKrwSamples(letCoeffsOil, dum);
|
||||
|
||||
// S=(1-So-Sgcr-Swco)/(1-Sogcr-Sgcr-Swco), krg = Krt*S^L/[S^L+E*(1.0-S)^T]
|
||||
const Scalar s_min_nw = letSgofTab.s1_critical+Swco;
|
||||
const Scalar s_max_nw = 1.0-letSgofTab.s2_critical;
|
||||
const std::vector<Scalar>& letCoeffsGas = {s_min_nw, s_max_nw,
|
||||
static_cast<Scalar>(letSgofTab.l1_relperm),
|
||||
static_cast<Scalar>(letSgofTab.e1_relperm),
|
||||
static_cast<Scalar>(letSgofTab.t1_relperm),
|
||||
static_cast<Scalar>(letSgofTab.krt1_relperm)};
|
||||
realParams.setKrnSamples(letCoeffsGas, dum);
|
||||
|
||||
// S=(So-Sorg)/(1-Sorg-Sgl-Swco), Pc = Pct + (pcir_pc-Pct)*(1-S)^L/[(1-S)^L+E*S^T]
|
||||
const std::vector<Scalar>& letCoeffsPc = {static_cast<Scalar>(letSgofTab.s2_residual),
|
||||
static_cast<Scalar>(letSgofTab.s1_residual+Swco),
|
||||
static_cast<Scalar>(letSgofTab.l_pc),
|
||||
static_cast<Scalar>(letSgofTab.e_pc),
|
||||
static_cast<Scalar>(letSgofTab.t_pc),
|
||||
static_cast<Scalar>(letSgofTab.pcir_pc),
|
||||
static_cast<Scalar>(letSgofTab.pct_pc)};
|
||||
realParams.setPcnwSamples(letCoeffsPc, dum);
|
||||
|
||||
realParams.finalize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_II:
|
||||
{
|
||||
const SgfnTable& sgfnTable = tableManager.getSgfnTables().getTable<SgfnTable>( satRegionIdx );
|
||||
if (!hasWater) {
|
||||
// oil and gas case
|
||||
const Sof2Table& sof2Table = tableManager.getSof2Tables().getTable<Sof2Table>( satRegionIdx );
|
||||
readGasOilEffectiveParametersFamily2_(effParams, Swco, tolcrit, sof2Table, sgfnTable);
|
||||
}
|
||||
else {
|
||||
const Sof3Table& sof3Table = tableManager.getSof3Tables().getTable<Sof3Table>( satRegionIdx );
|
||||
readGasOilEffectiveParametersFamily2_(effParams, Swco, tolcrit, sof3Table, sgfnTable);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGasOilEffectiveParametersSgof_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const SgofTable& sgofTable)
|
||||
{
|
||||
// convert the saturations of the SGOF keyword from gas to oil saturations
|
||||
std::vector<double> SoSamples(sgofTable.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sgofTable.numRows(); ++ sampleIdx) {
|
||||
SoSamples[sampleIdx] = (1.0 - Swco) - sgofTable.get("SG", sampleIdx);
|
||||
}
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SoSamples, normalizeKrValues_(tolcrit, sgofTable.getColumn("KROG")));
|
||||
realParams.setKrnSamples(SoSamples, normalizeKrValues_(tolcrit, sgofTable.getColumn("KRG")));
|
||||
realParams.setPcnwSamples(SoSamples, sgofTable.getColumn("PCOG").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGasOilEffectiveParametersSlgof_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const SlgofTable& slgofTable)
|
||||
{
|
||||
// convert the saturations of the SLGOF keyword from "liquid" to oil saturations
|
||||
std::vector<double> SoSamples(slgofTable.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < slgofTable.numRows(); ++ sampleIdx) {
|
||||
SoSamples[sampleIdx] = slgofTable.get("SL", sampleIdx) - Swco;
|
||||
}
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SoSamples, normalizeKrValues_(tolcrit, slgofTable.getColumn("KROG")));
|
||||
realParams.setKrnSamples(SoSamples, normalizeKrValues_(tolcrit, slgofTable.getColumn("KRG")));
|
||||
realParams.setPcnwSamples(SoSamples, slgofTable.getColumn("PCOG").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGasOilEffectiveParametersFamily2_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const Sof3Table& sof3Table,
|
||||
const SgfnTable& sgfnTable)
|
||||
{
|
||||
// convert the saturations of the SGFN keyword from gas to oil saturations
|
||||
std::vector<double> SoSamples(sgfnTable.numRows());
|
||||
std::vector<double> SoColumn = sof3Table.getColumn("SO").vectorCopy();
|
||||
for (size_t sampleIdx = 0; sampleIdx < sgfnTable.numRows(); ++ sampleIdx) {
|
||||
SoSamples[sampleIdx] = (1.0 - Swco) - sgfnTable.get("SG", sampleIdx);
|
||||
}
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SoColumn, normalizeKrValues_(tolcrit, sof3Table.getColumn("KROG")));
|
||||
realParams.setKrnSamples(SoSamples, normalizeKrValues_(tolcrit, sgfnTable.getColumn("KRG")));
|
||||
realParams.setPcnwSamples(SoSamples, sgfnTable.getColumn("PCOG").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGasOilEffectiveParametersFamily2_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const Sof2Table& sof2Table,
|
||||
const SgfnTable& sgfnTable)
|
||||
{
|
||||
// convert the saturations of the SGFN keyword from gas to oil saturations
|
||||
std::vector<double> SoSamples(sgfnTable.numRows());
|
||||
std::vector<double> SoColumn = sof2Table.getColumn("SO").vectorCopy();
|
||||
for (size_t sampleIdx = 0; sampleIdx < sgfnTable.numRows(); ++ sampleIdx) {
|
||||
SoSamples[sampleIdx] = (1.0 - Swco) - sgfnTable.get("SG", sampleIdx);
|
||||
}
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SoColumn, normalizeKrValues_(tolcrit, sof2Table.getColumn("KRO")));
|
||||
realParams.setKrnSamples(SoSamples, normalizeKrValues_(tolcrit, sgfnTable.getColumn("KRG")));
|
||||
realParams.setPcnwSamples(SoSamples, sgfnTable.getColumn("PCOG").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
template <class Container>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readOilWaterEffectiveParameters_(Container& dest,
|
||||
const EclipseState& eclState,
|
||||
unsigned satRegionIdx)
|
||||
{
|
||||
if (!hasOil || !hasWater)
|
||||
// we don't read anything if either the water or the oil phase is not active
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<OilWaterEffectiveTwoPhaseParams>();
|
||||
|
||||
const auto tolcrit = eclState.runspec().saturationFunctionControls()
|
||||
.minimumRelpermMobilityThreshold();
|
||||
|
||||
const auto& tableManager = eclState.getTableManager();
|
||||
auto& effParams = *dest[satRegionIdx];
|
||||
|
||||
switch (eclState.runspec().saturationFunctionControls().family()) {
|
||||
case SatFuncControls::KeywordFamily::Family_I:
|
||||
{
|
||||
if (tableManager.hasTables("SWOF")) {
|
||||
const auto& swofTable = tableManager.getSwofTables().getTable<SwofTable>(satRegionIdx);
|
||||
const std::vector<double> SwColumn = swofTable.getColumn("SW").vectorCopy();
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SwColumn, normalizeKrValues_(tolcrit, swofTable.getColumn("KRW")));
|
||||
realParams.setKrnSamples(SwColumn, normalizeKrValues_(tolcrit, swofTable.getColumn("KROW")));
|
||||
realParams.setPcnwSamples(SwColumn, swofTable.getColumn("PCOW").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
else if ( !tableManager.getSwofletTable().empty() ) {
|
||||
const auto& letTab = tableManager.getSwofletTable()[satRegionIdx];
|
||||
const std::vector<Scalar> dum; // dummy arg to conform with existing interface
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::LET);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::LET>();
|
||||
|
||||
// S=(Sw-Swcr)/(1-Sowcr-Swcr), krw = Krt*S^L/[S^L+E*(1.0-S)^T]
|
||||
const Scalar s_min_w = letTab.s1_critical;
|
||||
const Scalar s_max_w = 1.0-letTab.s2_critical;
|
||||
const std::vector<Scalar>& letCoeffsWat = {s_min_w, s_max_w,
|
||||
static_cast<Scalar>(letTab.l1_relperm),
|
||||
static_cast<Scalar>(letTab.e1_relperm),
|
||||
static_cast<Scalar>(letTab.t1_relperm),
|
||||
static_cast<Scalar>(letTab.krt1_relperm)};
|
||||
realParams.setKrwSamples(letCoeffsWat, dum);
|
||||
|
||||
// S=(So-Sowcr)/(1-Sowcr-Swcr), krow = Krt*S^L/[S^L+E*(1.0-S)^T]
|
||||
const Scalar s_min_nw = letTab.s2_critical;
|
||||
const Scalar s_max_nw = 1.0-letTab.s1_critical;
|
||||
const std::vector<Scalar>& letCoeffsOil = {s_min_nw, s_max_nw,
|
||||
static_cast<Scalar>(letTab.l2_relperm),
|
||||
static_cast<Scalar>(letTab.e2_relperm),
|
||||
static_cast<Scalar>(letTab.t2_relperm),
|
||||
static_cast<Scalar>(letTab.krt2_relperm)};
|
||||
realParams.setKrnSamples(letCoeffsOil, dum);
|
||||
|
||||
// S=(Sw-Swco)/(1-Swco-Sorw), Pc = Pct + (Pcir-Pct)*(1-S)^L/[(1-S)^L+E*S^T]
|
||||
const std::vector<Scalar>& letCoeffsPc = {static_cast<Scalar>(letTab.s1_residual),
|
||||
static_cast<Scalar>(letTab.s2_residual),
|
||||
static_cast<Scalar>(letTab.l_pc),
|
||||
static_cast<Scalar>(letTab.e_pc),
|
||||
static_cast<Scalar>(letTab.t_pc),
|
||||
static_cast<Scalar>(letTab.pcir_pc),
|
||||
static_cast<Scalar>(letTab.pct_pc)};
|
||||
realParams.setPcnwSamples(letCoeffsPc, dum);
|
||||
|
||||
realParams.finalize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_II:
|
||||
{
|
||||
const auto& swfnTable = tableManager.getSwfnTables().getTable<SwfnTable>(satRegionIdx);
|
||||
const std::vector<double> SwColumn = swfnTable.getColumn("SW").vectorCopy();
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SwColumn, normalizeKrValues_(tolcrit, swfnTable.getColumn("KRW")));
|
||||
realParams.setPcnwSamples(SwColumn, swfnTable.getColumn("PCOW").vectorCopy());
|
||||
|
||||
if (!hasGas) {
|
||||
const auto& sof2Table = tableManager.getSof2Tables().getTable<Sof2Table>(satRegionIdx);
|
||||
// convert the saturations of the SOF2 keyword from oil to water saturations
|
||||
std::vector<double> SwSamples(sof2Table.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sof2Table.numRows(); ++ sampleIdx)
|
||||
SwSamples[sampleIdx] = 1 - sof2Table.get("SO", sampleIdx);
|
||||
|
||||
realParams.setKrnSamples(SwSamples, normalizeKrValues_(tolcrit, sof2Table.getColumn("KRO")));
|
||||
} else {
|
||||
const auto& sof3Table = tableManager.getSof3Tables().getTable<Sof3Table>(satRegionIdx);
|
||||
// convert the saturations of the SOF3 keyword from oil to water saturations
|
||||
std::vector<double> SwSamples(sof3Table.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sof3Table.numRows(); ++ sampleIdx)
|
||||
SwSamples[sampleIdx] = 1 - sof3Table.get("SO", sampleIdx);
|
||||
|
||||
realParams.setKrnSamples(SwSamples, normalizeKrValues_(tolcrit, sof3Table.getColumn("KROW")));
|
||||
}
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
template <class Container>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGasWaterEffectiveParameters_(Container& dest,
|
||||
const EclipseState& eclState,
|
||||
unsigned satRegionIdx)
|
||||
{
|
||||
if (!hasGas || !hasWater || hasOil)
|
||||
// we don't read anything if either the gas or the water phase is not active or if oil is present
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<GasWaterEffectiveTwoPhaseParams>();
|
||||
|
||||
auto& effParams = *dest[satRegionIdx];
|
||||
|
||||
const auto tolcrit = eclState.runspec().saturationFunctionControls()
|
||||
.minimumRelpermMobilityThreshold();
|
||||
|
||||
const auto& tableManager = eclState.getTableManager();
|
||||
|
||||
switch (eclState.runspec().saturationFunctionControls().family()) {
|
||||
case SatFuncControls::KeywordFamily::Family_I:
|
||||
{
|
||||
throw std::domain_error("Saturation keyword family I is not applicable for a gas-water system");
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_II:
|
||||
{
|
||||
//Todo: allow also for Sgwfn table input as alternative to Sgfn and Swfn table input
|
||||
const SgfnTable& sgfnTable = tableManager.getSgfnTables().getTable<SgfnTable>( satRegionIdx );
|
||||
const SwfnTable& swfnTable = tableManager.getSwfnTables().getTable<SwfnTable>( satRegionIdx );
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
std::vector<double> SwColumn = swfnTable.getColumn("SW").vectorCopy();
|
||||
|
||||
realParams.setKrwSamples(SwColumn, normalizeKrValues_(tolcrit, swfnTable.getColumn("KRW")));
|
||||
std::vector<double> SwSamples(sgfnTable.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sgfnTable.numRows(); ++ sampleIdx)
|
||||
SwSamples[sampleIdx] = 1 - sgfnTable.get("SG", sampleIdx);
|
||||
realParams.setKrnSamples(SwSamples, normalizeKrValues_(tolcrit, sgfnTable.getColumn("KRG")));
|
||||
//Capillary pressure is read from SWFN.
|
||||
//For gas-water system the capillary pressure column values are set to 0 in SGFN
|
||||
realParams.setPcnwSamples(SwColumn, swfnTable.getColumn("PCOW").vectorCopy());
|
||||
realParams.finalize();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
template <class Container>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGasOilUnscaledPoints_(Container& dest,
|
||||
std::shared_ptr<EclEpsConfig> config,
|
||||
const EclipseState& /* eclState */,
|
||||
unsigned satRegionIdx)
|
||||
{
|
||||
if (!hasGas || !hasOil)
|
||||
// we don't read anything if either the gas or the oil phase is not active
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<EclEpsScalingPoints<Scalar> >();
|
||||
dest[satRegionIdx]->init(unscaledEpsInfo_[satRegionIdx],
|
||||
*config,
|
||||
EclTwoPhaseSystemType::GasOil);
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
template <class Container>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readOilWaterUnscaledPoints_(Container& dest,
|
||||
std::shared_ptr<EclEpsConfig> config,
|
||||
const EclipseState& /* eclState */,
|
||||
unsigned satRegionIdx)
|
||||
{
|
||||
if (!hasOil || !hasWater)
|
||||
// we don't read anything if either the water or the oil phase is not active
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<EclEpsScalingPoints<Scalar> >();
|
||||
dest[satRegionIdx]->init(unscaledEpsInfo_[satRegionIdx],
|
||||
*config,
|
||||
EclTwoPhaseSystemType::OilWater);
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
template <class Container>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
readGasWaterUnscaledPoints_(Container& dest,
|
||||
std::shared_ptr<EclEpsConfig> config,
|
||||
const EclipseState& /* eclState */,
|
||||
unsigned satRegionIdx)
|
||||
{
|
||||
if (hasOil)
|
||||
// we don't read anything if oil phase is active
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<EclEpsScalingPoints<Scalar> >();
|
||||
dest[satRegionIdx]->init(unscaledEpsInfo_[satRegionIdx],
|
||||
*config,
|
||||
EclTwoPhaseSystemType::GasWater);
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
std::tuple<EclEpsScalingPointsInfo<typename TraitsT::Scalar>,
|
||||
EclEpsScalingPoints<typename TraitsT::Scalar>>
|
||||
EclMaterialLawManager<TraitsT>::
|
||||
readScaledPoints_(const EclEpsConfig& config,
|
||||
const EclipseState& eclState,
|
||||
const EclEpsGridProperties& epsGridProperties,
|
||||
unsigned elemIdx,
|
||||
EclTwoPhaseSystemType type)
|
||||
{
|
||||
unsigned satRegionIdx = epsGridProperties.satRegion( elemIdx );
|
||||
|
||||
EclEpsScalingPointsInfo<Scalar> destInfo(unscaledEpsInfo_[satRegionIdx]);
|
||||
destInfo.extractScaled(eclState, epsGridProperties, elemIdx);
|
||||
|
||||
EclEpsScalingPoints<Scalar> destPoint;
|
||||
destPoint.init(destInfo, config, type);
|
||||
|
||||
return {destInfo, destPoint};
|
||||
}
|
||||
|
||||
template<class TraitsT>
|
||||
void EclMaterialLawManager<TraitsT>::
|
||||
initThreePhaseParams_(const EclipseState& /* eclState */,
|
||||
MaterialLawParams& materialParams,
|
||||
unsigned satRegionIdx,
|
||||
const EclEpsScalingPointsInfo<Scalar>& epsInfo,
|
||||
std::shared_ptr<OilWaterTwoPhaseHystParams> oilWaterParams,
|
||||
std::shared_ptr<GasOilTwoPhaseHystParams> gasOilParams,
|
||||
std::shared_ptr<GasWaterTwoPhaseHystParams> gasWaterParams)
|
||||
{
|
||||
materialParams.setApproach(threePhaseApproach_);
|
||||
|
||||
switch (materialParams.approach()) {
|
||||
case EclMultiplexerApproach::Stone1: {
|
||||
auto& realParams = materialParams.template getRealParams<EclMultiplexerApproach::Stone1>();
|
||||
realParams.setGasOilParams(gasOilParams);
|
||||
realParams.setOilWaterParams(oilWaterParams);
|
||||
realParams.setSwl(epsInfo.Swl);
|
||||
|
||||
if (!stoneEtas.empty()) {
|
||||
realParams.setEta(stoneEtas[satRegionIdx]);
|
||||
}
|
||||
else
|
||||
realParams.setEta(1.0);
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case EclMultiplexerApproach::Stone2: {
|
||||
auto& realParams = materialParams.template getRealParams<EclMultiplexerApproach::Stone2>();
|
||||
realParams.setGasOilParams(gasOilParams);
|
||||
realParams.setOilWaterParams(oilWaterParams);
|
||||
realParams.setSwl(epsInfo.Swl);
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case EclMultiplexerApproach::Default: {
|
||||
auto& realParams = materialParams.template getRealParams<EclMultiplexerApproach::Default>();
|
||||
realParams.setGasOilParams(gasOilParams);
|
||||
realParams.setOilWaterParams(oilWaterParams);
|
||||
realParams.setSwl(epsInfo.Swl);
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case EclMultiplexerApproach::TwoPhase: {
|
||||
auto& realParams = materialParams.template getRealParams<EclMultiplexerApproach::TwoPhase>();
|
||||
realParams.setGasOilParams(gasOilParams);
|
||||
realParams.setOilWaterParams(oilWaterParams);
|
||||
realParams.setGasWaterParams(gasWaterParams);
|
||||
realParams.setApproach(twoPhaseApproach_);
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case EclMultiplexerApproach::OnePhase: {
|
||||
// Nothing to do, no parameters.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template class EclMaterialLawManager<ThreePhaseMaterialTraits<double,0,1,2>>;
|
||||
template class EclMaterialLawManager<ThreePhaseMaterialTraits<float,0,1,2>>;
|
||||
|
||||
@@ -0,0 +1,287 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
Copyright 2022 Equinor ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/EclEpsGridProperties.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/* constructors*/
|
||||
template <class Traits>
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
HystParams(EclMaterialLawManager<Traits>::InitParams& init_params) :
|
||||
init_params_{init_params}, parent_{init_params_.parent_},
|
||||
eclState_{init_params_.eclState_}
|
||||
{
|
||||
gasOilParams_ = std::make_shared<GasOilTwoPhaseHystParams>();
|
||||
oilWaterParams_ = std::make_shared<OilWaterTwoPhaseHystParams>();
|
||||
gasWaterParams_ = std::make_shared<GasWaterTwoPhaseHystParams>();
|
||||
}
|
||||
|
||||
/* public methods, alphabetically sorted */
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
finalize()
|
||||
{
|
||||
if (hasGasOil_())
|
||||
this->gasOilParams_->finalize();
|
||||
if (hasOilWater_())
|
||||
this->oilWaterParams_->finalize();
|
||||
if (hasGasWater_())
|
||||
this->gasWaterParams_->finalize();
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
std::shared_ptr<typename EclMaterialLawManager<Traits>::GasOilTwoPhaseHystParams>
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
getGasOilParams()
|
||||
{
|
||||
return gasOilParams_;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
std::shared_ptr<typename EclMaterialLawManager<Traits>::OilWaterTwoPhaseHystParams>
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
getOilWaterParams()
|
||||
{
|
||||
return oilWaterParams_;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
std::shared_ptr<typename EclMaterialLawManager<Traits>::GasWaterTwoPhaseHystParams>
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
getGasWaterParams()
|
||||
{
|
||||
return gasWaterParams_;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
setConfig()
|
||||
{
|
||||
this->gasOilParams_->setConfig(this->parent_.hysteresisConfig_);
|
||||
this->oilWaterParams_->setConfig(this->parent_.hysteresisConfig_);
|
||||
this->gasWaterParams_->setConfig(this->parent_.hysteresisConfig_);
|
||||
} // namespace Opm
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
setDrainageParamsGasWater(unsigned elemIdx, unsigned satRegionIdx)
|
||||
{
|
||||
if (hasGasWater_()) {
|
||||
auto [gasWaterScaledInfo, gasWaterScaledPoints]
|
||||
= readScaledEpsPointsDrainage_(elemIdx, EclTwoPhaseSystemType::GasWater);
|
||||
GasWaterEpsTwoPhaseParams gasWaterDrainParams;
|
||||
gasWaterDrainParams.setConfig(this->parent_.gasWaterConfig_);
|
||||
gasWaterDrainParams.setUnscaledPoints(this->parent_.gasWaterUnscaledPointsVector_[satRegionIdx]);
|
||||
gasWaterDrainParams.setScaledPoints(gasWaterScaledPoints);
|
||||
gasWaterDrainParams.setEffectiveLawParams(this->parent_.gasWaterEffectiveParamVector_[satRegionIdx]);
|
||||
gasWaterDrainParams.finalize();
|
||||
this->gasWaterParams_->setDrainageParams(gasWaterDrainParams, gasWaterScaledInfo, EclTwoPhaseSystemType::GasWater);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
setDrainageParamsOilGas(unsigned elemIdx, unsigned satRegionIdx)
|
||||
{
|
||||
if (hasGasOil_()) {
|
||||
auto [gasOilScaledInfo, gasOilScaledPoints]
|
||||
= readScaledEpsPointsDrainage_(elemIdx, EclTwoPhaseSystemType::GasOil);
|
||||
GasOilEpsTwoPhaseParams gasOilDrainParams;
|
||||
gasOilDrainParams.setConfig(this->parent_.gasOilConfig_);
|
||||
gasOilDrainParams.setUnscaledPoints(this->parent_.gasOilUnscaledPointsVector_[satRegionIdx]);
|
||||
gasOilDrainParams.setScaledPoints(gasOilScaledPoints);
|
||||
gasOilDrainParams.setEffectiveLawParams(this->parent_.gasOilEffectiveParamVector_[satRegionIdx]);
|
||||
gasOilDrainParams.finalize();
|
||||
this->gasOilParams_->setDrainageParams(gasOilDrainParams, gasOilScaledInfo, EclTwoPhaseSystemType::GasOil);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
setDrainageParamsOilWater(unsigned elemIdx, unsigned satRegionIdx)
|
||||
{
|
||||
if (hasOilWater_()) {
|
||||
auto [oilWaterScaledInfo, oilWaterScaledPoints]
|
||||
= readScaledEpsPointsDrainage_(elemIdx, EclTwoPhaseSystemType::OilWater);
|
||||
// TODO: This will reassign the same EclEpsScalingPointsInfo for each facedir
|
||||
// since we currently does not support facedir for the scaling points info
|
||||
// When such support is added, we need to extend the below vector which has info for each cell
|
||||
// to include three more vectors, one with info for each facedir of a cell
|
||||
this->parent_.oilWaterScaledEpsInfoDrainage_[elemIdx] = oilWaterScaledInfo;
|
||||
OilWaterEpsTwoPhaseParams oilWaterDrainParams;
|
||||
oilWaterDrainParams.setConfig(this->parent_.oilWaterConfig_);
|
||||
oilWaterDrainParams.setUnscaledPoints(this->parent_.oilWaterUnscaledPointsVector_[satRegionIdx]);
|
||||
oilWaterDrainParams.setScaledPoints(oilWaterScaledPoints);
|
||||
oilWaterDrainParams.setEffectiveLawParams(this->parent_.oilWaterEffectiveParamVector_[satRegionIdx]);
|
||||
oilWaterDrainParams.finalize();
|
||||
oilWaterParams_->setDrainageParams(oilWaterDrainParams, oilWaterScaledInfo, EclTwoPhaseSystemType::OilWater);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
setImbibitionParamsGasWater(unsigned elemIdx, unsigned imbRegionIdx)
|
||||
{
|
||||
if (hasGasWater_()) {
|
||||
auto [gasWaterScaledInfo, gasWaterScaledPoints]
|
||||
= readScaledEpsPointsImbibition_(elemIdx, EclTwoPhaseSystemType::GasWater);
|
||||
GasWaterEpsTwoPhaseParams gasWaterImbParamsHyst;
|
||||
gasWaterImbParamsHyst.setConfig(this->parent_.gasWaterConfig_);
|
||||
gasWaterImbParamsHyst.setUnscaledPoints(this->parent_.gasWaterUnscaledPointsVector_[imbRegionIdx]);
|
||||
gasWaterImbParamsHyst.setScaledPoints(gasWaterScaledPoints);
|
||||
gasWaterImbParamsHyst.setEffectiveLawParams(this->parent_.gasWaterEffectiveParamVector_[imbRegionIdx]);
|
||||
gasWaterImbParamsHyst.finalize();
|
||||
this->gasWaterParams_->setImbibitionParams(gasWaterImbParamsHyst,
|
||||
gasWaterScaledInfo,
|
||||
EclTwoPhaseSystemType::GasWater);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
setImbibitionParamsOilGas(unsigned elemIdx, unsigned imbRegionIdx)
|
||||
{
|
||||
if (hasGasOil_()) {
|
||||
auto [gasOilScaledInfo, gasOilScaledPoints]
|
||||
= readScaledEpsPointsImbibition_(elemIdx, EclTwoPhaseSystemType::GasOil);
|
||||
|
||||
GasOilEpsTwoPhaseParams gasOilImbParamsHyst;
|
||||
gasOilImbParamsHyst.setConfig(this->parent_.gasOilConfig_);
|
||||
gasOilImbParamsHyst.setUnscaledPoints(this->parent_.gasOilUnscaledPointsVector_[imbRegionIdx]);
|
||||
gasOilImbParamsHyst.setScaledPoints(gasOilScaledPoints);
|
||||
gasOilImbParamsHyst.setEffectiveLawParams(this->parent_.gasOilEffectiveParamVector_[imbRegionIdx]);
|
||||
gasOilImbParamsHyst.finalize();
|
||||
this->gasOilParams_->setImbibitionParams(gasOilImbParamsHyst,
|
||||
gasOilScaledInfo,
|
||||
EclTwoPhaseSystemType::GasOil);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
setImbibitionParamsOilWater(unsigned elemIdx, unsigned imbRegionIdx)
|
||||
{
|
||||
if (hasOilWater_()) {
|
||||
auto [oilWaterScaledInfo, oilWaterScaledPoints]
|
||||
= readScaledEpsPointsImbibition_(elemIdx, EclTwoPhaseSystemType::OilWater);
|
||||
OilWaterEpsTwoPhaseParams oilWaterImbParamsHyst;
|
||||
oilWaterImbParamsHyst.setConfig(this->parent_.oilWaterConfig_);
|
||||
oilWaterImbParamsHyst.setUnscaledPoints(this->parent_.oilWaterUnscaledPointsVector_[imbRegionIdx]);
|
||||
oilWaterImbParamsHyst.setScaledPoints(oilWaterScaledPoints);
|
||||
oilWaterImbParamsHyst.setEffectiveLawParams(this->parent_.oilWaterEffectiveParamVector_[imbRegionIdx]);
|
||||
oilWaterImbParamsHyst.finalize();
|
||||
this->oilWaterParams_->setImbibitionParams(oilWaterImbParamsHyst,
|
||||
oilWaterScaledInfo,
|
||||
EclTwoPhaseSystemType::OilWater);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* private methods, alphabetically sorted */
|
||||
|
||||
template <class Traits>
|
||||
bool
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
hasGasOil_()
|
||||
{
|
||||
return this->parent_.hasGas && this->parent_.hasOil;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
bool
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
hasGasWater_()
|
||||
{
|
||||
return this->parent_.hasGas && this->parent_.hasWater && !this->parent_.hasOil;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
bool
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
hasOilWater_()
|
||||
{
|
||||
return this->parent_.hasOil && this->parent_.hasWater;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
std::tuple<
|
||||
EclEpsScalingPointsInfo<typename EclMaterialLawManager<Traits>::Scalar>,
|
||||
EclEpsScalingPoints<typename EclMaterialLawManager<Traits>::Scalar>
|
||||
>
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
readScaledEpsPoints_(const EclEpsGridProperties& epsGridProperties, unsigned elemIdx, EclTwoPhaseSystemType type)
|
||||
{
|
||||
const EclEpsConfig& config = *(this->parent_.gasOilConfig_);
|
||||
unsigned satRegionIdx = epsGridProperties.satRegion( elemIdx );
|
||||
|
||||
// Copy-construct a new instance of EclEpsScalingPointsInfo
|
||||
EclEpsScalingPointsInfo<Scalar> destInfo(this->parent_.unscaledEpsInfo_[satRegionIdx]);
|
||||
// TODO: currently epsGridProperties does not implement a face direction, e.g. SWLX, SWLY,...
|
||||
// when these keywords get implemented, we need to use include facedir in the lookup
|
||||
destInfo.extractScaled(this->eclState_, epsGridProperties, elemIdx);
|
||||
|
||||
EclEpsScalingPoints<Scalar> destPoint;
|
||||
destPoint.init(destInfo, config, type);
|
||||
return {destInfo, destPoint};
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
std::tuple<
|
||||
EclEpsScalingPointsInfo<typename EclMaterialLawManager<Traits>::Scalar>,
|
||||
EclEpsScalingPoints<typename EclMaterialLawManager<Traits>::Scalar>
|
||||
>
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
readScaledEpsPointsDrainage_(unsigned elemIdx, EclTwoPhaseSystemType type)
|
||||
{
|
||||
const auto& epsGridProperties = this->init_params_.epsGridProperties_;
|
||||
return readScaledEpsPoints_(*epsGridProperties, elemIdx, type);
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
std::tuple<
|
||||
EclEpsScalingPointsInfo<typename EclMaterialLawManager<Traits>::Scalar>,
|
||||
EclEpsScalingPoints<typename EclMaterialLawManager<Traits>::Scalar>
|
||||
>
|
||||
EclMaterialLawManager<Traits>::InitParams::HystParams::
|
||||
readScaledEpsPointsImbibition_(unsigned elemIdx, EclTwoPhaseSystemType type)
|
||||
{
|
||||
const auto& epsGridProperties = this->init_params_.epsImbGridProperties_;
|
||||
return readScaledEpsPoints_(*epsGridProperties, elemIdx, type);
|
||||
}
|
||||
|
||||
// Make some actual code, by realizing the previously defined templated class
|
||||
template class EclMaterialLawManager<ThreePhaseMaterialTraits<double,0,1,2>>::InitParams::HystParams;
|
||||
template class EclMaterialLawManager<ThreePhaseMaterialTraits<float,0,1,2>>::InitParams::HystParams;
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
@@ -0,0 +1,342 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
Copyright 2022 Equinor ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp>
|
||||
#include <opm/material/fluidmatrixinteractions/EclEpsGridProperties.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/* constructors*/
|
||||
|
||||
template <class Traits>
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
InitParams(EclMaterialLawManager<Traits>& parent, const EclipseState& eclState, size_t numCompressedElems) :
|
||||
parent_{parent},
|
||||
eclState_{eclState},
|
||||
numCompressedElems_{numCompressedElems}
|
||||
{
|
||||
// read end point scaling grid properties
|
||||
// TODO: these objects might require some memory, can this be simplified?
|
||||
if (this->parent_.enableHysteresis()) {
|
||||
this->epsImbGridProperties_
|
||||
= std::make_unique<EclEpsGridProperties>(this->eclState_, /*useImbibition=*/true);
|
||||
}
|
||||
this->epsGridProperties_
|
||||
= std::make_unique<EclEpsGridProperties>(this->eclState_, /*useImbibition=*/false);
|
||||
}
|
||||
|
||||
/* public methods */
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
run() {
|
||||
readEffectiveParameters_();
|
||||
readUnscaledEpsPointsVectors_();
|
||||
initSatnumRegionArray_();
|
||||
copySatnumArrays_();
|
||||
initOilWaterScaledEpsInfo_();
|
||||
initMaterialLawParamVectors_();
|
||||
std::vector<std::vector<int>*> satnumArray;
|
||||
std::vector<std::vector<int>*> imbnumArray;
|
||||
std::vector<std::vector<MaterialLawParams>*> mlpArray;
|
||||
initArrays_(satnumArray, imbnumArray, mlpArray);
|
||||
auto num_arrays = mlpArray.size();
|
||||
for (unsigned i=0; i<num_arrays; i++) {
|
||||
for (unsigned elemIdx = 0; elemIdx < this->numCompressedElems_; ++elemIdx) {
|
||||
unsigned satRegionIdx = satRegion_(*satnumArray[i], elemIdx);
|
||||
//unsigned satNumCell = this->parent_.satnumRegionArray_[elemIdx];
|
||||
HystParams hystParams {*this};
|
||||
hystParams.setConfig();
|
||||
hystParams.setDrainageParamsOilGas(elemIdx, satRegionIdx);
|
||||
hystParams.setDrainageParamsOilWater(elemIdx, satRegionIdx);
|
||||
hystParams.setDrainageParamsGasWater(elemIdx, satRegionIdx);
|
||||
if (this->parent_.enableHysteresis()) {
|
||||
unsigned imbRegionIdx = imbRegion_(*imbnumArray[i], elemIdx);
|
||||
hystParams.setImbibitionParamsOilGas(elemIdx, imbRegionIdx);
|
||||
hystParams.setImbibitionParamsOilWater(elemIdx, imbRegionIdx);
|
||||
hystParams.setImbibitionParamsGasWater(elemIdx, imbRegionIdx);
|
||||
}
|
||||
hystParams.finalize();
|
||||
initThreePhaseParams_(hystParams, (*mlpArray[i])[elemIdx], satRegionIdx, elemIdx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* private methods alphabetically sorted*/
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
copySatnumArrays_()
|
||||
{
|
||||
copyIntArray_(this->parent_.krnumXArray_, "KRNUMX");
|
||||
copyIntArray_(this->parent_.krnumYArray_, "KRNUMY");
|
||||
copyIntArray_(this->parent_.krnumZArray_, "KRNUMZ");
|
||||
copyIntArray_(this->parent_.imbnumXArray_, "IMBNUMX");
|
||||
copyIntArray_(this->parent_.imbnumYArray_, "IMBNUMY");
|
||||
copyIntArray_(this->parent_.imbnumZArray_, "IMBNUMZ");
|
||||
// create the information for the imbibition region (IMBNUM). By default this is
|
||||
// the same as the saturation region (SATNUM)
|
||||
this->parent_.imbnumRegionArray_ = this->parent_.satnumRegionArray_;
|
||||
copyIntArray_(this->parent_.imbnumRegionArray_, "IMBNUM");
|
||||
assert(this->numCompressedElems_ == this->parent_.satnumRegionArray_.size());
|
||||
assert(!this->parent_.enableHysteresis() || this->numCompressedElems_ == this->parent_.imbnumRegionArray_.size());
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
copyIntArray_(std::vector<int>& dest, const std::string keyword)
|
||||
{
|
||||
if (this->eclState_.fieldProps().has_int(keyword)) {
|
||||
dest.resize(this->numCompressedElems_);
|
||||
const auto& satnumRawData = this->eclState_.fieldProps().get_int(keyword);
|
||||
for (unsigned elemIdx = 0; elemIdx < this->numCompressedElems_; ++elemIdx) {
|
||||
dest[elemIdx] = satnumRawData[elemIdx] - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
unsigned
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
imbRegion_(std::vector<int>& array, unsigned elemIdx)
|
||||
{
|
||||
std::vector<int>& default_vec = this->parent_.imbnumRegionArray_;
|
||||
return satOrImbRegion_(array, default_vec, elemIdx);
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
initArrays_(
|
||||
std::vector<std::vector<int>*>& satnumArray,
|
||||
std::vector<std::vector<int>*>& imbnumArray,
|
||||
std::vector<std::vector<MaterialLawParams>*>& mlpArray)
|
||||
{
|
||||
satnumArray.push_back(&this->parent_.satnumRegionArray_);
|
||||
imbnumArray.push_back(&this->parent_.imbnumRegionArray_);
|
||||
mlpArray.push_back(&this->parent_.materialLawParams_);
|
||||
if (this->parent_.dirMaterialLawParams_) {
|
||||
if (this->parent_.hasDirectionalRelperms()) {
|
||||
satnumArray.push_back(&this->parent_.krnumXArray_);
|
||||
satnumArray.push_back(&this->parent_.krnumYArray_);
|
||||
satnumArray.push_back(&this->parent_.krnumZArray_);
|
||||
}
|
||||
if (this->parent_.hasDirectionalImbnum()) {
|
||||
imbnumArray.push_back(&this->parent_.imbnumXArray_);
|
||||
imbnumArray.push_back(&this->parent_.imbnumYArray_);
|
||||
imbnumArray.push_back(&this->parent_.imbnumZArray_);
|
||||
}
|
||||
mlpArray.push_back(&(this->parent_.dirMaterialLawParams_->materialLawParamsX_));
|
||||
mlpArray.push_back(&(this->parent_.dirMaterialLawParams_->materialLawParamsY_));
|
||||
mlpArray.push_back(&(this->parent_.dirMaterialLawParams_->materialLawParamsZ_));
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
initMaterialLawParamVectors_()
|
||||
{
|
||||
this->parent_.materialLawParams_.resize(this->numCompressedElems_);
|
||||
if (this->parent_.hasDirectionalImbnum() || this->parent_.hasDirectionalRelperms()) {
|
||||
this->parent_.dirMaterialLawParams_
|
||||
= std::make_unique<DirectionalMaterialLawParams<MaterialLawParams>>(this->numCompressedElems_);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
initOilWaterScaledEpsInfo_()
|
||||
{
|
||||
// This vector will be updated in the hystParams.setDrainageOilWater() in the run() method
|
||||
this->parent_.oilWaterScaledEpsInfoDrainage_.resize(this->numCompressedElems_);
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
initSatnumRegionArray_()
|
||||
{
|
||||
// copy the SATNUM grid property. in some cases this is not necessary, but it
|
||||
// should not require much memory anyway...
|
||||
auto &satnumArray = this->parent_.satnumRegionArray_;
|
||||
satnumArray.resize(this->numCompressedElems_);
|
||||
if (this->eclState_.fieldProps().has_int("SATNUM")) {
|
||||
const auto& satnumRawData = this->eclState_.fieldProps().get_int("SATNUM");
|
||||
for (unsigned elemIdx = 0; elemIdx < this->numCompressedElems_; ++elemIdx) {
|
||||
satnumArray[elemIdx] = satnumRawData[elemIdx] - 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::fill(satnumArray.begin(), satnumArray.end(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
initThreePhaseParams_(HystParams &hystParams,
|
||||
MaterialLawParams& materialParams,
|
||||
unsigned satRegionIdx,
|
||||
unsigned elemIdx)
|
||||
{
|
||||
const auto& epsInfo = this->parent_.oilWaterScaledEpsInfoDrainage_[elemIdx];
|
||||
|
||||
auto oilWaterParams = hystParams.getOilWaterParams();
|
||||
auto gasOilParams = hystParams.getGasOilParams();
|
||||
auto gasWaterParams = hystParams.getGasWaterParams();
|
||||
materialParams.setApproach(this->parent_.threePhaseApproach_);
|
||||
switch (materialParams.approach()) {
|
||||
case EclMultiplexerApproach::Stone1: {
|
||||
auto& realParams = materialParams.template getRealParams<EclMultiplexerApproach::Stone1>();
|
||||
realParams.setGasOilParams(gasOilParams);
|
||||
realParams.setOilWaterParams(oilWaterParams);
|
||||
realParams.setSwl(epsInfo.Swl);
|
||||
|
||||
if (!this->parent_.stoneEtas_.empty()) {
|
||||
realParams.setEta(this->parent_.stoneEtas_[satRegionIdx]);
|
||||
}
|
||||
else
|
||||
realParams.setEta(1.0);
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case EclMultiplexerApproach::Stone2: {
|
||||
auto& realParams = materialParams.template getRealParams<EclMultiplexerApproach::Stone2>();
|
||||
realParams.setGasOilParams(gasOilParams);
|
||||
realParams.setOilWaterParams(oilWaterParams);
|
||||
realParams.setSwl(epsInfo.Swl);
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case EclMultiplexerApproach::Default: {
|
||||
auto& realParams = materialParams.template getRealParams<EclMultiplexerApproach::Default>();
|
||||
realParams.setGasOilParams(gasOilParams);
|
||||
realParams.setOilWaterParams(oilWaterParams);
|
||||
realParams.setSwl(epsInfo.Swl);
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case EclMultiplexerApproach::TwoPhase: {
|
||||
auto& realParams = materialParams.template getRealParams<EclMultiplexerApproach::TwoPhase>();
|
||||
realParams.setGasOilParams(gasOilParams);
|
||||
realParams.setOilWaterParams(oilWaterParams);
|
||||
realParams.setGasWaterParams(gasWaterParams);
|
||||
realParams.setApproach(this->parent_.twoPhaseApproach_);
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case EclMultiplexerApproach::OnePhase: {
|
||||
// Nothing to do, no parameters.
|
||||
break;
|
||||
}
|
||||
} // end switch()
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
readEffectiveParameters_()
|
||||
{
|
||||
ReadEffectiveParams effectiveReader {*this};
|
||||
// populates effective parameter vectors in the parent class (EclMaterialManager)
|
||||
effectiveReader.read();
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
readUnscaledEpsPointsVectors_()
|
||||
{
|
||||
if (this->parent_.hasGas && this->parent_.hasOil) {
|
||||
readUnscaledEpsPoints_(
|
||||
this->parent_.gasOilUnscaledPointsVector_,
|
||||
this->parent_.gasOilConfig_,
|
||||
EclTwoPhaseSystemType::GasOil
|
||||
);
|
||||
}
|
||||
if (this->parent_.hasOil && this->parent_.hasWater) {
|
||||
readUnscaledEpsPoints_(
|
||||
this->parent_.oilWaterUnscaledPointsVector_,
|
||||
this->parent_.oilWaterConfig_,
|
||||
EclTwoPhaseSystemType::OilWater
|
||||
);
|
||||
}
|
||||
if (!this->parent_.hasOil) {
|
||||
readUnscaledEpsPoints_(
|
||||
this->parent_.gasWaterUnscaledPointsVector_,
|
||||
this->parent_.gasWaterConfig_,
|
||||
EclTwoPhaseSystemType::GasWater
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
template <class Container>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
readUnscaledEpsPoints_(Container& dest, std::shared_ptr<EclEpsConfig> config, EclTwoPhaseSystemType system_type)
|
||||
{
|
||||
const size_t numSatRegions = this->eclState_.runspec().tabdims().getNumSatTables();
|
||||
dest.resize(numSatRegions);
|
||||
for (unsigned satRegionIdx = 0; satRegionIdx < numSatRegions; ++satRegionIdx) {
|
||||
dest[satRegionIdx] = std::make_shared<EclEpsScalingPoints<Scalar> >();
|
||||
dest[satRegionIdx]->init(this->parent_.unscaledEpsInfo_[satRegionIdx], *config, system_type);
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
unsigned
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
satRegion_(std::vector<int>& array, unsigned elemIdx)
|
||||
{
|
||||
std::vector<int>& default_vec = this->parent_.satnumRegionArray_;
|
||||
return satOrImbRegion_(array, default_vec, elemIdx);
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
unsigned
|
||||
EclMaterialLawManager<Traits>::InitParams::
|
||||
satOrImbRegion_(std::vector<int>& array, std::vector<int>& default_vec, unsigned elemIdx)
|
||||
{
|
||||
int value;
|
||||
if (array.size() > 0) {
|
||||
value = array[elemIdx];
|
||||
}
|
||||
else { // use default value
|
||||
value = default_vec[elemIdx];
|
||||
}
|
||||
return static_cast<unsigned>(value);
|
||||
}
|
||||
|
||||
// Make some actual code, by realizing the previously defined templated class
|
||||
template class EclMaterialLawManager<ThreePhaseMaterialTraits<double,0,1,2>>::InitParams;
|
||||
template class EclMaterialLawManager<ThreePhaseMaterialTraits<float,0,1,2>>::InitParams;
|
||||
|
||||
} // namespace Opm
|
||||
@@ -0,0 +1,414 @@
|
||||
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
// vi: set et ts=4 sw=4 sts=4:
|
||||
/*
|
||||
Copyright 2022 Equinor ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <config.h>
|
||||
#include <opm/material/fluidmatrixinteractions/EclMaterialLawManager.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SgfnTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SgofTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SlgofTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/Sof2Table.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/Sof3Table.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SwfnTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SwofTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/* constructors*/
|
||||
template <class Traits>
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
ReadEffectiveParams(EclMaterialLawManager<Traits>::InitParams& init_params) :
|
||||
init_params_{init_params}, parent_{init_params_.parent_},
|
||||
eclState_{init_params_.eclState_}
|
||||
{
|
||||
}
|
||||
|
||||
/* public methods */
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
read() {
|
||||
auto& gasOilVector = this->parent_.gasOilEffectiveParamVector_;
|
||||
auto& oilWaterVector = this->parent_.oilWaterEffectiveParamVector_;
|
||||
auto& gasWaterVector = this->parent_.gasWaterEffectiveParamVector_;
|
||||
const size_t numSatRegions = this->eclState_.runspec().tabdims().getNumSatTables();
|
||||
gasOilVector.resize(numSatRegions);
|
||||
oilWaterVector.resize(numSatRegions);
|
||||
gasWaterVector.resize(numSatRegions);
|
||||
for (unsigned satRegionIdx = 0; satRegionIdx < numSatRegions; ++satRegionIdx) {
|
||||
readGasOilParameters_(gasOilVector, satRegionIdx);
|
||||
readOilWaterParameters_(oilWaterVector, satRegionIdx);
|
||||
readGasWaterParameters_(gasWaterVector, satRegionIdx);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* private methods, alphabetically sorted*/
|
||||
|
||||
// Relative permeability values not strictly greater than 'tolcrit' treated as zero.
|
||||
template <class Traits>
|
||||
std::vector<double>
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
normalizeKrValues_(const double tolcrit, const TableColumn& krValues) const
|
||||
{
|
||||
auto kr = krValues.vectorCopy();
|
||||
std::transform(kr.begin(), kr.end(), kr.begin(),
|
||||
[tolcrit](const double kri)
|
||||
{
|
||||
return (kri > tolcrit) ? kri : 0.0;
|
||||
});
|
||||
|
||||
return kr;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
readGasOilParameters_(GasOilEffectiveParamVector& dest, unsigned satRegionIdx)
|
||||
{
|
||||
if (!this->parent_.hasGas || !this->parent_.hasOil)
|
||||
// we don't read anything if either the gas or the oil phase is not active
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<GasOilEffectiveTwoPhaseParams>();
|
||||
|
||||
auto& effParams = *dest[satRegionIdx];
|
||||
|
||||
// the situation for the gas phase is complicated that all saturations are
|
||||
// shifted by the connate water saturation.
|
||||
const Scalar Swco = this->parent_.unscaledEpsInfo_[satRegionIdx].Swl;
|
||||
const auto tolcrit = this->eclState_.runspec().saturationFunctionControls()
|
||||
.minimumRelpermMobilityThreshold();
|
||||
|
||||
const auto& tableManager = this->eclState_.getTableManager();
|
||||
|
||||
switch (this->eclState_.runspec().saturationFunctionControls().family()) {
|
||||
case SatFuncControls::KeywordFamily::Family_I:
|
||||
{
|
||||
const TableContainer& sgofTables = tableManager.getSgofTables();
|
||||
const TableContainer& slgofTables = tableManager.getSlgofTables();
|
||||
if (!sgofTables.empty())
|
||||
readGasOilSgof_(effParams, Swco, tolcrit, sgofTables.getTable<SgofTable>(satRegionIdx));
|
||||
else if (!slgofTables.empty())
|
||||
readGasOilSlgof_(effParams, Swco, tolcrit, slgofTables.getTable<SlgofTable>(satRegionIdx));
|
||||
else if ( !tableManager.getSgofletTable().empty() ) {
|
||||
const auto& letSgofTab = tableManager.getSgofletTable()[satRegionIdx];
|
||||
const std::vector<Scalar> dum; // dummy arg to comform with existing interface
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::LET);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::LET>();
|
||||
|
||||
// S=(So-Sogcr)/(1-Sogcr-Sgcr-Swco), krog = Krt*S^L/[S^L+E*(1.0-S)^T]
|
||||
const Scalar s_min_w = letSgofTab.s2_critical;
|
||||
const Scalar s_max_w = 1.0-letSgofTab.s1_critical-Swco;
|
||||
const std::vector<Scalar>& letCoeffsOil = {s_min_w, s_max_w,
|
||||
static_cast<Scalar>(letSgofTab.l2_relperm),
|
||||
static_cast<Scalar>(letSgofTab.e2_relperm),
|
||||
static_cast<Scalar>(letSgofTab.t2_relperm),
|
||||
static_cast<Scalar>(letSgofTab.krt2_relperm)};
|
||||
realParams.setKrwSamples(letCoeffsOil, dum);
|
||||
|
||||
// S=(1-So-Sgcr-Swco)/(1-Sogcr-Sgcr-Swco), krg = Krt*S^L/[S^L+E*(1.0-S)^T]
|
||||
const Scalar s_min_nw = letSgofTab.s1_critical+Swco;
|
||||
const Scalar s_max_nw = 1.0-letSgofTab.s2_critical;
|
||||
const std::vector<Scalar>& letCoeffsGas = {s_min_nw, s_max_nw,
|
||||
static_cast<Scalar>(letSgofTab.l1_relperm),
|
||||
static_cast<Scalar>(letSgofTab.e1_relperm),
|
||||
static_cast<Scalar>(letSgofTab.t1_relperm),
|
||||
static_cast<Scalar>(letSgofTab.krt1_relperm)};
|
||||
realParams.setKrnSamples(letCoeffsGas, dum);
|
||||
|
||||
// S=(So-Sorg)/(1-Sorg-Sgl-Swco), Pc = Pct + (pcir_pc-Pct)*(1-S)^L/[(1-S)^L+E*S^T]
|
||||
const std::vector<Scalar>& letCoeffsPc = {static_cast<Scalar>(letSgofTab.s2_residual),
|
||||
static_cast<Scalar>(letSgofTab.s1_residual+Swco),
|
||||
static_cast<Scalar>(letSgofTab.l_pc),
|
||||
static_cast<Scalar>(letSgofTab.e_pc),
|
||||
static_cast<Scalar>(letSgofTab.t_pc),
|
||||
static_cast<Scalar>(letSgofTab.pcir_pc),
|
||||
static_cast<Scalar>(letSgofTab.pct_pc)};
|
||||
realParams.setPcnwSamples(letCoeffsPc, dum);
|
||||
|
||||
realParams.finalize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_II:
|
||||
{
|
||||
const SgfnTable& sgfnTable = tableManager.getSgfnTables().getTable<SgfnTable>( satRegionIdx );
|
||||
if (!this->parent_.hasWater) {
|
||||
// oil and gas case
|
||||
const Sof2Table& sof2Table = tableManager.getSof2Tables().getTable<Sof2Table>( satRegionIdx );
|
||||
readGasOilFamily2_(effParams, Swco, tolcrit, sof2Table, sgfnTable, /*columnName=*/"KRO");
|
||||
}
|
||||
else {
|
||||
const Sof3Table& sof3Table = tableManager.getSof3Tables().getTable<Sof3Table>( satRegionIdx );
|
||||
readGasOilFamily2_(effParams, Swco, tolcrit, sof3Table, sgfnTable, /* columnName=*/"KROG");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
template <class TableType>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
readGasOilFamily2_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const TableType& sofTable,
|
||||
const SgfnTable& sgfnTable,
|
||||
const std::string& columnName)
|
||||
{
|
||||
// convert the saturations of the SGFN keyword from gas to oil saturations
|
||||
std::vector<double> SoSamples(sgfnTable.numRows());
|
||||
std::vector<double> SoColumn = sofTable.getColumn("SO").vectorCopy();
|
||||
for (size_t sampleIdx = 0; sampleIdx < sgfnTable.numRows(); ++ sampleIdx) {
|
||||
SoSamples[sampleIdx] = (1.0 - Swco) - sgfnTable.get("SG", sampleIdx);
|
||||
}
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SoColumn, normalizeKrValues_(tolcrit, sofTable.getColumn(columnName)));
|
||||
realParams.setKrnSamples(SoSamples, normalizeKrValues_(tolcrit, sgfnTable.getColumn("KRG")));
|
||||
realParams.setPcnwSamples(SoSamples, sgfnTable.getColumn("PCOG").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
readGasOilSgof_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const SgofTable& sgofTable)
|
||||
{
|
||||
// convert the saturations of the SGOF keyword from gas to oil saturations
|
||||
std::vector<double> SoSamples(sgofTable.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sgofTable.numRows(); ++ sampleIdx) {
|
||||
SoSamples[sampleIdx] = (1.0 - Swco) - sgofTable.get("SG", sampleIdx);
|
||||
}
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SoSamples, normalizeKrValues_(tolcrit, sgofTable.getColumn("KROG")));
|
||||
realParams.setKrnSamples(SoSamples, normalizeKrValues_(tolcrit, sgofTable.getColumn("KRG")));
|
||||
realParams.setPcnwSamples(SoSamples, sgofTable.getColumn("PCOG").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
readGasOilSlgof_(GasOilEffectiveTwoPhaseParams& effParams,
|
||||
const Scalar Swco,
|
||||
const double tolcrit,
|
||||
const SlgofTable& slgofTable)
|
||||
{
|
||||
// convert the saturations of the SLGOF keyword from "liquid" to oil saturations
|
||||
std::vector<double> SoSamples(slgofTable.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < slgofTable.numRows(); ++ sampleIdx) {
|
||||
SoSamples[sampleIdx] = slgofTable.get("SL", sampleIdx) - Swco;
|
||||
}
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SoSamples, normalizeKrValues_(tolcrit, slgofTable.getColumn("KROG")));
|
||||
realParams.setKrnSamples(SoSamples, normalizeKrValues_(tolcrit, slgofTable.getColumn("KRG")));
|
||||
realParams.setPcnwSamples(SoSamples, slgofTable.getColumn("PCOG").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
readGasWaterParameters_(GasWaterEffectiveParamVector& dest, unsigned satRegionIdx)
|
||||
{
|
||||
if (!this->parent_.hasGas || !this->parent_.hasWater || this->parent_.hasOil)
|
||||
// we don't read anything if either the gas or the water phase is not active or if oil is present
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<GasWaterEffectiveTwoPhaseParams>();
|
||||
|
||||
auto& effParams = *dest[satRegionIdx];
|
||||
|
||||
const auto tolcrit = this->eclState_.runspec().saturationFunctionControls()
|
||||
.minimumRelpermMobilityThreshold();
|
||||
|
||||
const auto& tableManager = this->eclState_.getTableManager();
|
||||
|
||||
switch (this->eclState_.runspec().saturationFunctionControls().family()) {
|
||||
case SatFuncControls::KeywordFamily::Family_I:
|
||||
{
|
||||
throw std::domain_error("Saturation keyword family I is not applicable for a gas-water system");
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_II:
|
||||
{
|
||||
//Todo: allow also for Sgwfn table input as alternative to Sgfn and Swfn table input
|
||||
const SgfnTable& sgfnTable = tableManager.getSgfnTables().getTable<SgfnTable>( satRegionIdx );
|
||||
const SwfnTable& swfnTable = tableManager.getSwfnTables().getTable<SwfnTable>( satRegionIdx );
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
std::vector<double> SwColumn = swfnTable.getColumn("SW").vectorCopy();
|
||||
|
||||
realParams.setKrwSamples(SwColumn, normalizeKrValues_(tolcrit, swfnTable.getColumn("KRW")));
|
||||
std::vector<double> SwSamples(sgfnTable.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sgfnTable.numRows(); ++ sampleIdx)
|
||||
SwSamples[sampleIdx] = 1 - sgfnTable.get("SG", sampleIdx);
|
||||
realParams.setKrnSamples(SwSamples, normalizeKrValues_(tolcrit, sgfnTable.getColumn("KRG")));
|
||||
//Capillary pressure is read from SWFN.
|
||||
//For gas-water system the capillary pressure column values are set to 0 in SGFN
|
||||
realParams.setPcnwSamples(SwColumn, swfnTable.getColumn("PCOW").vectorCopy());
|
||||
realParams.finalize();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void
|
||||
EclMaterialLawManager<Traits>::InitParams::ReadEffectiveParams::
|
||||
readOilWaterParameters_(OilWaterEffectiveParamVector& dest, unsigned satRegionIdx)
|
||||
{
|
||||
if (!this->parent_.hasOil || !this->parent_.hasWater)
|
||||
// we don't read anything if either the water or the oil phase is not active
|
||||
return;
|
||||
|
||||
dest[satRegionIdx] = std::make_shared<OilWaterEffectiveTwoPhaseParams>();
|
||||
|
||||
const auto tolcrit = this->eclState_.runspec().saturationFunctionControls()
|
||||
.minimumRelpermMobilityThreshold();
|
||||
|
||||
const auto& tableManager = this->eclState_.getTableManager();
|
||||
auto& effParams = *dest[satRegionIdx];
|
||||
|
||||
switch (this->eclState_.runspec().saturationFunctionControls().family()) {
|
||||
case SatFuncControls::KeywordFamily::Family_I:
|
||||
{
|
||||
if (tableManager.hasTables("SWOF")) {
|
||||
const auto& swofTable = tableManager.getSwofTables().getTable<SwofTable>(satRegionIdx);
|
||||
const std::vector<double> SwColumn = swofTable.getColumn("SW").vectorCopy();
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SwColumn, normalizeKrValues_(tolcrit, swofTable.getColumn("KRW")));
|
||||
realParams.setKrnSamples(SwColumn, normalizeKrValues_(tolcrit, swofTable.getColumn("KROW")));
|
||||
realParams.setPcnwSamples(SwColumn, swofTable.getColumn("PCOW").vectorCopy());
|
||||
realParams.finalize();
|
||||
}
|
||||
else if ( !tableManager.getSwofletTable().empty() ) {
|
||||
const auto& letTab = tableManager.getSwofletTable()[satRegionIdx];
|
||||
const std::vector<Scalar> dum; // dummy arg to conform with existing interface
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::LET);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::LET>();
|
||||
|
||||
// S=(Sw-Swcr)/(1-Sowcr-Swcr), krw = Krt*S^L/[S^L+E*(1.0-S)^T]
|
||||
const Scalar s_min_w = letTab.s1_critical;
|
||||
const Scalar s_max_w = 1.0-letTab.s2_critical;
|
||||
const std::vector<Scalar>& letCoeffsWat = {s_min_w, s_max_w,
|
||||
static_cast<Scalar>(letTab.l1_relperm),
|
||||
static_cast<Scalar>(letTab.e1_relperm),
|
||||
static_cast<Scalar>(letTab.t1_relperm),
|
||||
static_cast<Scalar>(letTab.krt1_relperm)};
|
||||
realParams.setKrwSamples(letCoeffsWat, dum);
|
||||
|
||||
// S=(So-Sowcr)/(1-Sowcr-Swcr), krow = Krt*S^L/[S^L+E*(1.0-S)^T]
|
||||
const Scalar s_min_nw = letTab.s2_critical;
|
||||
const Scalar s_max_nw = 1.0-letTab.s1_critical;
|
||||
const std::vector<Scalar>& letCoeffsOil = {s_min_nw, s_max_nw,
|
||||
static_cast<Scalar>(letTab.l2_relperm),
|
||||
static_cast<Scalar>(letTab.e2_relperm),
|
||||
static_cast<Scalar>(letTab.t2_relperm),
|
||||
static_cast<Scalar>(letTab.krt2_relperm)};
|
||||
realParams.setKrnSamples(letCoeffsOil, dum);
|
||||
|
||||
// S=(Sw-Swco)/(1-Swco-Sorw), Pc = Pct + (Pcir-Pct)*(1-S)^L/[(1-S)^L+E*S^T]
|
||||
const std::vector<Scalar>& letCoeffsPc = {static_cast<Scalar>(letTab.s1_residual),
|
||||
static_cast<Scalar>(letTab.s2_residual),
|
||||
static_cast<Scalar>(letTab.l_pc),
|
||||
static_cast<Scalar>(letTab.e_pc),
|
||||
static_cast<Scalar>(letTab.t_pc),
|
||||
static_cast<Scalar>(letTab.pcir_pc),
|
||||
static_cast<Scalar>(letTab.pct_pc)};
|
||||
realParams.setPcnwSamples(letCoeffsPc, dum);
|
||||
|
||||
realParams.finalize();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_II:
|
||||
{
|
||||
const auto& swfnTable = tableManager.getSwfnTables().getTable<SwfnTable>(satRegionIdx);
|
||||
const std::vector<double> SwColumn = swfnTable.getColumn("SW").vectorCopy();
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
realParams.setKrwSamples(SwColumn, normalizeKrValues_(tolcrit, swfnTable.getColumn("KRW")));
|
||||
realParams.setPcnwSamples(SwColumn, swfnTable.getColumn("PCOW").vectorCopy());
|
||||
|
||||
if (!this->parent_.hasGas) {
|
||||
const auto& sof2Table = tableManager.getSof2Tables().getTable<Sof2Table>(satRegionIdx);
|
||||
// convert the saturations of the SOF2 keyword from oil to water saturations
|
||||
std::vector<double> SwSamples(sof2Table.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sof2Table.numRows(); ++ sampleIdx)
|
||||
SwSamples[sampleIdx] = 1 - sof2Table.get("SO", sampleIdx);
|
||||
|
||||
realParams.setKrnSamples(SwSamples, normalizeKrValues_(tolcrit, sof2Table.getColumn("KRO")));
|
||||
} else {
|
||||
const auto& sof3Table = tableManager.getSof3Tables().getTable<Sof3Table>(satRegionIdx);
|
||||
// convert the saturations of the SOF3 keyword from oil to water saturations
|
||||
std::vector<double> SwSamples(sof3Table.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sof3Table.numRows(); ++ sampleIdx)
|
||||
SwSamples[sampleIdx] = 1 - sof3Table.get("SO", sampleIdx);
|
||||
|
||||
realParams.setKrnSamples(SwSamples, normalizeKrValues_(tolcrit, sof3Table.getColumn("KROW")));
|
||||
}
|
||||
realParams.finalize();
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
}
|
||||
|
||||
// Make some actual code, by realizing the previously defined templated class
|
||||
template class EclMaterialLawManager<ThreePhaseMaterialTraits<double,0,1,2>>::InitParams::ReadEffectiveParams;
|
||||
template class EclMaterialLawManager<ThreePhaseMaterialTraits<float,0,1,2>>::InitParams::ReadEffectiveParams;
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
Reference in New Issue
Block a user