mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
1164 lines
34 KiB
C++
1164 lines
34 KiB
C++
|
/*
|
||
|
Copyright 2017 Statoil 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/>.
|
||
|
*/
|
||
|
|
||
|
#if HAVE_CONFIG_H
|
||
|
#include <config.h>
|
||
|
#endif
|
||
|
|
||
|
#include <opm/utility/ECLEndPointScaling.hpp>
|
||
|
|
||
|
#include <opm/utility/ECLGraph.hpp>
|
||
|
#include <opm/utility/ECLPhaseIndex.hpp>
|
||
|
#include <opm/utility/ECLResultData.hpp>
|
||
|
|
||
|
#include <cassert>
|
||
|
#include <exception>
|
||
|
#include <stdexcept>
|
||
|
#include <utility>
|
||
|
#include <vector>
|
||
|
|
||
|
namespace {
|
||
|
std::vector<Opm::SatFunc::EPSEvalInterface::TableEndPoints>
|
||
|
unscaledTwoPt(const std::vector<double>& min,
|
||
|
const std::vector<double>& max)
|
||
|
{
|
||
|
assert ((min.size() == max.size()) && "Internal Logic Error");
|
||
|
assert ((! min.empty()) && "Internal Logic Error");
|
||
|
|
||
|
using TEP = Opm::SatFunc::EPSEvalInterface::TableEndPoints;
|
||
|
|
||
|
auto tep = std::vector<TEP>{};
|
||
|
tep.reserve(min.size());
|
||
|
|
||
|
for (auto n = min.size(), i = 0*n; i < n; ++i) {
|
||
|
const auto smin = min[i];
|
||
|
|
||
|
// Ignore 'sdisp' in the two-point scaling.
|
||
|
tep.push_back(TEP{ smin, smin, max[i] });
|
||
|
}
|
||
|
|
||
|
return tep;
|
||
|
}
|
||
|
|
||
|
std::vector<Opm::SatFunc::EPSEvalInterface::TableEndPoints>
|
||
|
unscaledThreePt(const std::vector<double>& min ,
|
||
|
const std::vector<double>& disp,
|
||
|
const std::vector<double>& max )
|
||
|
{
|
||
|
assert ((min.size() == max .size()) && "Internal Logic Error");
|
||
|
assert ((min.size() == disp.size()) && "Internal Logic Error");
|
||
|
assert ((! min.empty()) && "Internal Logic Error");
|
||
|
|
||
|
using TEP = Opm::SatFunc::EPSEvalInterface::TableEndPoints;
|
||
|
|
||
|
auto tep = std::vector<TEP>{};
|
||
|
tep.reserve(min.size());
|
||
|
|
||
|
for (auto n = min.size(), i = 0*n; i < n; ++i) {
|
||
|
tep.push_back(TEP{ min[i], disp[i], max[i] });
|
||
|
}
|
||
|
|
||
|
return tep;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
// Class Opm::TwoPointScaling::Impl
|
||
|
// ---------------------------------------------------------------------
|
||
|
|
||
|
class Opm::SatFunc::TwoPointScaling::Impl
|
||
|
{
|
||
|
public:
|
||
|
Impl(std::vector<double> smin,
|
||
|
std::vector<double> smax)
|
||
|
: smin_(std::move(smin))
|
||
|
, smax_(std::move(smax))
|
||
|
{
|
||
|
if (this->smin_.size() != this->smax_.size()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Size Mismatch Between Minimum and "
|
||
|
"Maximum Saturation Arrays"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::vector<double>
|
||
|
eval(const TableEndPoints& tep,
|
||
|
const SaturationPoints& sp) const;
|
||
|
|
||
|
private:
|
||
|
std::vector<double> smin_;
|
||
|
std::vector<double> smax_;
|
||
|
};
|
||
|
|
||
|
std::vector<double>
|
||
|
Opm::SatFunc::TwoPointScaling::
|
||
|
Impl::eval(const TableEndPoints& tep,
|
||
|
const SaturationPoints& sp) const
|
||
|
{
|
||
|
const auto srng = tep.high - tep.low;
|
||
|
|
||
|
auto effsat = std::vector<double>{};
|
||
|
effsat.reserve(sp.size());
|
||
|
|
||
|
for (const auto& eval_pt : sp) {
|
||
|
const auto cell = eval_pt.cell;
|
||
|
|
||
|
const auto sLO = this->smin_[cell];
|
||
|
const auto sHI = this->smax_[cell];
|
||
|
|
||
|
effsat.push_back(0.0);
|
||
|
auto& s_eff = effsat.back();
|
||
|
|
||
|
if (! (eval_pt.sat > sLO)) {
|
||
|
// s <= sLO
|
||
|
s_eff = tep.low;
|
||
|
}
|
||
|
else if (! (eval_pt.sat < sHI)) {
|
||
|
// s >= sHI
|
||
|
s_eff = tep.high;
|
||
|
}
|
||
|
else {
|
||
|
// s \in (sLO, sHI)
|
||
|
const auto scaled_sat =
|
||
|
((eval_pt.sat - sLO) / (sHI - sLO)) * srng;
|
||
|
|
||
|
s_eff = tep.low + scaled_sat;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return effsat;
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
// Class Opm::ThreePointScaling::Impl
|
||
|
// ---------------------------------------------------------------------
|
||
|
|
||
|
class Opm::SatFunc::ThreePointScaling::Impl
|
||
|
{
|
||
|
public:
|
||
|
Impl(std::vector<double> smin ,
|
||
|
std::vector<double> sdisp,
|
||
|
std::vector<double> smax )
|
||
|
: smin_ (std::move(smin ))
|
||
|
, sdisp_(std::move(sdisp))
|
||
|
, smax_ (std::move(smax ))
|
||
|
{
|
||
|
if ((this->sdisp_.size() != this->smin_.size()) ||
|
||
|
(this->sdisp_.size() != this->smax_.size()))
|
||
|
{
|
||
|
throw std::invalid_argument {
|
||
|
"Size Mismatch Between Minimum, Displacing "
|
||
|
"and Maximum Saturation Arrays"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
std::vector<double>
|
||
|
eval(const TableEndPoints& tep,
|
||
|
const SaturationPoints& sp) const;
|
||
|
|
||
|
private:
|
||
|
std::vector<double> smin_;
|
||
|
std::vector<double> sdisp_;
|
||
|
std::vector<double> smax_;
|
||
|
};
|
||
|
|
||
|
std::vector<double>
|
||
|
Opm::SatFunc::ThreePointScaling::
|
||
|
Impl::eval(const TableEndPoints& tep,
|
||
|
const SaturationPoints& sp) const
|
||
|
{
|
||
|
auto effsat = std::vector<double>{};
|
||
|
effsat.reserve(sp.size());
|
||
|
|
||
|
for (const auto& eval_pt : sp) {
|
||
|
const auto cell = eval_pt.cell;
|
||
|
|
||
|
effsat.push_back(0.0);
|
||
|
auto& s_eff = effsat.back();
|
||
|
|
||
|
const auto sLO = this->smin_ [cell];
|
||
|
const auto sR = this->sdisp_[cell];
|
||
|
const auto sHI = this->smax_ [cell];
|
||
|
|
||
|
if (! (eval_pt.sat > sLO)) {
|
||
|
// s <= sLO
|
||
|
s_eff = tep.low;
|
||
|
}
|
||
|
else if (! (eval_pt.sat < sHI)) {
|
||
|
// s >= sHI
|
||
|
s_eff = tep.high;
|
||
|
}
|
||
|
else if (eval_pt.sat < sR) {
|
||
|
// s \in (sLO, sR)
|
||
|
const auto t = (eval_pt.sat - sLO) / (sR - sLO);
|
||
|
|
||
|
s_eff = tep.low + t*(tep.disp - tep.low);
|
||
|
}
|
||
|
else {
|
||
|
// s \in (sR, sHI)
|
||
|
const auto t = (eval_pt.sat - sR) / (sHI - sR);
|
||
|
|
||
|
s_eff = tep.disp + t*(tep.high - tep.disp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return effsat;
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
// EPS factory functions for two-point and three-point scaling options
|
||
|
// ---------------------------------------------------------------------
|
||
|
|
||
|
namespace Create {
|
||
|
using EPSOpt = ::Opm::SatFunc::CreateEPS::EPSOptions;
|
||
|
using RTEP = ::Opm::SatFunc::CreateEPS::RawTableEndPoints;
|
||
|
using TEP = ::Opm::SatFunc::EPSEvalInterface::TableEndPoints;
|
||
|
|
||
|
namespace TwoPoint {
|
||
|
using EPS = ::Opm::SatFunc::TwoPointScaling;
|
||
|
using EPSPtr = std::unique_ptr<EPS>;
|
||
|
|
||
|
struct Kr {
|
||
|
static EPSPtr
|
||
|
G(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
|
||
|
static EPSPtr
|
||
|
OG(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
|
||
|
static EPSPtr
|
||
|
OW(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
|
||
|
static EPSPtr
|
||
|
W(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
};
|
||
|
|
||
|
struct Pc {
|
||
|
static EPSPtr
|
||
|
GO(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
|
||
|
static EPSPtr
|
||
|
OW(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
};
|
||
|
|
||
|
static EPSPtr
|
||
|
scalingFunction(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init,
|
||
|
const EPSOpt& opt);
|
||
|
|
||
|
static std::vector<TEP>
|
||
|
unscaledEndPoints(const RTEP& ep, const EPSOpt& opt);
|
||
|
} // namespace TwoPoint
|
||
|
|
||
|
namespace ThreePoint {
|
||
|
using EPS = ::Opm::SatFunc::ThreePointScaling;
|
||
|
using EPSPtr = std::unique_ptr<EPS>;
|
||
|
|
||
|
struct Kr {
|
||
|
static EPSPtr
|
||
|
G(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
|
||
|
static EPSPtr
|
||
|
OG(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
|
||
|
static EPSPtr
|
||
|
OW(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
|
||
|
static EPSPtr
|
||
|
W(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init);
|
||
|
};
|
||
|
|
||
|
static EPSPtr
|
||
|
scalingFunction(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init,
|
||
|
const ::Opm::SatFunc::CreateEPS::EPSOptions& opt);
|
||
|
|
||
|
static std::vector<TEP>
|
||
|
unscaledEndPoints(const RTEP& ep, const EPSOpt& opt);
|
||
|
} // namespace ThreePoint
|
||
|
} // namespace Create
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// Implementation of Create::TwoPoint::scalingFunction()
|
||
|
Create::TwoPoint::EPSPtr
|
||
|
Create::TwoPoint::Kr::G(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto sgcr = G.rawLinearisedCellData<double>(init, "SGCR");
|
||
|
auto sgu = G.rawLinearisedCellData<double>(init, "SGU");
|
||
|
|
||
|
if ((sgcr.size() != sgu.size()) ||
|
||
|
(sgcr.size() != G.numCells()))
|
||
|
{
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Gas End-Point "
|
||
|
"Specifications (SGCR and/or SGU)"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return EPSPtr { new EPS { std::move(sgcr), std::move(sgu) } };
|
||
|
}
|
||
|
|
||
|
Create::TwoPoint::EPSPtr
|
||
|
Create::TwoPoint::Kr::OG(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto sogcr = G.rawLinearisedCellData<double>(init, "SOGCR");
|
||
|
|
||
|
if (sogcr.size() != G.numCells()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Critical Oil "
|
||
|
"Saturation in Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
auto smax = std::vector<double>(sogcr.size(), 1.0);
|
||
|
|
||
|
// Adjust maximum S_o for scaled connate gas saturations.
|
||
|
{
|
||
|
const auto sgl = G.rawLinearisedCellData<double>(init, "SGL");
|
||
|
|
||
|
if (sgl.size() != sogcr.size()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Connate Gas "
|
||
|
"Saturation in Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
for (auto n = sgl.size(), i = 0*n; i < n; ++i) {
|
||
|
smax[i] -= sgl[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Adjust maximum S_o for scaled connate water saturations (if relevant).
|
||
|
{
|
||
|
const auto swl = G.rawLinearisedCellData<double>(init, "SWL");
|
||
|
|
||
|
if (swl.size() == sogcr.size()) {
|
||
|
for (auto n = swl.size(), i = 0*n; i < n; ++i) {
|
||
|
smax[i] -= swl[i];
|
||
|
}
|
||
|
}
|
||
|
else if (! swl.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Mismatching Connate Water "
|
||
|
"Saturation in Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EPSPtr { new EPS { std::move(sogcr), std::move(smax) } };
|
||
|
}
|
||
|
|
||
|
Create::TwoPoint::EPSPtr
|
||
|
Create::TwoPoint::Kr::OW(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto sowcr = G.rawLinearisedCellData<double>(init, "SOWCR");
|
||
|
|
||
|
if (sowcr.size() != G.numCells()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Critical Oil "
|
||
|
"Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
auto smax = std::vector<double>(sowcr.size(), 1.0);
|
||
|
|
||
|
// Adjust maximum S_o for scaled connate water saturations.
|
||
|
{
|
||
|
const auto swl = G.rawLinearisedCellData<double>(init, "SWL");
|
||
|
|
||
|
if (swl.size() != sowcr.size()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Connate Water "
|
||
|
"Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
for (auto n = swl.size(), i = 0*n; i < n; ++i) {
|
||
|
smax[i] -= swl[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Adjust maximum S_o for scaled connate gas saturations (if relevant).
|
||
|
{
|
||
|
const auto sgl = G.rawLinearisedCellData<double>(init, "SGL");
|
||
|
|
||
|
if (sgl.size() == sowcr.size()) {
|
||
|
for (auto n = sgl.size(), i = 0*n; i < n; ++i) {
|
||
|
smax[i] -= sgl[i];
|
||
|
}
|
||
|
}
|
||
|
else if (! sgl.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Mismatching Connate Gas "
|
||
|
"Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EPSPtr { new EPS { std::move(sowcr), std::move(smax) } };
|
||
|
}
|
||
|
|
||
|
Create::TwoPoint::EPSPtr
|
||
|
Create::TwoPoint::Kr::W(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto swcr = G.rawLinearisedCellData<double>(init, "SWCR");
|
||
|
auto swu = G.rawLinearisedCellData<double>(init, "SWU");
|
||
|
|
||
|
if (swcr.empty() || swu.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing Water End-Point Specifications (SWCR and/or SWU)"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return EPSPtr { new EPS { std::move(swcr), std::move(swu) } };
|
||
|
}
|
||
|
|
||
|
Create::TwoPoint::EPSPtr
|
||
|
Create::TwoPoint::Pc::GO(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto sgl = G.rawLinearisedCellData<double>(init, "SGL");
|
||
|
auto sgu = G.rawLinearisedCellData<double>(init, "SGU");
|
||
|
|
||
|
if ((sgl.size() != sgu.size()) ||
|
||
|
(sgl.size() != G.numCells()))
|
||
|
{
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Connate or Maximum Gas "
|
||
|
"Saturation in Pcgo EPS"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return EPSPtr { new EPS { std::move(sgl), std::move(sgu) } };
|
||
|
}
|
||
|
|
||
|
Create::TwoPoint::EPSPtr
|
||
|
Create::TwoPoint::Pc::OW(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto swl = G.rawLinearisedCellData<double>(init, "SWL");
|
||
|
auto swu = G.rawLinearisedCellData<double>(init, "SWU");
|
||
|
|
||
|
if ((swl.size() != swu.size()) ||
|
||
|
(swl.size() != G.numCells()))
|
||
|
{
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Connate or Maximum Water "
|
||
|
"Saturation in Pcow EPS"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
return EPSPtr { new EPS { std::move(swl), std::move(swu) } };
|
||
|
}
|
||
|
|
||
|
Create::TwoPoint::EPSPtr
|
||
|
Create::TwoPoint::
|
||
|
scalingFunction(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init,
|
||
|
const ::Opm::SatFunc::CreateEPS::EPSOptions& opt)
|
||
|
{
|
||
|
using FCat = ::Opm::SatFunc::CreateEPS::FunctionCategory;
|
||
|
using SSys = ::Opm::SatFunc::CreateEPS::SubSystem;
|
||
|
using PhIdx = ::Opm::ECLPhaseIndex;
|
||
|
|
||
|
assert (((! opt.use3PtScaling) || (opt.curve == FCat::CapPress))
|
||
|
&& "Internal Error Selecting EPS Family");
|
||
|
|
||
|
if (opt.curve == FCat::Relperm) {
|
||
|
if (opt.subSys == SSys::OilWater) {
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
throw std::invalid_argument {
|
||
|
"Cannot Create an EPS for Gas Relperm "
|
||
|
"in an Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
return Create::TwoPoint::Kr::W(G, init);
|
||
|
}
|
||
|
|
||
|
return Create::TwoPoint::Kr::OW(G, init);
|
||
|
}
|
||
|
|
||
|
if (opt.subSys == SSys::OilGas) {
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
throw std::invalid_argument {
|
||
|
"Cannot Create an EPS for Water Relperm "
|
||
|
"in an Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
return Create::TwoPoint::Kr::G(G, init);
|
||
|
}
|
||
|
|
||
|
return Create::TwoPoint::Kr::OG(G, init);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (opt.curve == FCat::CapPress) {
|
||
|
if (opt.thisPh == PhIdx::Liquid) {
|
||
|
throw std::invalid_argument {
|
||
|
"Creating Capillary Pressure EPS as a Function "
|
||
|
"of Oil Saturation is not Supported"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
return Create::TwoPoint::Pc::GO(G, init);
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
return Create::TwoPoint::Pc::OW(G, init);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Invalid.
|
||
|
return EPSPtr{};
|
||
|
}
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// Implementation of Create::TwoPoint::unscaledEndPoints()
|
||
|
std::vector<Create::TEP>
|
||
|
Create::TwoPoint::unscaledEndPoints(const RTEP& ep, const EPSOpt& opt)
|
||
|
{
|
||
|
using FCat = ::Opm::SatFunc::CreateEPS::FunctionCategory;
|
||
|
using SSys = ::Opm::SatFunc::CreateEPS::SubSystem;
|
||
|
using PhIdx = ::Opm::ECLPhaseIndex;
|
||
|
|
||
|
assert (((opt.curve == FCat::CapPress) ||
|
||
|
(! opt.use3PtScaling)) && "Internal Logic Error");
|
||
|
|
||
|
if (opt.curve == FCat::CapPress) {
|
||
|
// Left node is connate saturation, right node is max saturation.
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Liquid) {
|
||
|
throw std::invalid_argument {
|
||
|
"No Capillary Pressure Function for Oil"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
return unscaledTwoPt(ep.conn.water, ep.smax.water);
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
return unscaledTwoPt(ep.conn.gas, ep.smax.gas);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (opt.curve == FCat::Relperm) {
|
||
|
// Left node is critical saturation, right node is max saturation.
|
||
|
|
||
|
if (opt.subSys == SSys::OilGas) {
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
throw std::invalid_argument {
|
||
|
"Void Request for Unscaled Water Saturation "
|
||
|
"End-Points in Oil-Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Liquid) {
|
||
|
return unscaledTwoPt(ep.crit.oil_in_gas, ep.smax.oil);
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
return unscaledTwoPt(ep.crit.gas, ep.smax.gas);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (opt.subSys == SSys::OilWater) {
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
return unscaledTwoPt(ep.crit.water, ep.smax.water);
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Liquid) {
|
||
|
return unscaledTwoPt(ep.crit.oil_in_water, ep.smax.oil);
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
throw std::invalid_argument {
|
||
|
"Void Request for Unscaled Gas Saturation "
|
||
|
"End-Points in Oil-Water System"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Invalid.
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// Implementation of Create::ThreePoint::scalingFunction()
|
||
|
|
||
|
Create::ThreePoint::EPSPtr
|
||
|
Create::ThreePoint::Kr::G(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto sgcr = G.rawLinearisedCellData<double>(init, "SGCR");
|
||
|
auto sgu = G.rawLinearisedCellData<double>(init, "SGU");
|
||
|
|
||
|
if ((sgcr.size() != sgu.size()) ||
|
||
|
(sgcr.size() != G.numCells()))
|
||
|
{
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Gas End-Point "
|
||
|
"Specifications (SGCR and/or SGU)"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
auto sr = std::vector<double>(G.numCells(), 1.0);
|
||
|
|
||
|
// Adjust displacing saturation for connate water.
|
||
|
{
|
||
|
const auto swl = G.rawLinearisedCellData<double>(init, "SWL");
|
||
|
|
||
|
if (swl.size() == sgcr.size()) {
|
||
|
for (auto n = swl.size(), i = 0*n; i < n; ++i) {
|
||
|
sr[i] -= swl[i];
|
||
|
}
|
||
|
}
|
||
|
else if (! swl.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Connate Water Saturation Array Mismatch "
|
||
|
"in Three-Point Scaling Option"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Adjust displacing saturation for critical S_o in O/G system.
|
||
|
{
|
||
|
const auto sogcr = G.rawLinearisedCellData<double>(init, "SOGCR");
|
||
|
|
||
|
if (sogcr.size() == sgcr.size()) {
|
||
|
for (auto n = sogcr.size(), i = 0*n; i < n; ++i) {
|
||
|
sr[i] -= sogcr[i];
|
||
|
}
|
||
|
}
|
||
|
else if (! sogcr.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Critical Oil Saturation (O/G System) Array "
|
||
|
"Size Mismatch in Three-Point Scaling Option"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EPSPtr {
|
||
|
new EPS { std::move(sgcr), std::move(sr), std::move(sgu) }
|
||
|
};
|
||
|
}
|
||
|
|
||
|
Create::ThreePoint::EPSPtr
|
||
|
Create::ThreePoint::Kr::OG(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto sogcr = G.rawLinearisedCellData<double>(init, "SOGCR");
|
||
|
|
||
|
if (sogcr.size() != G.numCells()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Critical Oil "
|
||
|
"Saturation in Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
auto smax = std::vector<double>(sogcr.size(), 1.0);
|
||
|
|
||
|
// Adjust maximum S_o for scaled connate gas saturations.
|
||
|
{
|
||
|
const auto sgl = G.rawLinearisedCellData<double>(init, "SGL");
|
||
|
|
||
|
if (sgl.size() != sogcr.size()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Connate Gas "
|
||
|
"Saturation in Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
for (auto n = sgl.size(), i = 0*n; i < n; ++i) {
|
||
|
smax[i] -= sgl[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
auto sdisp = std::vector<double>(sogcr.size(), 1.0);
|
||
|
|
||
|
// Adjust displacing S_o for scaled critical gas saturation.
|
||
|
{
|
||
|
const auto sgcr = G.rawLinearisedCellData<double>(init, "SGCR");
|
||
|
|
||
|
if (sgcr.size() != sogcr.size()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Scaled Critical Gas "
|
||
|
"Saturation in Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
for (auto n = sgcr.size(), i = 0*n; i < n; ++i) {
|
||
|
sdisp[i] -= sgcr[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Adjust displacing and maximum S_o for scaled connate water
|
||
|
// saturations (if relevant).
|
||
|
{
|
||
|
const auto swl = G.rawLinearisedCellData<double>(init, "SWL");
|
||
|
|
||
|
if (swl.size() == sogcr.size()) {
|
||
|
for (auto n = swl.size(), i = 0*n; i < n; ++i) {
|
||
|
sdisp[i] -= swl[i];
|
||
|
smax [i] -= swl[i];
|
||
|
}
|
||
|
}
|
||
|
else if (! swl.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Mismatching Scaled Connate Water "
|
||
|
"Saturation in Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EPSPtr {
|
||
|
new EPS { std::move(sogcr), std::move(sdisp), std::move(smax) }
|
||
|
};
|
||
|
}
|
||
|
|
||
|
Create::ThreePoint::EPSPtr
|
||
|
Create::ThreePoint::Kr::OW(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto sowcr = G.rawLinearisedCellData<double>(init, "SOWCR");
|
||
|
|
||
|
if (sowcr.size() != G.numCells()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Critical Oil "
|
||
|
"Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
auto smax = std::vector<double>(sowcr.size(), 1.0);
|
||
|
|
||
|
// Adjust maximum S_o for scaled connate water saturations.
|
||
|
{
|
||
|
const auto swl = G.rawLinearisedCellData<double>(init, "SWL");
|
||
|
|
||
|
if (swl.size() != sowcr.size()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Connate Water "
|
||
|
"Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
for (auto n = swl.size(), i = 0*n; i < n; ++i) {
|
||
|
smax[i] -= swl[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
auto sdisp = std::vector<double>(sowcr.size(), 1.0);
|
||
|
|
||
|
// Adjust displacing S_o for scaled critical water saturations.
|
||
|
{
|
||
|
const auto swcr = G.rawLinearisedCellData<double>(init, "SWCR");
|
||
|
|
||
|
if (swcr.size() != sowcr.size()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Scaled Critical Water "
|
||
|
"Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
for (auto n = swcr.size(), i = 0*n; i < n; ++i) {
|
||
|
sdisp[i] -= swcr[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Adjust displacing and maximum S_o for scaled connate gas saturations
|
||
|
// (if relevant).
|
||
|
{
|
||
|
const auto sgl = G.rawLinearisedCellData<double>(init, "SGL");
|
||
|
|
||
|
if (sgl.size() == sowcr.size()) {
|
||
|
for (auto n = sgl.size(), i = 0*n; i < n; ++i) {
|
||
|
sdisp[i] -= sgl[i];
|
||
|
smax [i] -= sgl[i];
|
||
|
}
|
||
|
}
|
||
|
else if (! sgl.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Mismatching Connate Gas "
|
||
|
"Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EPSPtr {
|
||
|
new EPS { std::move(sowcr), std::move(sdisp), std::move(smax) }
|
||
|
};
|
||
|
}
|
||
|
|
||
|
Create::ThreePoint::EPSPtr
|
||
|
Create::ThreePoint::Kr::W(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init)
|
||
|
{
|
||
|
auto swcr = G.rawLinearisedCellData<double>(init, "SWCR");
|
||
|
auto swu = G.rawLinearisedCellData<double>(init, "SWU");
|
||
|
|
||
|
if ((swcr.size() != G.numCells()) ||
|
||
|
(swcr.size() != swu.size()))
|
||
|
{
|
||
|
throw std::invalid_argument {
|
||
|
"Missing Water End-Point Specifications (SWCR and/or SWU)"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
auto sdisp = std::vector<double>(swcr.size(), 1.0);
|
||
|
|
||
|
// Adjust displacing S_w for scaled critical oil saturation.
|
||
|
{
|
||
|
const auto sowcr = G.rawLinearisedCellData<double>(init, "SOWCR");
|
||
|
|
||
|
if (sowcr.size() == swcr.size()) {
|
||
|
for (auto n = sowcr.size(), i = 0*n; i < n; ++i) {
|
||
|
sdisp[i] -= sowcr[i];
|
||
|
}
|
||
|
}
|
||
|
else if (! sowcr.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Scaled Critical "
|
||
|
"Oil Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Adjust displacing S_w for scaled connate gas saturation.
|
||
|
{
|
||
|
const auto sgl = G.rawLinearisedCellData<double>(init, "SGL");
|
||
|
|
||
|
if (sgl.size() == swcr.size()) {
|
||
|
for (auto n = sgl.size(), i = 0*n; i < n; ++i) {
|
||
|
sdisp[i] -= sgl[i];
|
||
|
}
|
||
|
}
|
||
|
else if (! sgl.empty()) {
|
||
|
throw std::invalid_argument {
|
||
|
"Missing or Mismatching Scaled Connate "
|
||
|
"Gas Saturation in Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return EPSPtr {
|
||
|
new EPS { std::move(swcr), std::move(sdisp), std::move(swu) }
|
||
|
};
|
||
|
}
|
||
|
|
||
|
Create::ThreePoint::EPSPtr
|
||
|
Create::ThreePoint::
|
||
|
scalingFunction(const ::Opm::ECLGraph& G,
|
||
|
const ::Opm::ECLInitFileData& init,
|
||
|
const ::Opm::SatFunc::CreateEPS::EPSOptions& opt)
|
||
|
{
|
||
|
using FCat = ::Opm::SatFunc::CreateEPS::FunctionCategory;
|
||
|
using SSys = ::Opm::SatFunc::CreateEPS::SubSystem;
|
||
|
using PhIdx = ::Opm::ECLPhaseIndex;
|
||
|
|
||
|
assert ((opt.use3PtScaling && (opt.curve == FCat::Relperm))
|
||
|
&& "Internal Error Selecting EPS Family");
|
||
|
|
||
|
if (opt.subSys == SSys::OilWater) {
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
throw std::invalid_argument {
|
||
|
"Cannot Create a Three-Point EPS for "
|
||
|
"Gas Relperm in an Oil/Water System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
return Create::ThreePoint::Kr::W(G, init);
|
||
|
}
|
||
|
|
||
|
return Create::ThreePoint::Kr::OW(G, init);
|
||
|
}
|
||
|
|
||
|
if (opt.subSys == SSys::OilGas) {
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
throw std::invalid_argument {
|
||
|
"Cannot Create a Three-Point EPS for "
|
||
|
"Water Relperm in an Oil/Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
return Create::ThreePoint::Kr::G(G, init);
|
||
|
}
|
||
|
|
||
|
return Create::ThreePoint::Kr::OG(G, init);
|
||
|
}
|
||
|
|
||
|
// Invalid.
|
||
|
return EPSPtr{};
|
||
|
}
|
||
|
|
||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||
|
// Implementation of Create::ThreePoint::unscaledEndPoints()
|
||
|
std::vector<Create::TEP>
|
||
|
Create::ThreePoint::unscaledEndPoints(const RTEP& ep, const EPSOpt& opt)
|
||
|
{
|
||
|
using FCat = ::Opm::SatFunc::CreateEPS::FunctionCategory;
|
||
|
using SSys = ::Opm::SatFunc::CreateEPS::SubSystem;
|
||
|
using PhIdx = ::Opm::ECLPhaseIndex;
|
||
|
|
||
|
assert ((opt.use3PtScaling && (opt.curve == FCat::Relperm))
|
||
|
&& "Internal Error Selecting EPS Family");
|
||
|
|
||
|
auto sdisp = [](const std::vector<double>& s1,
|
||
|
const std::vector<double>& s2)
|
||
|
-> std::vector<double>
|
||
|
{
|
||
|
auto sr = std::vector<double>(s1.size(), 1.0);
|
||
|
|
||
|
for (auto n = s1.size(), i = 0*n; i < n; ++i) {
|
||
|
sr[i] -= s1[i] + s2[i];
|
||
|
}
|
||
|
|
||
|
return sr;
|
||
|
};
|
||
|
|
||
|
// Left node is critical saturation, middle node is displacing critical
|
||
|
// saturation, and right node is maximum saturation.
|
||
|
|
||
|
if (opt.subSys == SSys::OilGas) {
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
throw std::invalid_argument {
|
||
|
"Void Request for Unscaled Water Saturation "
|
||
|
"End-Points in Oil-Gas System"
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Liquid) {
|
||
|
return unscaledThreePt(ep.crit.oil_in_gas,
|
||
|
sdisp(ep.crit.gas, ep.conn.water),
|
||
|
ep.smax.oil);
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
return unscaledThreePt(ep.crit.gas,
|
||
|
sdisp(ep.crit.oil_in_gas, ep.conn.water),
|
||
|
ep.smax.gas);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (opt.subSys == SSys::OilWater) {
|
||
|
if (opt.thisPh == PhIdx::Aqua) {
|
||
|
return unscaledThreePt(ep.crit.water,
|
||
|
sdisp(ep.crit.oil_in_water, ep.conn.gas),
|
||
|
ep.smax.water);
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Liquid) {
|
||
|
return unscaledThreePt(ep.crit.oil_in_water,
|
||
|
sdisp(ep.crit.water, ep.conn.gas),
|
||
|
ep.smax.oil);
|
||
|
}
|
||
|
|
||
|
if (opt.thisPh == PhIdx::Vapour) {
|
||
|
throw std::invalid_argument {
|
||
|
"Void Request for Unscaled Gas Saturation "
|
||
|
"End-Points in Oil-Water System"
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Invalid.
|
||
|
return {};
|
||
|
}
|
||
|
|
||
|
// #####################################################################
|
||
|
// =====================================================================
|
||
|
// Public Interface Below Separator
|
||
|
// =====================================================================
|
||
|
// #####################################################################
|
||
|
|
||
|
// Class Opm::SatFunc::EPSEvalInterface
|
||
|
Opm::SatFunc::EPSEvalInterface::~EPSEvalInterface()
|
||
|
{}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
|
||
|
// Class Opm::SatFunc::TwoPointScaling
|
||
|
Opm::SatFunc::TwoPointScaling::
|
||
|
TwoPointScaling(std::vector<double> smin,
|
||
|
std::vector<double> smax)
|
||
|
: pImpl_(new Impl(std::move(smin), std::move(smax)))
|
||
|
{}
|
||
|
|
||
|
Opm::SatFunc::TwoPointScaling::~TwoPointScaling()
|
||
|
{}
|
||
|
|
||
|
Opm::SatFunc::TwoPointScaling::
|
||
|
TwoPointScaling(const TwoPointScaling& rhs)
|
||
|
: pImpl_(new Impl(*rhs.pImpl_))
|
||
|
{}
|
||
|
|
||
|
Opm::SatFunc::TwoPointScaling::
|
||
|
TwoPointScaling(TwoPointScaling&& rhs)
|
||
|
: pImpl_(std::move(rhs.pImpl_))
|
||
|
{}
|
||
|
|
||
|
Opm::SatFunc::TwoPointScaling&
|
||
|
Opm::SatFunc::TwoPointScaling::operator=(const TwoPointScaling& rhs)
|
||
|
{
|
||
|
this->pImpl_.reset(new Impl(*rhs.pImpl_));
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
Opm::SatFunc::TwoPointScaling&
|
||
|
Opm::SatFunc::TwoPointScaling::operator=(TwoPointScaling&& rhs)
|
||
|
{
|
||
|
this->pImpl_ = std::move(rhs.pImpl_);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
std::vector<double>
|
||
|
Opm::SatFunc::TwoPointScaling::eval(const TableEndPoints& tep,
|
||
|
const SaturationPoints& sp) const
|
||
|
{
|
||
|
return this->pImpl_->eval(tep, sp);
|
||
|
}
|
||
|
|
||
|
std::unique_ptr<Opm::SatFunc::EPSEvalInterface>
|
||
|
Opm::SatFunc::TwoPointScaling::clone() const
|
||
|
{
|
||
|
return std::unique_ptr<TwoPointScaling>(new TwoPointScaling(*this));
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
|
||
|
// Class Opm::SatFunc::ThreePointScaling
|
||
|
Opm::SatFunc::ThreePointScaling::
|
||
|
ThreePointScaling(std::vector<double> smin,
|
||
|
std::vector<double> sdisp,
|
||
|
std::vector<double> smax)
|
||
|
: pImpl_(new Impl(std::move(smin), std::move(sdisp), std::move(smax)))
|
||
|
{}
|
||
|
|
||
|
Opm::SatFunc::ThreePointScaling::~ThreePointScaling()
|
||
|
{}
|
||
|
|
||
|
Opm::SatFunc::ThreePointScaling::
|
||
|
ThreePointScaling(const ThreePointScaling& rhs)
|
||
|
: pImpl_(new Impl(*rhs.pImpl_))
|
||
|
{}
|
||
|
|
||
|
Opm::SatFunc::ThreePointScaling::ThreePointScaling(ThreePointScaling&& rhs)
|
||
|
: pImpl_(std::move(rhs.pImpl_))
|
||
|
{}
|
||
|
|
||
|
Opm::SatFunc::ThreePointScaling&
|
||
|
Opm::SatFunc::ThreePointScaling::operator=(const ThreePointScaling& rhs)
|
||
|
{
|
||
|
this->pImpl_.reset(new Impl(*rhs.pImpl_));
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
Opm::SatFunc::ThreePointScaling&
|
||
|
Opm::SatFunc::ThreePointScaling::operator=(ThreePointScaling&& rhs)
|
||
|
{
|
||
|
this->pImpl_ = std::move(rhs.pImpl_);
|
||
|
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
std::vector<double>
|
||
|
Opm::SatFunc::ThreePointScaling::eval(const TableEndPoints& tep,
|
||
|
const SaturationPoints& sp) const
|
||
|
{
|
||
|
return this->pImpl_->eval(tep, sp);
|
||
|
}
|
||
|
|
||
|
std::unique_ptr<Opm::SatFunc::EPSEvalInterface>
|
||
|
Opm::SatFunc::ThreePointScaling::clone() const
|
||
|
{
|
||
|
return std::unique_ptr<ThreePointScaling>(new ThreePointScaling(*this));
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
// Factory function Opm::SatFunc::CreateEPS::fromECLOutput()
|
||
|
|
||
|
std::unique_ptr<Opm::SatFunc::EPSEvalInterface>
|
||
|
Opm::SatFunc::CreateEPS::
|
||
|
fromECLOutput(const ECLGraph& G,
|
||
|
const ECLInitFileData& init,
|
||
|
const EPSOptions& opt)
|
||
|
{
|
||
|
if ((opt.curve == FunctionCategory::CapPress) ||
|
||
|
(! opt.use3PtScaling))
|
||
|
{
|
||
|
return Create::TwoPoint::scalingFunction(G, init, opt);
|
||
|
}
|
||
|
|
||
|
if ((opt.curve == FunctionCategory::Relperm) && opt.use3PtScaling)
|
||
|
{
|
||
|
return Create::ThreePoint::scalingFunction(G, init, opt);
|
||
|
}
|
||
|
|
||
|
// Invalid
|
||
|
return std::unique_ptr<Opm::SatFunc::EPSEvalInterface>{};
|
||
|
}
|
||
|
|
||
|
// ---------------------------------------------------------------------
|
||
|
// Factory function Opm::SatFunc::CreateEPS::unscaledEndPoints()
|
||
|
|
||
|
std::vector<Opm::SatFunc::EPSEvalInterface::TableEndPoints>
|
||
|
Opm::SatFunc::CreateEPS::
|
||
|
unscaledEndPoints(const RawTableEndPoints& ep,
|
||
|
const EPSOptions& opt)
|
||
|
{
|
||
|
if ((opt.curve == FunctionCategory::CapPress) ||
|
||
|
(! opt.use3PtScaling))
|
||
|
{
|
||
|
return Create::TwoPoint::unscaledEndPoints(ep, opt);
|
||
|
}
|
||
|
|
||
|
if ((opt.curve == FunctionCategory::Relperm) && opt.use3PtScaling)
|
||
|
{
|
||
|
return Create::ThreePoint::unscaledEndPoints(ep, opt);
|
||
|
}
|
||
|
|
||
|
// Invalid
|
||
|
return {};
|
||
|
}
|