Merge pull request #3406 from totto82/wsf_gsf
Implement WSF/GSF satfunc familiy for CO2STORE
This commit is contained in:
commit
61cec09d0a
@ -1050,6 +1050,8 @@ if(ENABLE_ECL_INPUT)
|
||||
opm/input/eclipse/EclipseState/Tables/PvdoTable.hpp
|
||||
opm/input/eclipse/EclipseState/Tables/OilvisctTable.hpp
|
||||
opm/input/eclipse/EclipseState/Tables/SgfnTable.hpp
|
||||
opm/input/eclipse/EclipseState/Tables/WsfTable.hpp
|
||||
opm/input/eclipse/EclipseState/Tables/GsfTable.hpp
|
||||
opm/input/eclipse/EclipseState/Tables/MiscTable.hpp
|
||||
opm/input/eclipse/EclipseState/Tables/SgwfnTable.hpp
|
||||
opm/input/eclipse/EclipseState/Tables/PvdsTable.hpp
|
||||
|
@ -330,6 +330,7 @@ public:
|
||||
enum class KeywordFamily {
|
||||
Family_I, // SGOF, SWOF, SLGOF
|
||||
Family_II, // SGFN, SOF{2,3}, SWFN
|
||||
Family_III, // GSF, WSF
|
||||
Undefined,
|
||||
};
|
||||
|
||||
|
41
opm/input/eclipse/EclipseState/Tables/GsfTable.hpp
Normal file
41
opm/input/eclipse/EclipseState/Tables/GsfTable.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
Copyright (C) 2023 Equinor AS
|
||||
|
||||
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/>.
|
||||
*/
|
||||
#ifndef OPM_PARSER_GSF_TABLE_HPP
|
||||
#define OPM_PARSER_GSF_TABLE_HPP
|
||||
|
||||
#include "SimpleTable.hpp"
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class DeckItem;
|
||||
|
||||
class GsfTable : public SimpleTable {
|
||||
|
||||
public:
|
||||
GsfTable( const DeckItem& item, const int tableID );
|
||||
|
||||
const TableColumn& getSgColumn() const;
|
||||
const TableColumn& getKrgColumn() const;
|
||||
const TableColumn& getPcgwColumn() const;
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -132,6 +132,9 @@ namespace Opm {
|
||||
const TableContainer& getMsfnTables() const;
|
||||
const TableContainer& getTlpmixpaTables() const;
|
||||
|
||||
const TableContainer& getWsfTables() const;
|
||||
const TableContainer& getGsfTables() const;
|
||||
|
||||
const JFunc& getJFunc() const;
|
||||
|
||||
const std::vector<PvtgTable>& getPvtgTables() const;
|
||||
|
39
opm/input/eclipse/EclipseState/Tables/WsfTable.hpp
Normal file
39
opm/input/eclipse/EclipseState/Tables/WsfTable.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
Copyright (C) 2023 Equinor AS
|
||||
|
||||
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/>.
|
||||
*/
|
||||
#ifndef OPM_PARSER_WSF_TABLE_HPP
|
||||
#define OPM_PARSER_WSF_TABLE_HPP
|
||||
|
||||
#include "SimpleTable.hpp"
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class DeckItem;
|
||||
|
||||
class WsfTable : public SimpleTable {
|
||||
|
||||
public:
|
||||
WsfTable( const DeckItem& item, const int tableID );
|
||||
|
||||
const TableColumn& getSwColumn() const;
|
||||
const TableColumn& getKrwColumn() const;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -105,6 +105,15 @@ namespace Opm {
|
||||
const bool oil,
|
||||
const bool wat);
|
||||
|
||||
/// Add saturation function tables corresponding to family III (WSF,
|
||||
/// GSF) to the tabular data (TABDIMS and TAB vectors).
|
||||
///
|
||||
/// \param[in] es Valid \c EclipseState object with accurate table
|
||||
/// dimensions ("TABDIMS" keyword) and an initialised \c
|
||||
/// TableManager sub-object.
|
||||
///
|
||||
void addSatFunc_FamilyThree(const EclipseState& es);
|
||||
|
||||
/// Add gas PVT tables (keywords PVDG and PVTG) to the tabular data
|
||||
/// (TABDIMS and TAB vectors).
|
||||
///
|
||||
|
@ -27,6 +27,8 @@
|
||||
#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/GsfTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/WsfTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/Tabdims.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableColumn.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableContainer.hpp>
|
||||
@ -72,7 +74,7 @@ namespace {
|
||||
* If SWFN, SGFN and SOF3 are specified in the deck it return II
|
||||
* If keywords are missing or mixed, an error is given.
|
||||
*/
|
||||
enum class SatfuncFamily { none = 0, I = 1, II = 2 };
|
||||
enum class SatfuncFamily { none = 0, I = 1, II = 2, III = 3 };
|
||||
|
||||
SatfuncFamily
|
||||
getSaturationFunctionFamily(const Opm::TableManager& tm,
|
||||
@ -101,6 +103,10 @@ namespace {
|
||||
(twoP && tm.hasTables("SOF2")))) ||
|
||||
(wat && tm.hasTables("SWFN"));
|
||||
|
||||
const auto family3 = //WSF, GSF gas-water CO2STORE case
|
||||
tm.hasTables("GSF") &&
|
||||
tm.hasTables("WSF");
|
||||
|
||||
if (gas && tm.hasTables("SGOF") && tm.hasTables("SLGOF")) {
|
||||
throw std::invalid_argument("Both SGOF and SLGOF have been specified but these tables are mutually exclusive!");
|
||||
}
|
||||
@ -110,12 +116,19 @@ namespace {
|
||||
"Use either SGOF (or SLGOF) and/or SWOF or SGFN/SWFN and SOF2/SOF3");
|
||||
}
|
||||
|
||||
if (family3 && !(gas && wat)) {
|
||||
throw std::invalid_argument("Saturation family 3 should only be used for GAS and WATER case");
|
||||
}
|
||||
|
||||
if (family1)
|
||||
return SatfuncFamily::I;
|
||||
|
||||
if (family2)
|
||||
return SatfuncFamily::II;
|
||||
|
||||
if (family3)
|
||||
return SatfuncFamily::III;
|
||||
|
||||
throw std::invalid_argument {
|
||||
"Saturation functions must be specified using "
|
||||
"either family 1 or family 2 keywords\n"
|
||||
@ -135,6 +148,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
const auto famI = [&swofTables]( int i ) {
|
||||
return swofTables.getTable<Opm::SwofTable>( i ).getSwColumn().front();
|
||||
@ -147,7 +161,9 @@ namespace {
|
||||
const auto famII = [&swfnTables]( int i ) {
|
||||
return swfnTables.getTable<Opm::SwfnTable>( i ).getSwColumn().front();
|
||||
};
|
||||
|
||||
const auto famIII = [&wsfTables]( int i ) {
|
||||
return wsfTables.getTable<Opm::WsfTable>( i ).getSwColumn().front();
|
||||
};
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( !swofTables.empty() )
|
||||
@ -158,6 +174,7 @@ namespace {
|
||||
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::III: return map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -175,6 +192,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
const auto famI = [&swofTables]( int i ) {
|
||||
return swofTables.getTable<Opm::SwofTable>( i ).getSwColumn().back();
|
||||
@ -187,7 +205,9 @@ namespace {
|
||||
const auto famII = [&swfnTables]( int i ) {
|
||||
return swfnTables.getTable<Opm::SwfnTable>( i ).getSwColumn().back();
|
||||
};
|
||||
|
||||
const auto famIII = [&wsfTables]( int i ) {
|
||||
return wsfTables.getTable<Opm::WsfTable>( i ).getSwColumn().back();
|
||||
};
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( !swofTables.empty() )
|
||||
@ -198,6 +218,8 @@ namespace {
|
||||
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::III: return map( famIII, Opm::fun::iota( num_tables ) );
|
||||
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -216,6 +238,7 @@ namespace {
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
const auto famI_sgof = [&sgofTables]( int i ) {
|
||||
return sgofTables.getTable<Opm::SgofTable>( i ).getSgColumn().front();
|
||||
@ -232,7 +255,9 @@ namespace {
|
||||
const auto famII = [&sgfnTables]( int i ) {
|
||||
return sgfnTables.getTable<Opm::SgfnTable>( i ).getSgColumn().front();
|
||||
};
|
||||
|
||||
const auto famIII = [&gsfTables]( int i ) {
|
||||
return gsfTables.getTable<Opm::GsfTable>( i ).getSgColumn().front();
|
||||
};
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() )
|
||||
@ -247,6 +272,8 @@ namespace {
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, 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");
|
||||
@ -267,6 +294,7 @@ namespace {
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
const auto famI_sgof = [&sgofTables]( int i ) {
|
||||
return sgofTables.getTable<Opm::SgofTable>( i ).getSgColumn().back();
|
||||
@ -284,6 +312,9 @@ namespace {
|
||||
const auto famII = [&sgfnTables]( int i ) {
|
||||
return sgfnTables.getTable<Opm::SgfnTable>( i ).getSgColumn().back();
|
||||
};
|
||||
const auto famIII = [&gsfTables]( int i ) {
|
||||
return gsfTables.getTable<Opm::GsfTable>( i ).getSgColumn().back();
|
||||
};
|
||||
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
@ -299,6 +330,8 @@ namespace {
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, 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");
|
||||
@ -375,6 +408,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
const auto famI = [&swofTables, tolcrit](const int i) -> double
|
||||
{
|
||||
@ -389,7 +423,10 @@ namespace {
|
||||
{
|
||||
return critical_water(swfnTables.getTable<Opm::SwfnTable>(i), tolcrit);
|
||||
};
|
||||
|
||||
const auto famIII = [&wsfTables, tolcrit](const int i) -> double
|
||||
{
|
||||
return critical_water(wsfTables.getTable<Opm::WsfTable>(i), tolcrit);
|
||||
};
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( !swofTables.empty() )
|
||||
@ -400,6 +437,8 @@ 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 ) );
|
||||
case SatfuncFamily::III: return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
|
||||
default: throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
}
|
||||
@ -448,6 +487,7 @@ namespace {
|
||||
const auto& sgofTables = tm.getSgofTables();
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
const auto famI_sgof = [&sgofTables, tolcrit](const int i) -> double
|
||||
{
|
||||
@ -468,6 +508,11 @@ namespace {
|
||||
return critical_gas(sgfnTables.getTable<Opm::SgfnTable>(i), tolcrit);
|
||||
};
|
||||
|
||||
const auto famIII = [&gsfTables, tolcrit](const int i) -> double
|
||||
{
|
||||
return critical_gas(gsfTables.getTable<Opm::GsfTable>(i), tolcrit);
|
||||
};
|
||||
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() )
|
||||
@ -482,6 +527,8 @@ namespace {
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, 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");
|
||||
@ -580,7 +627,8 @@ namespace {
|
||||
return ph.active(::Opm::Phase::GAS)
|
||||
? Opm::fun::map( famII_3p, Opm::fun::iota( num_tables ) )
|
||||
: Opm::fun::map( famII_2p, Opm::fun::iota( num_tables ) );
|
||||
|
||||
case SatfuncFamily::III:
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a oil system");
|
||||
default: throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
}
|
||||
@ -674,7 +722,8 @@ namespace {
|
||||
return ph.active(::Opm::Phase::WATER)
|
||||
? Opm::fun::map( famII_3p, Opm::fun::iota( num_tables ) )
|
||||
: Opm::fun::map( famII_2p, Opm::fun::iota( num_tables ) );
|
||||
|
||||
case SatfuncFamily::III:
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a oil system");
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -693,6 +742,7 @@ namespace {
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
const auto& famI_sgof = [&sgofTables]( int i ) {
|
||||
return sgofTables.getTable<Opm::SgofTable>( i ).getKrgColumn().back();
|
||||
@ -710,6 +760,10 @@ namespace {
|
||||
return sgfnTables.getTable<Opm::SgfnTable>( i ).getKrgColumn().back();
|
||||
};
|
||||
|
||||
const auto& famIII = [&gsfTables]( int i ) {
|
||||
return gsfTables.getTable<Opm::GsfTable>( i ).getKrgColumn().back();
|
||||
};
|
||||
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() )
|
||||
@ -722,6 +776,8 @@ 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 ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -741,6 +797,7 @@ namespace {
|
||||
const auto& sgofLetTables = tm.getSgofletTable();
|
||||
const auto& slgofTables = tm.getSlgofTables();
|
||||
const auto& sgfnTables = tm.getSgfnTables();
|
||||
const auto& gsfTables = tm.getGsfTables();
|
||||
|
||||
auto sr = std::vector<double>(num_tables, 0.0);
|
||||
if (ph.active(Opm::Phase::OIL)) {
|
||||
@ -786,6 +843,14 @@ namespace {
|
||||
return sgfn.getKrgColumn().eval(ix);
|
||||
};
|
||||
|
||||
const auto famIII = [&gsfTables, &sr](const int i) -> double
|
||||
{
|
||||
const auto& gsf = gsfTables.getTable<Opm::GsfTable>(i);
|
||||
const auto ix = gsf.getSgColumn().lookup(sr[i]);
|
||||
|
||||
return gsf.getKrgColumn().eval(ix);
|
||||
};
|
||||
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() )
|
||||
@ -798,6 +863,8 @@ 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 ) );
|
||||
case SatfuncFamily::III:
|
||||
return Opm::fun::map( famIII, Opm::fun::iota( num_tables ) );
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -816,6 +883,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
auto sr = std::vector<double>(num_tables, 0.0);
|
||||
if (ph.active(Opm::Phase::OIL)) {
|
||||
@ -853,6 +921,14 @@ namespace {
|
||||
return swfn.getKrwColumn().eval(ix);
|
||||
};
|
||||
|
||||
const auto& famIII = [&wsfTables, &sr](const int i) -> double
|
||||
{
|
||||
const auto& wsf = wsfTables.getTable<Opm::WsfTable>(i);
|
||||
const auto ix = wsf.getSwColumn().lookup(sr[i]);
|
||||
|
||||
return wsf.getKrwColumn().eval(ix);
|
||||
};
|
||||
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( !swofTables.empty() )
|
||||
@ -864,6 +940,8 @@ namespace {
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, 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");
|
||||
}
|
||||
@ -930,6 +1008,8 @@ namespace {
|
||||
return ph.active(::Opm::Phase::GAS)
|
||||
? Opm::fun::map( famII_3p, Opm::fun::iota( num_tables ) )
|
||||
: Opm::fun::map( famII_2p, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a oil system");
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -1006,6 +1086,8 @@ namespace {
|
||||
return ph.active(::Opm::Phase::WATER)
|
||||
? Opm::fun::map( famII_3p, Opm::fun::iota( num_tables ) )
|
||||
: Opm::fun::map( famII_2p, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a oil system");
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -1063,6 +1145,8 @@ 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 ) );
|
||||
case SatfuncFamily::III:
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a oil system");
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -1105,6 +1189,8 @@ namespace {
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a oil system");
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -1171,6 +1257,8 @@ namespace {
|
||||
return ph.active(::Opm::Phase::GAS) && ph.active(::Opm::Phase::WATER)
|
||||
? Opm::fun::map( famII_3p, Opm::fun::iota( num_tables ) )
|
||||
: Opm::fun::map( famII_2p, Opm::fun::iota( num_tables ) );
|
||||
case SatfuncFamily::III:
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a oil system");
|
||||
default:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -1188,6 +1276,7 @@ namespace {
|
||||
const auto& swofTables = tm.getSwofTables();
|
||||
const auto& swofLetTables = tm.getSwofletTable();
|
||||
const auto& swfnTables = tm.getSwfnTables();
|
||||
const auto& wsfTables = tm.getWsfTables();
|
||||
|
||||
const auto& famI = [&swofTables]( int i ) {
|
||||
return swofTables.getTable<Opm::SwofTable>( i ).getKrwColumn().back();
|
||||
@ -1201,6 +1290,10 @@ namespace {
|
||||
return swfnTables.getTable<Opm::SwfnTable>( i ).getKrwColumn().back();
|
||||
};
|
||||
|
||||
const auto& famIII = [&wsfTables]( int i ) {
|
||||
return wsfTables.getTable<Opm::WsfTable>( i ).getKrwColumn().back();
|
||||
};
|
||||
|
||||
switch( getSaturationFunctionFamily( tm, ph ) ) {
|
||||
case SatfuncFamily::I:
|
||||
if( !swofTables.empty() )
|
||||
@ -1213,6 +1306,8 @@ namespace {
|
||||
|
||||
case SatfuncFamily::II:
|
||||
return Opm::fun::map( famII, 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");
|
||||
}
|
||||
|
@ -103,12 +103,19 @@ namespace {
|
||||
(twoP && deck.hasKeyword<Opm::ParserKeywords::SOF2>()))) ||
|
||||
(wat && deck.hasKeyword<Opm::ParserKeywords::SWFN>());
|
||||
|
||||
const auto family3 = //WSF, GSF gas-water CO2STORE case
|
||||
deck.hasKeyword<Opm::ParserKeywords::GSF>() &&
|
||||
deck.hasKeyword<Opm::ParserKeywords::WSF>();
|
||||
|
||||
if (family1)
|
||||
return Opm::SatFuncControls::KeywordFamily::Family_I;
|
||||
|
||||
if (family2)
|
||||
return Opm::SatFuncControls::KeywordFamily::Family_II;
|
||||
|
||||
if (family3)
|
||||
return Opm::SatFuncControls::KeywordFamily::Family_III;
|
||||
|
||||
return Opm::SatFuncControls::KeywordFamily::Undefined;
|
||||
}
|
||||
|
||||
|
@ -101,6 +101,8 @@
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SsfnTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SwfnTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/SwofTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/GsfTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/WsfTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableContainer.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/WatvisctTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/AqutabTable.hpp>
|
||||
@ -421,6 +423,9 @@ std::optional<JFunc> make_jfunc(const Deck& deck) {
|
||||
addTables( "SSFN", m_tabdims.getNumSatTables() );
|
||||
addTables( "MSFN", m_tabdims.getNumSatTables() );
|
||||
|
||||
addTables( "GSF", m_tabdims.getNumSatTables() );
|
||||
addTables( "WSF", m_tabdims.getNumSatTables() );
|
||||
|
||||
addTables( "PLYADS", m_tabdims.getNumSatTables() );
|
||||
addTables( "PLYROCK", m_tabdims.getNumSatTables());
|
||||
addTables( "PLYVISC", m_tabdims.getNumPVTTables());
|
||||
@ -508,6 +513,9 @@ std::optional<JFunc> make_jfunc(const Deck& deck) {
|
||||
initSimpleTableContainer<SsfnTable>(deck, "SSFN" , m_tabdims.getNumSatTables());
|
||||
initSimpleTableContainer<MsfnTable>(deck, "MSFN" , m_tabdims.getNumSatTables());
|
||||
|
||||
initSimpleTableContainer<WsfTable>(deck, "WSF" , m_tabdims.getNumSatTables());
|
||||
initSimpleTableContainer<GsfTable>(deck, "GSF" , m_tabdims.getNumSatTables());
|
||||
|
||||
initSimpleTableContainer<RsvdTable>(deck, "RSVD" , m_eqldims.getNumEquilRegions());
|
||||
initSimpleTableContainer<RvvdTable>(deck, "RVVD" , m_eqldims.getNumEquilRegions());
|
||||
initSimpleTableContainer<RvwvdTable>(deck, "RVWVD" , m_eqldims.getNumEquilRegions());
|
||||
@ -917,6 +925,14 @@ std::optional<JFunc> make_jfunc(const Deck& deck) {
|
||||
return getTables("SSFN");
|
||||
}
|
||||
|
||||
const TableContainer& TableManager::getWsfTables() const {
|
||||
return getTables("WSF");
|
||||
}
|
||||
|
||||
const TableContainer& TableManager::getGsfTables() const {
|
||||
return getTables("GSF");
|
||||
}
|
||||
|
||||
const TableContainer& TableManager::getRsvdTables() const {
|
||||
return getTables("RSVD");
|
||||
}
|
||||
|
@ -90,6 +90,8 @@
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TlpmixpaTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TracerVdTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/WatvisctTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/GsfTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/WsfTable.hpp>
|
||||
|
||||
#include <opm/common/utility/OpmInputError.hpp>
|
||||
|
||||
@ -730,6 +732,55 @@ SgfnTable::getJFuncColumn() const
|
||||
return SimpleTable::getColumn(2);
|
||||
}
|
||||
|
||||
GsfTable::GsfTable(const DeckItem& item, const int tableID)
|
||||
{
|
||||
m_schema.addColumn(ColumnSchema("SG", Table::STRICTLY_INCREASING, Table::DEFAULT_NONE));
|
||||
m_schema.addColumn(ColumnSchema("KRG", Table::INCREASING, Table::DEFAULT_LINEAR));
|
||||
m_schema.addColumn(ColumnSchema("PCGW", Table::INCREASING, Table::DEFAULT_LINEAR));
|
||||
|
||||
SimpleTable::init("GSF", item, tableID);
|
||||
}
|
||||
|
||||
|
||||
const TableColumn&
|
||||
GsfTable::getSgColumn() const
|
||||
{
|
||||
return SimpleTable::getColumn(0);
|
||||
}
|
||||
|
||||
const TableColumn&
|
||||
GsfTable::getKrgColumn() const
|
||||
{
|
||||
return SimpleTable::getColumn(1);
|
||||
}
|
||||
|
||||
const TableColumn&
|
||||
GsfTable::getPcgwColumn() const
|
||||
{
|
||||
return SimpleTable::getColumn(2);
|
||||
}
|
||||
|
||||
WsfTable::WsfTable(const DeckItem& item, const int tableID)
|
||||
{
|
||||
m_schema.addColumn(ColumnSchema("SW", Table::STRICTLY_INCREASING, Table::DEFAULT_NONE));
|
||||
m_schema.addColumn(ColumnSchema("KRW", Table::INCREASING, Table::DEFAULT_LINEAR));
|
||||
|
||||
SimpleTable::init("WSF", item, tableID);
|
||||
}
|
||||
|
||||
|
||||
const TableColumn&
|
||||
WsfTable::getSwColumn() const
|
||||
{
|
||||
return SimpleTable::getColumn(0);
|
||||
}
|
||||
|
||||
const TableColumn&
|
||||
WsfTable::getKrwColumn() const
|
||||
{
|
||||
return SimpleTable::getColumn(1);
|
||||
}
|
||||
|
||||
SsfnTable::SsfnTable(const DeckItem& item, const int tableID)
|
||||
{
|
||||
m_schema.addColumn(ColumnSchema("SolventFraction", Table::STRICTLY_INCREASING, Table::DEFAULT_NONE));
|
||||
|
@ -8,6 +8,7 @@
|
||||
"item": "NTSFUN"
|
||||
},
|
||||
"requires": ["GAS"],
|
||||
"prohibits": ["GSF"],
|
||||
"items": [
|
||||
{
|
||||
"name": "DATA",
|
||||
|
@ -8,7 +8,7 @@
|
||||
"item": "NTSFUN"
|
||||
},
|
||||
"requires": ["GAS", "OIL"],
|
||||
"prohibits": ["SLGOF"],
|
||||
"prohibits": ["SLGOF", "GSF"],
|
||||
"items": [
|
||||
{
|
||||
"name": "DATA",
|
||||
|
@ -8,7 +8,7 @@
|
||||
"item": "NTSFUN"
|
||||
},
|
||||
"requires": ["GAS"],
|
||||
"prohibits": ["SGOF"],
|
||||
"prohibits": ["SGOF", "GSF"],
|
||||
"items": [
|
||||
{
|
||||
"name": "DATA",
|
||||
|
@ -8,6 +8,7 @@
|
||||
"item": "NTSFUN"
|
||||
},
|
||||
"requires": ["WATER"],
|
||||
"prohibits": ["WSF"],
|
||||
"items": [
|
||||
{
|
||||
"name": "DATA",
|
||||
|
@ -8,6 +8,7 @@
|
||||
"item": "NTSFUN"
|
||||
},
|
||||
"requires": ["OIL", "WATER"],
|
||||
"prohibits": ["WSF"],
|
||||
"items": [
|
||||
{
|
||||
"name": "DATA",
|
||||
|
24
src/opm/input/eclipse/share/keywords/001_Eclipse300/G/GSF
Normal file
24
src/opm/input/eclipse/share/keywords/001_Eclipse300/G/GSF
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "GSF",
|
||||
"sections": [
|
||||
"PROPS"
|
||||
],
|
||||
"size": {
|
||||
"keyword": "TABDIMS",
|
||||
"item": "NTSFUN"
|
||||
},
|
||||
"requires": ["GAS"],
|
||||
"prohibits": ["SGOF", "SLGOF", "SGFN"],
|
||||
"items": [
|
||||
{
|
||||
"name": "DATA",
|
||||
"value_type": "DOUBLE",
|
||||
"size_type": "ALL",
|
||||
"dimension": [
|
||||
"1",
|
||||
"1",
|
||||
"Pressure"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
23
src/opm/input/eclipse/share/keywords/001_Eclipse300/W/WSF
Normal file
23
src/opm/input/eclipse/share/keywords/001_Eclipse300/W/WSF
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "WSF",
|
||||
"sections": [
|
||||
"PROPS"
|
||||
],
|
||||
"size": {
|
||||
"keyword": "TABDIMS",
|
||||
"item": "NTSFUN"
|
||||
},
|
||||
"requires": ["WATER"],
|
||||
"prohibits": ["SWOF", "SWFN"],
|
||||
"items": [
|
||||
{
|
||||
"name": "DATA",
|
||||
"value_type": "DOUBLE",
|
||||
"size_type": "ALL",
|
||||
"dimension": [
|
||||
"1",
|
||||
"1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -1056,6 +1056,7 @@ set( keywords
|
||||
001_Eclipse300/D/DZV
|
||||
001_Eclipse300/G/GASVISCT
|
||||
001_Eclipse300/G/GCONPROD
|
||||
001_Eclipse300/G/GSF
|
||||
001_Eclipse300/H/HEATCR
|
||||
001_Eclipse300/H/HEATCRT
|
||||
001_Eclipse300/L/LIVEOIL
|
||||
@ -1082,6 +1083,7 @@ set( keywords
|
||||
001_Eclipse300/T/TREFS
|
||||
001_Eclipse300/W/WINJTEMP
|
||||
001_Eclipse300/W/WATDENT
|
||||
001_Eclipse300/W/WSF
|
||||
001_Eclipse300/Z/ZFACT1
|
||||
001_Eclipse300/Z/ZFACT1S
|
||||
001_Eclipse300/Z/ZFACTOR
|
||||
|
@ -26,6 +26,9 @@
|
||||
#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/GsfTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/WsfTable.hpp>
|
||||
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableManager.hpp>
|
||||
|
||||
namespace Opm {
|
||||
@ -164,6 +167,11 @@ readGasOilParameters_(GasOilEffectiveParamVector& dest, unsigned satRegionIdx)
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_III:
|
||||
{
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a gas-oil system");
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -290,6 +298,29 @@ readGasWaterParameters_(GasWaterEffectiveParamVector& dest, unsigned satRegionId
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_III:
|
||||
{
|
||||
const GsfTable& gsfTable = tableManager.getGsfTables().getTable<GsfTable>( satRegionIdx );
|
||||
const WsfTable& wsfTable = tableManager.getWsfTables().getTable<WsfTable>( satRegionIdx );
|
||||
|
||||
effParams.setApproach(SatCurveMultiplexerApproach::PiecewiseLinear);
|
||||
auto& realParams = effParams.template getRealParams<SatCurveMultiplexerApproach::PiecewiseLinear>();
|
||||
|
||||
std::vector<double> SwColumn = wsfTable.getColumn("SW").vectorCopy();
|
||||
|
||||
realParams.setKrwSamples(SwColumn, normalizeKrValues_(tolcrit, wsfTable.getColumn("KRW")));
|
||||
std::vector<double> SwSamples(gsfTable.numRows());
|
||||
for (size_t sampleIdx = 0; sampleIdx < gsfTable.numRows(); ++ sampleIdx)
|
||||
SwSamples[sampleIdx] = 1 - gsfTable.get("SG", sampleIdx);
|
||||
realParams.setKrnSamples(SwSamples, normalizeKrValues_(tolcrit, gsfTable.getColumn("KRG")));
|
||||
//Capillary pressure is read from GSF.
|
||||
// TODO need to check if gas/water sg
|
||||
std::vector<double> SgColumn = gsfTable.getColumn("SG").vectorCopy();
|
||||
realParams.setPcnwSamples(SgColumn, gsfTable.getColumn("PCGW").vectorCopy());
|
||||
realParams.finalize();
|
||||
|
||||
break;
|
||||
}
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
@ -401,6 +432,11 @@ readOilWaterParameters_(OilWaterEffectiveParamVector& dest, unsigned satRegionId
|
||||
break;
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Family_III:
|
||||
{
|
||||
throw std::domain_error("Saturation keyword family III is not applicable for a oil-water system");
|
||||
}
|
||||
|
||||
case SatFuncControls::KeywordFamily::Undefined:
|
||||
throw std::domain_error("No valid saturation keyword family specified");
|
||||
}
|
||||
|
@ -34,6 +34,8 @@
|
||||
#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/WsfTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/GsfTable.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/Tabdims.hpp>
|
||||
#include <opm/input/eclipse/EclipseState/Tables/TableContainer.hpp>
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
@ -420,6 +422,84 @@ namespace { namespace SatFunc {
|
||||
return numActRows;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/// Create linearised and padded 'TAB' vector entries of normalised
|
||||
/// GSF tables for all saturation function regions from Family Two
|
||||
/// table data (GSF 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 GSF tables for all saturation
|
||||
/// regions.
|
||||
///
|
||||
/// \return Linearised and padded 'TAB' vector values for output
|
||||
/// GSF tables. A unit-converted copy of the input table \p
|
||||
/// gsf with added derivatives.
|
||||
std::vector<double>
|
||||
fromGSF(const std::size_t numRows,
|
||||
const double tolcrit,
|
||||
const Opm::UnitSystem& units,
|
||||
const Opm::TableContainer& gsf)
|
||||
{
|
||||
using Gsf = ::Opm::GsfTable;
|
||||
|
||||
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<Gsf>(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)
|
||||
{
|
||||
const 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
|
||||
@ -1164,6 +1244,82 @@ namespace { namespace SatFunc {
|
||||
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).
|
||||
///
|
||||
/// \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] units Active unit system. Needed to convert SI
|
||||
/// convention capillary pressure values (Pascal) to declared
|
||||
/// conventions of the run specification.
|
||||
///
|
||||
/// \param[in] swfn Collection of WSF tables for all saturation
|
||||
/// regions.
|
||||
///
|
||||
/// \return Linearised and padded 'TAB' vector values for output
|
||||
/// WSF tables. A unit-converted copy of the input table \p
|
||||
/// wsf with added derivatives.
|
||||
std::vector<double>
|
||||
fromWsf(const std::size_t numRows,
|
||||
const double tolcrit,
|
||||
const Opm::TableContainer& wsf)
|
||||
{
|
||||
using WSF = ::Opm::WsfTable;
|
||||
|
||||
const auto numTab = wsf.size();
|
||||
const auto numDep = std::size_t{2}; // Krw, {zero pc}
|
||||
|
||||
return detail::createSatfuncTable(numTab, numRows, numDep,
|
||||
[tolcrit, &wsf]
|
||||
(const std::size_t tableID,
|
||||
const std::size_t primID,
|
||||
Opm::LinearisedOutputTable& linTable)
|
||||
-> std::size_t
|
||||
{
|
||||
const auto& t = wsf.getTable<WSF>(tableID);
|
||||
|
||||
auto numActRows = std::size_t{0};
|
||||
|
||||
// Sw
|
||||
{
|
||||
const auto& Sw = t.getSwColumn();
|
||||
|
||||
numActRows = Sw.size();
|
||||
std::copy(std::begin(Sw), std::end(Sw),
|
||||
linTable.column(tableID, primID, 0));
|
||||
}
|
||||
|
||||
// Krw(Sw)
|
||||
detail::outputRelperm(t.getKrwColumn(), tolcrit,
|
||||
linTable.column(tableID, primID, 1));
|
||||
|
||||
// Pcow = zero
|
||||
{
|
||||
const auto& krw = t.getKrwColumn();
|
||||
std::transform(std::begin(krw), std::end(krw),
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
} // Water
|
||||
|
||||
|
||||
@ -2306,17 +2462,26 @@ namespace Opm {
|
||||
tabMgr.hasTables("SOF2"))) ||
|
||||
(wat && tabMgr.hasTables("SWFN"));
|
||||
|
||||
if ((famI + famII) != 1) {
|
||||
// Both Fam I && Fam II or neither of them. Can't have that.
|
||||
const auto famIII = // GSF WSF
|
||||
tabMgr.hasTables("GSF") &&
|
||||
tabMgr.hasTables("WSF");
|
||||
|
||||
if ((famI + famII + famIII) != 1) {
|
||||
// No known saturation function family or at least two of the families I, II, or II. Can't have that.
|
||||
return; // Logging here?
|
||||
}
|
||||
else if (famI) {
|
||||
this->addSatFunc_FamilyOne(es, gas, oil, wat);
|
||||
}
|
||||
else {
|
||||
else if (famII){
|
||||
// Family II
|
||||
this->addSatFunc_FamilyTwo(es, gas, oil, wat);
|
||||
}
|
||||
else {
|
||||
// Family II
|
||||
assert(gas && wat && !oil);
|
||||
this->addSatFunc_FamilyThree(es);
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<int>& Tables::tabdims() const
|
||||
@ -2502,6 +2667,38 @@ namespace Opm {
|
||||
}
|
||||
}
|
||||
|
||||
void Tables::addSatFunc_FamilyThree(const EclipseState& es)
|
||||
{
|
||||
const auto& tabMgr = es.getTableManager();
|
||||
const auto& tabd = es.runspec().tabdims();
|
||||
const auto nssfun = tabd.getNumSatNodes();
|
||||
const auto tolcrit = es.runspec()
|
||||
.saturationFunctionControls()
|
||||
.minimumRelpermMobilityThreshold();
|
||||
|
||||
{
|
||||
const auto& tables = tabMgr.getGsfTables();
|
||||
const auto gsf =
|
||||
SatFunc::Gas::fromGSF(nssfun, tolcrit,
|
||||
this->units, tables);
|
||||
|
||||
this->addData(Ix::SgfnTableStart, gsf);
|
||||
this->m_tabdims[Ix::SgfnNumSatNodes] = nssfun;
|
||||
this->m_tabdims[Ix::SgfnNumTables] = tables.size();
|
||||
}
|
||||
|
||||
{
|
||||
const auto& tables = tabMgr.getWsfTables();
|
||||
|
||||
const auto wsf =
|
||||
SatFunc::Water::fromWsf(nssfun, tolcrit, tables);
|
||||
|
||||
this->addData(Ix::SwfnTableStart, wsf);
|
||||
this->m_tabdims[Ix::SwfnNumSatNodes] = nssfun;
|
||||
this->m_tabdims[Ix::SwfnNumTables] = tables.size();
|
||||
}
|
||||
}
|
||||
|
||||
void Tables::addGasPVTTables(const EclipseState& es)
|
||||
{
|
||||
const auto& tabMgr = es.getTableManager();
|
||||
|
@ -452,6 +452,119 @@ static const char* letDeckString =
|
||||
" 0.0 0.03 1.8 1.9 1.0 0.95 0.0 0.01 3.5 4.0 1.1 1.0 1.0 1.0 1.0 0.2 0.01 /\n"
|
||||
"\n";
|
||||
|
||||
static const char* fam3DeckStringGasWater =
|
||||
"RUNSPEC\n"
|
||||
"\n"
|
||||
"DIMENS\n"
|
||||
" 10 10 3 /\n"
|
||||
"\n"
|
||||
"TABDIMS\n"
|
||||
"/\n"
|
||||
"\n"
|
||||
"WATER\n"
|
||||
"GAS\n"
|
||||
"\n"
|
||||
"DISGAS\n"
|
||||
"\n"
|
||||
"FIELD\n"
|
||||
"\n"
|
||||
"GRID\n"
|
||||
"\n"
|
||||
"DX\n"
|
||||
" 300*1000 /\n"
|
||||
"DY\n"
|
||||
" 300*1000 /\n"
|
||||
"DZ\n"
|
||||
" 100*20 100*30 100*50 /\n"
|
||||
"\n"
|
||||
"TOPS\n"
|
||||
" 100*8325 /\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"PORO\n"
|
||||
" 300*0.15 /\n"
|
||||
"PROPS\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"GSF\n"
|
||||
"0 0 0\n"
|
||||
"0.001 0 0\n"
|
||||
"0.02 0 0\n"
|
||||
"0.05 0.005 0\n"
|
||||
"0.12 0.025 0\n"
|
||||
"0.2 0.075 0\n"
|
||||
"0.25 0.125 0\n"
|
||||
"0.3 0.190 0\n"
|
||||
"0.4 0.410 0\n"
|
||||
"0.45 0.60 0\n"
|
||||
"0.5 0.72 0\n"
|
||||
"0.6 0.87 0\n"
|
||||
"0.7 0.94 0\n"
|
||||
"0.85 0.98 0\n"
|
||||
"0.88 0.984 0 /\n"
|
||||
"\n"
|
||||
"WSF\n"
|
||||
"0.12 0 \n"
|
||||
"0.22 0 \n"
|
||||
"0.55 0.005 \n"
|
||||
"0.88 0.984 /\n";
|
||||
|
||||
static const char* fam2DeckStringGasWater =
|
||||
"RUNSPEC\n"
|
||||
"\n"
|
||||
"DIMENS\n"
|
||||
" 10 10 3 /\n"
|
||||
"\n"
|
||||
"TABDIMS\n"
|
||||
"/\n"
|
||||
"\n"
|
||||
"WATER\n"
|
||||
"GAS\n"
|
||||
"\n"
|
||||
"DISGAS\n"
|
||||
"\n"
|
||||
"FIELD\n"
|
||||
"\n"
|
||||
"GRID\n"
|
||||
"\n"
|
||||
"DX\n"
|
||||
" 300*1000 /\n"
|
||||
"DY\n"
|
||||
" 300*1000 /\n"
|
||||
"DZ\n"
|
||||
" 100*20 100*30 100*50 /\n"
|
||||
"\n"
|
||||
"TOPS\n"
|
||||
" 100*8325 /\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"PORO\n"
|
||||
" 300*0.15 /\n"
|
||||
"PROPS\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"SGFN\n"
|
||||
"0 0 0\n"
|
||||
"0.001 0 0\n"
|
||||
"0.02 0 0\n"
|
||||
"0.05 0.005 0\n"
|
||||
"0.12 0.025 0\n"
|
||||
"0.2 0.075 0\n"
|
||||
"0.25 0.125 0\n"
|
||||
"0.3 0.190 0\n"
|
||||
"0.4 0.410 0\n"
|
||||
"0.45 0.60 0\n"
|
||||
"0.5 0.72 0\n"
|
||||
"0.6 0.87 0\n"
|
||||
"0.7 0.94 0\n"
|
||||
"0.85 0.98 0\n"
|
||||
"0.88 0.984 0 /\n"
|
||||
"\n"
|
||||
"SWFN\n"
|
||||
"0.12 0 0\n"
|
||||
"0.22 0 0\n"
|
||||
"0.55 0.005 0\n"
|
||||
"0.88 0.984 0 /\n";
|
||||
|
||||
template <class Scalar>
|
||||
inline Scalar computeLetCurve(const Scalar S, const Scalar L, const Scalar E, const Scalar T)
|
||||
@ -676,6 +789,60 @@ inline void testAll()
|
||||
}
|
||||
}
|
||||
|
||||
// Water gas
|
||||
{
|
||||
const auto fam2Deck = parser.parseString(fam2DeckStringGasWater);
|
||||
const Opm::EclipseState fam2EclState(fam2Deck);
|
||||
|
||||
Opm::EclMaterialLawManager<MaterialTraits> fam2materialLawManager;
|
||||
fam2materialLawManager.initFromState(fam2EclState);
|
||||
fam2materialLawManager.initParamsForElements(fam2EclState, n);
|
||||
|
||||
const auto fam3Deck = parser.parseString(fam3DeckStringGasWater);
|
||||
const Opm::EclipseState fam3EclState(fam3Deck);
|
||||
|
||||
MaterialLawManager fam3materialLawManager;
|
||||
fam3materialLawManager.initFromState(fam3EclState);
|
||||
fam3materialLawManager.initParamsForElements(fam3EclState, n);
|
||||
|
||||
for (unsigned elemIdx = 0; elemIdx < n; ++ elemIdx) {
|
||||
for (int i = 0; i < 100; ++ i) {
|
||||
Scalar Sw = 0;
|
||||
Scalar So = Scalar(i)/100;
|
||||
Scalar Sg = 1 - Sw - So;
|
||||
FluidState fs;
|
||||
fs.setSaturation(waterPhaseIdx, Sw);
|
||||
fs.setSaturation(oilPhaseIdx, So);
|
||||
fs.setSaturation(gasPhaseIdx, Sg);
|
||||
|
||||
Scalar pcFam2[numPhases] = { 0.0, 0.0 };
|
||||
Scalar pcFam3[numPhases] = { 0.0, 0.0 };
|
||||
MaterialLaw::capillaryPressures(pcFam2,
|
||||
fam2materialLawManager.materialLawParams(elemIdx),
|
||||
fs);
|
||||
MaterialLaw::capillaryPressures(pcFam3,
|
||||
fam3materialLawManager.materialLawParams(elemIdx),
|
||||
fs);
|
||||
|
||||
Scalar krFam2[numPhases] = { 0.0, 0.0 };
|
||||
Scalar krFam3[numPhases] = { 0.0, 0.0 };
|
||||
MaterialLaw::relativePermeabilities(krFam2,
|
||||
fam2materialLawManager.materialLawParams(elemIdx),
|
||||
fs);
|
||||
MaterialLaw::relativePermeabilities(krFam3,
|
||||
fam3materialLawManager.materialLawParams(elemIdx),
|
||||
fs);
|
||||
|
||||
for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
|
||||
if (std::abs(pcFam2[phaseIdx] - pcFam3[phaseIdx]) > 1e-5)
|
||||
throw std::logic_error("Discrepancy between capillary pressure of family 2 and family 3 keywords");
|
||||
if (std::abs(krFam2[phaseIdx] - krFam3[phaseIdx]) > 1e-1)
|
||||
throw std::logic_error("Discrepancy between relative permeabilities of family 2 and family 3 keywords");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// LET: Curves from input parameters interpreted via MaterialLawManager versus directly computed curves.
|
||||
{
|
||||
const auto letDeck = parser.parseString(letDeckString);
|
||||
|
Loading…
Reference in New Issue
Block a user