From ee105b7bbf4b7cd903a319eb5f507e49d78bdfa4 Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Thu, 11 Nov 2021 16:58:53 +0100 Subject: [PATCH] Remove base class DeckViewInternal and create new class DeckView --- CMakeLists_files.cmake | 2 + GenerateKeywords.cmake | 1 + opm/parser/eclipse/Deck/Deck.hpp | 131 +++++------- opm/parser/eclipse/Deck/DeckSection.hpp | 58 +++++- opm/parser/eclipse/Deck/DeckView.hpp | 84 ++++++++ src/opm/parser/eclipse/Deck/Deck.cpp | 145 ++++--------- src/opm/parser/eclipse/Deck/DeckSection.cpp | 105 ++++++---- src/opm/parser/eclipse/Deck/DeckView.cpp | 85 ++++++++ tests/parser/DeckTests.cpp | 218 +++++++++++++++++--- tests/parser/WellTests.cpp | 4 +- 10 files changed, 574 insertions(+), 259 deletions(-) create mode 100644 opm/parser/eclipse/Deck/DeckView.hpp create mode 100644 src/opm/parser/eclipse/Deck/DeckView.cpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 33e6ed3f7..50e181b84 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -46,6 +46,7 @@ if(ENABLE_ECL_INPUT) src/opm/io/eclipse/SummaryNode.cpp src/opm/json/JsonObject.cpp src/opm/parser/eclipse/Deck/Deck.cpp + src/opm/parser/eclipse/Deck/DeckView.cpp src/opm/parser/eclipse/Deck/DeckTree.cpp src/opm/parser/eclipse/Deck/FileDeck.cpp src/opm/parser/eclipse/Deck/DeckItem.cpp @@ -871,6 +872,7 @@ if(ENABLE_ECL_INPUT) opm/parser/eclipse/EclipseState/Schedule/UDQ/UDQFunctionTable.hpp opm/parser/eclipse/Deck/DeckItem.hpp opm/parser/eclipse/Deck/Deck.hpp + opm/parser/eclipse/Deck/DeckView.hpp opm/parser/eclipse/Deck/FileDeck.hpp opm/parser/eclipse/Deck/DeckSection.hpp opm/parser/eclipse/Deck/DeckTree.hpp diff --git a/GenerateKeywords.cmake b/GenerateKeywords.cmake index f837ca3da..50d276cb6 100644 --- a/GenerateKeywords.cmake +++ b/GenerateKeywords.cmake @@ -4,6 +4,7 @@ set(genkw_SOURCES src/opm/json/JsonObject.cpp src/opm/parser/eclipse/Deck/DeckTree.cpp src/opm/parser/eclipse/Deck/DeckValue.cpp src/opm/parser/eclipse/Deck/Deck.cpp + src/opm/parser/eclipse/Deck/DeckView.cpp src/opm/parser/eclipse/Deck/DeckItem.cpp src/opm/parser/eclipse/Deck/DeckKeyword.cpp src/opm/parser/eclipse/Deck/DeckRecord.cpp diff --git a/opm/parser/eclipse/Deck/Deck.hpp b/opm/parser/eclipse/Deck/Deck.hpp index 124426729..94c43a5fb 100644 --- a/opm/parser/eclipse/Deck/Deck.hpp +++ b/opm/parser/eclipse/Deck/Deck.hpp @@ -20,6 +20,7 @@ #ifndef DECK_HPP #define DECK_HPP +#include #include #include #include @@ -27,6 +28,7 @@ #include #include +#include #include #include #include @@ -56,80 +58,14 @@ namespace Opm { */ class DeckOutput; - class DeckViewInternal { + + + class Deck { public: - typedef std::vector< DeckKeyword >::const_iterator const_iterator; - - bool hasKeyword( const std::string& keyword ) const; - template< class Keyword > - bool hasKeyword() const { - return hasKeyword( Keyword::keywordName ); - } - - const DeckKeyword& getKeyword( const std::string& keyword, size_t index ) const; - const DeckKeyword& getKeyword( const std::string& keyword ) const; - const DeckKeyword& getKeyword( size_t index ) const; - - const DeckKeyword& operator[](std::size_t index) const; - DeckKeyword& getKeyword( size_t index ); - template< class Keyword > - const DeckKeyword& getKeyword() const { - return getKeyword( Keyword::keywordName ); - } - template< class Keyword > - const DeckKeyword& getKeyword( size_t index ) const { - return getKeyword( Keyword::keywordName, index ); - } - template< class Keyword > - std::size_t count() const { - return count( Keyword::keywordName ); - } - - const std::vector< const DeckKeyword* > getKeywordList( const std::string& keyword ) const; - template< class Keyword > - const std::vector< const DeckKeyword* > getKeywordList() const { - return getKeywordList( Keyword::keywordName ); - } - - size_t count(const std::string& keyword) const; - size_t size() const; - - const_iterator begin() const; - const_iterator end() const; - - - protected: - void add( const DeckKeyword*, const_iterator, const_iterator ); - - const std::vector< size_t >& offsets( const std::string& ) const; - - DeckViewInternal( const_iterator first, const_iterator last ); - explicit DeckViewInternal( std::pair< const_iterator, const_iterator > ); - DeckViewInternal() = default; - void init( const_iterator, const_iterator ); - - private: - const_iterator first; - const_iterator last; - std::map< std::string, std::vector< size_t > > keywordMap; - - }; - - class Deck : private DeckViewInternal { - public: - using DeckViewInternal::const_iterator; - using DeckViewInternal::hasKeyword; - using DeckViewInternal::getKeyword; - using DeckViewInternal::getKeywordList; - using DeckViewInternal::count; - using DeckViewInternal::size; - using DeckViewInternal::begin; - using DeckViewInternal::end; - using DeckViewInternal::operator[]; - using iterator = std::vector< DeckKeyword >::iterator; + using const_iterator = std::vector< DeckKeyword >::const_iterator; - Deck(); + Deck() = default; Deck( const Deck& ); Deck( Deck&& ); @@ -141,8 +77,6 @@ namespace Opm { void addKeyword( DeckKeyword&& keyword ); void addKeyword( const DeckKeyword& keyword ); - DeckKeyword& getKeyword( size_t ); - const UnitSystem& getDefaultUnitSystem() const; const UnitSystem& getActiveUnitSystem() const; UnitSystem& getActiveUnitSystem(); @@ -162,6 +96,30 @@ namespace Opm { iterator end(); void write( DeckOutput& output ) const ; friend std::ostream& operator<<(std::ostream& os, const Deck& deck); + const_iterator begin() const; + const_iterator end() const; + + const DeckKeyword& getKeyword( const std::string& keyword, size_t index ) const; + const DeckKeyword& getKeyword( const std::string& keyword ) const; + const DeckKeyword& getKeyword( size_t index ) const; + DeckKeyword& getKeyword( size_t index ); + + const DeckKeyword& operator[](std::size_t index) const; + + template< class Keyword > + const DeckKeyword& getKeyword() const { + return getKeyword( Keyword::keywordName ); + } + template< class Keyword > + const DeckKeyword& getKeyword( size_t index ) const { + return getKeyword( Keyword::keywordName, index ); + } + + std::vector< const DeckKeyword* > getKeywordList( const std::string& keyword ) const; + template< class Keyword > + std::vector< const DeckKeyword* > getKeywordList() const { + return getKeywordList( Keyword::keywordName ); + } template void serializeOp(Serializer& serializer) @@ -172,12 +130,30 @@ namespace Opm { serializer(m_dataFile); serializer(input_path); serializer(unit_system_access_count); - if (!serializer.isSerializing()) - this->init(this->keywordList.begin(), this->keywordList.end()); } + bool hasKeyword( const std::string& keyword ) const; + + template< class Keyword > + bool hasKeyword() const { + return this->hasKeyword( Keyword::keywordName ); + } + + + + const std::vector index(const std::string& keyword) const { + return this->global_view().index(keyword); + } + + template< class Keyword > + std::size_t count() const { + return count( Keyword::keywordName ); + } + size_t count(const std::string& keyword) const; + + + private: - Deck(std::vector&& keywordList); std::vector< DeckKeyword > keywordList; UnitSystem defaultUnits; @@ -187,6 +163,9 @@ namespace Opm { std::string input_path; DeckTree file_tree; mutable std::size_t unit_system_access_count = 0; + + const DeckView& global_view() const; + mutable std::unique_ptr m_global_view{nullptr}; }; } #endif /* DECK_HPP */ diff --git a/opm/parser/eclipse/Deck/DeckSection.hpp b/opm/parser/eclipse/Deck/DeckSection.hpp index 029f0d103..e77b15452 100644 --- a/opm/parser/eclipse/Deck/DeckSection.hpp +++ b/opm/parser/eclipse/Deck/DeckSection.hpp @@ -41,9 +41,8 @@ enum class Section { class Parser; -class DeckSection : public DeckViewInternal { +class DeckSection : public DeckView { public: - using DeckViewInternal::const_iterator; DeckSection( const Deck& deck, const std::string& startKeyword ); const std::string& name() const; @@ -64,6 +63,53 @@ class DeckSection : public DeckViewInternal { const Parser&, bool ensureKeywordSectionAffiliation = false); + + // --------------------------------------------------------------------------------- + // Highly deprecated shims + const DeckKeyword& getKeyword(const std::string& keyword, std::size_t index) const { + auto view = this->operator[](keyword); + return view[index]; + } + + const DeckKeyword& getKeyword(const std::string& keyword) const { + auto view = this->operator[](keyword); + return view.back(); + } + + template + const DeckKeyword& getKeyword() const { + auto view = this->operator[](Keyword::keywordName); + return view.back(); + } + + + + std::vector getKeywordList(const std::string& keyword) const { + std::vector kw_list; + auto view = this->operator[](keyword); + for (const auto& kw : view) + kw_list.push_back(&kw); + return kw_list; + } + + template + std::vector getKeywordList() const { + return this->getKeywordList(Keyword::keywordName); + } + + + bool hasKeyword(const std::string& keyword) const { + return this->has_keyword(keyword); + } + + template + bool hasKeyword() const { + return this->has_keyword(Keyword::keywordName); + } + + // --------------------------------------------------------------------------------- + + private: std::string section_name; const UnitSystem& units; @@ -72,49 +118,41 @@ class DeckSection : public DeckViewInternal { class RUNSPECSection : public DeckSection { public: - using DeckSection::const_iterator; explicit RUNSPECSection(const Deck& deck) : DeckSection(deck, "RUNSPEC") {} }; class GRIDSection : public DeckSection { public: - using DeckSection::const_iterator; explicit GRIDSection(const Deck& deck) : DeckSection(deck, "GRID") {} }; class EDITSection : public DeckSection { public: - using DeckSection::const_iterator; explicit EDITSection(const Deck& deck) : DeckSection(deck, "EDIT") {} }; class PROPSSection : public DeckSection { public: - using DeckSection::const_iterator; explicit PROPSSection(const Deck& deck) : DeckSection(deck, "PROPS") {} }; class REGIONSSection : public DeckSection { public: - using DeckSection::const_iterator; explicit REGIONSSection(const Deck& deck) : DeckSection(deck, "REGIONS") {} }; class SOLUTIONSection : public DeckSection { public: - using DeckSection::const_iterator; explicit SOLUTIONSection(const Deck& deck) : DeckSection(deck, "SOLUTION") {} }; class SUMMARYSection : public DeckSection { public: - using DeckSection::const_iterator; explicit SUMMARYSection(const Deck& deck) : DeckSection(deck, "SUMMARY") {} }; class SCHEDULESection : public DeckSection { public: - using DeckSection::const_iterator; explicit SCHEDULESection(const Deck& deck) : DeckSection(deck, "SCHEDULE") {} }; } diff --git a/opm/parser/eclipse/Deck/DeckView.hpp b/opm/parser/eclipse/Deck/DeckView.hpp new file mode 100644 index 000000000..fdac59934 --- /dev/null +++ b/opm/parser/eclipse/Deck/DeckView.hpp @@ -0,0 +1,84 @@ +/* + Copyright 2021 Statoil ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#ifndef DECKVIEW_HPP +#define DECKVIEW_HPP + +#include + +namespace Opm { + + +class DeckView { +public: + typedef std::vector> storage_type; + + + struct Iterator : public storage_type::iterator { + Iterator(storage_type::const_iterator inner_iter) : + inner(inner_iter) + {} + + const DeckKeyword& operator*() { return this->inner->get(); } + const DeckKeyword* operator->() { return &this->inner->get(); } + + Iterator& operator++() { ++this->inner; return *this; } + Iterator operator++(int) { auto tmp = *this; ++this->inner; return tmp; } + + + Iterator& operator--() { --this->inner; return *this; } + Iterator operator--(int) { auto tmp = *this; --this->inner; return tmp; } + + Iterator::difference_type operator-(const Iterator &other) { return this->inner - other.inner; } + Iterator operator+(Iterator::difference_type shift) { Iterator tmp = *this; tmp.inner += shift; return tmp;} + + friend bool operator== (const Iterator& a, const Iterator& b) { return a.inner == b.inner; }; + friend bool operator!= (const Iterator& a, const Iterator& b) { return a.inner != b.inner; }; + private: + storage_type::const_iterator inner; + }; + + Iterator begin() const { return Iterator(this->keywords.begin()); } + Iterator end() const { return Iterator(this->keywords.end()); } + + const DeckKeyword& operator[](std::size_t index) const; + DeckView operator[](const std::string& keyword) const; + std::vector index(const std::string& keyword) const; + std::size_t count(const std::string& keyword) const; + const DeckKeyword& front() const; + const DeckKeyword& back() const; + + DeckView() = default; + void add_keyword(const DeckKeyword& kw); + bool has_keyword(const std::string& kw) const; + bool empty() const; + std::size_t size() const; + + template + bool has_keyword() const { + return this->has_keyword( Keyword::keywordName ); + } + +private: + storage_type keywords; + std::unordered_map> keyword_index; +}; + +} +#endif diff --git a/src/opm/parser/eclipse/Deck/Deck.cpp b/src/opm/parser/eclipse/Deck/Deck.cpp index 1aa22e6d8..5de8e0b57 100644 --- a/src/opm/parser/eclipse/Deck/Deck.cpp +++ b/src/opm/parser/eclipse/Deck/Deck.cpp @@ -30,122 +30,58 @@ namespace fs = std::filesystem; namespace Opm { - bool DeckViewInternal::hasKeyword( const std::string& keyword ) const { - return this->keywordMap.find( keyword ) != this->keywordMap.end(); + std::vector< const DeckKeyword* > Deck::getKeywordList( const std::string& keyword ) const { + std::vector pointers; + auto view = this->global_view().operator[](keyword); + for (const auto& kw : view) + pointers.push_back(&kw); + return pointers; } - const DeckKeyword& DeckViewInternal::getKeyword( const std::string& keyword, size_t index ) const { - if( !this->hasKeyword( keyword ) ) - throw std::invalid_argument("Keyword " + keyword + " not in deck."); - - return this->getKeyword( this->offsets( keyword ).at( index ) ); + Deck::const_iterator Deck::begin() const { + return this->keywordList.begin(); } - const DeckKeyword& DeckViewInternal::getKeyword( const std::string& keyword ) const { - if( !this->hasKeyword( keyword ) ) - throw std::invalid_argument("Keyword " + keyword + " not in deck."); - - return this->getKeyword( this->offsets( keyword ).back() ); - } - - const DeckKeyword& DeckViewInternal::getKeyword( size_t index ) const { - if( index >= this->size() ) - throw std::out_of_range("Keyword index " + std::to_string( index ) + " is out of range."); - - return *( this->begin() + index ); - } - - const DeckKeyword& DeckViewInternal::operator[](std::size_t index) const { - return this->getKeyword(index); + Deck::const_iterator Deck::end() const { + return this->keywordList.end(); } - size_t DeckViewInternal::count( const std::string& keyword ) const { - if( !this->hasKeyword( keyword ) ) return 0; +std::size_t Deck::count(const std::string& keyword) const { + return this->global_view().count(keyword); +} - return this->offsets( keyword ).size(); +const DeckView& Deck::global_view() const { + if (!this->m_global_view) { + this->m_global_view = std::make_unique(); + for (const auto& kw : this->keywordList) + this->m_global_view->add_keyword(kw); + } + return *this->m_global_view; +} + + + + const DeckKeyword& Deck::getKeyword( const std::string& keyword, size_t index ) const { + return this->global_view().operator[](keyword)[index]; } - const std::vector< const DeckKeyword* > DeckViewInternal::getKeywordList( const std::string& keyword ) const { - if( !hasKeyword( keyword ) ) return {}; - - const auto& indices = this->offsets( keyword ); - - std::vector< const DeckKeyword* > ret; - ret.reserve( indices.size() ); - - for( size_t i : indices ) - ret.push_back( &this->getKeyword( i ) ); - - return ret; + const DeckKeyword& Deck::getKeyword( const std::string& keyword ) const { + return this->global_view().operator[](keyword).back(); } - size_t DeckViewInternal::size() const { - return std::distance( this->begin(), this->end() ); + const DeckKeyword& Deck::getKeyword( size_t index ) const { + return this->operator[](index); } - DeckViewInternal::const_iterator DeckViewInternal::begin() const { - return this->first; + const DeckKeyword& Deck::operator[](std::size_t index) const { + return this->keywordList.at(index); } - DeckViewInternal::const_iterator DeckViewInternal::end() const { - return this->last; - } - void DeckViewInternal::add( const DeckKeyword* kw, const_iterator f, const_iterator l ) { - this->keywordMap[ kw->name() ].push_back( std::distance( f, l ) - 1 ); - this->first = f; - this->last = l; - } - - static const std::vector< size_t > empty_indices = {}; - const std::vector< size_t >& DeckViewInternal::offsets( const std::string& keyword ) const { - if( !hasKeyword( keyword ) ) return empty_indices; - - return this->keywordMap.find( keyword )->second; - } - - DeckViewInternal::DeckViewInternal( const_iterator first_arg, const_iterator last_arg) - { - this->init(first_arg, last_arg); - } - - void DeckViewInternal::init( const_iterator first_arg, const_iterator last_arg ) { - this->first = first_arg; - this->last = last_arg; - - this->keywordMap.clear(); - - size_t index = 0; - for( const auto& kw : *this ) - this->keywordMap[ kw.name() ].push_back( index++ ); - } - - DeckViewInternal::DeckViewInternal( std::pair< const_iterator, const_iterator > limits ) : - DeckViewInternal( limits.first, limits.second ) - {} - - Deck::Deck() : - Deck( std::vector() ) - {} - - /* - This constructor should be ssen as a technical implemtation detail of the - default constructor, and not something which should be invoked directly. - The point is that the derived class DeckViewInternal contains iterators to the - keywordList member in the base class - this represents some ordering - challenges in the construction phase. - */ - Deck::Deck( std::vector&& x) : - DeckViewInternal(x.begin(), x.end()), - keywordList(std::move(x)), - defaultUnits( UnitSystem::newMETRIC() ) - { - } Deck::Deck( const Deck& d ) - : DeckViewInternal(d.begin(), d.end()) - , keywordList( d.keywordList ) + : keywordList( d.keywordList ) , defaultUnits( d.defaultUnits ) , activeUnits( d.activeUnits ) , m_dataFile( d.m_dataFile ) @@ -153,12 +89,10 @@ namespace Opm { , file_tree( d.file_tree ) , unit_system_access_count(d.unit_system_access_count) { - this->init(this->keywordList.begin(), this->keywordList.end()); } Deck::Deck( Deck&& d ) - : DeckViewInternal(d.begin(), d.end()) - , keywordList( std::move(d.keywordList) ) + : keywordList( std::move(d.keywordList) ) , defaultUnits( d.defaultUnits ) , activeUnits( d.activeUnits ) , m_dataFile( d.m_dataFile ) @@ -166,7 +100,6 @@ namespace Opm { , file_tree( std::move(d.file_tree) ) , unit_system_access_count(d.unit_system_access_count) { - this->init(this->keywordList.begin(), this->keywordList.end()); } Deck Deck::serializeObject() @@ -193,9 +126,7 @@ namespace Opm { this->selectActiveUnitSystem( UnitSystem::UnitType::UNIT_TYPE_PVT_M ); this->keywordList.push_back( std::move( keyword ) ); - auto fst = this->keywordList.begin(); - auto lst = this->keywordList.end(); - this->add( &this->keywordList.back(), fst, lst ); + this->m_global_view = nullptr; } void Deck::addKeyword( const DeckKeyword& keyword ) { @@ -311,7 +242,6 @@ namespace Opm { m_dataFile = data.m_dataFile; input_path = data.input_path; unit_system_access_count = data.unit_system_access_count; - this->init(this->keywordList.begin(), this->keywordList.end()); activeUnits = data.activeUnits; return *this; @@ -344,4 +274,9 @@ namespace Opm { bool Deck::empty() const { return this->keywordList.size() == 0; } + + bool Deck::hasKeyword(const std::string& keyword) const { + return this->global_view().has_keyword(keyword); + } + } diff --git a/src/opm/parser/eclipse/Deck/DeckSection.cpp b/src/opm/parser/eclipse/Deck/DeckSection.cpp index 4847f788a..d17c7ea6c 100644 --- a/src/opm/parser/eclipse/Deck/DeckSection.cpp +++ b/src/opm/parser/eclipse/Deck/DeckSection.cpp @@ -17,53 +17,80 @@ along with OPM. If not, see . */ -#include -#include #include #include +#include +#include +#include #include #include +#include #include #include #include +#include +#include +#include +#include +#include namespace Opm { - static bool isSectionDelimiter( const DeckKeyword& keyword ) { - const auto& name = keyword.name(); - for( const auto& x : { "RUNSPEC", "GRID", "EDIT", "PROPS", - "REGIONS", "SOLUTION", "SUMMARY", "SCHEDULE" } ) - if( name == x ) return true; - return false; +const std::unordered_map section_index = { + {"RUNSPEC", 0}, + {"GRID", 1}, + {"EDIT", 2}, + {"PROPS", 3}, + {"REGIONS", 4}, + {"SOLUTION", 5}, + {"SUMMARY", 6}, + {"SCHEDULE", 7} +}; + + std::pair index_pair(const Deck& deck, const std::string& section) { + if (!deck.hasKeyword(section)) + return {0,0}; + + auto start_index = deck.index(section).front(); + std::unordered_set end_set; + { + auto this_section_index = section_index.at(section); + + for (const auto& [section_name, index] : section_index) { + if (index > this_section_index) + end_set.insert(section_name); + } + } + + if (end_set.empty()) + return {start_index, deck.size()}; + + std::size_t deck_index = start_index; + while (true) { + const auto& kw = deck[deck_index]; + if (end_set.count(kw.name()) == 1) + break; + + deck_index++; + + if (deck_index == deck.size()) + break; + } + return {start_index, deck_index}; } - static std::pair< DeckViewInternal::const_iterator, DeckViewInternal::const_iterator > - find_section( const Deck& deck, const std::string& keyword ) { - - const auto fn = [&keyword]( const DeckKeyword& kw ) { - return kw.name() == keyword; - }; - - auto first = std::find_if( deck.begin(), deck.end(), fn ); - - 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" ); - - return { first, last }; - } DeckSection::DeckSection( const Deck& deck, const std::string& section ) - : DeckViewInternal( find_section( deck, section ) ), - section_name( section ), - units( deck.getActiveUnitSystem() ) - {} + : section_name( section ) + , units( deck.getActiveUnitSystem() ) + { + auto [start_index, end_index] = index_pair(deck, section); + for (std::size_t index = start_index; index < end_index; index++) + this->add_keyword(deck.getKeyword(index)); + } + const std::string& DeckSection::name() const { return this->section_name; @@ -73,13 +100,13 @@ namespace Opm { return this->units; } - bool DeckSection::hasRUNSPEC(const Deck& deck) { return deck.hasKeyword( "RUNSPEC" ); } - bool DeckSection::hasGRID(const Deck& deck) { return deck.hasKeyword( "GRID" ); } - bool DeckSection::hasEDIT(const Deck& deck) { return deck.hasKeyword( "EDIT" ); } - bool DeckSection::hasPROPS(const Deck& deck) { return deck.hasKeyword( "PROPS" ); } - bool DeckSection::hasREGIONS(const Deck& deck) { return deck.hasKeyword( "REGIONS" ); } - bool DeckSection::hasSOLUTION(const Deck& deck) { return deck.hasKeyword( "SOLUTION" ); } - bool DeckSection::hasSUMMARY(const Deck& deck) { return deck.hasKeyword( "SUMMARY" ); } - bool DeckSection::hasSCHEDULE(const Deck& deck) { return deck.hasKeyword( "SCHEDULE" ); } +bool DeckSection::hasRUNSPEC(const Deck& deck) { return deck.hasKeyword(); } +bool DeckSection::hasGRID(const Deck& deck) { return deck.hasKeyword(); } +bool DeckSection::hasEDIT(const Deck& deck) { return deck.hasKeyword(); } +bool DeckSection::hasPROPS(const Deck& deck) { return deck.hasKeyword(); } +bool DeckSection::hasREGIONS(const Deck& deck) { return deck.hasKeyword(); } +bool DeckSection::hasSOLUTION(const Deck& deck) { return deck.hasKeyword(); } +bool DeckSection::hasSUMMARY(const Deck& deck) { return deck.hasKeyword(); } +bool DeckSection::hasSCHEDULE(const Deck& deck) { return deck.hasKeyword(); } } diff --git a/src/opm/parser/eclipse/Deck/DeckView.cpp b/src/opm/parser/eclipse/Deck/DeckView.cpp new file mode 100644 index 000000000..8055206d3 --- /dev/null +++ b/src/opm/parser/eclipse/Deck/DeckView.cpp @@ -0,0 +1,85 @@ +/* + Copyright 2021 Statoil ASA. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + along with OPM. If not, see . +*/ + +#include + +#include + + +void Opm::DeckView::add_keyword(const Opm::DeckKeyword& kw) { + this->keyword_index[kw.name()].push_back(this->keywords.size()); + this->keywords.push_back(std::cref(kw)); +} + +bool Opm::DeckView::has_keyword(const std::string& kw) const { + return this->keyword_index.find(kw) != this->keyword_index.end(); +} + +bool Opm::DeckView::empty() const { + return this->keywords.empty(); +} + +std::size_t Opm::DeckView::size() const { + return this->keywords.size(); +} + +const Opm::DeckKeyword& Opm::DeckView::operator[](std::size_t kw_index) const { + return this->keywords.at(kw_index).get(); +} + +Opm::DeckView Opm::DeckView::operator[](const std::string& kw_name) const { + DeckView dw; + auto iter = this->keyword_index.find(kw_name); + if (iter != this->keyword_index.end()) { + for (const auto& kw_index : iter->second) { + const auto& kw = this->keywords[kw_index].get(); + dw.add_keyword(kw); + } + } + return dw; +} + +const Opm::DeckKeyword& Opm::DeckView::front() const { + if (this->empty()) + throw std::logic_error("Tried to get front() from empty DeckView"); + + return this->keywords.front().get(); +} + +const Opm::DeckKeyword& Opm::DeckView::back() const { + if (this->empty()) + throw std::logic_error("Tried to get back() from empty DeckView"); + + return this->keywords.back().get(); +} + +std::vector Opm::DeckView::index(const std::string& keyword) const { + auto iter = this->keyword_index.find(keyword); + if (iter != this->keyword_index.end()) + return iter->second; + + return {}; +} + +std::size_t Opm::DeckView::count(const std::string& keyword) const { + auto iter = this->keyword_index.find(keyword); + if (iter == this->keyword_index.end()) + return 0; + + return iter->second.size(); +} diff --git a/tests/parser/DeckTests.cpp b/tests/parser/DeckTests.cpp index bdcebf88a..985ef3140 100644 --- a/tests/parser/DeckTests.cpp +++ b/tests/parser/DeckTests.cpp @@ -29,10 +29,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include @@ -44,7 +46,7 @@ using namespace Opm; BOOST_AUTO_TEST_CASE(hasKeyword_empty_returnFalse) { Deck deck; BOOST_CHECK_EQUAL(false, deck.hasKeyword("Bjarne")); - BOOST_CHECK_THROW( deck.getKeyword("Bjarne") , std::invalid_argument); + BOOST_CHECK_THROW( deck.getKeyword("Bjarne") , std::exception); } std::pair, std::vector> make_dims() { @@ -64,7 +66,7 @@ BOOST_AUTO_TEST_CASE(getKeyword_singlekeyword_outRange_throws) { Deck deck; Parser parser; deck.addKeyword( DeckKeyword( parser.getKeyword("GRID"))); - BOOST_CHECK_THROW(deck.getKeyword("GRID" , 10) , std::out_of_range); + BOOST_CHECK_THROW(deck.getKeyword("GRID" , 10) , std::exception); } @@ -108,7 +110,8 @@ BOOST_AUTO_TEST_CASE(size_twokeyword_return2) { deck.addKeyword(keyword); deck.addKeyword(keyword); BOOST_CHECK_EQUAL(2U , deck.size()); - BOOST_CHECK_THROW( deck.getKeyword("GRID" , 3) , std::out_of_range); + + BOOST_CHECK_THROW( deck.getKeyword("GRID" , 3) , std::exception); } BOOST_AUTO_TEST_CASE(getKeywordList_OK) { @@ -126,12 +129,12 @@ BOOST_AUTO_TEST_CASE(getKeywordList_OK) { BOOST_AUTO_TEST_CASE(keywordList_getbyindexoutofbounds_exceptionthrown) { Parser parser; Deck deck; - BOOST_CHECK_THROW(deck.getKeyword(0), std::out_of_range); + BOOST_CHECK_THROW(deck.getKeyword(0), std::exception); deck.addKeyword( DeckKeyword( parser.getKeyword("GRID"))); deck.addKeyword( DeckKeyword( parser.getKeyword("GRID"))); deck.addKeyword( DeckKeyword( parser.getKeyword("INIT"))); BOOST_CHECK_NO_THROW(deck.getKeyword(2)); - BOOST_CHECK_THROW(deck.getKeyword(3), std::out_of_range); + BOOST_CHECK_THROW(deck.getKeyword(3), std::exception); } BOOST_AUTO_TEST_CASE(keywordList_getbyindex_correctkeywordreturned) { @@ -159,14 +162,14 @@ BOOST_AUTO_TEST_CASE(DummyDefaultsString) { deckStringItem.push_backDummyDefault(); BOOST_CHECK_EQUAL(deckStringItem.data_size(), 1U); BOOST_CHECK_EQUAL(true, deckStringItem.defaultApplied(0)); - BOOST_CHECK_THROW(deckStringItem.get< std::string >(0), std::invalid_argument); + BOOST_CHECK_THROW(deckStringItem.get< std::string >(0), std::exception); } BOOST_AUTO_TEST_CASE(GetStringAtIndex_NoData_ExceptionThrown) { DeckItem deckStringItem( "TEST", std::string() ); - BOOST_CHECK_THROW(deckStringItem.get< std::string >(0), std::out_of_range); + BOOST_CHECK_THROW(deckStringItem.get< std::string >(0), std::exception); deckStringItem.push_back("SA"); - BOOST_CHECK_THROW(deckStringItem.get< std::string >(1), std::out_of_range); + BOOST_CHECK_THROW(deckStringItem.get< std::string >(1), std::exception); } BOOST_AUTO_TEST_CASE(size_variouspushes_sizecorrect) { @@ -216,9 +219,9 @@ BOOST_AUTO_TEST_CASE(GetDoubleAtIndex_NoData_ExceptionThrown) { printf("Current type: %s \n",tag_name(deckDoubleItem.getType()).c_str()); BOOST_CHECK(deckDoubleItem.getType() == type_tag::fdouble); - BOOST_CHECK_THROW(deckDoubleItem.get< double >(0), std::out_of_range); + BOOST_CHECK_THROW(deckDoubleItem.get< double >(0), std::exception); deckDoubleItem.push_back(1.89); - BOOST_CHECK_THROW(deckDoubleItem.get< double >(1), std::out_of_range); + BOOST_CHECK_THROW(deckDoubleItem.get< double >(1), std::exception); } @@ -263,7 +266,7 @@ BOOST_AUTO_TEST_CASE(DummyDefaultsDouble) { deckDoubleItem.push_backDummyDefault(); BOOST_CHECK_EQUAL(deckDoubleItem.data_size(), 1U); BOOST_CHECK_EQUAL(true, deckDoubleItem.defaultApplied(0)); - BOOST_CHECK_THROW(deckDoubleItem.get< double >(0), std::invalid_argument); + BOOST_CHECK_THROW(deckDoubleItem.get< double >(0), std::exception); } BOOST_AUTO_TEST_CASE(PushBackMultipleDouble) { @@ -280,8 +283,8 @@ BOOST_AUTO_TEST_CASE(GetSIWithoutDimensionThrows) { DeckItem item( "HEI", double() , {},{}); item.push_back(10.22 , 100 ); - BOOST_CHECK_THROW( item.getSIDouble(0) , std::invalid_argument ); - BOOST_CHECK_THROW( item.getSIDoubleData() , std::invalid_argument ); + BOOST_CHECK_THROW( item.getSIDouble(0) , std::exception ); + BOOST_CHECK_THROW( item.getSIDoubleData() , std::exception ); } BOOST_AUTO_TEST_CASE(GetSISingleDimensionCorrect) { @@ -339,14 +342,14 @@ BOOST_AUTO_TEST_CASE(DummyDefaultsInt) { BOOST_CHECK_EQUAL(true, deckIntItem.defaultApplied(0)); BOOST_CHECK_EQUAL( false , deckIntItem.hasValue(0)); BOOST_CHECK_EQUAL( false , deckIntItem.hasValue(1)); - BOOST_CHECK_THROW(deckIntItem.get< int >(0), std::invalid_argument); + BOOST_CHECK_THROW(deckIntItem.get< int >(0), std::exception); } BOOST_AUTO_TEST_CASE(GetIntAtIndex_NoData_ExceptionThrown) { DeckItem deckIntItem( "TEST", int() ); deckIntItem.push_back(100); BOOST_CHECK(deckIntItem.get< int >(0) == 100); - BOOST_CHECK_THROW(deckIntItem.get< int >(1), std::out_of_range); + BOOST_CHECK_THROW(deckIntItem.get< int >(1), std::exception); } BOOST_AUTO_TEST_CASE(InitializeDefaultApplied) { @@ -375,8 +378,8 @@ BOOST_AUTO_TEST_CASE(DefaultNotAppliedInt) { BOOST_CHECK( deckIntItem.get< int >(0) == 100 ); BOOST_CHECK( !deckIntItem.defaultApplied(0) ); - BOOST_CHECK_THROW( deckIntItem.defaultApplied(1), std::out_of_range ); - BOOST_CHECK_THROW( deckIntItem.get< int >(1), std::out_of_range ); + BOOST_CHECK_THROW( deckIntItem.defaultApplied(1), std::exception ); + BOOST_CHECK_THROW( deckIntItem.get< int >(1), std::exception ); } BOOST_AUTO_TEST_CASE(UseDefault) { @@ -387,8 +390,8 @@ BOOST_AUTO_TEST_CASE(UseDefault) { BOOST_CHECK( deckIntItem.defaultApplied(0) ); BOOST_CHECK( deckIntItem.get< int >(0) == 100 ); - BOOST_CHECK_THROW( deckIntItem.defaultApplied(1), std::out_of_range ); - BOOST_CHECK_THROW( deckIntItem.get< int >(1), std::out_of_range ); + BOOST_CHECK_THROW( deckIntItem.defaultApplied(1), std::exception ); + BOOST_CHECK_THROW( deckIntItem.get< int >(1), std::exception ); } BOOST_AUTO_TEST_CASE(DefaultAppliedInt) { @@ -439,9 +442,9 @@ BOOST_AUTO_TEST_CASE(addItem_multipleItems_sizecorrect) { BOOST_AUTO_TEST_CASE(addItem_differentItemsSameName_throws) { DeckRecord deckRecord; deckRecord.addItem( DeckItem { "TEST", int() } ); - BOOST_CHECK_THROW( deckRecord.addItem( DeckItem { "TEST", int() } ), std::invalid_argument ); + BOOST_CHECK_THROW( deckRecord.addItem( DeckItem { "TEST", int() } ), std::exception ); std::vector< DeckItem > items = { DeckItem { "TEST", int() }, DeckItem { "TEST" , int() } }; - BOOST_CHECK_THROW( DeckRecord( std::move( items ) ), std::invalid_argument ); + BOOST_CHECK_THROW( DeckRecord( std::move( items ) ), std::exception ); } BOOST_AUTO_TEST_CASE(get_byIndex_returnsItem) { @@ -453,7 +456,7 @@ BOOST_AUTO_TEST_CASE(get_byIndex_returnsItem) { BOOST_AUTO_TEST_CASE(get_indexoutofbounds_throws) { DeckRecord deckRecord; deckRecord.addItem( DeckItem { "TEST", int() } ); - BOOST_CHECK_THROW(deckRecord.getItem(1), std::out_of_range); + BOOST_CHECK_THROW(deckRecord.getItem(1), std::exception); } BOOST_AUTO_TEST_CASE(get_byName_returnsItem) { @@ -465,7 +468,7 @@ BOOST_AUTO_TEST_CASE(get_byName_returnsItem) { BOOST_AUTO_TEST_CASE(get_byNameNonExisting_throws) { DeckRecord deckRecord; deckRecord.addItem( DeckItem { "TEST", int() } ); - BOOST_CHECK_THROW(deckRecord.getItem("INVALID"), std::invalid_argument); + BOOST_CHECK_THROW(deckRecord.getItem("INVALID"), std::exception); } BOOST_AUTO_TEST_CASE(StringsWithSpaceOK) { @@ -507,7 +510,7 @@ BOOST_AUTO_TEST_CASE(size_noRecords_returnszero) { Parser parser; DeckKeyword deckKeyword( parser.getKeyword("GRID"));; BOOST_CHECK_EQUAL(0U, deckKeyword.size()); - BOOST_CHECK_THROW(deckKeyword.getRecord(0), std::out_of_range); + BOOST_CHECK_THROW(deckKeyword.getRecord(0), std::exception); } @@ -676,9 +679,170 @@ BOOST_AUTO_TEST_CASE(STRING_TO_BOOL) { BOOST_CHECK( !DeckItem::to_bool("N")); BOOST_CHECK( !DeckItem::to_bool("0") ); // - BOOST_CHECK_THROW(DeckItem::to_bool("NO - not valid"), std::invalid_argument); - BOOST_CHECK_THROW(DeckItem::to_bool("YE"), std::invalid_argument); - BOOST_CHECK_THROW(DeckItem::to_bool("YE"), std::invalid_argument); + BOOST_CHECK_THROW(DeckItem::to_bool("NO - not valid"), std::exception); + BOOST_CHECK_THROW(DeckItem::to_bool("YE"), std::exception); + BOOST_CHECK_THROW(DeckItem::to_bool("YE"), std::exception); } +BOOST_AUTO_TEST_CASE(DeckView2Test) { + std::string deck_string = R"( +START +7 OCT 2020 / + +DIMENS + 10 10 3 / + +GRID +DXV + 10*100.0 / +DYV + 10*100.0 / +DZV + 3*10.0 / + +DEPTHZ + 121*2000.0 / + +PORO + 300*0.3 / + +SCHEDULE + +VFPPROD +-- table_num, datum_depth, flo, wfr, gfr, pressure, alq, unit, table_vals +42 7.0E+03 LIQ WCT GOR THP ' ' METRIC BHP / +1.0 / flo axis +0.0 1.0 / THP axis +0.0 / WFR axis +0.0 / GFR axis +0.0 / ALQ axis +-- Table itself: thp_idx wfr_idx gfr_idx alq_idx +1 1 1 1 0.0 / +2 1 1 1 1.0 / + +VFPPROD +-- table_num, datum_depth, flo, wfr, gfr, pressure, alq, unit, table_vals +43 7.0E+03 LIQ WCT GOR THP 'GRAT' METRIC BHP / +1.0 / flo axis +0.0 1.0 / THP axis +0.0 / WFR axis +0.0 / GFR axis +0.0 / ALQ axis +-- Table itself: thp_idx wfr_idx gfr_idx alq_idx +1 1 1 1 0.0 / +2 1 1 1 1.0 / + +WELSPECS -- 0 + 'P1' 'G' 10 10 2005 'LIQ' / + 'P2' 'G' 10 10 2005 'LIQ' / +/ + +COMPDAT + 'P1' 9 9 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 / + 'P2' 9 9 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 / +/ + +WCONPROD + 'P1' 'OPEN' 'ORAT' 123.4 0.0 0.0 0.0 0.0 100 100 42 'UDA' / + 'P2' 'OPEN' 'ORAT' 123.4 0.0 0.0 0.0 0.0 100 100 43 'UDA' / +/ + +DATES + 10 'JAN' 2000 / +/ + +DATES + 20 'JAN' 2000 / +/ + +DATES + 30 'JAN' 2000 / +/ + +)"; + + Parser parser; + auto deck = parser.parseString(deck_string); + DeckView dw; + for (const auto& kw : deck) + dw.add_keyword(kw); + + BOOST_CHECK(dw.has_keyword("DATES")); + BOOST_CHECK(!dw.has_keyword("RADIAL")); + BOOST_CHECK(!dw.empty()); + BOOST_CHECK_EQUAL(dw.size(), 17); + + BOOST_CHECK_THROW(dw[100], std::exception); + const auto& start = dw[0]; + BOOST_CHECK_EQUAL(start.name(), "START"); + BOOST_CHECK_EQUAL(dw.front().name(), "START"); + BOOST_CHECK(dw.back() == dw[16]); + { + DeckView dw2; + BOOST_CHECK_THROW(dw2.back(), std::exception); + BOOST_CHECK_THROW(dw2.front(), std::exception); + } + const auto& radial_kw = dw["RADIAL"]; + BOOST_CHECK(radial_kw.empty()); + + + const auto& dates_view = dw["DATES"]; + BOOST_CHECK_EQUAL(dates_view.size(), 3); + const auto& first_dates = dates_view.front(); + const auto& rec0 = first_dates[0]; + const auto& month = rec0.getItem(1).get(0); + BOOST_CHECK_EQUAL(month, "JAN"); + + const auto& last_dates = dates_view.back(); + const auto& rec1 = last_dates[0]; + const auto& day = rec1.getItem(0).get(0); + BOOST_CHECK_EQUAL(day, 30); + + + BOOST_CHECK(dw.has_keyword()); + std::vector expected = {"START", "DIMENS", "GRID", "DXV", "DYV", "DZV", "DEPTHZ", "PORO", + "SCHEDULE", "VFPPROD", "VFPPROD", "WELSPECS", "COMPDAT", "WCONPROD", + "DATES", "DATES", "DATES"}; + std::vector actual; + for (const auto& kw : dw) + actual.push_back(kw.name()); + + BOOST_CHECK( actual == expected ); + + const auto& radial_index = dw.index("RADIAL"); + BOOST_CHECK( radial_index.empty() ); + + auto dates_index = dw.index("DATES"); + std::vector dates_expected = {14, 15, 16}; + BOOST_CHECK(dates_index == dates_expected); + + + BOOST_CHECK_EQUAL(dw.count("RADIAL"), 0); + BOOST_CHECK_EQUAL(dw.count("VFPPROD"), 2); + BOOST_CHECK_EQUAL(dw.count("SCHEDULE"), 1); + + + bool have_grid0 = std::any_of(dw.begin(), dw.end(), [](const DeckKeyword& kw) { + return kw.name() == "GRID"; + }); + BOOST_CHECK( have_grid0 ); + + bool have_grid1 = std::any_of(dw.begin() + 3, dw.end(), [](const DeckKeyword& kw) { + return kw.name() == "GRID"; + }); + BOOST_CHECK( !have_grid1 ); + + auto is_vfpprod = [](const DeckKeyword& kw) { return kw.name() == "VFPPROD"; }; + auto iter = std::find_if(dw.begin(), dw.end(), is_vfpprod); + BOOST_CHECK( iter != dw.end() ); + + auto iter2 = std::find_if(iter + 1, dw.end(), is_vfpprod); + BOOST_CHECK( iter2 != dw.end() ); + + auto iter3 = std::find_if(iter2 + 1, dw.end(), is_vfpprod); + BOOST_CHECK( iter3 == dw.end() ); + + auto count = std::count_if(dw.begin(), dw.end(), is_vfpprod); + BOOST_CHECK_EQUAL(count, 2); +} diff --git a/tests/parser/WellTests.cpp b/tests/parser/WellTests.cpp index 31f5da743..428df706d 100644 --- a/tests/parser/WellTests.cpp +++ b/tests/parser/WellTests.cpp @@ -854,8 +854,8 @@ BOOST_AUTO_TEST_CASE(WCONPROD_BHP_CMode) BOOST_AUTO_TEST_CASE(BHP_CMODE) { - BOOST_CHECK_THROW( WCONHIST::properties(WCONHIST::all_specified_CMODE_THP()) , std::invalid_argument); - BOOST_CHECK_THROW( WCONPROD::properties(WCONPROD::all_specified_CMODE_BHP()) , std::invalid_argument); + BOOST_CHECK_THROW( WCONHIST::properties(WCONHIST::all_specified_CMODE_THP()) , std::exception); + BOOST_CHECK_THROW( WCONPROD::properties(WCONPROD::all_specified_CMODE_BHP()) , std::exception); }