diff --git a/opm/input/eclipse/EclipseState/Tables/FlatTable.hpp b/opm/input/eclipse/EclipseState/Tables/FlatTable.hpp index e7846f457..566c74767 100644 --- a/opm/input/eclipse/EclipseState/Tables/FlatTable.hpp +++ b/opm/input/eclipse/EclipseState/Tables/FlatTable.hpp @@ -426,6 +426,89 @@ struct WatdentTable : public FlatTable< WATDENTRecord > { } }; +struct SatFuncLETRecord { + static constexpr std::size_t size = 17; + + double s1_residual; + double s1_critical; + double l1_relperm; + double e1_relperm; + double t1_relperm; + double krt1_relperm; + double s2_residual; + double s2_critical; + double l2_relperm; + double e2_relperm; + double t2_relperm; + double krt2_relperm; + double l_pc; + double e_pc; + double t_pc; + double pcir_pc; + double pct_pc; + + bool operator==(const SatFuncLETRecord& data) const { + return s1_residual == data.s1_residual && + s1_critical == data.s1_critical && + l1_relperm == data.l1_relperm && + e1_relperm == data.e1_relperm && + t1_relperm == data.t1_relperm && + krt1_relperm == data.krt1_relperm && + s2_residual == data.s2_residual && + s2_critical == data.s2_critical && + l2_relperm == data.l2_relperm && + e2_relperm == data.e2_relperm && + t2_relperm == data.t2_relperm && + krt2_relperm == data.krt2_relperm && + l_pc == data.l_pc && + e_pc == data.e_pc && + t_pc == data.t_pc && + pcir_pc == data.pcir_pc && + pct_pc == data.pct_pc; + } + + template + void serializeOp(Serializer& serializer) + { + serializer(s1_residual); + serializer(s1_critical); + serializer(l1_relperm); + serializer(e1_relperm); + serializer(t1_relperm); + serializer(krt1_relperm); + serializer(s2_residual); + serializer(s2_critical); + serializer(l2_relperm); + serializer(e2_relperm); + serializer(t2_relperm); + serializer(krt2_relperm); + serializer(l_pc); + serializer(e_pc); + serializer(t_pc); + serializer(pcir_pc); + serializer(pct_pc); + } +}; + +struct SwofletTable : public FlatTable< SatFuncLETRecord > { + using FlatTable< SatFuncLETRecord >::FlatTable; + + static SwofletTable serializeObject() + { + return SwofletTable({{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0}}); + } +}; + + +struct SgofletTable : public FlatTable< SatFuncLETRecord > { + using FlatTable< SatFuncLETRecord >::FlatTable; + + static SgofletTable serializeObject() + { + return SgofletTable({{1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0}}); + } +}; + } #endif //OPM_FLAT_TABLE_HPP diff --git a/opm/input/eclipse/EclipseState/Tables/TableManager.hpp b/opm/input/eclipse/EclipseState/Tables/TableManager.hpp index df3b804b9..87443371e 100644 --- a/opm/input/eclipse/EclipseState/Tables/TableManager.hpp +++ b/opm/input/eclipse/EclipseState/Tables/TableManager.hpp @@ -163,6 +163,8 @@ namespace Opm { const ShrateTable& getShrateTable() const; const Stone1exTable& getStone1exTable() const; const WatdentTable& getWatdentTable() const; + const SgofletTable& getSgofletTable() const; + const SwofletTable& getSwofletTable() const; const std::map& getPlymwinjTables() const; const std::map& getSkprwatTables() const; const std::map& getSkprpolyTables() const; @@ -217,6 +219,8 @@ namespace Opm { m_stone1exTable.serializeOp(serializer); m_viscrefTable.serializeOp(serializer); m_watdentTable.serializeOp(serializer); + m_sgofletTable.serializeOp(serializer); + m_swofletTable.serializeOp(serializer); serializer.vector(m_pvtwsaltTables); serializer.vector(m_rwgsaltTables); serializer.vector(m_bdensityTables); @@ -356,6 +360,8 @@ namespace Opm { Stone1exTable m_stone1exTable; ViscrefTable m_viscrefTable; WatdentTable m_watdentTable; + SgofletTable m_sgofletTable; + SwofletTable m_swofletTable; std::vector m_pvtwsaltTables; std::vector m_rwgsaltTables; std::vector m_bdensityTables; diff --git a/src/opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.cpp b/src/opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.cpp index b5e5b19e6..b46360166 100644 --- a/src/opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.cpp +++ b/src/opm/input/eclipse/EclipseState/Grid/SatfuncPropertyInitializers.cpp @@ -93,8 +93,8 @@ namespace { } const auto family1 = // SGOF/SLGOF and/or SWOF - (gas && (tm.hasTables("SGOF") || tm.hasTables("SLGOF"))) || - (wat && tm.hasTables("SWOF")); + (gas && ((tm.hasTables("SGOF") || !tm.getSgofletTable().empty()) || tm.hasTables("SLGOF"))) || + (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 @@ -135,18 +135,27 @@ namespace { return std::vector(num_tables, 0.0); const auto& swofTables = tm.getSwofTables(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& swfnTables = tm.getSwfnTables(); const auto famI = [&swofTables]( int i ) { return swofTables.getTable( i ).getSwColumn().front(); }; + const auto famI_let = [&swofLetTables]( int i ) { + return swofLetTables[i].s1_residual; + }; + const auto famII = [&swfnTables]( int i ) { return swfnTables.getTable( i ).getSwColumn().front(); }; switch( getSaturationFunctionFamily( tm, ph ) ) { - case SatfuncFamily::I: return map( famI, Opm::fun::iota( num_tables ) ); + case SatfuncFamily::I: + if( !swofTables.empty() ) + return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + else if ( !swofLetTables.empty() ) + return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: return map( famII, Opm::fun::iota( num_tables ) ); default: throw std::domain_error("No valid saturation keyword family specified"); @@ -163,18 +172,27 @@ namespace { return std::vector(num_tables, 0.0); const auto& swofTables = tm.getSwofTables(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& swfnTables = tm.getSwfnTables(); const auto famI = [&swofTables]( int i ) { return swofTables.getTable( i ).getSwColumn().back(); }; + const auto famI_let = [&swofLetTables]( int i ) { + return 1.0 - swofLetTables[i].s2_residual; + }; + const auto famII = [&swfnTables]( int i ) { return swfnTables.getTable( i ).getSwColumn().back(); }; switch( getSaturationFunctionFamily( tm, ph ) ) { - case SatfuncFamily::I: return map( famI, Opm::fun::iota( num_tables ) ); + case SatfuncFamily::I: + if( !swofTables.empty() ) + return map( famI, Opm::fun::iota( num_tables ) ); + else if ( !swofLetTables.empty() ) + return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: return map( famII, Opm::fun::iota( num_tables ) ); default: throw std::domain_error("No valid saturation keyword family specified"); @@ -191,6 +209,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& sgofTables = tm.getSgofTables(); + const auto& sgofLetTables = tm.getSgofletTable(); const auto& slgofTables = tm.getSlgofTables(); const auto& sgfnTables = tm.getSgfnTables(); @@ -198,6 +217,10 @@ namespace { return sgofTables.getTable( i ).getSgColumn().front(); }; + const auto famI_sgof_let = [&sgofLetTables]( int i ) { + return sgofLetTables[i].s1_residual; + }; + const auto famI_slgof = [&slgofTables]( int i ) { return 1.0 - slgofTables.getTable( i ).getSlColumn().back(); }; @@ -208,11 +231,13 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - if( sgofTables.empty() && slgofTables.empty() ) + if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() ) throw std::runtime_error( "Saturation keyword family I requires either sgof or slgof non-empty" ); if( !sgofTables.empty() ) return Opm::fun::map( famI_sgof, Opm::fun::iota( num_tables ) ); + else if( !sgofLetTables.empty() ) + return Opm::fun::map( famI_sgof_let, Opm::fun::iota( num_tables ) ); else return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) ); @@ -234,6 +259,8 @@ namespace { return std::vector(num_tables, 0.0); const auto& sgofTables = tm.getSgofTables(); + const auto& sgofLetTables = tm.getSgofletTable(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& slgofTables = tm.getSlgofTables(); const auto& sgfnTables = tm.getSgfnTables(); @@ -241,6 +268,11 @@ namespace { return sgofTables.getTable( i ).getSgColumn().back(); }; + const auto famI_sgof_let = [&swofLetTables]( int i ) { + // Assume this to be 1-swco + return 1.0 - swofLetTables[i].s1_residual; + }; + const auto famI_slgof = [&slgofTables]( int i ) { return 1.0 - slgofTables.getTable( i ).getSlColumn().front(); }; @@ -251,11 +283,13 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - if( sgofTables.empty() && slgofTables.empty() ) + if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() ) throw std::runtime_error( "Saturation keyword family I requires either sgof or slgof non-empty" ); if( !sgofTables.empty() ) return Opm::fun::map( famI_sgof, Opm::fun::iota( num_tables ) ); + else if( !sgofLetTables.empty() ) + return Opm::fun::map( famI_sgof_let, Opm::fun::iota( num_tables ) ); else return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) ); @@ -335,6 +369,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& swofTables = tm.getSwofTables(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& swfnTables = tm.getSwfnTables(); const auto famI = [&swofTables, tolcrit](const int i) -> double @@ -342,13 +377,21 @@ namespace { return critical_water(swofTables.getTable(i), tolcrit); }; + const auto famI_let = [&swofLetTables]( int i ) { + return swofLetTables[i].s1_critical; + }; + const auto famII = [&swfnTables, tolcrit](const int i) -> double { return critical_water(swfnTables.getTable(i), tolcrit); }; switch( getSaturationFunctionFamily( tm, ph ) ) { - case SatfuncFamily::I: return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + case SatfuncFamily::I: + if( !swofTables.empty() ) + return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + else if ( !swofLetTables.empty() ) + return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: return Opm::fun::map( famII, Opm::fun::iota( num_tables ) ); default: throw std::domain_error("No valid saturation keyword family specified"); } @@ -396,6 +439,7 @@ namespace { const auto& sgfnTables = tm.getSgfnTables(); const auto& sgofTables = tm.getSgofTables(); + const auto& sgofLetTables = tm.getSgofletTable(); const auto& slgofTables = tm.getSlgofTables(); const auto famI_sgof = [&sgofTables, tolcrit](const int i) -> double @@ -403,6 +447,10 @@ namespace { return critical_gas(sgofTables.getTable(i), tolcrit); }; + const auto famI_sgof_let = [&sgofLetTables]( int i ) { + return sgofLetTables[i].s1_critical; + }; + const auto famI_slgof = [&slgofTables, tolcrit](const int i) -> double { return critical_gas(slgofTables.getTable(i), tolcrit); @@ -415,11 +463,13 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - if( sgofTables.empty() && slgofTables.empty() ) + if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() ) throw std::runtime_error( "Saturation keyword family I requires either sgof or slgof non-empty" ); if( !sgofTables.empty() ) return Opm::fun::map( famI_sgof, Opm::fun::iota( num_tables ) ); + else if( !sgofLetTables.empty() ) + return Opm::fun::map( famI_sgof_let, Opm::fun::iota( num_tables ) ); else return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) ); @@ -486,6 +536,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& swofTables = tm.getSwofTables(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& sof2Tables = tm.getSof2Tables(); const auto& sof3Tables = tm.getSof3Tables(); @@ -494,6 +545,10 @@ namespace { return critical_oil_water(swofTables.getTable(i), tolcrit); }; + const auto famI_let = [&swofLetTables]( int i ) { + return swofLetTables[i].s2_critical; + }; + const auto famII_2p = [&sof2Tables, tolcrit](const int i) -> double { return critical_oil(sof2Tables.getTable(i), tolcrit); @@ -506,7 +561,11 @@ namespace { }; switch( getSaturationFunctionFamily( tm, ph ) ) { - case SatfuncFamily::I: return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + case SatfuncFamily::I: + if( !swofTables.empty() ) + return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + else if ( !swofLetTables.empty() ) + return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: return ph.active(::Opm::Phase::GAS) ? Opm::fun::map( famII_3p, Opm::fun::iota( num_tables ) ) @@ -559,6 +618,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& sgofTables = tm.getSgofTables(); + const auto& sgofLetTables = tm.getSgofletTable(); const auto& slgofTables = tm.getSlgofTables(); const auto& sof2Tables = tm.getSof2Tables(); const auto& sof3Tables = tm.getSof3Tables(); @@ -568,6 +628,10 @@ namespace { return critical_oil_gas(sgofTables.getTable(i), tolcrit) - swco[i]; }; + const auto famI_sgof_let = [&sgofLetTables]( int i ) { + return sgofLetTables[i].s2_critical; + }; + const auto famI_slgof = [&slgofTables, &swco, tolcrit](const int i) -> double { return critical_oil_gas(slgofTables.getTable(i), tolcrit) - swco[i]; @@ -586,11 +650,13 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - if( sgofTables.empty() && slgofTables.empty() ) + if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() ) throw std::runtime_error( "Saturation keyword family I requires either sgof or slgof non-empty" ); if( !sgofTables.empty() ) return Opm::fun::map( famI_sgof, Opm::fun::iota( num_tables ) ); + else if( !sgofLetTables.empty() ) + return Opm::fun::map( famI_sgof_let, Opm::fun::iota( num_tables ) ); else return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) ); @@ -614,6 +680,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& sgofTables = tm.getSgofTables(); + const auto& sgofLetTables = tm.getSgofletTable(); const auto& slgofTables = tm.getSlgofTables(); const auto& sgfnTables = tm.getSgfnTables(); @@ -621,6 +688,10 @@ namespace { return sgofTables.getTable( i ).getKrgColumn().back(); }; + const auto& famI_sgof_let = [&sgofLetTables]( int i ) { + return sgofLetTables[i].krt1_relperm; + }; + const auto& famI_slgof = [&slgofTables]( int i ) { return slgofTables.getTable( i ).getKrgColumn().front(); }; @@ -631,10 +702,12 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - if( sgofTables.empty() && slgofTables.empty() ) + if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() ) throw std::runtime_error( "Saturation keyword family I requires either sgof or slgof non-empty" ); if( !sgofTables.empty() ) return Opm::fun::map( famI_sgof, Opm::fun::iota( num_tables ) ); + else if( !sgofLetTables.empty() ) + return Opm::fun::map( famI_sgof_let, Opm::fun::iota( num_tables ) ); else return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: @@ -655,6 +728,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& sgofTables = tm.getSgofTables(); + const auto& sgofLetTables = tm.getSgofletTable(); const auto& slgofTables = tm.getSlgofTables(); const auto& sgfnTables = tm.getSgfnTables(); @@ -681,6 +755,11 @@ namespace { return sgof.getKrgColumn().eval(ix); }; + const auto famI_sgof_let = [&sgofLetTables, &sr](const int i) -> double + { + return sgofLetTables[i].krt1_relperm; + }; + const auto famI_slgof = [&slgofTables, &sr](const int i) -> double { const auto& slgof = slgofTables.getTable(i); @@ -699,10 +778,12 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - if( sgofTables.empty() && slgofTables.empty() ) + if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() ) throw std::runtime_error( "Saturation keyword family I requires either sgof or slgof non-empty" ); if( !sgofTables.empty() ) return Opm::fun::map( famI_sgof, Opm::fun::iota( num_tables ) ); + else if( !sgofLetTables.empty() ) + return Opm::fun::map( famI_sgof_let, Opm::fun::iota( num_tables ) ); else return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: @@ -723,6 +804,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& swofTables = tm.getSwofTables(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& swfnTables = tm.getSwfnTables(); auto sr = std::vector(num_tables, 0.0); @@ -748,6 +830,11 @@ namespace { return swof.getKrwColumn().eval(ix); }; + const auto& famI_let = [&swofLetTables, &sr](const int i) -> double + { + return swofLetTables[i].krt1_relperm; + }; + const auto& famII = [&swfnTables, &sr](const int i) -> double { const auto& swfn = swfnTables.getTable(i); @@ -758,7 +845,10 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + if( !swofTables.empty() ) + return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + else if( !swofLetTables.empty() ) + return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: return Opm::fun::map( famII, Opm::fun::iota( num_tables ) ); default: @@ -778,6 +868,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& swofTables = tm.getSwofTables(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& sof2Tables = tm.getSof2Tables(); const auto& sof3Tables = tm.getSof3Tables(); @@ -790,6 +881,11 @@ namespace { return swof.getKrowColumn().eval(ix); }; + const auto famI_let = [&swofLetTables, &ep](const int i) -> double + { + return swofLetTables[i].krt2_relperm; + }; + const auto famII_3p = [&sof3Tables, &ep](const int i) -> double { const auto& sof3 = sof3Tables.getTable(i); @@ -810,7 +906,10 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + if ( !swofTables.empty() ) + return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + else if ( !swofLetTables.empty() ) + return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: return ph.active(::Opm::Phase::GAS) ? Opm::fun::map( famII_3p, Opm::fun::iota( num_tables ) ) @@ -832,6 +931,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& sgofTables = tm.getSgofTables(); + const auto& sgofLetTables = tm.getSgofletTable(); const auto& slgofTables = tm.getSlgofTables(); const auto& sof2Tables = tm.getSof2Tables(); const auto& sof3Tables = tm.getSof3Tables(); @@ -845,6 +945,11 @@ namespace { return sgof.getKrogColumn().eval(ix); }; + const auto famI_sgof_let = [&sgofLetTables, &ep](const int i) -> double + { + return sgofLetTables[i].krt2_relperm; + }; + const auto famI_slgof = [&slgofTables, &ep](const int i) -> double { const auto& slgof = slgofTables.getTable(i); @@ -873,10 +978,12 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - if( sgofTables.empty() && slgofTables.empty() ) + if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() ) throw std::runtime_error( "Saturation keyword family I requires either sgof or slgof non-empty" ); if( !sgofTables.empty() ) return Opm::fun::map( famI_sgof, Opm::fun::iota( num_tables ) ); + else if( !sgofLetTables.empty() ) + return Opm::fun::map( famI_sgof_let, Opm::fun::iota( num_tables ) ); else return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: @@ -908,6 +1015,7 @@ namespace { return std::vector(num_tables, 0.0); const auto& sgofTables = tm.getSgofTables(); + const auto& sgofLetTables = tm.getSgofletTable(); const auto& slgofTables = tm.getSlgofTables(); const auto& sgfnTables = tm.getSgfnTables(); @@ -915,6 +1023,10 @@ namespace { return sgofTables.getTable( i ).getPcogColumn().back(); }; + const auto& famI_sgof_let = [&sgofLetTables]( int i ) { + return sgofLetTables[i].pct_pc; + }; + const auto& famI_slgof = [&slgofTables]( int i ) { return slgofTables.getTable( i ).getPcogColumn().front(); }; @@ -925,10 +1037,12 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - if( sgofTables.empty() && slgofTables.empty() ) + if( sgofTables.empty() && sgofLetTables.empty() && slgofTables.empty() ) throw std::runtime_error( "Saturation keyword family I requires either sgof or slgof non-empty" ); if( !sgofTables.empty() ) return Opm::fun::map( famI_sgof, Opm::fun::iota( num_tables ) ); + else if( !sgofLetTables.empty() ) + return Opm::fun::map( famI_sgof_let, Opm::fun::iota( num_tables ) ); else return Opm::fun::map( famI_slgof, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: @@ -949,19 +1063,27 @@ namespace { return std::vector(num_tables, 0.0); const auto& swofTables = tm.getSwofTables(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& swfnTables = tm.getSwfnTables(); const auto& famI = [&swofTables]( int i ) { return swofTables.getTable( i ).getPcowColumn().front(); }; + const auto& famI_let = [&swofLetTables]( int i ) { + return swofLetTables[i].pct_pc; + }; + const auto& famII = [&swfnTables]( int i ) { return swfnTables.getTable( i ).getPcowColumn().front(); }; switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + if (!swofTables.empty()) + return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + else if (!swofLetTables.empty()) + return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: return Opm::fun::map( famII, Opm::fun::iota( num_tables ) ); default: @@ -981,6 +1103,8 @@ namespace { const auto wat = ph.active(::Opm::Phase::WATER); const auto& other_f1 = wat ? tm.getSwofTables() : tm.getSgofTables(); + const auto& wat_f1_let = tm.getSwofletTable(); + const auto& gas_f1_let = tm.getSgofletTable(); const auto& sof2Tables = tm.getSof2Tables(); const auto& sof3Tables = tm.getSof3Tables(); @@ -993,6 +1117,18 @@ namespace { : other_f1.getTable( i ).getKrogColumn().front(); }; + const auto& famI_let_wat = [&wat_f1_let]( int i ) { + // In O/W/G runs this relies on Krog(Sg=0) == Krow(Sw=Swco), + // meaning that in each region krt2_relperm is equal for SGOFLET and SWOFLET. + return wat_f1_let[i].krt2_relperm; + }; + + const auto& famI_let_gas = [&gas_f1_let]( int i ) { + // In O/W/G runs this relies on Krog(Sg=0) == Krow(Sw=Swco), + // meaning that in each region krt2_relperm is equal for SGOFLET and SWOFLET. + return gas_f1_let[i].krt2_relperm; + }; + const auto& famII_2p = [&sof2Tables]( int i ) { return sof2Tables.getTable( i ).getKroColumn().back(); }; @@ -1003,7 +1139,12 @@ namespace { switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + if ( !other_f1.empty() ) + return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + else if ( !wat_f1_let.empty() ) + return Opm::fun::map( famI_let_wat, Opm::fun::iota( num_tables ) ); + else if ( !gas_f1_let.empty() ) + return Opm::fun::map( famI_let_gas, Opm::fun::iota( num_tables ) ); case SatfuncFamily::II: return ph.active(::Opm::Phase::GAS) && ph.active(::Opm::Phase::WATER) ? Opm::fun::map( famII_3p, Opm::fun::iota( num_tables ) ) @@ -1023,19 +1164,28 @@ namespace { return std::vector(num_tables, 0.0); const auto& swofTables = tm.getSwofTables(); + const auto& swofLetTables = tm.getSwofletTable(); const auto& swfnTables = tm.getSwfnTables(); const auto& famI = [&swofTables]( int i ) { return swofTables.getTable( i ).getKrwColumn().back(); }; + const auto& famI_let = [&swofLetTables]( int i ) { + return swofLetTables[i].krt1_relperm; + }; + const auto& famII = [&swfnTables]( int i ) { return swfnTables.getTable( i ).getKrwColumn().back(); }; switch( getSaturationFunctionFamily( tm, ph ) ) { case SatfuncFamily::I: - return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + if( !swofTables.empty() ) + return Opm::fun::map( famI, Opm::fun::iota( num_tables ) ); + else if( !swofLetTables.empty() ) + return Opm::fun::map( famI_let, Opm::fun::iota( num_tables ) ); + case SatfuncFamily::II: return Opm::fun::map( famII, Opm::fun::iota( num_tables ) ); default: diff --git a/src/opm/input/eclipse/EclipseState/Runspec.cpp b/src/opm/input/eclipse/EclipseState/Runspec.cpp index ed94d5916..2dc4a22e3 100644 --- a/src/opm/input/eclipse/EclipseState/Runspec.cpp +++ b/src/opm/input/eclipse/EclipseState/Runspec.cpp @@ -88,7 +88,8 @@ namespace { const auto family1 = // SGOF/SLGOF and/or SWOF (gas && (deck.hasKeyword() || deck.hasKeyword())) || - (wat && deck.hasKeyword()); + (wat && deck.hasKeyword()) || + (wat && deck.hasKeyword()); // note: we allow for SOF2 to be part of family1 for threeP + // solvent simulations. diff --git a/src/opm/input/eclipse/EclipseState/Tables/TableManager.cpp b/src/opm/input/eclipse/EclipseState/Tables/TableManager.cpp index 59e93ab00..10131a7a5 100644 --- a/src/opm/input/eclipse/EclipseState/Tables/TableManager.cpp +++ b/src/opm/input/eclipse/EclipseState/Tables/TableManager.cpp @@ -211,6 +211,12 @@ DensityTable make_density_table(const GravityTable& gravity) { if( deck.hasKeyword( "WATDENT" ) ) this->m_watdentTable = WatdentTable( deck["WATDENT"].back() ); + if( deck.hasKeyword( "SGOFLET" ) ) + this->m_sgofletTable = SgofletTable( deck["SGOFLET"].back() ); + + if( deck.hasKeyword( "SWOFLET" ) ) + this->m_swofletTable = SwofletTable( deck["SWOFLET"].back() ); + if( deck.hasKeyword( "RTEMP" ) ) m_rtemp = deck["RTEMP"].back().getRecord(0).getItem("TEMP").getSIDouble( 0 ); else if (deck.hasKeyword( "RTEMPA" ) ) @@ -297,6 +303,8 @@ DensityTable make_density_table(const GravityTable& gravity) { result.m_stone1exTable = Stone1exTable::serializeObject(); result.m_viscrefTable = ViscrefTable::serializeObject(); result.m_watdentTable = WatdentTable::serializeObject(); + result.m_sgofletTable = SgofletTable::serializeObject(); + result.m_swofletTable = SwofletTable::serializeObject(); result.m_pvtwsaltTables = {PvtwsaltTable::serializeObject()}; result.m_rwgsaltTables = {RwgsaltTable::serializeObject()}; result.m_bdensityTables = {BrineDensityTable::serializeObject()}; @@ -1117,6 +1125,14 @@ DensityTable make_density_table(const GravityTable& gravity) { return this->m_watdentTable; } + const SgofletTable& TableManager::getSgofletTable() const { + return this->m_sgofletTable; + } + + const SwofletTable& TableManager::getSwofletTable() const { + return this->m_swofletTable; + } + const TableContainer& TableManager::getMsfnTables() const { return getTables("MSFN"); } @@ -1241,6 +1257,8 @@ DensityTable make_density_table(const GravityTable& gravity) { m_stone1exTable == data.m_stone1exTable && m_viscrefTable == data.m_viscrefTable && m_watdentTable == data.m_watdentTable && + m_sgofletTable == data.m_sgofletTable && + m_swofletTable == data.m_swofletTable && m_pvtwsaltTables == data.m_pvtwsaltTables && m_rwgsaltTables == data.m_rwgsaltTables && m_bdensityTables == data.m_bdensityTables && diff --git a/src/opm/input/eclipse/EclipseState/Tables/Tables.cpp b/src/opm/input/eclipse/EclipseState/Tables/Tables.cpp index 4302cbe72..b3a862def 100644 --- a/src/opm/input/eclipse/EclipseState/Tables/Tables.cpp +++ b/src/opm/input/eclipse/EclipseState/Tables/Tables.cpp @@ -1551,5 +1551,6 @@ template FlatTable< ShrateRecord >::FlatTable( const DeckKeyword& ); template FlatTable< Stone1exRecord >::FlatTable( const DeckKeyword& ); template FlatTable< TlmixparRecord>::FlatTable( const DeckKeyword& ); template FlatTable< WATDENTRecord >::FlatTable( const DeckKeyword& ); +template FlatTable< SatFuncLETRecord >::FlatTable( const DeckKeyword& ); } // namespace Opm diff --git a/src/opm/input/eclipse/share/keywords/keyword_list.cmake b/src/opm/input/eclipse/share/keywords/keyword_list.cmake index ff304d0e3..ba84fb1dd 100644 --- a/src/opm/input/eclipse/share/keywords/keyword_list.cmake +++ b/src/opm/input/eclipse/share/keywords/keyword_list.cmake @@ -1119,6 +1119,7 @@ set( keywords 900_OPM/S/SALTSOL 900_OPM/S/SBIOF 900_OPM/S/SCALC + 900_OPM/S/SGOFLET 900_OPM/S/SKPRPOLY 900_OPM/S/SKPRWAT 900_OPM/S/SMICR @@ -1126,6 +1127,7 @@ set( keywords 900_OPM/S/SPIDER 900_OPM/S/SPOLYMW 900_OPM/S/SUREA + 900_OPM/S/SWOFLET 900_OPM/T/TLPMIXPA 900_OPM/V/VAPWAT 900_OPM/W/WMICP diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/S/SGOFLET b/src/opm/parser/eclipse/share/keywords/900_OPM/S/SGOFLET new file mode 100644 index 000000000..9b0824031 --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/S/SGOFLET @@ -0,0 +1,115 @@ +{ + "name": "SGOFLET", + "sections": [ + "PROPS" + ], + "size": { + "keyword": "TABDIMS", + "item": "NTSFUN" + }, + "requires": ["GAS", "OIL"], + "items": [ + { + "name": "SG_0", + "value_type": "DOUBLE", + "default": 0, + "dimension": "1" + }, + { + "name": "SG_CRITICAL", + "value_type": "DOUBLE", + "default": 0, + "dimension": "1" + }, + { + "name": "L_GAS", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "E_GAS", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "T_GAS", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "KRT_GAS", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "SO_0", + "value_type": "DOUBLE", + "default": 0, + "dimension": "1" + }, + { + "name": "SO_CRITICAL", + "value_type": "DOUBLE", + "default": 0, + "dimension": "1" + }, + { + "name": "L_OIL", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "E_OIL", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "T_OIL", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "KRT_OIL", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "L_PC", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "E_PC", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "T_PC", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "PCIR", + "value_type": "DOUBLE", + "default": 0, + "dimension": "Pressure" + }, + { + "name": "PCT", + "value_type": "DOUBLE", + "default": 0, + "dimension": "Pressure" + } + ] +} diff --git a/src/opm/parser/eclipse/share/keywords/900_OPM/S/SWOFLET b/src/opm/parser/eclipse/share/keywords/900_OPM/S/SWOFLET new file mode 100644 index 000000000..bb34b9af8 --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/900_OPM/S/SWOFLET @@ -0,0 +1,115 @@ +{ + "name": "SWOFLET", + "sections": [ + "PROPS" + ], + "size": { + "keyword": "TABDIMS", + "item": "NTSFUN" + }, + "requires": ["OIL", "WATER"], + "items": [ + { + "name": "SW_RESIDUAL", + "value_type": "DOUBLE", + "default": 0, + "dimension": "1" + }, + { + "name": "SW_CRITICAL", + "value_type": "DOUBLE", + "default": 0, + "dimension": "1" + }, + { + "name": "L_WATER", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "E_WATER", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "T_WATER", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "KRT_WATER", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "SO_RESIDUAL", + "value_type": "DOUBLE", + "default": 0, + "dimension": "1" + }, + { + "name": "SO_CRITICAL", + "value_type": "DOUBLE", + "default": 0, + "dimension": "1" + }, + { + "name": "L_OIL", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "E_OIL", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "T_OIL", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "KRT_OIL", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "L_PC", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "E_PC", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "T_PC", + "value_type": "DOUBLE", + "default": 1, + "dimension": "1" + }, + { + "name": "PCIR", + "value_type": "DOUBLE", + "default": 0, + "dimension": "Pressure" + }, + { + "name": "PCT", + "value_type": "DOUBLE", + "default": 0, + "dimension": "Pressure" + } + ] +}