diff --git a/opm/parser/eclipse/Deck/Section.cpp b/opm/parser/eclipse/Deck/Section.cpp index daed8dbc8..6a9783091 100644 --- a/opm/parser/eclipse/Deck/Section.cpp +++ b/opm/parser/eclipse/Deck/Section.cpp @@ -49,10 +49,11 @@ namespace Opm { }; auto first = std::find_if( deck.begin(), deck.end(), fn ); - if( first == deck.end() ) - throw std::invalid_argument( std::string( "Deck requires a '" ) + keyword + "' section" ); - auto last = std::find_if( first + 1, deck.end(), &isSectionDelimiter ); + if( first == deck.end() ) + return { first, first }; + + auto last = std::find_if( first + 1, deck.end(), isSectionDelimiter ); if( last != deck.end() && last->name() == keyword ) throw std::invalid_argument( std::string( "Deck contains the '" ) + keyword + "' section multiple times" ); diff --git a/opm/parser/eclipse/Deck/tests/SectionTests.cpp b/opm/parser/eclipse/Deck/tests/SectionTests.cpp index d6d42cb94..acc5163d5 100644 --- a/opm/parser/eclipse/Deck/tests/SectionTests.cpp +++ b/opm/parser/eclipse/Deck/tests/SectionTests.cpp @@ -77,7 +77,7 @@ BOOST_AUTO_TEST_CASE(IteratorTest) { BOOST_AUTO_TEST_CASE(RUNSPECSection_EmptyDeck) { DeckPtr deck(new Deck()); - BOOST_REQUIRE_THROW(RUNSPECSection section(*deck), std::invalid_argument); + BOOST_REQUIRE_NO_THROW(RUNSPECSection section(*deck)); } BOOST_AUTO_TEST_CASE(RUNSPECSection_ReadSimpleDeck) { diff --git a/opm/parser/eclipse/EclipseState/Eclipse3DProperties.cpp b/opm/parser/eclipse/EclipseState/Eclipse3DProperties.cpp index ade8adfdd..66818f927 100644 --- a/opm/parser/eclipse/EclipseState/Eclipse3DProperties.cpp +++ b/opm/parser/eclipse/EclipseState/Eclipse3DProperties.cpp @@ -449,6 +449,17 @@ namespace Opm { } } + std::vector< int > Eclipse3DProperties::getRegions( const std::string& kw ) const { + if( !this->hasDeckIntGridProperty( kw ) ) return {}; + + const auto& property = this->getIntGridProperty( kw ); + + std::set< int > regions( property.getData().begin(), + property.getData().end() ); + + return { regions.begin(), regions.end() }; + } + /// Due to the post processor which might be applied to the GridProperty /// objects it is essential that this method use the m_intGridProperties / /// m_doubleGridProperties fields directly and *NOT* use the public methods diff --git a/opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp b/opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp index 273ddb3ea..4efdb07e0 100644 --- a/opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp +++ b/opm/parser/eclipse/EclipseState/Eclipse3DProperties.hpp @@ -61,6 +61,7 @@ namespace Opm { const GridProperty& getRegion(const DeckItem& regionItem) const; + std::vector< int > getRegions( const std::string& keyword ) const; std::string getDefaultRegionKeyword() const; const GridProperty& getIntGridProperty ( const std::string& keyword ) const; diff --git a/opm/parser/eclipse/EclipseState/EclipseState.cpp b/opm/parser/eclipse/EclipseState/EclipseState.cpp index b0105a1ce..f1a0738a2 100644 --- a/opm/parser/eclipse/EclipseState/EclipseState.cpp +++ b/opm/parser/eclipse/EclipseState/EclipseState.cpp @@ -49,25 +49,39 @@ namespace Opm { + static IOConfig mkIOConfig( const Deck& deck ) { + IOConfig config( deck.getDataFile() ); + + if( Section::hasGRID( deck ) ) + config.handleGridSection( GRIDSection( deck ) ); + + if( Section::hasRUNSPEC( deck ) ) + config.handleRunspecSection( RUNSPECSection( deck ) ); + + return config; + } EclipseState::EclipseState(std::shared_ptr deckptr, ParseContext parseContext) : EclipseState(*deckptr, parseContext) {} EclipseState::EclipseState(const Deck& deck, ParseContext parseContext) : - m_deckUnitSystem( deck.getActiveUnitSystem() ), m_parseContext( parseContext ), + m_ioConfig( std::make_shared< IOConfig >( mkIOConfig( deck ) ) ), m_tables( deck ), - m_inputGrid( std::make_shared(deck, nullptr)), - m_eclipseProperties( deck, m_tables, *m_inputGrid) + m_inputGrid( std::make_shared(deck, nullptr) ), + m_eclipseProperties( deck, m_tables, *m_inputGrid ), + m_schedule( std::make_shared( m_parseContext, m_inputGrid, deck, m_ioConfig ) ), + m_simulationConfig( std::make_shared( m_parseContext, deck, m_eclipseProperties ) ), + m_summaryConfig( deck, *m_schedule, m_eclipseProperties, m_inputGrid->getNXYZ() ), + m_nnc( deck, m_inputGrid ), + m_deckUnitSystem( deck.getActiveUnitSystem() ) + { // after Eclipse3DProperties has been constructed, we have complete ACTNUM info if (m_eclipseProperties.hasDeckIntGridProperty("ACTNUM")) m_inputGrid->resetACTNUM(m_eclipseProperties.getIntGridProperty("ACTNUM").getData().data()); - initIOConfig(deck); - - m_schedule = ScheduleConstPtr(new Schedule(m_parseContext, getInputGrid(), deck, m_ioConfig)); initIOConfigPostSchedule(deck); if (deck.hasKeyword( "TITLE" )) { @@ -77,14 +91,9 @@ namespace Opm { m_title = boost::algorithm::join( itemValue, " " ); } - m_initConfig = std::make_shared(deck); - m_simulationConfig = std::make_shared(m_parseContext, deck, - m_eclipseProperties); - initTransMult(); initFaults(deck); initMULTREGT(deck); - m_nnc = NNC(deck, getInputGrid()); m_messageContainer.appendMessages(m_tables.getMessageContainer()); m_messageContainer.appendMessages(m_schedule->getMessageContainer()); @@ -104,6 +113,10 @@ namespace Opm { return std::make_shared( m_inputGrid->c_ptr() ); } + const SummaryConfig& EclipseState::getSummaryConfig() const { + return this->m_summaryConfig; + } + const Eclipse3DProperties& EclipseState::get3DProperties() const { return m_eclipseProperties; } @@ -166,20 +179,6 @@ namespace Opm { return m_title; } - void EclipseState::initIOConfig(const Deck& deck) { - std::string dataFile = deck.getDataFile(); - m_ioConfig = std::make_shared(dataFile); - - if (Section::hasGRID(deck)) { - auto gridSection = std::make_shared(deck); - m_ioConfig->handleGridSection(gridSection); - } - if (Section::hasRUNSPEC(deck)) { - auto runspecSection = std::make_shared(deck); - m_ioConfig->handleRunspecSection(runspecSection); - } - } - // Hmmm - would have thought this should iterate through the SCHEDULE section as well? void EclipseState::initIOConfigPostSchedule(const Deck& deck) { if (Section::hasSOLUTION(deck)) { @@ -261,17 +260,6 @@ namespace Opm { } - std::vector< int > EclipseState::getRegions( const std::string& kw ) const { - if( !this->get3DProperties().hasDeckIntGridProperty( kw ) ) return {}; - - const auto& property = this->get3DProperties().getIntGridProperty( kw ); - - std::set< int > regions( property.getData().begin(), - property.getData().end() ); - - return { regions.begin(), regions.end() }; - } - void EclipseState::complainAboutAmbiguousKeyword(const Deck& deck, const std::string& keywordName) { m_messageContainer.error("The " + keywordName + " keyword must be unique in the deck. Ignoring all!"); diff --git a/opm/parser/eclipse/EclipseState/EclipseState.hpp b/opm/parser/eclipse/EclipseState/EclipseState.hpp index 9228800c7..fac310174 100644 --- a/opm/parser/eclipse/EclipseState/EclipseState.hpp +++ b/opm/parser/eclipse/EclipseState/EclipseState.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -82,6 +83,7 @@ namespace Opm { std::shared_ptr< const SimulationConfig > getSimulationConfig() const; std::shared_ptr< const EclipseGrid > getInputGrid() const; std::shared_ptr< EclipseGrid > getInputGridCopy() const; + const SummaryConfig& getSummaryConfig() const; const MessageContainer& getMessageContainer() const; MessageContainer& getMessageContainer(); std::string getTitle() const; @@ -95,8 +97,6 @@ namespace Opm { const TableManager& getTableManager() const; - std::vector< int > getRegions( const std::string& kw ) 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 // units... @@ -107,7 +107,6 @@ namespace Opm { void applyModifierDeck(const Deck& deck); private: - void initIOConfig(const Deck& deck); void initIOConfigPostSchedule(const Deck& deck); void initTransMult(); void initFaults(const Deck& deck); @@ -118,23 +117,23 @@ namespace Opm { void complainAboutAmbiguousKeyword(const Deck& deck, const std::string& keywordName); + ParseContext m_parseContext; std::shared_ptr< IOConfig > m_ioConfig; std::shared_ptr< const InitConfig > m_initConfig; - std::shared_ptr< const Schedule > m_schedule; + const TableManager m_tables; + std::shared_ptr m_inputGrid; + Eclipse3DProperties m_eclipseProperties; + std::shared_ptr< const Schedule > m_schedule; std::shared_ptr< const SimulationConfig > m_simulationConfig; + SummaryConfig m_summaryConfig; std::string m_title; std::shared_ptr m_transMult; FaultCollection m_faults; NNC m_nnc; - - const UnitSystem& m_deckUnitSystem; - const ParseContext m_parseContext; - const TableManager m_tables; - std::shared_ptr m_inputGrid; - Eclipse3DProperties m_eclipseProperties; MessageContainer m_messageContainer; + const UnitSystem& m_deckUnitSystem; }; typedef std::shared_ptr EclipseStatePtr; diff --git a/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp b/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp index 97ae10316..f6be503ea 100644 --- a/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp +++ b/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.cpp @@ -267,6 +267,10 @@ namespace Opm { return m_nz; } + std::array< int, 3 > EclipseGrid::getNXYZ() const { + return {{ int( m_nx ), int( m_ny ), int( m_nz ) }}; + } + size_t EclipseGrid::getCartesianSize( ) const { return m_nx * m_ny * m_nz; } diff --git a/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp b/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp index c853bcbcd..0b6aae68b 100644 --- a/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp +++ b/opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp @@ -87,6 +87,7 @@ namespace Opm { size_t getNX( ) const; size_t getNY( ) const; size_t getNZ( ) const; + std::array< int, 3 > getNXYZ() const; size_t getCartesianSize( ) const; bool isPinchActive( ) const; double getPinchThresholdThickness( ) const; diff --git a/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp b/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp index 132780361..4b23b23cd 100644 --- a/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp +++ b/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.cpp @@ -295,11 +295,11 @@ namespace Opm { - void IOConfig::handleGridSection(std::shared_ptr gridSection) { - m_write_INIT_file = gridSection->hasKeyword("INIT"); + void IOConfig::handleGridSection( const GRIDSection& gridSection) { + m_write_INIT_file = gridSection.hasKeyword("INIT"); - if (gridSection->hasKeyword("GRIDFILE")) { - const auto& gridfilekeyword = gridSection->getKeyword("GRIDFILE"); + if (gridSection.hasKeyword("GRIDFILE")) { + const auto& gridfilekeyword = gridSection.getKeyword("GRIDFILE"); if (gridfilekeyword.size() > 0) { const auto& rec = gridfilekeyword.getRecord(0); const auto& item1 = rec.getItem(0); @@ -314,17 +314,17 @@ namespace Opm { } } } - if (gridSection->hasKeyword("NOGGF")) { + if (gridSection.hasKeyword("NOGGF")) { m_write_EGRID_file = false; } } - void IOConfig::handleRunspecSection(std::shared_ptr runspecSection) { - m_FMTIN = runspecSection->hasKeyword("FMTIN"); //Input files are formatted - m_FMTOUT = runspecSection->hasKeyword("FMTOUT"); //Output files are to be formatted - m_UNIFIN = runspecSection->hasKeyword("UNIFIN"); //Input files are unified - m_UNIFOUT = runspecSection->hasKeyword("UNIFOUT"); //Output files are to be unified + void IOConfig::handleRunspecSection( const RUNSPECSection& runspecSection) { + m_FMTIN = runspecSection.hasKeyword("FMTIN"); //Input files are formatted + m_FMTOUT = runspecSection.hasKeyword("FMTOUT"); //Output files are to be formatted + m_UNIFIN = runspecSection.hasKeyword("UNIFIN"); //Input files are unified + m_UNIFOUT = runspecSection.hasKeyword("UNIFOUT"); //Output files are to be unified } diff --git a/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp b/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp index cf09f8b43..921660fdd 100644 --- a/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp +++ b/opm/parser/eclipse/EclipseState/IOConfig/IOConfig.hpp @@ -142,8 +142,8 @@ namespace Opm { bool reset_global = false); void handleRPTSCHEDRestart(std::shared_ptr< const TimeMap > timemap, size_t timestep, size_t restart); void handleSolutionSection(std::shared_ptr< const TimeMap > timemap, std::shared_ptr solutionSection); - void handleGridSection(std::shared_ptr gridSection); - void handleRunspecSection(std::shared_ptr runspecSection); + void handleGridSection( const GRIDSection& ); + void handleRunspecSection( const RUNSPECSection& ); void setWriteInitialRestartFile(bool writeInitialRestartFile); /// This method will internalize variables with information of diff --git a/opm/parser/eclipse/EclipseState/IOConfig/tests/IOConfigTest.cpp b/opm/parser/eclipse/EclipseState/IOConfig/tests/IOConfigTest.cpp index 652e3e6b3..7e93d829b 100644 --- a/opm/parser/eclipse/EclipseState/IOConfig/tests/IOConfigTest.cpp +++ b/opm/parser/eclipse/EclipseState/IOConfig/tests/IOConfigTest.cpp @@ -209,8 +209,8 @@ BOOST_AUTO_TEST_CASE(IOConfigTest) { IOConfigPtr ioConfigPtr; BOOST_CHECK_NO_THROW(ioConfigPtr = std::make_shared()); - std::shared_ptr gridSection = std::make_shared(*deck); - std::shared_ptr runspecSection = std::make_shared(*deck); + GRIDSection gridSection( *deck ); + RUNSPECSection runspecSection( *deck ); ioConfigPtr->handleGridSection(gridSection); ioConfigPtr->handleRunspecSection(runspecSection); @@ -433,8 +433,8 @@ BOOST_AUTO_TEST_CASE(IOConfigTest) { IOConfigPtr ioConfigPtr3; BOOST_CHECK_NO_THROW(ioConfigPtr3 = std::make_shared()); - std::shared_ptr gridSection3 = std::make_shared(*deck3); - std::shared_ptr runspecSection3 = std::make_shared(*deck3); + GRIDSection gridSection3( *deck3 ); + RUNSPECSection runspecSection3( *deck3 ); ioConfigPtr3->handleGridSection(gridSection3); ioConfigPtr3->handleRunspecSection(runspecSection3); @@ -454,8 +454,8 @@ BOOST_AUTO_TEST_CASE(IOConfigTest) { IOConfigPtr ioConfigPtr4; BOOST_CHECK_NO_THROW(ioConfigPtr4 = std::make_shared()); - std::shared_ptr gridSection4 = std::make_shared(*deck4); - std::shared_ptr runspecSection4 = std::make_shared(*deck4); + GRIDSection gridSection4( *deck4 ); + RUNSPECSection runspecSection4( *deck4 ); ioConfigPtr4->handleGridSection(gridSection4); ioConfigPtr4->handleRunspecSection(runspecSection4); diff --git a/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.cpp b/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.cpp index f5df162a5..43ef9f97f 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.cpp +++ b/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.cpp @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -46,11 +45,7 @@ namespace Opm { { } - std::vector Compsegs::compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword, - EclipseGridConstPtr grid) { - // the thickness of grid cells will be required in the future for more complete support. - // Silence warning about unused argument - static_cast(grid); + std::vector Compsegs::compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword ) { // only handle the second record here // The first record here only contains the well name diff --git a/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.hpp b/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.hpp index a8fb3c10d..0ca8a0158 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/MSW/Compsegs.hpp @@ -30,7 +30,6 @@ namespace Opm { class CompletionSet; class DeckKeyword; - class EclipseGrid; class SegmentSet; struct Compsegs { @@ -53,8 +52,7 @@ namespace Opm { Compsegs(int i_in, int j_in, int k_in, int branch_number_in, double distance_start_in, double distance_end_in, WellCompletion::DirectionEnum dir_in, double center_depth_in, int segment_number_in); - static std::vector> compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword, - std::shared_ptr< const EclipseGrid > grid); + static std::vector> compsegsFromCOMPSEGSKeyword( const DeckKeyword& compsegsKeyword ); // get the segment number information and depth information based on the information from SegmentSet static void processCOMPSEGS(std::vector>& compsegs, std::shared_ptr< const SegmentSet > segment_set); diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index ba3579136..05fcbb025 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -1312,7 +1312,7 @@ namespace Opm { const std::string& well_name = record1.getItem("WELL").getTrimmedString(0); WellPtr well = getWell(well_name); - std::vector compsegs_vector = Compsegs::compsegsFromCOMPSEGSKeyword(keyword, m_grid); + std::vector compsegs_vector = Compsegs::compsegsFromCOMPSEGSKeyword( keyword ); SegmentSetConstPtr current_segmentSet = well->getSegmentSet(currentStep); Compsegs::processCOMPSEGS(compsegs_vector, current_segmentSet); diff --git a/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp b/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp index 214621377..2861f556a 100644 --- a/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp +++ b/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.cpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -38,6 +39,7 @@ #include #include +#include namespace Opm { @@ -52,30 +54,29 @@ namespace Opm { static inline std::vector< ERT::smspec_node > keywordWG( ecl_smspec_var_type var_type, const DeckKeyword& keyword, - const EclipseState& es ) { + const Schedule& schedule ) { const auto mknode = [&keyword,var_type]( const std::string& name ) { return ERT::smspec_node( var_type, name, keyword.name() ); }; - const auto find = []( ecl_smspec_var_type v, const EclipseState& est ) { + const auto find = []( ecl_smspec_var_type v, const Schedule& sc ) { if( v == ECL_SMSPEC_WELL_VAR ) - return fun::map( wellName, est.getSchedule()->getWells() ); + return fun::map( wellName, sc.getWells() ); else - return fun::map( groupName, est.getSchedule()->getGroups() ); + return fun::map( groupName, sc.getGroups() ); }; const auto& item = keyword.getDataRecord().getDataItem(); const auto wgnames = item.size() > 0 && item.hasValue( 0 ) ? item.getData< std::string >() - : find( var_type, es ); + : find( var_type, schedule ); return fun::map( mknode, wgnames ); } static inline std::vector< ERT::smspec_node > keywordF( - const DeckKeyword& keyword, - const EclipseState& /* es */ ) { + const DeckKeyword& keyword ) { std::vector< ERT::smspec_node > res; res.push_back( ERT::smspec_node( keyword.name() ) ); @@ -106,11 +107,9 @@ namespace Opm { static inline std::vector< ERT::smspec_node > keywordB( const DeckKeyword& keyword, - const EclipseState& es ) { + std::array< int, 3 > dims ) { - auto dims = dimensions( *es.getInputGrid() ); - - const auto mkrecord = [&dims,&keyword]( const DeckRecord& record ) { + const auto mkrecord = [dims,&keyword]( const DeckRecord& record ) { auto ijk = getijk( record ); return ERT::smspec_node( keyword.name(), dims.data(), ijk.data() ); }; @@ -120,36 +119,40 @@ namespace Opm { static inline std::vector< ERT::smspec_node > keywordR( const DeckKeyword& keyword, - const EclipseState& es ) { + const Eclipse3DProperties& props, + std::array< int, 3 > dims ) { - auto dims = dimensions( *es.getInputGrid() ); + /* RUNSUM is not a region keyword but a directive for how to format and + * print output. Unfortunately its *recognised* as a region keyword + * because of its structure and position. Hence the special handling of ignoring it. + */ + if( keyword.name() == "RUNSUM" ) return {}; - const auto mknode = [&dims,&keyword]( int region ) { + const auto mknode = [dims,&keyword]( int region ) { return ERT::smspec_node( keyword.name(), dims.data(), region ); }; const auto& item = keyword.getDataRecord().getDataItem(); const auto regions = item.size() > 0 && item.hasValue( 0 ) ? item.getData< int >() - : es.getRegions( "FIPNUM" ); + : props.getRegions( "FIPNUM" ); return fun::map( mknode, regions ); } static inline std::vector< ERT::smspec_node > keywordC( const DeckKeyword& keyword, - const EclipseState& es ) { + const Schedule& schedule, + std::array< int, 3 > dims ) { std::vector< ERT::smspec_node > nodes; const auto& keywordstring = keyword.name(); - const auto& schedule = es.getSchedule(); - const auto last_timestep = schedule->getTimeMap()->last(); - auto dims = dimensions( *es.getInputGrid() ); + const auto last_timestep = schedule.getTimeMap()->last(); for( const auto& record : keyword ) { if( record.getItem( 0 ).defaultApplied( 0 ) ) { - for( const auto& well : schedule->getWells() ) { + for( const auto& well : schedule.getWells() ) { const auto& name = wellName( well ); @@ -178,7 +181,7 @@ namespace Opm { } else { /* well specified, block coordinates defaulted */ - for( const auto& completion : *schedule->getWell( name ).getCompletions( last_timestep ) ) { + for( const auto& completion : *schedule.getWell( name ).getCompletions( last_timestep ) ) { auto ijk = getijk( *completion ); nodes.emplace_back( keywordstring, name, dims.data(), ijk.data() ); } @@ -189,27 +192,40 @@ namespace Opm { return nodes; } - std::vector< ERT::smspec_node > handleKW( const DeckKeyword& keyword, const EclipseState& es ) { + std::vector< ERT::smspec_node > handleKW( const DeckKeyword& keyword, + const Schedule& schedule, + const Eclipse3DProperties& props, + 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: /* intentional fall-through */ - case ECL_SMSPEC_GROUP_VAR: return keywordWG( var_type, keyword, es ); - case ECL_SMSPEC_FIELD_VAR: return keywordF( keyword, es ); - case ECL_SMSPEC_BLOCK_VAR: return keywordB( keyword, es ); - case ECL_SMSPEC_REGION_VAR: return keywordR( keyword, es ); - case ECL_SMSPEC_COMPLETION_VAR: return keywordC( keyword, es ); + case ECL_SMSPEC_GROUP_VAR: return keywordWG( var_type, 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 ); default: return {}; } } - SummaryConfig::SummaryConfig( const Deck& deck, const EclipseState& es ) { + SummaryConfig::SummaryConfig( const Deck& deck, const EclipseState& es ) + : SummaryConfig( deck, + *es.getSchedule(), + es.get3DProperties(), + dimensions( *es.getInputGrid() ) ) + {} + + SummaryConfig::SummaryConfig( const Deck& deck, + const Schedule& schedule, + const Eclipse3DProperties& props, + std::array< int, 3 > n_xyz ) { SUMMARYSection section( deck ); - const auto handler = [&es]( const DeckKeyword& kw ) { - return handleKW( kw, es ); - }; + + using namespace std::placeholders; + const auto handler = std::bind( handleKW, _1, schedule, props, n_xyz ); this->keywords = fun::concat( fun::map( handler, section ) ); } diff --git a/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp b/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp index 466efd66a..06ee4c500 100644 --- a/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp +++ b/opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp @@ -20,6 +20,7 @@ #ifndef OPM_SUMMARY_CONFIG_HPP #define OPM_SUMMARY_CONFIG_HPP +#include #include #include @@ -27,14 +28,20 @@ namespace Opm { class Deck; + class Eclipse3DProperties; class EclipseState; class ParserKeyword; + class Schedule; class SummaryConfig { public: typedef std::vector< ERT::smspec_node >::const_iterator const_iterator; SummaryConfig( const Deck&, const EclipseState& ); + SummaryConfig( const Deck&, const Schedule&, + const Eclipse3DProperties&, std::array< int, 3 > ); + SummaryConfig( const Deck&, const Schedule&, + const Eclipse3DProperties&, int, int, int ); const_iterator begin() const; const_iterator end() const; diff --git a/opm/parser/eclipse/EclipseState/tests/Eclipse3DPropertiesTests.cpp b/opm/parser/eclipse/EclipseState/tests/Eclipse3DPropertiesTests.cpp index e735f30ab..70467a6be 100644 --- a/opm/parser/eclipse/EclipseState/tests/Eclipse3DPropertiesTests.cpp +++ b/opm/parser/eclipse/EclipseState/tests/Eclipse3DPropertiesTests.cpp @@ -235,3 +235,31 @@ BOOST_AUTO_TEST_CASE(PermxUnitAppliedCorrectly) { BOOST_CHECK_CLOSE(4 * Opm::Metric::Permeability, permx.iget(i, j, 0), 0.0001); } } + +BOOST_AUTO_TEST_CASE(getRegions) { + const char* input = + "START -- 0 \n" + "10 MAI 2007 / \n" + "RUNSPEC\n" + "\n" + "DIMENS\n" + " 2 2 1 /\n" + "GRID\n" + "DXV \n 2*400 /\n" + "DYV \n 2*400 /\n" + "DZV \n 1*400 /\n" + "REGIONS\n" + "FIPNUM\n" + "1 1 2 3 /\n"; + + auto deck = Opm::Parser().parseString(input, Opm::ParseContext()); + Setup s( deck ); + + std::vector< int > ref = { 1, 2, 3 }; + const auto regions = s.props.getRegions( "FIPNUM" ); + + BOOST_CHECK_EQUAL_COLLECTIONS( ref.begin(), ref.end(), + regions.begin(), regions.end() ); + + BOOST_CHECK( s.props.getRegions( "EQLNUM" ).empty() ); +} diff --git a/opm/parser/eclipse/EclipseState/tests/EclipseStateTests.cpp b/opm/parser/eclipse/EclipseState/tests/EclipseStateTests.cpp index df6fd8779..d9bde9ac8 100644 --- a/opm/parser/eclipse/EclipseState/tests/EclipseStateTests.cpp +++ b/opm/parser/eclipse/EclipseState/tests/EclipseStateTests.cpp @@ -584,31 +584,3 @@ BOOST_AUTO_TEST_CASE(TestIOConfigCreationWithSolutionRPTSOL) { BOOST_CHECK_EQUAL(true, ioConfig->getWriteRestartFile(0)); } } - -BOOST_AUTO_TEST_CASE(getRegions) { - const char* input = - "START -- 0 \n" - "10 MAI 2007 / \n" - "RUNSPEC\n" - "\n" - "DIMENS\n" - " 2 2 1 /\n" - "GRID\n" - "DXV \n 2*400 /\n" - "DYV \n 2*400 /\n" - "DZV \n 1*400 /\n" - "REGIONS\n" - "FIPNUM\n" - "1 1 2 3 /\n"; - - const auto deck = Parser().parseString(input, ParseContext()); - EclipseState es( deck, ParseContext() ); - - std::vector< int > ref = { 1, 2, 3 }; - const auto regions = es.getRegions( "FIPNUM" ); - - BOOST_CHECK_EQUAL_COLLECTIONS( ref.begin(), ref.end(), - regions.begin(), regions.end() ); - - BOOST_CHECK( es.getRegions( "EQLNUM" ).empty() ); -} diff --git a/opm/parser/eclipse/Units/ConversionFactors.hpp b/opm/parser/eclipse/Units/ConversionFactors.hpp index 93b267800..76e6a47da 100644 --- a/opm/parser/eclipse/Units/ConversionFactors.hpp +++ b/opm/parser/eclipse/Units/ConversionFactors.hpp @@ -237,7 +237,83 @@ namespace Opm { const double Timestep = day; } +namespace conversions { + /* + * It is VERY important that the dim enum has the same order as the + * metric and field arrays. C++ does not support designated initializers, so + * this cannot be done in a declaration-order independent matter. + */ + + enum class dim : int { + length, + time, + density, + pressure, + temperature_absolute, + temperature, + viscosity, + permeability, + liquid_surface_volume, + gas_surface_volume, + volume, + liquid_surface_rate, + gas_surface_rate, + rate, + transmissibility, + mass, + }; + + /* lookup tables for SI-to-unit system + * + * We assume that all values in the report structures are plain SI units, + * but output can be configured to use other (inconsistent) unit systems. + * These lookup tables are passed to the convert function that translates + * between SI and the target unit. + */ + + const double si2metric[] = { + 1 / Metric::Length, + 1 / Metric::Time, + 1 / Metric::Density, + 1 / Metric::Pressure, + 1 / Metric::AbsoluteTemperature, + 1 / Metric::Temperature, + 1 / Metric::Viscosity, + 1 / Metric::Permeability, + 1 / Metric::LiquidSurfaceVolume, + 1 / Metric::GasSurfaceVolume, + 1 / Metric::ReservoirVolume, + 1 / ( Metric::LiquidSurfaceVolume / Metric::Time ), + 1 / ( Metric::GasSurfaceVolume / Metric::Time ), + 1 / ( Metric::ReservoirVolume / Metric::Time ), + 1 / Metric::Transmissibility, + 1 / Metric::Mass, + }; + + const double si2field[] = { + 1 / Field::Length, + 1 / Field::Time, + 1 / Field::Density, + 1 / Field::Pressure, + 1 / Field::AbsoluteTemperature, + 1 / Field::Temperature, + 1 / Field::Viscosity, + 1 / Field::Permeability, + 1 / Field::LiquidSurfaceVolume, + 1 / Field::GasSurfaceVolume, + 1 / Field::ReservoirVolume, + 1 / ( Field::LiquidSurfaceVolume / Field::Time ), + 1 / ( Field::GasSurfaceVolume / Field::Time ), + 1 / ( Field::ReservoirVolume / Field::Time ), + 1 / Field::Transmissibility, + 1 / Field::Mass, + }; + + inline double from_si( const double* table, dim d, double val ) { + return val * table[ static_cast< int >( d ) ]; + } } +} #endif