diff --git a/opm/parser/eclipse/Deck/Section.cpp b/opm/parser/eclipse/Deck/Section.cpp index 09b842ef3..39848a93b 100644 --- a/opm/parser/eclipse/Deck/Section.cpp +++ b/opm/parser/eclipse/Deck/Section.cpp @@ -21,34 +21,49 @@ #include #include #include +#include +#include #include #include namespace Opm { - Section::Section(DeckConstPtr deck, const std::string& startKeyword, const std::vector& stopKeywords ) : m_name( startKeyword ) { - populateKeywords(deck, startKeyword, stopKeywords); + Section::NullStream Section::nullStream; + + Section::Section(DeckConstPtr deck, const std::string& startKeywordName) + : m_name(startKeywordName) + { + populateSection(deck, startKeywordName); } - void Section::populateKeywords(DeckConstPtr deck, const std::string& startKeyword, - const std::vector& stopKeywords) + void Section::populateSection(DeckConstPtr deck, const std::string& startKeywordName) { // find the first occurence of the section's start keyword - size_t i = 0; - for (; isize() && deck->getKeyword(i)->name() != startKeyword; i++); - - if (i == deck->size()) - throw std::invalid_argument(std::string("Deck requires a '")+startKeyword+"' section"); - - for (; isize(); i++) { - if (std::find(stopKeywords.begin(), stopKeywords.end(), deck->getKeyword(i)->name()) != stopKeywords.end()) + size_t startKeywordIdx = 0; + for (; startKeywordIdxsize(); startKeywordIdx++) { + if (deck->getKeyword(startKeywordIdx)->name() == startKeywordName) break; - m_keywords.addKeyword(deck->getKeyword(i)); } - for (; isize(); i++) - if (deck->getKeyword(i)->name() == startKeyword) - throw std::invalid_argument(std::string("Deck contains the '")+startKeyword+"' section multiple times"); + if (startKeywordIdx >= deck->size()) + throw std::invalid_argument(std::string("Deck requires a '")+startKeywordName+"' section"); + + // make sure that the section identifier is unique + for (size_t j = startKeywordIdx + 1; j < deck->size(); j++) + if (deck->getKeyword(j)->name() == startKeywordName) + throw std::invalid_argument(std::string("Deck contains the '")+startKeywordName+"' section multiple times"); + + // populate the section with keywords + for (size_t curKeywordIdx = startKeywordIdx; + curKeywordIdx < deck->size(); + curKeywordIdx++) + { + const std::string &keywordName = deck->getKeyword(curKeywordIdx)->name(); + if (curKeywordIdx > startKeywordIdx && isSectionDelimiter(keywordName)) + break; + + m_keywords.addKeyword(deck->getKeyword(curKeywordIdx)); + } } size_t Section::count(const std::string& keyword) const { @@ -83,8 +98,123 @@ namespace Opm { return m_keywords.getKeyword(index); } - bool Section::hasSection(DeckConstPtr deck, const std::string& startKeyword) { - return deck->hasKeyword(startKeyword); + bool Section::checkSectionTopology(DeckConstPtr deck, std::ostream& os) + { + if (deck->size() == 0) { + os << "empty decks are invalid\n"; + return false; + } + + if (deck->getKeyword(0)->name() != "RUNSPEC") { + os << "The first keyword of a valid deck must be RUNSPEC\n"; + return false; + } + + std::string curSectionName = deck->getKeyword(0)->name(); + size_t curKwIdx = 1; + for (; curKwIdx < deck->size(); ++curKwIdx) { + const std::string& curKeywordName = deck->getKeyword(curKwIdx)->name(); + if (!isSectionDelimiter(curKeywordName)) + continue; + + if (curSectionName == "RUNSPEC") { + if (curKeywordName != "GRID") { + os << "The RUNSPEC section must be followed by GRID instead of " + << curKeywordName << "\n"; + return false; + } + + curSectionName = curKeywordName; + } + else if (curSectionName == "GRID") { + if (curKeywordName != "EDIT" && curKeywordName != "PROPS") { + os << "The GRID section must be followed by EDIT or PROPS instead of " + << curKeywordName << "\n"; + return false; + } + + curSectionName = curKeywordName; + } + else if (curSectionName == "EDIT") { + if (curKeywordName != "PROPS") { + os << "The EDIT section must be followed by PROPS instead of " + << curKeywordName << "\n"; + return false; + } + + curSectionName = curKeywordName; + } + else if (curSectionName == "PROPS") { + if (curKeywordName != "REGIONS" && curKeywordName != "SOLUTION") { + os << "The PROPS section must be followed by REGIONS or SOLUTION instead of " + << curKeywordName << "\n"; + return false; + } + + curSectionName = curKeywordName; + } + else if (curSectionName == "REGIONS") { + if (curKeywordName != "SOLUTION") { + os << "The REGIONS section must be followed by SOLUTION instead of " + << curKeywordName << "\n"; + return false; + } + + curSectionName = curKeywordName; + } + else if (curSectionName == "SOLUTION") { + if (curKeywordName != "SUMMARY" && curKeywordName != "SCHEDULE") { + os << "The SOLUTION section must be followed by SUMMARY or SCHEDULE instead of " + << curKeywordName << "\n"; + return false; + } + + curSectionName = curKeywordName; + } + else if (curSectionName == "SUMMARY") { + if (curKeywordName != "SCHEDULE") { + os << "The SUMMARY section must be followed by SCHEDULE instead of " + << curKeywordName << "\n"; + return false; + } + + curSectionName = curKeywordName; + } + else if (curSectionName == "SCHEDULE") { + // schedule is the last section, so every section delimiter after it is wrong... + os << "The SCHEDULE section must be the last one (" + << curKeywordName << " specified after SCHEDULE)\n"; + return false; + } + } + + // SCHEDULE is the last section and it is mandatory, so make sure it is there + if (curSectionName != "SCHEDULE") { + os << "The last section of a valid deck must be SCHEDULE\n"; + return false; + } + + return true; + } + + bool Section::isSectionDelimiter(const std::string& keywordName) { + static std::set sectionDelimiters; + if (sectionDelimiters.size() == 0) { + sectionDelimiters.insert("RUNSPEC"); + sectionDelimiters.insert("GRID"); + sectionDelimiters.insert("EDIT"); + sectionDelimiters.insert("PROPS"); + sectionDelimiters.insert("REGIONS"); + sectionDelimiters.insert("SOLUTION"); + sectionDelimiters.insert("SUMMARY"); + sectionDelimiters.insert("SCHEDULE"); + } + + return sectionDelimiters.count(keywordName) > 0; + } + + bool Section::hasSection(DeckConstPtr deck, const std::string& startKeywordName) { + return deck->hasKeyword(startKeywordName); } } diff --git a/opm/parser/eclipse/Deck/Section.hpp b/opm/parser/eclipse/Deck/Section.hpp index 5844b6f1c..17fad3e1b 100644 --- a/opm/parser/eclipse/Deck/Section.hpp +++ b/opm/parser/eclipse/Deck/Section.hpp @@ -23,12 +23,23 @@ #include #include +#include +#include +#include + namespace Opm { class Section : public boost::iterator_facade { + // see https://stackoverflow.com/questions/11826554/standard-no-op-output-stream + class NullStream : public std::ostream + { + public: + int overflow(int c) { return c; } + }; + static NullStream nullStream; public: - Section(DeckConstPtr deck, const std::string& startKeyword, const std::vector& stopKeywords ); + Section(DeckConstPtr deck, const std::string& startKeyword); bool hasKeyword( const std::string& keyword ) const; std::vector::iterator begin(); std::vector::iterator end(); @@ -45,50 +56,55 @@ namespace Opm { static bool hasEDIT(DeckConstPtr deck) { return hasSection( deck , "EDIT" ); } static bool hasGRID(DeckConstPtr deck) { return hasSection( deck , "GRID" ); } static bool hasRUNSPEC(DeckConstPtr deck) { return hasSection( deck , "RUNSPEC" ); } + + // returns whether the deck has all mandatory sections and if all sections are in + // the right order + static bool checkSectionTopology(DeckConstPtr deck, std::ostream& os = nullStream); + private: KeywordContainer m_keywords; std::string m_name; + static bool isSectionDelimiter(const std::string& keywordName); static bool hasSection(DeckConstPtr deck, const std::string& startKeyword); - void populateKeywords(DeckConstPtr deck, const std::string& startKeyword, const std::vector& stopKeywords); + void populateSection(DeckConstPtr deck, const std::string& startKeyword); }; typedef std::shared_ptr
SectionPtr; typedef std::shared_ptr SectionConstPtr; - class RUNSPECSection : public Section { public: - RUNSPECSection(DeckConstPtr deck) : Section (deck, "RUNSPEC", std::vector() = {"GRID", "EDIT", "PROPS", "REGIONS", "SOLUTION", "SUMMARY", "SCHEDULE"}) {} + RUNSPECSection(DeckConstPtr deck) : Section(deck, "RUNSPEC") {} }; class GRIDSection : public Section { public: - GRIDSection(DeckConstPtr deck) : Section (deck, "GRID", std::vector() = {"RUNSPEC", "EDIT", "PROPS", "REGIONS", "SOLUTION", "SUMMARY", "SCHEDULE"}) {} + GRIDSection(DeckConstPtr deck) : Section(deck, "GRID") {} }; class EDITSection : public Section { public: - EDITSection(DeckConstPtr deck) : Section (deck, "EDIT", std::vector() = {"RUNSPEC", "GRID", "PROPS", "REGIONS", "SOLUTION", "SUMMARY", "SCHEDULE"}) {} + EDITSection(DeckConstPtr deck) : Section(deck, "EDIT") {} }; class PROPSSection : public Section { public: - PROPSSection(DeckConstPtr deck) : Section (deck, "PROPS", std::vector() = {"RUNSPEC", "GRID", "EDIT", "REGIONS", "SOLUTION", "SUMMARY", "SCHEDULE"}) {} + PROPSSection(DeckConstPtr deck) : Section(deck, "PROPS") {} }; class REGIONSSection : public Section { public: - REGIONSSection(DeckConstPtr deck) : Section (deck, "REGIONS", std::vector() = {"RUNSPEC", "GRID", "EDIT", "PROPS", "SOLUTION", "SUMMARY", "SCHEDULE"}) {} + REGIONSSection(DeckConstPtr deck) : Section(deck, "REGIONS") {} }; class SOLUTIONSection : public Section { public: - SOLUTIONSection(DeckConstPtr deck) : Section (deck, "SOLUTION", std::vector() = {"RUNSPEC", "GRID", "EDIT", "PROPS", "REGIONS", "SUMMARY", "SCHEDULE"}) {} + SOLUTIONSection(DeckConstPtr deck) : Section(deck, "SOLUTION") {} }; class SCHEDULESection : public Section { public: - SCHEDULESection(DeckConstPtr deck) : Section (deck, "SCHEDULE", std::vector() = {"RUNSPEC", "GRID", "EDIT", "PROPS", "REGIONS", "SOLUTION", "SUMMARY"}) {} + SCHEDULESection(DeckConstPtr deck) : Section(deck, "SCHEDULE") {} }; } diff --git a/opm/parser/eclipse/Deck/tests/SectionTests.cpp b/opm/parser/eclipse/Deck/tests/SectionTests.cpp index 97166d160..deb2a638d 100644 --- a/opm/parser/eclipse/Deck/tests/SectionTests.cpp +++ b/opm/parser/eclipse/Deck/tests/SectionTests.cpp @@ -30,43 +30,47 @@ using namespace Opm; BOOST_AUTO_TEST_CASE(SectionTest) { DeckPtr deck(new Deck()); - DeckKeywordPtr test1(new DeckKeyword("TEST1")); - deck->addKeyword(test1); - DeckKeywordPtr test2(new DeckKeyword("TEST2")); - deck->addKeyword(test2); - DeckKeywordPtr test3(new DeckKeyword("TEST3")); - deck->addKeyword(test3); - DeckKeywordPtr test4(new DeckKeyword("TEST4")); - deck->addKeyword(test4); - Section section(deck, "TEST1", std::vector() = {"TEST3", "TEST4"}); - BOOST_CHECK_EQUAL(true, section.hasKeyword("TEST1")); - BOOST_CHECK_EQUAL(true, section.hasKeyword("TEST2")); - BOOST_CHECK_EQUAL(false, section.hasKeyword("TEST3")); - BOOST_CHECK_EQUAL(false, section.hasKeyword("TEST4")); + deck->addKeyword(std::make_shared("TEST0")); + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST3")); - BOOST_CHECK_EQUAL( section.name() , "TEST1" ); - BOOST_CHECK_EQUAL( section.count("TEST1") , 1); + Section runspecSection(deck, "RUNSPEC"); + Section gridSection(deck, "GRID"); + BOOST_CHECK(runspecSection.hasKeyword("TEST1")); + BOOST_CHECK(gridSection.hasKeyword("TEST2")); + BOOST_CHECK(!runspecSection.hasKeyword("TEST0")); + BOOST_CHECK(!gridSection.hasKeyword("TEST0")); + BOOST_CHECK(!runspecSection.hasKeyword("TEST3")); + BOOST_CHECK(!gridSection.hasKeyword("TEST3")); + BOOST_CHECK(!runspecSection.hasKeyword("TEST2")); + BOOST_CHECK(!gridSection.hasKeyword("TEST1")); } BOOST_AUTO_TEST_CASE(IteratorTest) { DeckPtr deck(new Deck()); - DeckKeywordPtr test1(new DeckKeyword("TEST1")); + DeckKeywordPtr test1(new DeckKeyword("RUNSPEC")); deck->addKeyword(test1); DeckKeywordPtr test2(new DeckKeyword("TEST2")); deck->addKeyword(test2); DeckKeywordPtr test3(new DeckKeyword("TEST3")); deck->addKeyword(test3); - DeckKeywordPtr test4(new DeckKeyword("TEST4")); + DeckKeywordPtr test4(new DeckKeyword("GRID")); deck->addKeyword(test4); - Section section(deck, "TEST1", std::vector() = {"TEST3", "TEST4"}); + Section section(deck, "RUNSPEC"); int numberOfItems = 0; for (auto iter=section.begin(); iter != section.end(); ++iter) { std::cout << (*iter)->name() << std::endl; numberOfItems++; } - BOOST_CHECK_EQUAL(2, numberOfItems); + + // the keywords expected here are RUNSPEC, TEST2 and TEST3... + BOOST_CHECK_EQUAL(3, numberOfItems); } BOOST_AUTO_TEST_CASE(RUNSPECSection_EmptyDeck) { @@ -76,25 +80,20 @@ BOOST_AUTO_TEST_CASE(RUNSPECSection_EmptyDeck) { BOOST_AUTO_TEST_CASE(RUNSPECSection_ReadSimpleDeck) { DeckPtr deck(new Deck()); - DeckKeywordPtr test1(new DeckKeyword("TEST1")); - deck->addKeyword(test1); - DeckKeywordPtr runSpec(new DeckKeyword("RUNSPEC")); - deck->addKeyword(runSpec); - DeckKeywordPtr test2(new DeckKeyword("TEST2")); - deck->addKeyword(test2); - DeckKeywordPtr test3(new DeckKeyword("TEST3")); - deck->addKeyword(test3); - DeckKeywordPtr grid(new DeckKeyword("GRID")); - deck->addKeyword(grid); - DeckKeywordPtr test4(new DeckKeyword("TEST4")); - deck->addKeyword(test4); + deck->addKeyword(std::make_shared("TEST1")); + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST2")); + deck->addKeyword(std::make_shared("TEST3")); + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST4")); + RUNSPECSection section(deck); - BOOST_CHECK_EQUAL(false, section.hasKeyword("TEST1")); - BOOST_CHECK_EQUAL(true, section.hasKeyword("RUNSPEC")); - BOOST_CHECK_EQUAL(true, section.hasKeyword("TEST2")); - BOOST_CHECK_EQUAL(true, section.hasKeyword("TEST3")); - BOOST_CHECK_EQUAL(false, section.hasKeyword("GRID")); - BOOST_CHECK_EQUAL(false, section.hasKeyword("TEST4")); + BOOST_CHECK(!section.hasKeyword("TEST1")); + BOOST_CHECK(section.hasKeyword("RUNSPEC")); + BOOST_CHECK(section.hasKeyword("TEST2")); + BOOST_CHECK(section.hasKeyword("TEST3")); + BOOST_CHECK(!section.hasKeyword("GRID")); + BOOST_CHECK(!section.hasKeyword("TEST4")); } BOOST_AUTO_TEST_CASE(RUNSPECSection_ReadSmallestPossibleDeck) { @@ -225,3 +224,247 @@ BOOST_AUTO_TEST_CASE(SCHEDULESection_NotTerminated) { BOOST_CHECK( Section::hasSCHEDULE(deck )); BOOST_CHECK( !Section::hasREGIONS(deck )); } + +BOOST_AUTO_TEST_CASE(Section_ValidDecks) { + // minimal deck + DeckPtr deck(new Deck()); + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST5")); + + BOOST_CHECK(Opm::Section::checkSectionTopology(deck)); + + // deck with all optional sections + deck.reset(new Deck()); + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("EDIT")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("REGIONS")); + deck->addKeyword(std::make_shared("TEST5")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST6")); + + deck->addKeyword(std::make_shared("SUMMARY")); + deck->addKeyword(std::make_shared("TEST7")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST8")); + + BOOST_CHECK(Opm::Section::checkSectionTopology(deck)); +} + +BOOST_AUTO_TEST_CASE(Section_InvalidDecks) { + // keyword before RUNSPEC + DeckPtr deck(new Deck()); + + deck->addKeyword(std::make_shared("TEST0")); + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST5")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); + + // wrong section order + deck.reset(new Deck()); + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("EDIT")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("REGIONS")); + deck->addKeyword(std::make_shared("TEST5")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST6")); + + deck->addKeyword(std::make_shared("SUMMARY")); + deck->addKeyword(std::make_shared("TEST7")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST8")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); + + // duplicate section + deck.reset(new Deck()); + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST21")); + + deck->addKeyword(std::make_shared("EDIT")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("REGIONS")); + deck->addKeyword(std::make_shared("TEST5")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST6")); + + deck->addKeyword(std::make_shared("SUMMARY")); + deck->addKeyword(std::make_shared("TEST7")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST8")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); + + // section after SCHEDULE + deck.reset(new Deck()); + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("REGIONS")); + deck->addKeyword(std::make_shared("TEST5")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST6")); + + deck->addKeyword(std::make_shared("SUMMARY")); + deck->addKeyword(std::make_shared("TEST7")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST8")); + + deck->addKeyword(std::make_shared("EDIT")); + deck->addKeyword(std::make_shared("TEST3")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); + + // missing RUNSPEC + deck.reset(new Deck()); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST5")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); + + // missing GRID + deck.reset(new Deck()); + + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST5")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); + + // missing PROPS + deck.reset(new Deck()); + + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST4")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST5")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); + + // missing SOLUTION + deck.reset(new Deck()); + + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("SCHEDULE")); + deck->addKeyword(std::make_shared("TEST5")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); + + // missing SCHEDULE + deck.reset(new Deck()); + + deck->addKeyword(std::make_shared("RUNSPEC")); + deck->addKeyword(std::make_shared("TEST1")); + + deck->addKeyword(std::make_shared("GRID")); + deck->addKeyword(std::make_shared("TEST2")); + + deck->addKeyword(std::make_shared("PROPS")); + deck->addKeyword(std::make_shared("TEST3")); + + deck->addKeyword(std::make_shared("SOLUTION")); + deck->addKeyword(std::make_shared("TEST4")); + + BOOST_CHECK(!Opm::Section::checkSectionTopology(deck)); +}