Add ParseContext behaviour to trimming of well/group names

This commit is contained in:
Joakim Hove 2019-08-09 12:12:30 +02:00
parent b55e073182
commit 49d32a02fb
8 changed files with 109 additions and 23 deletions

View File

@ -248,7 +248,7 @@ namespace Opm
void handleUDQ(const DeckKeyword& keyword, size_t currentStep);
void handleWLIST(const DeckKeyword& keyword, size_t currentStep);
void handleCOMPORD(const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& compordKeyword, size_t currentStep);
void handleWELSPECS( const SCHEDULESection&, size_t, size_t , const UnitSystem& unit_system);
void handleWELSPECS( const SCHEDULESection&, size_t, size_t , const UnitSystem& unit_system, const ParseContext& parseContext, ErrorGuard& errors);
void handleWCONHIST( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleWCONPROD( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleWGRUPCON( const DeckKeyword& keyword, size_t currentStep);
@ -273,7 +273,7 @@ namespace Opm
void handleGEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleWEFAC( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);
void handleTUNING( const DeckKeyword& keyword, size_t currentStep);
void handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system);
void handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system, const ParseContext& parseContext, ErrorGuard& errors);
void handleGRUPNET( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system);
void handleWRFT( const DeckKeyword& keyword, size_t currentStep);
void handleWTEST( const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors);

View File

@ -271,6 +271,14 @@ namespace Opm {
*/
const static std::string PARSE_MISSING_SECTIONS;
/*
When defining wells and groups with the WELSPECS and GRUPTREE keywords
we do not allow leading or trailing spaces. The code in Schedule.cpp
will *unconditionally* remove the spaces, but with PARSE_WGNAME_SPACE
setting you can additionally configure the normal IGNORE|WARN|ERROR
behavior.
*/
const static std::string PARSE_WGNAME_SPACE;
/*
If you have configured a specific well in the summary section,

View File

@ -75,6 +75,30 @@ namespace {
return (fnmatch(pattern.c_str(), name.c_str(), flags) == 0);
}
/*
The function trim_wgname() is used to trim the leading and trailing spaces
away from the group and well arguments given in the WELSPECS and GRUPTREE
keywords. If the deck argument contains a leading or trailing space that is
treated as an input error, and the action taken is regulated by the setting
ParseContext::PARSE_WGNAME_SPACE.
Observe that the spaces are trimmed *unconditionally* - i.e. if the
ParseContext::PARSE_WGNAME_SPACE setting is set to InputError::IGNORE that
means that we do not inform the user about "our fix", but it is *not* possible
to configure the parser to leave the spaces intact.
*/
std::string trim_wgname(const DeckKeyword& keyword, const std::string& wgname_arg, const ParseContext& parseContext, ErrorGuard errors) {
std::string wgname = boost::algorithm::trim_copy(wgname_arg);
if (wgname != wgname_arg) {
std::string msg = "Illegal space: \"" + wgname_arg + "\" found when defining WELL/GROUP in keyword: " + keyword.name() + " at " + keyword.getFileName() + ":" + std::to_string(keyword.getLineNumber());
parseContext.handleError(ParseContext::PARSE_WGNAME_SPACE, msg, errors);
}
return wgname;
}
}
Schedule::Schedule( const Deck& deck,
@ -228,7 +252,7 @@ namespace {
handleWLIST( keyword, currentStep );
else if (keyword.name() == "WELSPECS")
handleWELSPECS( section, keywordIdx, currentStep, unit_system);
handleWELSPECS( section, keywordIdx, currentStep, unit_system, parseContext, errors);
else if (keyword.name() == "WHISTCTL")
handleWHISTCTL(keyword, currentStep, parseContext, errors);
@ -291,7 +315,7 @@ namespace {
handleWELTARG(section, keyword, currentStep, parseContext, errors);
else if (keyword.name() == "GRUPTREE")
handleGRUPTREE(keyword, currentStep, unit_system);
handleGRUPTREE(keyword, currentStep, unit_system, parseContext, errors);
else if (keyword.name() == "GRUPNET")
handleGRUPNET(keyword, currentStep, unit_system);
@ -527,7 +551,9 @@ namespace {
void Schedule::handleWELSPECS( const SCHEDULESection& section,
size_t index,
size_t currentStep,
const UnitSystem& unit_system) {
const UnitSystem& unit_system,
const ParseContext& parseContext,
ErrorGuard& errors) {
const auto COMPORD_in_timestep = [&]() -> const DeckKeyword* {
auto itr = section.begin() + index;
for( ; itr != section.end(); ++itr ) {
@ -543,8 +569,8 @@ namespace {
for (size_t recordNr = 0; recordNr < keyword.size(); recordNr++) {
const auto& record = keyword.getRecord(recordNr);
const std::string& wellName = record.getItem("WELL").getTrimmedString(0);
const std::string& groupName = record.getItem("GROUP").getTrimmedString(0);
const std::string& wellName = trim_wgname(keyword, record.getItem("WELL").get<std::string>(0), parseContext, errors);
const std::string& groupName = trim_wgname(keyword, record.getItem("GROUP").get<std::string>(0), parseContext, errors);
if (!hasGroup(groupName))
addGroup(groupName , currentStep, unit_system);
@ -1761,10 +1787,10 @@ namespace {
}
}
void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system) {
void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, const UnitSystem& unit_system, const ParseContext& parseContext, ErrorGuard& errors) {
for( const auto& record : keyword ) {
const std::string& childName = record.getItem("CHILD_GROUP").getTrimmedString(0);
const std::string& parentName = record.getItem("PARENT_GROUP").getTrimmedString(0);
const std::string& childName = trim_wgname(keyword, record.getItem("CHILD_GROUP").get<std::string>(0), parseContext, errors);
const std::string& parentName = trim_wgname(keyword, record.getItem("PARENT_GROUP").get<std::string>(0), parseContext, errors);
if (!hasGroup(parentName))
addGroup( parentName , currentStep, unit_system );

View File

@ -78,6 +78,7 @@ namespace Opm {
addKey(PARSE_EXTRA_DATA, InputError::THROW_EXCEPTION);
addKey(PARSE_MISSING_INCLUDE, InputError::EXIT1);
addKey(PARSE_LONG_KEYWORD, InputError::WARN);
addKey(PARSE_WGNAME_SPACE, InputError::THROW_EXCEPTION);
addKey(UNIT_SYSTEM_MISMATCH, InputError::THROW_EXCEPTION);
@ -315,6 +316,7 @@ namespace Opm {
const std::string ParseContext::PARSE_MISSING_SECTIONS = "PARSE_MISSING_SECTIONS";
const std::string ParseContext::PARSE_MISSING_INCLUDE = "PARSE_MISSING_INCLUDE";
const std::string ParseContext::PARSE_LONG_KEYWORD = "PARSE_LONG_KEYWORD";
const std::string ParseContext::PARSE_WGNAME_SPACE = "PARSE_WGNAME_SPACE";
const std::string ParseContext::UNIT_SYSTEM_MISMATCH = "UNIT_SYSTEM_MISMATCH";

View File

@ -6665,15 +6665,15 @@ TUNING
WELSPECS
'INJE1 ' 'P' 24 25 9110 'WATER' 60 /
'PRODU2 ' 'P' 5 1 9110 'OIL' 60 /
'PRODU3 ' 'P' 8 2 9110 'OIL' 60 /
'PRODU4 ' 'P' 11 3 9110 'OIL' 60 /
'PRODU5 ' 'P' 10 4 9110 'OIL' 60 /
'PRODU6 ' 'P' 12 5 9110 'OIL' 60 /
'PRODU7 ' 'P' 4 6 9110 'OIL' 60 /
'PRODU8 ' 'P' 8 7 9110 'OIL' 60 /
'PRODU9 ' 'P' 14 8 9110 'OIL' 60 /
'INJE1' 'P' 24 25 9110 'WATER' 60 /
'PRODU2' 'P' 5 1 9110 'OIL' 60 /
'PRODU3' 'P' 8 2 9110 'OIL' 60 /
'PRODU4' 'P' 11 3 9110 'OIL' 60 /
'PRODU5' 'P' 10 4 9110 'OIL' 60 /
'PRODU6' 'P' 12 5 9110 'OIL' 60 /
'PRODU7' 'P' 4 6 9110 'OIL' 60 /
'PRODU8' 'P' 8 7 9110 'OIL' 60 /
'PRODU9' 'P' 14 8 9110 'OIL' 60 /
'PRODU10' 'P' 11 9 9110 'OIL' 60 /
'PRODU11' 'P' 12 10 9110 'OIL' 60 /
'PRODU12' 'P' 10 11 9110 'OIL' 60 /

View File

@ -1094,6 +1094,58 @@ BOOST_AUTO_TEST_CASE(createDeckWithWPIMULT) {
BOOST_CHECK_EQUAL(year, 2011);
}
BOOST_AUTO_TEST_CASE(WELSPECS_WGNAME_SPACE) {
Opm::Parser parser;
const std::string input = R"(
START -- 0
10 'JAN' 2000 /
RUNSPEC
DIMENS
10 10 10 /
GRID
DX
1000*0.25 /
DY
1000*0.25 /
DZ
1000*0.25 /
TOPS
100*0.25 /
SCHEDULE
DATES -- 1
10 OKT 2008 /
/
WELSPECS
' PROD1' 'G1' 1 1 10 'OIL' /
'PROD2' 'G2' 2 2 10 'OIL' /
'PROD3' 'H1' 3 3 10 'OIL' /
/
GCONPROD
'G1' 'ORAT' 1000 /
/
DATES -- 2
10 NOV 2008 /
/
GCONPROD
'G*' 'ORAT' 2000 /
/
)";
auto deck = parser.parseString(input);
EclipseGrid grid( deck );
TableManager table ( deck );
Eclipse3DProperties eclipseProperties ( deck , table, grid);
Runspec runspec (deck);
ParseContext parseContext;
ErrorGuard errors;
parseContext.update(ParseContext::PARSE_WGNAME_SPACE, InputError::THROW_EXCEPTION);
BOOST_CHECK_THROW( Opm::Schedule(deck, grid, eclipseProperties, runspec, parseContext, errors), std::invalid_argument);
parseContext.update(ParseContext::PARSE_WGNAME_SPACE, InputError::IGNORE);
BOOST_CHECK_NO_THROW( Opm::Schedule(deck, grid, eclipseProperties, runspec, parseContext, errors));
}
BOOST_AUTO_TEST_CASE(createDeckModifyMultipleGCONPROD) {
Opm::Parser parser;
const std::string input = R"(

View File

@ -21,8 +21,7 @@ SCHEDULE
WELSPECS
'W_1' 'GROUP1' 30 37 1* 'OIL' 7* /
-- the spaces around the names are intentional!
' W_2 ' ' GROUP1 ' 20 51 1* 'OIL' 7* /
'W_2' 'GROUP1' 20 51 1* 'OIL' 7* /
/
TSTEP

View File

@ -23,8 +23,7 @@ SCHEDULE
GRUPTREE
'INJE' 'FIELD' /
-- the spaces around the names are intentional!
' PROD ' ' FIELD ' /
'PROD' 'FIELD' /
'MANI-PROD' 'PROD' /
'MANI-INJ' 'INJE' /
'DUMMY-PROD' 'MANI-PROD' /