Support for SGWFN sat functions (format type 2)
This commit is contained in:
parent
c419f8951d
commit
9696d58498
@ -343,8 +343,8 @@ public:
|
||||
|
||||
enum class KeywordFamily {
|
||||
Family_I, // SGOF, SWOF, SLGOF
|
||||
Family_II, // SGFN, SOF{2,3}, SWFN
|
||||
Family_III, // GSF, WSF
|
||||
Family_II, // SGFN, SOF{2,3}, SWFN, SGWFN
|
||||
Family_III, // GSF, WSF
|
||||
|
||||
Undefined,
|
||||
};
|
||||
|
@ -23,6 +23,7 @@
|
||||
#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/SgwfnTable.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>
|
||||
@ -70,8 +71,8 @@ namespace {
|
||||
* Description; there are several alternative families of keywords which
|
||||
* can be used to enter relperm and capillary pressure tables.
|
||||
*
|
||||
* If SWOF and SGOF are specified in the deck it return I
|
||||
* If SWFN, SGFN and SOF3 are specified in the deck it return II
|
||||
* If SWOF and SGOF are specified in the deck it returns I
|
||||
* If SGWFN, SWFN, SGFN and SOF3 are specified in the deck it returns II
|
||||
* If keywords are missing or mixed, an error is given.
|
||||
*/
|
||||
enum class SatfuncFamily { none = 0, I = 1, II = 2, III = 3 };
|
||||
@ -97,8 +98,8 @@ namespace {
|
||||
(wat && (tm.hasTables("SWOF") || !tm.getSwofletTable().empty()));
|
||||
// note: we allow for SOF2 to be part of family1 for threeP + solvent simulations.
|
||||
|
||||
const auto family2 = // SGFN, SOF{2,3}, SWFN
|
||||
(gas && tm.hasTables("SGFN")) ||
|
||||
const auto family2 = // SGFN, SOF{2,3}, SWFN, SGWFN
|
||||
(gas && (tm.hasTables("SGFN") || tm.hasTables("SGWFN"))) ||
|
||||
(oil && ((threeP && tm.hasTables("SOF3")) ||
|
||||
(twoP && tm.hasTables("SOF2")))) ||
|
||||
(wat && tm.hasTables("SWFN"));
|
||||
@ -132,7 +133,7 @@ namespace {
|
||||
throw std::invalid_argument {
|
||||
"Saturation functions must be specified using "
|
||||
"either family 1 or family 2 keywords\n"
|
||||
"Use either SGOF (or SLGOF) and/or SWOF or SGFN/SWFN and SOF2/SOF3"
|
||||
"Use either SGOF (or SLGOF) and/or SWOF or SGFN/SWFN or SGWFN and SOF2/SOF3"
|
||||
};
|
||||
}
|
||||
|
||||
@ -148,6 +149,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
const auto famI = [&swofTables]( int i ) {
|
||||
@ -161,6 +163,9 @@ namespace {
|
||||
const auto famII = [&swfnTables]( int i ) {
|
||||
return swfnTables.getTable<Opm::SwfnTable>( i ).getSwColumn().front();
|
||||
};
|
||||
const auto famII_sgwfn = [&sgwfnTables]( int i ) {
|
||||
return 1.0 - sgwfnTables.getTable<Opm::SgwfnTable>( i ).getSgColumn().back();
|
||||
};
|
||||
const auto famIII = [&wsfTables]( int i ) {
|
||||
return wsfTables.getTable<Opm::WsfTable>( i ).getSwColumn().front();
|
||||
};
|
||||
@ -173,7 +178,11 @@ namespace {
|
||||
else
|
||||
throw std::domain_error("Either SWOF or SWOFLET tables must be provided");
|
||||
|
||||
case SatfuncFamily::II: return map( famII, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::II:
|
||||
if( !swfnTables.empty() )
|
||||
return map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III: return map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
@ -192,6 +201,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
const auto famI = [&swofTables]( int i ) {
|
||||
@ -205,6 +215,9 @@ namespace {
|
||||
const auto famII = [&swfnTables]( int i ) {
|
||||
return swfnTables.getTable<Opm::SwfnTable>( i ).getSwColumn().back();
|
||||
};
|
||||
const auto famII_sgwfn = [&sgwfnTables]( int i ) {
|
||||
return 1.0 - sgwfnTables.getTable<Opm::SgwfnTable>( i ).getSgColumn().front();
|
||||
};
|
||||
const auto famIII = [&wsfTables]( int i ) {
|
||||
return wsfTables.getTable<Opm::WsfTable>( i ).getSwColumn().back();
|
||||
};
|
||||
@ -217,7 +230,11 @@ namespace {
|
||||
else
|
||||
throw std::domain_error("Either SWOF or SWOFLET tables must be provided");
|
||||
|
||||
case SatfuncFamily::II: return map( famII, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::II:
|
||||
if( !swfnTables.empty() )
|
||||
return map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III: return map( famIII, Opm::fun::iota( num_tables ) );
|
||||
|
||||
default:
|
||||
@ -238,6 +255,7 @@ namespace {
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
const auto famI_sgof = [&sgofTables]( int i ) {
|
||||
@ -255,6 +273,9 @@ namespace {
|
||||
const auto famII = [&sgfnTables]( int i ) {
|
||||
return sgfnTables.getTable<Opm::SgfnTable>( i ).getSgColumn().front();
|
||||
};
|
||||
const auto famII_sgwfn = [&sgwfnTables]( int i ) {
|
||||
return sgwfnTables.getTable<Opm::SgwfnTable>( i ).getSgColumn().front();
|
||||
};
|
||||
const auto famIII = [&gsfTables]( int i ) {
|
||||
return gsfTables.getTable<Opm::GsfTable>( i ).getSgColumn().front();
|
||||
};
|
||||
@ -271,7 +292,10 @@ namespace {
|
||||
return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) );
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
if( !sgfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
|
||||
@ -294,6 +318,7 @@ namespace {
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
const auto famI_sgof = [&sgofTables]( int i ) {
|
||||
@ -312,6 +337,9 @@ namespace {
|
||||
const auto famII = [&sgfnTables]( int i ) {
|
||||
return sgfnTables.getTable<Opm::SgfnTable>( i ).getSgColumn().back();
|
||||
};
|
||||
const auto famII_sgwfn = [&sgwfnTables]( int i ) {
|
||||
return sgwfnTables.getTable<Opm::SgwfnTable>( i ).getSgColumn().back();
|
||||
};
|
||||
const auto famIII = [&gsfTables]( int i ) {
|
||||
return gsfTables.getTable<Opm::GsfTable>( i ).getSgColumn().back();
|
||||
};
|
||||
@ -329,7 +357,10 @@ namespace {
|
||||
return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) );
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
if( !sgfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
|
||||
@ -395,6 +426,21 @@ namespace {
|
||||
table.getKrwColumn(), tolcrit);
|
||||
}
|
||||
|
||||
/// Maximum water saturation for which Krgw(1-Sw) <= tolcrit.
|
||||
///
|
||||
/// Expected Table Format:
|
||||
/// [1-Sw, Krgw(1-Sw), ...other...]
|
||||
///
|
||||
/// Krgw decreasing.
|
||||
double critical_water_sgwfn(const Opm::SgwfnTable& sgwfnTable, const double tolcrit)
|
||||
{
|
||||
const auto sg_at_crit_krgw =
|
||||
crit_sat_decreasing_KR(sgwfnTable.getSgColumn(),
|
||||
sgwfnTable.getKrgwColumn(), tolcrit);
|
||||
// Sw = 1 - Sg
|
||||
return 1.0 - sg_at_crit_krgw;
|
||||
}
|
||||
|
||||
std::vector<double>
|
||||
findCriticalWater(const Opm::TableManager& tm,
|
||||
const Opm::Phases& ph,
|
||||
@ -408,6 +454,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
const auto famI = [&swofTables, tolcrit](const int i) -> double
|
||||
@ -423,6 +470,10 @@ namespace {
|
||||
{
|
||||
return critical_water(swfnTables.getTable<Opm::SwfnTable>(i), tolcrit);
|
||||
};
|
||||
const auto famII_sgwfn = [&sgwfnTables, tolcrit](const int i) -> double
|
||||
{
|
||||
return critical_water_sgwfn(sgwfnTables.getTable<Opm::SgwfnTable>(i), tolcrit);
|
||||
};
|
||||
const auto famIII = [&wsfTables, tolcrit](const int i) -> double
|
||||
{
|
||||
return critical_water(wsfTables.getTable<Opm::WsfTable>(i), tolcrit);
|
||||
@ -436,7 +487,11 @@ namespace {
|
||||
else
|
||||
throw std::domain_error("Either SWOF or SWOFLET tables must be provided");
|
||||
|
||||
case SatfuncFamily::II: return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::II:
|
||||
if( !swfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III: return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
|
||||
default: throw std::domain_error("No valid saturation keyword family specified");
|
||||
@ -484,6 +539,7 @@ namespace {
|
||||
return std::vector<double>(num_tables, 0.0);
|
||||
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& sgofTables = tm.getSgofTables();
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
@ -508,6 +564,11 @@ namespace {
|
||||
return critical_gas(sgfnTables.getTable<Opm::SgfnTable>(i), tolcrit);
|
||||
};
|
||||
|
||||
const auto famII_sgwfn = [&sgwfnTables, tolcrit](const int i) -> double
|
||||
{
|
||||
return critical_gas(sgwfnTables.getTable<Opm::SgwfnTable>(i), tolcrit);
|
||||
};
|
||||
|
||||
const auto famIII = [&gsfTables, tolcrit](const int i) -> double
|
||||
{
|
||||
return critical_gas(gsfTables.getTable<Opm::GsfTable>(i), tolcrit);
|
||||
@ -526,7 +587,10 @@ namespace {
|
||||
return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) );
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
if( !sgfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
|
||||
@ -742,6 +806,7 @@ namespace {
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
const auto& famI_sgof = [&sgofTables]( int i ) {
|
||||
@ -760,6 +825,10 @@ namespace {
|
||||
return sgfnTables.getTable<Opm::SgfnTable>( i ).getKrgColumn().back();
|
||||
};
|
||||
|
||||
const auto& famII_sgwfn = [&sgwfnTables]( int i ) {
|
||||
return sgwfnTables.getTable<Opm::SgwfnTable>( i ).getKrgColumn().back();
|
||||
};
|
||||
|
||||
const auto& famIII = [&gsfTables]( int i ) {
|
||||
return gsfTables.getTable<Opm::GsfTable>( i ).getKrgColumn().back();
|
||||
};
|
||||
@ -775,7 +844,10 @@ namespace {
|
||||
else
|
||||
return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
if( !sgfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
@ -797,6 +869,7 @@ namespace {
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
auto sr = std::vector<double>(num_tables, 0.0);
|
||||
@ -843,6 +916,14 @@ namespace {
|
||||
return sgfn.getKrgColumn().eval(ix);
|
||||
};
|
||||
|
||||
const auto famII_sgwfn = [&sgwfnTables, &sr](const int i) -> double
|
||||
{
|
||||
const auto& sgwfn = sgwfnTables.getTable<Opm::SgwfnTable>(i);
|
||||
const auto ix = sgwfn.getSgColumn().lookup(sr[i]);
|
||||
|
||||
return sgwfn.getKrgColumn().eval(ix);
|
||||
};
|
||||
|
||||
const auto famIII = [&gsfTables, &sr](const int i) -> double
|
||||
{
|
||||
const auto& gsf = gsfTables.getTable<Opm::GsfTable>(i);
|
||||
@ -862,7 +943,10 @@ namespace {
|
||||
else
|
||||
return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
if( !sgfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
@ -883,6 +967,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
auto sr = std::vector<double>(num_tables, 0.0);
|
||||
@ -921,6 +1006,14 @@ namespace {
|
||||
return swfn.getKrwColumn().eval(ix);
|
||||
};
|
||||
|
||||
const auto& famII_sgwfn = [&sgwfnTables, &sr](const int i) -> double
|
||||
{
|
||||
const auto& sgwfn = sgwfnTables.getTable<Opm::SgwfnTable>(i);
|
||||
const auto ix = sgwfn.getSgColumn().lookup(1. - sr[i]);
|
||||
|
||||
return sgwfn.getKrgwColumn().eval(ix);
|
||||
};
|
||||
|
||||
const auto& famIII = [&wsfTables, &sr](const int i) -> double
|
||||
{
|
||||
const auto& wsf = wsfTables.getTable<Opm::WsfTable>(i);
|
||||
@ -939,7 +1032,10 @@ namespace {
|
||||
throw std::domain_error("Either SWOF or SWOFLET tables must be provided");
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
if( !swfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
@ -1115,6 +1211,7 @@ namespace {
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
const auto& famI_sgof = [&sgofTables]( int i ) {
|
||||
@ -1133,6 +1230,10 @@ namespace {
|
||||
return sgfnTables.getTable<Opm::SgfnTable>( i ).getPcogColumn().back();
|
||||
};
|
||||
|
||||
const auto& famII_sgwfn = [&sgwfnTables]( int i ) {
|
||||
return sgwfnTables.getTable<Opm::SgwfnTable>( i ).getPcgwColumn().back();
|
||||
};
|
||||
|
||||
const auto& famIII = [&gsfTables]( int i ) {
|
||||
return gsfTables.getTable<Opm::GsfTable>( i ).getPcgwColumn().back();
|
||||
};
|
||||
@ -1148,7 +1249,10 @@ namespace {
|
||||
else
|
||||
return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
if( !sgfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
@ -1162,7 +1266,8 @@ namespace {
|
||||
{
|
||||
const auto num_tables = tm.getTabdims().getNumSatTables();
|
||||
|
||||
if (! ph.active(::Opm::Phase::WATER))
|
||||
if (! ph.active(::Opm::Phase::WATER) ||
|
||||
! ph.active(::Opm::Phase::OIL))
|
||||
return std::vector<double>(num_tables, 0.0);
|
||||
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
@ -1279,6 +1384,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& sgwfnTables = tm.getSgwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
const auto& famI = [&swofTables]( int i ) {
|
||||
@ -1293,6 +1399,10 @@ namespace {
|
||||
return swfnTables.getTable<Opm::SwfnTable>( i ).getKrwColumn().back();
|
||||
};
|
||||
|
||||
const auto& famII_sgwfn = [&sgwfnTables]( int i ) {
|
||||
return sgwfnTables.getTable<Opm::SgwfnTable>( i ).getKrgwColumn().front();
|
||||
};
|
||||
|
||||
const auto& famIII = [&wsfTables]( int i ) {
|
||||
return wsfTables.getTable<Opm::WsfTable>( i ).getKrwColumn().back();
|
||||
};
|
||||
@ -1305,10 +1415,11 @@ namespace {
|
||||
return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
throw std::domain_error("Either SWOF or SWOFLET tables must be provided");
|
||||
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
if( !swfnTables.empty() )
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
else
|
||||
return Opm::fun::map( famII_sgwfn, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
|
@ -96,11 +96,13 @@ namespace {
|
||||
// note: we allow for SOF2 to be part of family1 for threeP +
|
||||
// solvent simulations.
|
||||
|
||||
const auto family2 = // SGFN, SOF{2,3}, SWFN
|
||||
(gas && deck.hasKeyword<Opm::ParserKeywords::SGFN>()) ||
|
||||
const auto family2 = // SGFN, SOF{2,3}, SWFN, SGWFN
|
||||
(gas && (deck.hasKeyword<Opm::ParserKeywords::SGFN>() ||
|
||||
deck.hasKeyword<Opm::ParserKeywords::SGWFN>())) ||
|
||||
(oil && ((threeP && deck.hasKeyword<Opm::ParserKeywords::SOF3>()) ||
|
||||
(twoP && deck.hasKeyword<Opm::ParserKeywords::SOF2>()))) ||
|
||||
(wat && deck.hasKeyword<Opm::ParserKeywords::SWFN>());
|
||||
(wat && (deck.hasKeyword<Opm::ParserKeywords::SWFN>() ||
|
||||
deck.hasKeyword<Opm::ParserKeywords::SGWFN>()));
|
||||
const auto family3 = //WSF, GSF gas-water CO2STORE case
|
||||
deck.hasKeyword<Opm::ParserKeywords::GSF>() &&
|
||||
deck.hasKeyword<Opm::ParserKeywords::WSF>();
|
||||
|
@ -21,6 +21,7 @@
|
||||
#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/SgwfnTable.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>
|
||||
@ -276,25 +277,34 @@ readGasWaterParameters_(GasWaterEffectiveParamVector& dest, unsigned satRegionId
|
||||
|
||||
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().template getTable<SgfnTable>( satRegionIdx );
|
||||
const SwfnTable& swfnTable = tableManager.getSwfnTables().template getTable<SwfnTable>( satRegionIdx );
|
||||
|
||||
const TableContainer& sgwfnTables = tableManager.getSgwfnTables();
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
if (!sgwfnTables.empty()){
|
||||
const SgwfnTable& sgwfnTable = tableManager.getSgwfnTables().template getTable<SgwfnTable>( satRegionIdx );
|
||||
std::vector<double> SwSamples(sgwfnTable.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < sgwfnTable.numRows(); ++ sampleIdx)
|
||||
SwSamples[sampleIdx] = 1 - sgwfnTable.get("SG", sampleIdx);
|
||||
realParams.setKrwSamples(SwSamples, normalizeKrValues_(tolcrit, sgwfnTable.getColumn("KRGW")));
|
||||
realParams.setKrnSamples(SwSamples, normalizeKrValues_(tolcrit, sgwfnTable.getColumn("KRG")));
|
||||
realParams.setPcnwSamples(SwSamples, sgwfnTable.getColumn("PCGW").vectorCopy());
|
||||
}
|
||||
else {
|
||||
const SgfnTable& sgfnTable = tableManager.getSgfnTables().template getTable<SgfnTable>( satRegionIdx );
|
||||
const SwfnTable& swfnTable = tableManager.getSwfnTables().template getTable<SwfnTable>( satRegionIdx );
|
||||
|
||||
std::vector<double> SwColumn = swfnTable.getColumn("SW").vectorCopy();
|
||||
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.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;
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include <opm/input/eclipse/EclipseState/Tables/PvtoTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SgfnTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SgofTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SgwfnTable.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>
|
||||
@ -500,6 +501,83 @@ namespace { namespace SatFunc {
|
||||
return numActRows;
|
||||
});
|
||||
}
|
||||
|
||||
/// Create linearised and padded 'TAB' vector entries of normalised
|
||||
/// SGFN tables for all saturation function regions from Family Two
|
||||
/// table data (SGWFN keyword).
|
||||
///
|
||||
/// \param[in] numRows Number of rows to allocate in the output
|
||||
/// vector for each table. Expected to be equal to the number of
|
||||
/// declared saturation nodes in the simulation run's TABDIMS
|
||||
/// keyword (Item 3).
|
||||
///
|
||||
/// \param tolcrit Minimum relative permeability threshold value for
|
||||
/// phase to be considered mobile. Values less than this threshold
|
||||
/// are output as zero.
|
||||
///
|
||||
/// \param[in] units Active unit system. Needed to convert SI
|
||||
/// convention capillary pressure values (Pascal) to declared
|
||||
/// conventions of the run specification.
|
||||
///
|
||||
/// \param[in] gsf Collection of SGFN tables for all saturation
|
||||
/// regions.
|
||||
///
|
||||
/// \return Linearised and padded 'TAB' vector values for output
|
||||
/// SGFN tables. Corresponds to unit-converted copies of columns
|
||||
/// 1, 2, and 4--with added derivatives--of the input SGWFN tables.
|
||||
std::vector<double>
|
||||
fromSGWFN(const std::size_t numRows,
|
||||
const double tolcrit,
|
||||
const Opm::UnitSystem& units,
|
||||
const Opm::TableContainer& gsf)
|
||||
{
|
||||
using Sgwfn = ::Opm::SgwfnTable;
|
||||
|
||||
const auto numTab = gsf.size();
|
||||
const auto numDep = std::size_t{2}; // Krg, Pcgw
|
||||
|
||||
return detail::createSatfuncTable(numTab, numRows, numDep,
|
||||
[tolcrit, &units, &gsf](const std::size_t tableID,
|
||||
const std::size_t primID,
|
||||
Opm::LinearisedOutputTable& linTable)
|
||||
-> std::size_t
|
||||
{
|
||||
const auto& t = gsf.getTable<Sgwfn>(tableID);
|
||||
|
||||
auto numActRows = std::size_t{0};
|
||||
|
||||
// Sg
|
||||
{
|
||||
const auto& Sg = t.getSgColumn();
|
||||
|
||||
numActRows = Sg.size();
|
||||
std::copy(std::begin(Sg), std::end(Sg),
|
||||
linTable.column(tableID, primID, 0));
|
||||
}
|
||||
|
||||
// Krg(Sg)
|
||||
detail::outputRelperm(t.getKrgColumn(), tolcrit,
|
||||
linTable.column(tableID, primID, 1));
|
||||
|
||||
// Pcgw(Sg)
|
||||
{
|
||||
constexpr auto uPress = ::Opm::UnitSystem::measure::pressure;
|
||||
|
||||
const auto& pc = t.getPcgwColumn();
|
||||
std::transform(std::begin(pc), std::end(pc),
|
||||
linTable.column(tableID, primID, 2),
|
||||
[&units](const double Pc) -> double
|
||||
{
|
||||
return units.from_si(uPress, Pc);
|
||||
});
|
||||
}
|
||||
|
||||
// Inform createSatfuncTable() of number of active rows in
|
||||
// this table. Needed to compute slopes of piecewise linear
|
||||
// interpolants.
|
||||
return numActRows;
|
||||
});
|
||||
}
|
||||
} // Gas
|
||||
|
||||
/// Functions to create linearised, padded, and normalised SOFN output
|
||||
@ -1245,6 +1323,87 @@ namespace { namespace SatFunc {
|
||||
});
|
||||
}
|
||||
|
||||
/// Create linearised and padded 'TAB' vector entries of normalised
|
||||
/// SWFN tables for all saturation function regions from Family Two
|
||||
/// table data (SGWFN keyword).
|
||||
///
|
||||
/// \param[in] numRows Number of rows to allocate for each table in
|
||||
/// the output vector. Expected to be equal to the number of
|
||||
/// declared saturation nodes in the simulation run's TABDIMS
|
||||
/// keyword (Item 3).
|
||||
///
|
||||
/// \param tolcrit Minimum relative permeability threshold value for
|
||||
/// phase to be considered mobile. Values less than this threshold
|
||||
/// are output as zero.
|
||||
///
|
||||
/// \param[in] swof Collection of SWOF tables for all saturation
|
||||
/// regions.
|
||||
///
|
||||
/// \return Linearised and padded 'TAB' vector values for output
|
||||
/// SWFN tables. Corresponds to unit-converted copies of columns
|
||||
/// 1, 3, and 4 --with added derivatives--of the input SGWFN tables.
|
||||
std::vector<double>
|
||||
fromSGWFN(const std::size_t numRows,
|
||||
const double tolcrit,
|
||||
const Opm::TableContainer& swfn)
|
||||
{
|
||||
using SWFN = ::Opm::SgwfnTable;
|
||||
|
||||
const auto numTab = swfn.size();
|
||||
const auto numDep = std::size_t{2}; // Krw, Pcow
|
||||
|
||||
return detail::createSatfuncTable(numTab, numRows, numDep,
|
||||
[tolcrit, &swfn]
|
||||
(const std::size_t tableID,
|
||||
const std::size_t primID,
|
||||
Opm::LinearisedOutputTable& linTable)
|
||||
-> std::size_t
|
||||
{
|
||||
const auto& t = swfn.getTable<SWFN>(tableID);
|
||||
|
||||
auto numActRows = std::size_t{0};
|
||||
|
||||
// Sw
|
||||
{
|
||||
const auto& Sg = t.getSgColumn();
|
||||
numActRows = Sg.size();
|
||||
auto Sw = std::vector<double>{};
|
||||
Sw.reserve(numActRows);
|
||||
std::transform(std::begin(Sg), std::end(Sg),
|
||||
std::back_inserter(Sw),
|
||||
[](const auto sg) { return 1.0 - sg; });
|
||||
std::copy(Sw.rbegin(), Sw.rend(),
|
||||
linTable.column(tableID, primID, 0));
|
||||
}
|
||||
|
||||
// Krgw(Sw)
|
||||
{
|
||||
const auto& kr = t.getKrgwColumn();
|
||||
const auto krgw = std::vector<double> {
|
||||
std::begin(kr), std::end(kr)
|
||||
};
|
||||
detail::outputRelperm(krgw.rbegin(), krgw.rend(), tolcrit,
|
||||
linTable.column(tableID, primID, 1));
|
||||
}
|
||||
|
||||
// Pcow(Sw) = zero
|
||||
{
|
||||
const auto& pc = t.getPcgwColumn();
|
||||
std::transform(std::begin(pc), std::end(pc),
|
||||
linTable.column(tableID, primID, 2),
|
||||
[](const double) -> double
|
||||
{
|
||||
return 0.0;
|
||||
});
|
||||
}
|
||||
|
||||
// Inform createSatfuncTable() of number of active rows in
|
||||
// this table. Needed to compute slopes of piecewise linear
|
||||
// interpolants.
|
||||
return numActRows;
|
||||
});
|
||||
}
|
||||
|
||||
/// Create linearised and padded 'TAB' vector entries of normalised
|
||||
/// WSF tables for all saturation function regions from Family Three
|
||||
/// table data (WSF keyword).
|
||||
@ -2456,8 +2615,8 @@ namespace Opm {
|
||||
(gas && !tabMgr.getSgofletTable().empty()) ||
|
||||
(wat && !tabMgr.getSwofletTable().empty());
|
||||
|
||||
const auto famII = // SGFN, SOF{2,3}, SWFN
|
||||
(gas && tabMgr.hasTables("SGFN")) ||
|
||||
const auto famII = // SGFN, SOF{2,3}, SWFN, SGWFN
|
||||
(gas && (tabMgr.hasTables("SGFN") || tabMgr.hasTables("SGWFN"))) ||
|
||||
(oil && ((threeP && tabMgr.hasTables("SOF3")) ||
|
||||
tabMgr.hasTables("SOF2"))) ||
|
||||
(wat && tabMgr.hasTables("SWFN"));
|
||||
@ -2621,15 +2780,25 @@ namespace Opm {
|
||||
.minimumRelpermMobilityThreshold();
|
||||
|
||||
if (gas) {
|
||||
const auto& tables = tabMgr.getSgfnTables();
|
||||
if ( !tabMgr.getSgfnTables().empty() ) {
|
||||
const auto& tables = tabMgr.getSgfnTables();
|
||||
|
||||
const auto sgfn =
|
||||
SatFunc::Gas::fromSGFN(nssfun, tolcrit,
|
||||
this->units, tables);
|
||||
|
||||
this->addData(Ix::SgfnTableStart, sgfn);
|
||||
this->m_tabdims[Ix::SgfnNumSatNodes] = nssfun;
|
||||
this->m_tabdims[Ix::SgfnNumTables] = tables.size();
|
||||
const auto sgfn =
|
||||
SatFunc::Gas::fromSGFN(nssfun, tolcrit,
|
||||
this->units, tables);
|
||||
this->addData(Ix::SgfnTableStart, sgfn);
|
||||
this->m_tabdims[Ix::SgfnNumSatNodes] = nssfun;
|
||||
this->m_tabdims[Ix::SgfnNumTables] = tables.size();
|
||||
}
|
||||
else {
|
||||
const auto& tables = tabMgr.getSgwfnTables();
|
||||
const auto sgfn =
|
||||
SatFunc::Gas::fromSGWFN(nssfun, tolcrit,
|
||||
this->units, tables);
|
||||
this->addData(Ix::SgfnTableStart, sgfn);
|
||||
this->m_tabdims[Ix::SgfnNumSatNodes] = nssfun;
|
||||
this->m_tabdims[Ix::SgfnNumTables] = tables.size();
|
||||
}
|
||||
}
|
||||
|
||||
if (oil) {
|
||||
@ -2656,14 +2825,22 @@ namespace Opm {
|
||||
}
|
||||
|
||||
if (wat) {
|
||||
const auto& tables = tabMgr.getSwfnTables();
|
||||
|
||||
const auto swfn =
|
||||
SatFunc::Water::fromSWFN(nssfun, tolcrit, this->units, tables);
|
||||
|
||||
this->addData(Ix::SwfnTableStart, swfn);
|
||||
this->m_tabdims[Ix::SwfnNumSatNodes] = nssfun;
|
||||
this->m_tabdims[Ix::SwfnNumTables] = tables.size();
|
||||
if ( !tabMgr.getSwfnTables().empty() ) {
|
||||
const auto& tables = tabMgr.getSwfnTables();
|
||||
const auto swfn =
|
||||
SatFunc::Water::fromSWFN(nssfun, tolcrit, this->units, tables);
|
||||
this->m_tabdims[Ix::SwfnNumTables] = tables.size();
|
||||
this->addData(Ix::SwfnTableStart, swfn);
|
||||
this->m_tabdims[Ix::SwfnNumSatNodes] = nssfun;
|
||||
}
|
||||
else {
|
||||
const auto& tables = tabMgr.getSgwfnTables();
|
||||
const auto swfn =
|
||||
SatFunc::Water::fromSGWFN(nssfun, tolcrit, tables);
|
||||
this->m_tabdims[Ix::SwfnNumTables] = tables.size();
|
||||
this->addData(Ix::SwfnTableStart, swfn);
|
||||
this->m_tabdims[Ix::SwfnNumSatNodes] = nssfun;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -787,6 +787,80 @@ SOGCR -- Requires 'OIL'
|
||||
)"), Opm::OpmInputError);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(SGWFN) {
|
||||
std::string deck_string = R"(
|
||||
RUNSPEC
|
||||
|
||||
DIMENS
|
||||
6 6 3 /
|
||||
|
||||
WATER
|
||||
GAS
|
||||
CO2STORE
|
||||
|
||||
TABDIMS
|
||||
/
|
||||
|
||||
GRID
|
||||
|
||||
DXV
|
||||
6*100.0 /
|
||||
DYV
|
||||
6*100.0 /
|
||||
DZV
|
||||
3*5.0 /
|
||||
|
||||
TOPS
|
||||
36*2000.0 /
|
||||
|
||||
PERMX
|
||||
108*100.0 /
|
||||
PERMY
|
||||
108*100.0 /
|
||||
PERMZ
|
||||
108*10.0 /
|
||||
PORO
|
||||
108*0.3 /
|
||||
|
||||
PROPS
|
||||
|
||||
SGWFN
|
||||
0.00 0.00 0.9 0.0
|
||||
0.05 0.02 0.8 5.
|
||||
0.10 0.03 0.5 10.0
|
||||
0.80 1.00 0.0 20.0
|
||||
/
|
||||
)";
|
||||
const auto es = ::Opm::EclipseState {
|
||||
::Opm::Parser{}.parseString(deck_string)
|
||||
};
|
||||
const auto& tm = es.getTableManager();
|
||||
const auto& ph = es.runspec().phases();
|
||||
const auto tolcrit = 0.0;
|
||||
|
||||
auto rtepPtr = satfunc::getRawTableEndpoints(tm, ph, tolcrit);
|
||||
|
||||
// Water end-points
|
||||
{
|
||||
const auto swl = rtepPtr.connate .water;
|
||||
const auto swcr = rtepPtr.critical.water;
|
||||
const auto swu = rtepPtr.maximum .water;
|
||||
BOOST_CHECK_CLOSE(swl [0], 0.2, 1.0e-10);
|
||||
BOOST_CHECK_CLOSE(swcr[0], 0.2, 1.0e-10);
|
||||
BOOST_CHECK_CLOSE(swu [0], 1.0, 1.0e-10);
|
||||
}
|
||||
|
||||
// Gas end-points
|
||||
{
|
||||
const auto sgl = rtepPtr.connate .gas;
|
||||
const auto sgcr = rtepPtr.critical.gas;
|
||||
const auto sgu = rtepPtr.maximum .gas;
|
||||
BOOST_CHECK_CLOSE(sgl [0], 0.0, 1.0e-10);
|
||||
BOOST_CHECK_CLOSE(sgcr[0], 0.0, 1.0e-10);
|
||||
BOOST_CHECK_CLOSE(sgu [0], 0.8, 1.0e-10);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
std::string satfunc_model_setup()
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user