Understand ENDSCALE and SCALECRS

Exposes the semantics defined by ENDSCALE (and SCALECRS) in
Runspec.endpoint_scaling.
This commit is contained in:
Jørgen Kvalsvik
2017-01-03 15:42:41 +01:00
parent 083b834cd1
commit 36d2e1349d
5 changed files with 308 additions and 3 deletions

View File

@@ -80,6 +80,7 @@ EclipseState/EclipseState.cpp
EclipseState/EclipseConfig.cpp
EclipseState/Eclipse3DProperties.cpp
EclipseState/Runspec.cpp
EclipseState/EndpointScaling.cpp
#
EclipseState/checkDeck.cpp
#

View 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 );
}
}

View File

@@ -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;
}
}

View File

@@ -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;
};
}

View File

@@ -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 );
}
}