Understand ENDSCALE and SCALECRS
Exposes the semantics defined by ENDSCALE (and SCALECRS) in Runspec.endpoint_scaling.
This commit is contained in:
@@ -80,6 +80,7 @@ EclipseState/EclipseState.cpp
|
||||
EclipseState/EclipseConfig.cpp
|
||||
EclipseState/Eclipse3DProperties.cpp
|
||||
EclipseState/Runspec.cpp
|
||||
EclipseState/EndpointScaling.cpp
|
||||
#
|
||||
EclipseState/checkDeck.cpp
|
||||
#
|
||||
|
||||
113
opm/parser/eclipse/EclipseState/EndpointScaling.cpp
Normal file
113
opm/parser/eclipse/EclipseState/EndpointScaling.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Runspec.hpp>
|
||||
#include <opm/parser/eclipse/Utility/String.hpp>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
EndpointScaling::operator bool() const noexcept {
|
||||
return this->options[ static_cast< ue >( option::any ) ];
|
||||
}
|
||||
|
||||
bool EndpointScaling::directional() const noexcept {
|
||||
return this->options[ static_cast< ue >( option::directional ) ];
|
||||
}
|
||||
|
||||
bool EndpointScaling::nondirectional() const noexcept {
|
||||
return bool( *this ) && !this->directional();
|
||||
}
|
||||
|
||||
bool EndpointScaling::reversible() const noexcept {
|
||||
return this->options[ static_cast< ue >( option::reversible ) ];
|
||||
}
|
||||
|
||||
bool EndpointScaling::irreversible() const noexcept {
|
||||
return bool( *this ) && !this->reversible();
|
||||
}
|
||||
|
||||
bool EndpointScaling::twopoint() const noexcept {
|
||||
return bool( *this ) && !this->threepoint();
|
||||
}
|
||||
|
||||
bool EndpointScaling::threepoint() const noexcept {
|
||||
return this->options[ static_cast< ue >( option::threepoint ) ];
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool threepoint_scaling( const Deck& deck ) {
|
||||
if( !deck.hasKeyword( "SCALECRS" ) ) return false;
|
||||
|
||||
/*
|
||||
* the manual says that Y and N are acceptable values for "YES" and "NO", so
|
||||
* it's *VERY* likely that only the first character is checked. We preserve
|
||||
* this behaviour
|
||||
*/
|
||||
const auto value = std::toupper(
|
||||
deck.getKeyword( "SCALECRS" )
|
||||
.getRecord( 0 )
|
||||
.getItem( "VALUE" )
|
||||
.get< std::string >( 0 ).front() );
|
||||
|
||||
if( value != 'Y' && value != 'N' )
|
||||
throw std::invalid_argument( "SCALECRS takes 'YES' or 'NO'" );
|
||||
|
||||
return value == 'Y';
|
||||
}
|
||||
|
||||
bool endscale_nodir( const DeckKeyword& kw ) {
|
||||
if( kw.getRecord( 0 ).getItem( 0 ).defaultApplied( 0 ) )
|
||||
return true;
|
||||
|
||||
const auto& value = uppercase( kw.getRecord( 0 )
|
||||
.getItem( 0 )
|
||||
.get< std::string >( 0 ) );
|
||||
|
||||
if( value != "DIRECT" && value != "NODIR" )
|
||||
throw std::invalid_argument(
|
||||
"ENDSCALE argument 1 must be defaulted, 'DIRECT' or 'NODIR', was "
|
||||
+ value
|
||||
);
|
||||
|
||||
return value == "NODIR";
|
||||
}
|
||||
|
||||
bool endscale_revers( const DeckKeyword& kw ) {
|
||||
if( kw.getRecord( 0 ).getItem( 1 ).defaultApplied( 0 ) )
|
||||
return true;
|
||||
|
||||
const auto& value = uppercase( kw.getRecord( 0 )
|
||||
.getItem( 1 )
|
||||
.get< std::string >( 0 ) );
|
||||
|
||||
if( value != "IRREVERS" && value != "REVERS" )
|
||||
throw std::invalid_argument(
|
||||
"ENDSCALE argument 2 must be defaulted, 'REVERS' or 'IRREVERS', was "
|
||||
+ value
|
||||
);
|
||||
|
||||
const auto& item0 = kw.getRecord( 0 ).getItem( 0 );
|
||||
if( value == "IRREVERS"
|
||||
&& uppercase( item0.get< std::string >( 0 ) ) != "DIRECT" )
|
||||
throw std::invalid_argument( "'IRREVERS' requires 'DIRECT'" );
|
||||
|
||||
return value == "REVERS";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EndpointScaling::EndpointScaling( const Deck& deck ) {
|
||||
if( !deck.hasKeyword( "ENDSCALE" ) ) return;
|
||||
|
||||
const auto& endscale = deck.getKeyword( "ENDSCALE" );
|
||||
const bool direct = !endscale_nodir( endscale );
|
||||
const bool revers = endscale_revers( endscale );
|
||||
const bool threep = threepoint_scaling( deck );
|
||||
|
||||
this->options.set( static_cast< ue >( option::any ), true );
|
||||
this->options.set( static_cast< ue >( option::directional ), direct );
|
||||
this->options.set( static_cast< ue >( option::reversible ), revers );
|
||||
this->options.set( static_cast< ue >( option::threepoint ), threep );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -62,23 +62,26 @@ size_t Phases::size() const noexcept {
|
||||
return this->bits.count();
|
||||
}
|
||||
|
||||
|
||||
Runspec::Runspec( const Deck& deck ) :
|
||||
active_phases( Phases{ deck.hasKeyword( "OIL" ),
|
||||
deck.hasKeyword( "GAS" ),
|
||||
deck.hasKeyword( "WATER" ),
|
||||
deck.hasKeyword( "SOLVENT" ),
|
||||
} ),
|
||||
m_tabdims( deck )
|
||||
m_tabdims( deck ),
|
||||
endscale( deck )
|
||||
{}
|
||||
|
||||
const Phases& Runspec::phases() const noexcept {
|
||||
return this->active_phases;
|
||||
}
|
||||
|
||||
|
||||
const Tabdims& Runspec::tabdims() const noexcept {
|
||||
return this->m_tabdims;
|
||||
}
|
||||
|
||||
const EndpointScaling& Runspec::endpoint_scaling() const noexcept {
|
||||
return this->endscale;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -51,15 +51,45 @@ class Phases {
|
||||
std::bitset< 4 > bits;
|
||||
};
|
||||
|
||||
class EndpointScaling {
|
||||
public:
|
||||
EndpointScaling() noexcept = default;
|
||||
explicit EndpointScaling( const Deck& );
|
||||
|
||||
/* true if endpoint scaling is enabled, otherwise false */
|
||||
operator bool() const noexcept;
|
||||
|
||||
bool directional() const noexcept;
|
||||
bool nondirectional() const noexcept;
|
||||
bool reversible() const noexcept;
|
||||
bool irreversible() const noexcept;
|
||||
bool twopoint() const noexcept;
|
||||
bool threepoint() const noexcept;
|
||||
|
||||
private:
|
||||
enum class option {
|
||||
any = 0,
|
||||
directional = 1,
|
||||
reversible = 2,
|
||||
threepoint = 3,
|
||||
};
|
||||
|
||||
using ue = std::underlying_type< option >::type;
|
||||
std::bitset< 4 > options;
|
||||
};
|
||||
|
||||
class Runspec {
|
||||
public:
|
||||
explicit Runspec( const Deck& );
|
||||
|
||||
const Phases& phases() const noexcept;
|
||||
const Tabdims& tabdims() const noexcept;
|
||||
const EndpointScaling& endpoint_scaling() const noexcept;
|
||||
|
||||
private:
|
||||
Phases active_phases;
|
||||
Tabdims m_tabdims;
|
||||
EndpointScaling endscale;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -107,3 +107,161 @@ BOOST_AUTO_TEST_CASE(TABDIMS) {
|
||||
BOOST_CHECK_EQUAL( tabdims.getNumRSNodes( ) , 20 );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( EndpointScalingWithoutENDSCALE ) {
|
||||
const std::string input = R"(
|
||||
RUNSPEC
|
||||
)";
|
||||
|
||||
Runspec runspec( Parser{}.parseString( input, ParseContext{} ) );
|
||||
const auto& endscale = runspec.endpoint_scaling();
|
||||
|
||||
BOOST_CHECK( !endscale );
|
||||
BOOST_CHECK( !endscale.directional() );
|
||||
BOOST_CHECK( !endscale.nondirectional() );
|
||||
BOOST_CHECK( !endscale.reversible() );
|
||||
BOOST_CHECK( !endscale.irreversible() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( EndpointScalingDefaulted ) {
|
||||
const std::string input = R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
/
|
||||
)";
|
||||
|
||||
Runspec runspec( Parser{}.parseString( input, ParseContext{} ) );
|
||||
const auto& endscale = runspec.endpoint_scaling();
|
||||
|
||||
BOOST_CHECK( endscale );
|
||||
BOOST_CHECK( !endscale.directional() );
|
||||
BOOST_CHECK( endscale.nondirectional() );
|
||||
BOOST_CHECK( endscale.reversible() );
|
||||
BOOST_CHECK( !endscale.irreversible() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( EndpointScalingDIRECT ) {
|
||||
const std::string input = R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
DIRECT /
|
||||
)";
|
||||
|
||||
Runspec runspec( Parser{}.parseString( input, ParseContext{} ) );
|
||||
const auto& endscale = runspec.endpoint_scaling();
|
||||
|
||||
BOOST_CHECK( endscale );
|
||||
BOOST_CHECK( endscale.directional() );
|
||||
BOOST_CHECK( !endscale.nondirectional() );
|
||||
BOOST_CHECK( endscale.reversible() );
|
||||
BOOST_CHECK( !endscale.irreversible() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( EndpointScalingDIRECT_IRREVERS ) {
|
||||
const std::string input = R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
direct IRREVERS /
|
||||
)";
|
||||
|
||||
Runspec runspec( Parser{}.parseString( input, ParseContext{} ) );
|
||||
const auto& endscale = runspec.endpoint_scaling();
|
||||
|
||||
BOOST_CHECK( endscale );
|
||||
BOOST_CHECK( endscale.directional() );
|
||||
BOOST_CHECK( !endscale.nondirectional() );
|
||||
BOOST_CHECK( !endscale.reversible() );
|
||||
BOOST_CHECK( endscale.irreversible() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( SCALECRS_without_ENDSCALE ) {
|
||||
const std::string input = R"(
|
||||
RUNSPEC
|
||||
SCALECRS
|
||||
/
|
||||
)";
|
||||
|
||||
Runspec runspec( Parser{}.parseString( input, ParseContext{} ) );
|
||||
const auto& endscale = runspec.endpoint_scaling();
|
||||
|
||||
BOOST_CHECK( !endscale );
|
||||
BOOST_CHECK( !endscale.twopoint() );
|
||||
BOOST_CHECK( !endscale.threepoint() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( SCALECRS_N ) {
|
||||
const std::string N = R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
/
|
||||
SCALECRS
|
||||
N /
|
||||
)";
|
||||
|
||||
const std::string defaulted = R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
/
|
||||
SCALECRS
|
||||
/
|
||||
)";
|
||||
|
||||
for( const auto& input : { N, defaulted } ) {
|
||||
Runspec runspec( Parser{}.parseString( input, ParseContext{} ) );
|
||||
const auto& endscale = runspec.endpoint_scaling();
|
||||
|
||||
BOOST_CHECK( endscale );
|
||||
BOOST_CHECK( endscale.twopoint() );
|
||||
BOOST_CHECK( !endscale.threepoint() );
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( SCALECRS_Y ) {
|
||||
const std::string input = R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
/
|
||||
SCALECRS
|
||||
Y /
|
||||
)";
|
||||
|
||||
Runspec runspec( Parser{}.parseString( input, ParseContext{} ) );
|
||||
const auto& endscale = runspec.endpoint_scaling();
|
||||
|
||||
BOOST_CHECK( endscale );
|
||||
BOOST_CHECK( !endscale.twopoint() );
|
||||
BOOST_CHECK( endscale.threepoint() );
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE( endpoint_scaling_throw_invalid_argument ) {
|
||||
|
||||
const std::string inputs[] = {
|
||||
R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
NODIR IRREVERSIBLE / -- irreversible requires direct
|
||||
)",
|
||||
R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
* IRREVERSIBLE / -- irreversible requires direct *specified*
|
||||
)",
|
||||
R"(
|
||||
RUNSPEC
|
||||
ENDSCALE -- ENDSCALE can't take arbitrary input (takes enumeration)
|
||||
broken /
|
||||
)",
|
||||
R"(
|
||||
RUNSPEC
|
||||
ENDSCALE
|
||||
/
|
||||
SCALECRS -- SCALECRS takes YES/NO
|
||||
broken /
|
||||
)",
|
||||
};
|
||||
|
||||
for( auto&& input : inputs ) {
|
||||
auto deck = Parser{}.parseString( input, ParseContext{} );
|
||||
std::cout << input << std::endl;
|
||||
BOOST_CHECK_THROW( Runspec{ deck }, std::invalid_argument );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user