Merge pull request #2788 from joakim-hove/deck-view

Refactor Deck and DeckView class hierarchy
This commit is contained in:
Joakim Hove 2021-11-12 10:14:09 +01:00 committed by GitHub
commit 01a7149b36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 574 additions and 259 deletions

View File

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

View File

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

View File

@ -20,6 +20,7 @@
#ifndef DECK_HPP
#define DECK_HPP
#include <functional>
#include <map>
#include <memory>
#include <ostream>
@ -27,6 +28,7 @@
#include <vector>
#include <string>
#include <opm/parser/eclipse/Deck/DeckView.hpp>
#include <opm/parser/eclipse/Deck/DeckTree.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Units/UnitSystem.hpp>
@ -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<class Serializer>
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<std::size_t> 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<DeckKeyword>&& 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<DeckView> m_global_view{nullptr};
};
}
#endif /* DECK_HPP */

View File

@ -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<class Keyword>
const DeckKeyword& getKeyword() const {
auto view = this->operator[](Keyword::keywordName);
return view.back();
}
std::vector<const DeckKeyword*> getKeywordList(const std::string& keyword) const {
std::vector<const DeckKeyword*> kw_list;
auto view = this->operator[](keyword);
for (const auto& kw : view)
kw_list.push_back(&kw);
return kw_list;
}
template <class Keyword>
std::vector<const DeckKeyword*> getKeywordList() const {
return this->getKeywordList(Keyword::keywordName);
}
bool hasKeyword(const std::string& keyword) const {
return this->has_keyword(keyword);
}
template <class Keyword>
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") {}
};
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#ifndef DECKVIEW_HPP
#define DECKVIEW_HPP
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
namespace Opm {
class DeckView {
public:
typedef std::vector<std::reference_wrapper<const DeckKeyword>> 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<std::size_t> 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<class Keyword>
bool has_keyword() const {
return this->has_keyword( Keyword::keywordName );
}
private:
storage_type keywords;
std::unordered_map<std::string, std::vector<std::size_t>> keyword_index;
};
}
#endif

View File

@ -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<const DeckKeyword *> 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<DeckView>();
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<DeckKeyword>() )
{}
/*
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<DeckKeyword>&& 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);
}
}

View File

@ -17,53 +17,80 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <exception>
#include <algorithm>
#include <cassert>
#include <exception>
#include <iostream>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Deck/DeckSection.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/E.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/G.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/P.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/R.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/S.hpp>
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<std::string, std::size_t> section_index = {
{"RUNSPEC", 0},
{"GRID", 1},
{"EDIT", 2},
{"PROPS", 3},
{"REGIONS", 4},
{"SOLUTION", 5},
{"SUMMARY", 6},
{"SCHEDULE", 7}
};
std::pair<std::size_t, std::size_t> 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<std::string> 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);
}
}
static std::pair< DeckViewInternal::const_iterator, DeckViewInternal::const_iterator >
find_section( const Deck& deck, const std::string& keyword ) {
if (end_set.empty())
return {start_index, deck.size()};
const auto fn = [&keyword]( const DeckKeyword& kw ) {
return kw.name() == keyword;
};
std::size_t deck_index = start_index;
while (true) {
const auto& kw = deck[deck_index];
if (end_set.count(kw.name()) == 1)
break;
auto first = std::find_if( deck.begin(), deck.end(), fn );
deck_index++;
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 };
if (deck_index == deck.size())
break;
}
return {start_index, deck_index};
}
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<ParserKeywords::RUNSPEC>(); }
bool DeckSection::hasGRID(const Deck& deck) { return deck.hasKeyword<ParserKeywords::GRID>(); }
bool DeckSection::hasEDIT(const Deck& deck) { return deck.hasKeyword<ParserKeywords::EDIT>(); }
bool DeckSection::hasPROPS(const Deck& deck) { return deck.hasKeyword<ParserKeywords::PROPS>(); }
bool DeckSection::hasREGIONS(const Deck& deck) { return deck.hasKeyword<ParserKeywords::REGIONS>(); }
bool DeckSection::hasSOLUTION(const Deck& deck) { return deck.hasKeyword<ParserKeywords::SOLUTION>(); }
bool DeckSection::hasSUMMARY(const Deck& deck) { return deck.hasKeyword<ParserKeywords::SUMMARY>(); }
bool DeckSection::hasSCHEDULE(const Deck& deck) { return deck.hasKeyword<ParserKeywords::SCHEDULE>(); }
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include <functional>
#include <opm/parser/eclipse/Deck/DeckView.hpp>
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<std::size_t> 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();
}

View File

@ -29,10 +29,12 @@
#include <opm/parser/eclipse/Deck/DeckTree.hpp>
#include <opm/parser/eclipse/Deck/DeckOutput.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/Deck/DeckView.hpp>
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
#include <opm/parser/eclipse/Parser/ErrorGuard.hpp>
#include <opm/parser/eclipse/Parser/ParseContext.hpp>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Parser/ParserKeywords/D.hpp>
#include <opm/parser/eclipse/Parser/ParserItem.hpp>
#include <opm/parser/eclipse/Parser/ParserRecord.hpp>
#include <opm/common/OpmLog/KeywordLocation.hpp>
@ -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<Dimension>, std::vector<Dimension>> 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<std::string>();
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<double>();
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 <vals>
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 <vals>
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<std::string>(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<int>(0);
BOOST_CHECK_EQUAL(day, 30);
BOOST_CHECK(dw.has_keyword<ParserKeywords::DATES>());
std::vector<std::string> expected = {"START", "DIMENS", "GRID", "DXV", "DYV", "DZV", "DEPTHZ", "PORO",
"SCHEDULE", "VFPPROD", "VFPPROD", "WELSPECS", "COMPDAT", "WCONPROD",
"DATES", "DATES", "DATES"};
std::vector<std::string> 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<std::size_t> 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);
}

View File

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