ParseContext treatment of unknown wells/groups.

This commit is contained in:
Joakim Hove 2016-06-29 16:38:09 +02:00
parent 433b8ce73e
commit d3f415c5aa
9 changed files with 188 additions and 99 deletions

View File

@ -20,6 +20,7 @@
#include <memory>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Deck/Section.hpp>
#include <opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseConfig.hpp>
@ -35,11 +36,12 @@ namespace Opm {
EclipseConfig::EclipseConfig(const Deck& deck,
const Eclipse3DProperties& eclipse3DProperties,
const GridDims& inputGrid,
const Schedule& schedule) :
const Schedule& schedule,
const ParseContext& parseContext) :
m_ioConfig( std::make_shared<IOConfig>(deck)),
m_initConfig( std::make_shared<const InitConfig>(deck)),
m_simulationConfig(std::make_shared<const SimulationConfig>(deck, eclipse3DProperties)),
m_summaryConfig( deck, schedule, eclipse3DProperties, inputGrid.getNXYZ())
m_summaryConfig( deck, schedule, eclipse3DProperties, parseContext , inputGrid.getNXYZ())
{
// Hmmm - would have thought this should iterate through the SCHEDULE section as well?
if (Section::hasSOLUTION(deck)) {

View File

@ -32,7 +32,7 @@ namespace Opm {
class IOConfig;
class InitConfig;
class SimulationConfig;
class ParseContext;
class EclipseConfig
{
@ -40,7 +40,8 @@ namespace Opm {
EclipseConfig(const Deck& deck,
const Eclipse3DProperties& eclipse3DProperties,
const GridDims& gridDims,
const Schedule& schedule);
const Schedule& schedule,
const ParseContext& parseContext);
std::shared_ptr< const IOConfig > getIOConfigConst() const;
std::shared_ptr< IOConfig > getIOConfig() const;

View File

@ -61,7 +61,7 @@ namespace Opm {
m_inputGrid( std::make_shared<EclipseGrid>(deck, nullptr) ),
m_schedule( std::make_shared<Schedule>( m_parseContext, m_inputGrid, deck ) ),
m_eclipseProperties( deck, m_tables, *m_inputGrid ),
m_eclipseConfig( deck, m_eclipseProperties, m_gridDims, *m_schedule),
m_eclipseConfig( deck, m_eclipseProperties, m_gridDims, *m_schedule , parseContext),
m_inputNnc( deck, m_gridDims ),
m_deckUnitSystem( deck.getActiveUnitSystem() )
@ -148,6 +148,10 @@ namespace Opm {
return m_eclipseConfig.getInitConfig();
}
const EclipseConfig& EclipseState::getEclipseConfig() const {
return m_eclipseConfig;
}
SimulationConfigConstPtr EclipseState::getSimulationConfig() const {
return m_eclipseConfig.getSimulationConfig();
}

View File

@ -90,6 +90,7 @@ namespace Opm {
const Eclipse3DProperties& get3DProperties() const;
const TableManager& getTableManager() const;
const EclipseConfig& getEclipseConfig() const;
// the unit system used by the deck. note that it is rarely needed to convert
// units because internally to opm-parser everything is represented by SI

View File

@ -18,6 +18,8 @@
*/
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/MessageContainer.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
@ -37,6 +39,7 @@
#include <ert/ecl/ecl_smspec.h>
#include <iostream>
#include <algorithm>
#include <array>
#include <functional>
@ -64,37 +67,52 @@ namespace Opm {
return __ALL_expands_keywords;
}
/*
When the error handling config says that the error should be
logged, the handleMissingWell and handleMissingGroup routines
cheat. Ideally we should have a MessageContainer instance around
and pass that to the parseContext::handlError() routine. Instead
we:
1. We instantiate new MessageContainer() which is just
immediately dropped to floor, leaving the messages behind.
2. Print a message on stderr.
The case of incorrectly/missing well/group names in the SUMMARY
section did just not seem important enough to warrant the
refactoring required to pass a mutable proper MessageContainer
all the way down here.
*/
static void handleMissingWell( const ParseContext& parseContext , const std::string& keyword, const std::string& well) {
std::string msg = std::string("Error in keyword:") + keyword + std::string(" No such well: ") + well;
MessageContainer msgContainer;
if (parseContext.get( ParseContext::SUMMARY_UNKNOWN_WELL) == InputError::WARN)
std::cerr << "ERROR: " << msg << std::endl;
parseContext.handleError( ParseContext::SUMMARY_UNKNOWN_WELL , msgContainer , msg );
}
static void handleMissingGroup( const ParseContext& parseContext , const std::string& keyword, const std::string& group) {
std::string msg = std::string("Error in keyword:") + keyword + std::string(" No such group: ") + group;
MessageContainer msgContainer;
if (parseContext.get( ParseContext::SUMMARY_UNKNOWN_GROUP) == InputError::WARN)
std::cerr << "ERROR: " << msg << std::endl;
parseContext.handleError( ParseContext::SUMMARY_UNKNOWN_GROUP , msgContainer , msg );
}
template< typename T >
static std::string name( const T* x ) {
return x->name();
}
static inline std::vector< ERT::smspec_node > keywordW(
const DeckKeyword& keyword,
const Schedule& schedule ) {
const auto mknode = [&keyword]( const std::string& name ) {
return ERT::smspec_node( ECL_SMSPEC_WELL_VAR, name, keyword.name() );
};
const auto missing = [&schedule]( const std::string& name ) {
return !schedule.hasWell( name );
};
const auto& item = keyword.getDataRecord().getDataItem();
auto wnames = item.hasValue( 0 )
? item.getData< std::string >()
: fun::map( name< Well >, schedule.getWells() );
/* filter all requested names that were not in the Deck */
wnames.erase(
std::remove_if( wnames.begin(), wnames.end(), missing ),
wnames.end() );
return fun::map( mknode, wnames );
}
static inline std::vector< ERT::smspec_node > keywordW(
static inline std::vector< ERT::smspec_node > defaultW(
const std::string& keyword,
const Schedule& schedule ) {
@ -102,47 +120,60 @@ namespace Opm {
return ERT::smspec_node( ECL_SMSPEC_WELL_VAR, wname, keyword );
};
auto wnames = fun::map( name< Well >, schedule.getWells() );
return fun::map( mknode, wnames );
return fun::map( mknode, fun::map( name< Well >, schedule.getWells() ) );
}
static inline std::vector< ERT::smspec_node > keywordG(
const DeckKeyword& keyword,
const Schedule& schedule ) {
const auto mknode = [&keyword]( const std::string& name ) {
return ERT::smspec_node( ECL_SMSPEC_GROUP_VAR, name, keyword.name() );
};
const auto missing = [&schedule]( const std::string& name ) {
return !schedule.hasGroup( name );
};
static inline std::vector< ERT::smspec_node > keywordW(const ParseContext& parseContext,
const DeckKeyword& keyword,
const Schedule& schedule ) {
const auto& item = keyword.getDataRecord().getDataItem();
auto gnames = item.hasValue( 0 )
? item.getData< std::string >()
: fun::map( name< Group >, schedule.getGroups() );
gnames.erase(
std::remove_if( gnames.begin(), gnames.end(), missing ),
gnames.end() );
return fun::map( mknode, gnames );
if (item.hasValue( 0 )) {
std::vector<ERT::smspec_node> nodes;
for (const std::string& well : item.getData< std::string >()) {
if (schedule.hasWell( well ))
nodes.emplace_back( ECL_SMSPEC_WELL_VAR , well , keyword.name());
else
handleMissingWell( parseContext , keyword.name() , well );
}
return nodes;
} else
return defaultW( keyword.name() , schedule );
}
static inline std::vector< ERT::smspec_node > keywordG(
const std::string& keyword,
const Schedule& schedule ) {
const auto mknode = [&keyword]( const std::string& name ) {
return ERT::smspec_node( ECL_SMSPEC_GROUP_VAR, name, keyword );
static inline std::vector< ERT::smspec_node > defaultG(const std::string& keyword,
const Schedule& schedule ) {
const auto mknode = [&keyword]( const std::string& gname ) {
return ERT::smspec_node( ECL_SMSPEC_GROUP_VAR, gname, keyword );
};
auto gnames = fun::map( name< Group >, schedule.getGroups() );
return fun::map( mknode, gnames );
return fun::map( mknode, fun::map( name< Group >, schedule.getGroups() ) );
}
static inline std::vector< ERT::smspec_node > keywordG(const ParseContext& parseContext,
const DeckKeyword& keyword,
const Schedule& schedule ) {
const auto& item = keyword.getDataRecord().getDataItem();
if (item.hasValue( 0 )) {
std::vector<ERT::smspec_node> nodes;
for (const std::string& group : item.getData< std::string >()) {
if (schedule.hasGroup( group ))
nodes.emplace_back( ECL_SMSPEC_GROUP_VAR , group , keyword.name());
else
handleMissingGroup( parseContext , keyword.name() , group );
}
return nodes;
} else
return defaultG( keyword.name() , schedule );
}
static inline std::vector< ERT::smspec_node > keywordF(
const DeckKeyword& keyword ) {
@ -217,10 +248,10 @@ namespace Opm {
return fun::map( mknode, regions );
}
static inline std::vector< ERT::smspec_node > keywordC(
const DeckKeyword& keyword,
const Schedule& schedule,
std::array< int, 3 > dims ) {
static inline std::vector< ERT::smspec_node > keywordC(const ParseContext& parseContext,
const DeckKeyword& keyword,
const Schedule& schedule,
std::array< int, 3 > dims ) {
std::vector< ERT::smspec_node > nodes;
const auto& keywordstring = keyword.name();
@ -251,18 +282,22 @@ namespace Opm {
} else {
const auto& name = record.getItem( 0 ).get< std::string >( 0 );
/* all specified */
if( !record.getItem( 1 ).defaultApplied( 0 ) ) {
auto ijk = getijk( record, 1 );
nodes.emplace_back( keywordstring, name, dims.data(), ijk.data() );
}
else {
/* well specified, block coordinates defaulted */
for( const auto& completion : *schedule.getWell( name )->getCompletions( last_timestep ) ) {
auto ijk = getijk( *completion );
nodes.emplace_back( keywordstring, name, dims.data(), ijk.data() );
}
}
if (!schedule.hasWell( name ))
handleMissingWell( parseContext , keyword.name() , name );
else {
/* all specified */
if( !record.getItem( 1 ).defaultApplied( 0 ) ) {
auto ijk = getijk( record, 1 );
nodes.emplace_back( keywordstring, name, dims.data(), ijk.data() );
}
else {
/* well specified, block coordinates defaulted */
for( const auto& completion : *schedule.getWell( name )->getCompletions( last_timestep ) ) {
auto ijk = getijk( *completion );
nodes.emplace_back( keywordstring, name, dims.data(), ijk.data() );
}
}
}
}
}
@ -272,16 +307,17 @@ namespace Opm {
std::vector< ERT::smspec_node > handleKW( const DeckKeyword& keyword,
const Schedule& schedule,
const Eclipse3DProperties& props,
const ParseContext& parseContext,
std::array< int, 3 > n_xyz ) {
const auto var_type = ecl_smspec_identify_var_type( keyword.name().c_str() );
switch( var_type ) {
case ECL_SMSPEC_WELL_VAR: return keywordW( keyword, schedule );
case ECL_SMSPEC_GROUP_VAR: return keywordG( keyword, schedule );
case ECL_SMSPEC_WELL_VAR: return keywordW( parseContext , keyword, schedule );
case ECL_SMSPEC_GROUP_VAR: return keywordG( parseContext , keyword, schedule );
case ECL_SMSPEC_FIELD_VAR: return keywordF( keyword );
case ECL_SMSPEC_BLOCK_VAR: return keywordB( keyword, n_xyz );
case ECL_SMSPEC_REGION_VAR: return keywordR( keyword, props, n_xyz );
case ECL_SMSPEC_COMPLETION_VAR: return keywordC( keyword, schedule, n_xyz );
case ECL_SMSPEC_COMPLETION_VAR: return keywordC( parseContext , keyword, schedule, n_xyz );
default: return {};
}
@ -296,10 +332,10 @@ namespace Opm {
const auto var_type = ecl_smspec_identify_var_type(keyword.c_str());
switch (var_type) {
case ECL_SMSPEC_WELL_VAR:
for(auto&k :keywordW(keyword, schedule)) all.push_back(k);
for(auto&k :defaultW(keyword, schedule)) all.push_back(k);
break;
case ECL_SMSPEC_GROUP_VAR:
for(auto& k:keywordG(keyword, schedule)) all.push_back(k);
for(auto& k:defaultG(keyword, schedule)) all.push_back(k);
break;
case ECL_SMSPEC_FIELD_VAR:
for(auto& k:keywordF(keyword)) all.push_back(k);
@ -315,22 +351,24 @@ namespace Opm {
return all;
}
SummaryConfig::SummaryConfig( const Deck& deck, const EclipseState& es )
SummaryConfig::SummaryConfig( const Deck& deck, const EclipseState& es , const ParseContext& parseContext)
: SummaryConfig( deck,
*es.getSchedule(),
es.get3DProperties(),
parseContext,
dimensions( *es.getInputGrid() ) )
{}
SummaryConfig::SummaryConfig( const Deck& deck,
const Schedule& schedule,
const Eclipse3DProperties& props,
const ParseContext& parseContext,
std::array< int, 3 > n_xyz ) {
SUMMARYSection section( deck );
using namespace std::placeholders;
const auto handler = std::bind( handleKW, _1, schedule, props, n_xyz );
const auto handler = std::bind( handleKW, _1, schedule, props, parseContext , n_xyz );
/* This line of code does not compile on VS2015
* this->keywords = fun::concat( fun::map( handler, section ) );

View File

@ -32,16 +32,17 @@ namespace Opm {
class EclipseState;
class ParserKeyword;
class Schedule;
class ParseContext;
class SummaryConfig {
public:
typedef std::vector< ERT::smspec_node >::const_iterator const_iterator;
SummaryConfig( const Deck&, const EclipseState& );
SummaryConfig( const Deck&, const EclipseState& , const ParseContext& );
SummaryConfig( const Deck&, const Schedule&,
const Eclipse3DProperties&, std::array< int, 3 > );
const Eclipse3DProperties&, const ParseContext&, std::array< int, 3 > );
SummaryConfig( const Deck&, const Schedule&,
const Eclipse3DProperties&, int, int, int );
const Eclipse3DProperties&, const ParseContext&, int, int, int );
const_iterator begin() const;
const_iterator end() const;

View File

@ -95,10 +95,10 @@ static std::vector< std::string > sorted_key_names( const SummaryConfig& summary
return ret;
}
static SummaryConfig createSummary( std::string input ) {
static SummaryConfig createSummary( std::string input , const ParseContext& parseContext = ParseContext()) {
auto deck = createDeck( input );
EclipseState state( deck, ParseContext() );
return SummaryConfig( *deck, state );
EclipseState state( deck, parseContext );
return state.getEclipseConfig().getSummaryConfig();
}
BOOST_AUTO_TEST_CASE(wells_all) {
@ -124,16 +124,6 @@ BOOST_AUTO_TEST_CASE(wells_select) {
names.begin(), names.end() );
}
BOOST_AUTO_TEST_CASE(wells_select_unknown_well) {
const auto input = "WWCT\n'W_1' 'WX2' 'unknown'/\n";
const auto summary = createSummary( input );
const auto wells = { "WX2", "W_1" };
const auto names = sorted_names( summary );
BOOST_CHECK_EQUAL_COLLECTIONS(
wells.begin(), wells.end(),
names.begin(), names.end() );
}
BOOST_AUTO_TEST_CASE(fields) {
const auto input = "FOPT\n";
@ -234,3 +224,41 @@ BOOST_AUTO_TEST_CASE(summary_ALL) {
key_names.begin(), key_names.end());
}
BOOST_AUTO_TEST_CASE(INVALID_WELL1) {
ParseContext parseContext;
const auto input = "CWIR\n"
"NEW-WELL /\n"
"/\n";
parseContext.updateKey( ParseContext::SUMMARY_UNKNOWN_WELL , InputError::THROW_EXCEPTION );
BOOST_CHECK_THROW( createSummary( input , parseContext ) , std::invalid_argument);
parseContext.updateKey( ParseContext::SUMMARY_UNKNOWN_WELL , InputError::IGNORE );
BOOST_CHECK_NO_THROW( createSummary( input , parseContext ))
}
BOOST_AUTO_TEST_CASE(INVALID_WELL2) {
ParseContext parseContext;
const auto input = "WWCT\n"
" NEW-WELL /\n";
parseContext.updateKey( ParseContext::SUMMARY_UNKNOWN_WELL , InputError::THROW_EXCEPTION );
BOOST_CHECK_THROW( createSummary( input , parseContext ) , std::invalid_argument);
parseContext.updateKey( ParseContext::SUMMARY_UNKNOWN_WELL , InputError::IGNORE );
BOOST_CHECK_NO_THROW( createSummary( input , parseContext ))
}
BOOST_AUTO_TEST_CASE(INVALID_GROUP) {
ParseContext parseContext;
const auto input = "GWCT\n"
" NEW-GR /\n";
parseContext.updateKey( ParseContext::SUMMARY_UNKNOWN_GROUP , InputError::THROW_EXCEPTION );
BOOST_CHECK_THROW( createSummary( input , parseContext ) , std::invalid_argument);
parseContext.updateKey( ParseContext::SUMMARY_UNKNOWN_GROUP , InputError::IGNORE );
BOOST_CHECK_NO_THROW( createSummary( input , parseContext ))
}

View File

@ -69,6 +69,9 @@ namespace Opm {
addKey(UNSUPPORTED_INITIAL_THPRES);
addKey(INTERNAL_ERROR_UNINITIALIZED_THPRES);
addKey(SUMMARY_UNKNOWN_WELL);
addKey(SUMMARY_UNKNOWN_GROUP);
}
void ParseContext::initEnv() {
@ -242,6 +245,9 @@ namespace Opm {
const std::string ParseContext::INTERNAL_ERROR_UNINITIALIZED_THPRES = "INTERNAL_ERROR_UNINITIALIZED_THPRES";
const std::string ParseContext::PARSE_MISSING_SECTIONS = "PARSE_MISSING_SECTIONS";
const std::string ParseContext::SUMMARY_UNKNOWN_WELL = "SUMMARY_UNKNOWN_WELL";
const std::string ParseContext::SUMMARY_UNKNOWN_GROUP = "SUMMARY_UNKNOWN_GROUP";
}

View File

@ -207,6 +207,14 @@ namespace Opm {
*/
const static std::string PARSE_MISSING_SECTIONS;
/*
If you have configured a specific well in the summary section,
which is not recognized - how to handle.
*/
const static std::string SUMMARY_UNKNOWN_WELL;
const static std::string SUMMARY_UNKNOWN_GROUP;
private:
void initDefault();
void initEnv();