diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index 054531e40..86fb1408b 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -58,6 +58,7 @@ namespace Opm class TimeMap; class UnitSystem; class ErrorGuard; + class WListManager; class Schedule { public: @@ -133,6 +134,7 @@ namespace Opm const OilVaporizationProperties& getOilVaporizationProperties(size_t timestep) const; const WellTestConfig& wtestConfig(size_t timestep) const; + const WListManager& getWListManager(size_t timeStep) const; const Actions& actionConfig() const; void evalAction(const SummaryState& summary_state, size_t timeStep); @@ -174,6 +176,7 @@ namespace Opm std::map>> vfpprod_tables; std::map>> vfpinj_tables; DynamicState> wtest_config; + DynamicState> wlist_manager; WellProducer::ControlModeEnum m_controlModeWHISTCTL; Actions actions; @@ -188,6 +191,7 @@ namespace Opm bool handleGroupFromWELSPECS(const std::string& groupName, GroupTree& newTree) const; void addGroup(const std::string& groupName , size_t timeStep); void addWell(const std::string& wellName, const DeckRecord& record, size_t timeStep, WellCompletion::CompletionOrderEnum wellCompletionOrder); + void handleWLIST(const DeckKeyword& keyword, size_t currentStep); void handleCOMPORD(const ParseContext& parseContext, ErrorGuard& errors, const DeckKeyword& compordKeyword, size_t currentStep); void handleWELSPECS( const SCHEDULESection&, size_t, size_t ); void handleWCONProducer( const DeckKeyword& keyword, size_t currentStep, bool isPredictionMode, const ParseContext& parseContext, ErrorGuard& errors); diff --git a/opm/parser/eclipse/EclipseState/Schedule/WList.hpp b/opm/parser/eclipse/EclipseState/Schedule/WList.hpp index f5c92d261..814a4ed0b 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/WList.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/WList.hpp @@ -29,6 +29,7 @@ public: std::size_t size() const; void add(const std::string& well); void del(const std::string& well); + bool has(const std::string& well) const; std::vector wells() const; storage::const_iterator begin() const; diff --git a/opm/parser/eclipse/EclipseState/Schedule/WListManager.hpp b/opm/parser/eclipse/EclipseState/Schedule/WListManager.hpp index b74155f28..8d1915368 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/WListManager.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/WListManager.hpp @@ -29,6 +29,7 @@ class WListManager { public: bool hasList(const std::string&) const; WList& getList(const std::string& name); + const WList& getList(const std::string& name) const; WList& newList(const std::string& name); void delWell(const std::string& well); private: diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index 3ba4aaab7..32996f7a4 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -54,6 +54,8 @@ #include #include #include +#include +#include #include #include #include @@ -81,7 +83,8 @@ namespace Opm { m_tuning( this->m_timeMap ), m_messageLimits( this->m_timeMap ), m_runspec( runspec ), - wtest_config(this->m_timeMap, std::make_shared() ) + wtest_config(this->m_timeMap, std::make_shared() ), + wlist_manager( this->m_timeMap, std::make_shared()) { m_controlModeWHISTCTL = WellProducer::CMODE_UNDEFINED; addGroup( "FIELD", 0 ); @@ -209,6 +212,9 @@ namespace Opm { currentStep += keyword.getRecord(0).getItem(0).size(); // This is a bit weird API. } + else if (keyword.name() == "WLIST") + handleWLIST( keyword, currentStep ); + else if (keyword.name() == "WELSPECS") handleWELSPECS( section, keywordIdx, currentStep ); @@ -888,6 +894,50 @@ namespace Opm { } + void Schedule::handleWLIST(const DeckKeyword& keyword, size_t currentStep) { + const std::string legal_actions = "NEW:ADD:DEL:MOV"; + const auto& current = *this->wlist_manager.get(currentStep); + std::shared_ptr new_wlm(new WListManager(current)); + for (const auto& record : keyword) { + const std::string& name = record.getItem("NAME").getTrimmedString(0); + const std::string& action = record.getItem("ACTION").getTrimmedString(0); + const std::vector& wells = record.getItem("WELLS").getData(); + + if (legal_actions.find(action) == std::string::npos) + throw std::invalid_argument("The action:" + action + " is not recognized."); + + for (const auto& well : wells) { + if (!this->hasWell(well)) + throw std::invalid_argument("The well: " + well + " has not been defined in the WELSPECS"); + } + + if (name[0] != '*') + throw std::invalid_argument("The list name in WLIST must start with a '*'"); + + if (action == "NEW") + new_wlm->newList(name); + + if (!new_wlm->hasList(name)) + throw std::invalid_argument("Invalid well list: " + name); + + auto& wlist = new_wlm->getList(name); + if (action == "MOV") { + for (const auto& well : wells) + new_wlm->delWell(well); + } + + if (action == "DEL") { + for (const auto& well : wells) + wlist.del(well); + } else { + for (const auto& well : wells) + wlist.add(well); + } + + } + this->wlist_manager.update(currentStep, new_wlm); + } + void Schedule::handleWTEST(const DeckKeyword& keyword, size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors) { const auto& current = *this->wtest_config.get(currentStep); std::shared_ptr new_config(new WellTestConfig(current)); @@ -2084,7 +2134,10 @@ namespace Opm { return *ptr; } - + const WListManager& Schedule::getWListManager(size_t timeStep) const { + const auto& ptr = this->wlist_manager.get(timeStep); + return *ptr; + } size_t Schedule::size() const { diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/WList.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/WList.cpp index 61f6250b4..d5fe99feb 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/WList.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/WList.cpp @@ -27,6 +27,10 @@ std::size_t WList::size() const { } +bool WList::has(const std::string& well) const { + return (this->well_list.find(well) != this->well_list.end()); +} + void WList::add(const std::string& well) { this->well_list.insert(well); } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/WListManager.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/WListManager.cpp index 88956a54f..c28898d2f 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/WListManager.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/WListManager.cpp @@ -38,6 +38,10 @@ namespace Opm { return this->wlists.at(name); } + const WList& WListManager::getList(const std::string& name) const { + return this->wlists.at(name); + } + void WListManager::delWell(const std::string& well) { for (auto& pair: this->wlists) { auto& wlist = pair.second; diff --git a/src/opm/parser/eclipse/share/keywords/000_Eclipse100/W/WLIST b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/W/WLIST new file mode 100644 index 000000000..35df7617c --- /dev/null +++ b/src/opm/parser/eclipse/share/keywords/000_Eclipse100/W/WLIST @@ -0,0 +1,5 @@ +{"name" : "WLIST", "sections" : ["SCHEDULE"], "items" : + [{"name" : "NAME" , "value_type" : "STRING"}, + {"name" : "ACTION" , "value_type" : "STRING"}, + {"name" : "WELLS" , "value_type" : "STRING", "size_type" : "ALL"}]} + diff --git a/src/opm/parser/eclipse/share/keywords/keyword_list.cmake b/src/opm/parser/eclipse/share/keywords/keyword_list.cmake index fda201268..5a0ac0285 100644 --- a/src/opm/parser/eclipse/share/keywords/keyword_list.cmake +++ b/src/opm/parser/eclipse/share/keywords/keyword_list.cmake @@ -389,6 +389,7 @@ set( keywords 000_Eclipse100/W/WINJMULT 000_Eclipse100/W/WLIFT 000_Eclipse100/W/WLIMTOL + 000_Eclipse100/W/WLIST 000_Eclipse100/W/WORKLIM 000_Eclipse100/W/WORKTHP 000_Eclipse100/W/WPAVE diff --git a/tests/parser/WLIST.cpp b/tests/parser/WLIST.cpp index c1b585937..80e784bcb 100644 --- a/tests/parser/WLIST.cpp +++ b/tests/parser/WLIST.cpp @@ -24,9 +24,16 @@ #include +#include +#include #include #include +#include +#include + +using namespace Opm; + BOOST_AUTO_TEST_CASE(CreateWLIST) { Opm::WList wlist; BOOST_CHECK_EQUAL(wlist.size(), 0); @@ -72,6 +79,7 @@ BOOST_AUTO_TEST_CASE(WLISTManager) { wlist1.add("B"); wlist1.add("C"); } + // If a new list is added with the same name as an existing list the old // list is dropped and a new list is created. { @@ -94,3 +102,153 @@ BOOST_AUTO_TEST_CASE(WLISTManager) { BOOST_CHECK( std::find(wlist1.begin(), wlist1.end(), "W1") == wlist1.end()); BOOST_CHECK( std::find(wlist2.begin(), wlist2.end(), "W1") == wlist2.end()); } + + +static std::string WELSPECS() { + return + "WELSPECS\n" + " \'W1\' \'OP\' 1 1 1.0 \'OIL\' 7* /\n" + " \'W2\' \'OP\' 2 1 1.0 \'OIL\' 7* /\n" + " \'W3\' \'OP\' 3 1 1.0 \'OIL\' 7* /\n" + " \'W4\' \'OP\' 4 1 1.0 \'OIL\' 7* /\n" + "/\n"; +} + +static Opm::Schedule createSchedule(const std::string& schedule) { + Opm::Parser parser; + std::string input = + "START -- 0 \n" + "10 MAI 2007 / \n" + "SCHEDULE\n"+ schedule; + + /* + "SCHEDULE\n" + "WELSPECS\n" + " \'W_1\' \'OP\' 30 37 3.33 \'OIL\' 7* / \n" + "/ \n" + "DATES -- 1\n" + " 10 \'JUN\' 2007 / \n" + "/\n" + "DATES -- 2,3\n" + " 10 JLY 2007 / \n" + " 10 AUG 2007 / \n" + "/\n" + "WELSPECS\n" + " \'WX2\' \'OP\' 30 37 3.33 \'OIL\' 7* / \n" + " \'W_3\' \'OP\' 20 51 3.92 \'OIL\' 7* / \n" + "/\n"; + */ + + auto deck = parser.parseString(input); + EclipseGrid grid(10,10,10); + TableManager table ( deck ); + Eclipse3DProperties eclipseProperties ( deck , table, grid); + Runspec runspec (deck); + return Schedule(deck, grid , eclipseProperties, runspec ); +} + + +BOOST_AUTO_TEST_CASE(WlistFromDeck) { + std::string no_wlist = WELSPECS(); + no_wlist += + "DATES\n" + "10 JLY 2007 /\n" + "10 AUG 2007 /\n" + "/\n"; + + + Opm::Schedule sched = createSchedule(no_wlist); + auto& wlm = sched.getWListManager(1); + BOOST_CHECK(!wlm.hasList("LIST1")); +} + +BOOST_AUTO_TEST_CASE(WlistInvalid) { + std::string wlist_invalid_well = WELSPECS() + + "WLIST\n" + " \'*LIST1\' \'NEW\' WELLX /\n" + "/\n" + "DATES\n" + "10 JLY 2007 /\n" + "10 AUG 2007 /\n" + "/\n"; + + std::string wlist_invalid_action = WELSPECS() + + "WLIST\n" + " \'*LIST1\' \'NEWX\' W1 /\n" + "/\n" + "DATES\n" + "10 JLY 2007 /\n" + "10 AUG 2007 /\n" + "/\n"; + + std::string wlist_invalid_list1 = WELSPECS() + + "WLIST\n" + " \'LIST1\' \'NEW\' W1 /\n" + "/\n" + "DATES\n" + "10 JLY 2007 /\n" + "10 AUG 2007 /\n" + "/\n"; + + std::string wlist_invalid_list2 = WELSPECS() + + "WLIST\n" + " \'*LIST1\' \'NEW\' W1 /\n" + " \'*LIST2\' \'ADD\' W2 /\n" + "/\n" + "DATES\n" + "10 JLY 2007 /\n" + "10 AUG 2007 /\n" + "/\n"; + + BOOST_CHECK_THROW( createSchedule(wlist_invalid_well), std::invalid_argument); + BOOST_CHECK_THROW( createSchedule(wlist_invalid_well), std::invalid_argument); + BOOST_CHECK_THROW( createSchedule(wlist_invalid_action), std::invalid_argument); + BOOST_CHECK_THROW( createSchedule(wlist_invalid_list1), std::invalid_argument); + BOOST_CHECK_THROW( createSchedule(wlist_invalid_list2), std::invalid_argument); +} + +BOOST_AUTO_TEST_CASE(Wlist) { + std::string wlist = WELSPECS() + + "WLIST\n" + " \'*LIST1\' \'NEW\' W1 W2 /\n" + " \'*LIST1\' \'ADD\' W3 W4 /\n" + " \'*LIST2\' \'NEW\' W1 W3 /\n" + "/\n" + "DATES\n" + "10 JLY 2007 /\n" + "10 AUG 2007 /\n" + "/\n" + "WLIST\n" + " \'*LIST3\' \'NEW\' /\n" + " \'*LIST3\' \'MOV\' W1 W3 /\n" + "/\n"; + + auto sched = createSchedule(wlist); + { + const auto& wlm = sched.getWListManager(1); + const auto& wl1 = wlm.getList("*LIST1"); + const auto& wl2 = wlm.getList("*LIST2"); + + BOOST_CHECK_EQUAL(wl1.wells().size(), 4 ); + BOOST_CHECK_EQUAL(wl2.wells().size(), 2 ); + } + { + const auto& wlm = sched.getWListManager(2); + const auto& wl1 = wlm.getList("*LIST1"); + const auto& wl2 = wlm.getList("*LIST2"); + const auto& wl3 = wlm.getList("*LIST3"); + + BOOST_CHECK_EQUAL(wl1.wells().size(), 2 ); + BOOST_CHECK_EQUAL(wl2.wells().size(), 0 ); + BOOST_CHECK_EQUAL(wl3.wells().size(), 2 ); + + BOOST_CHECK( wl1.has("W2")); + BOOST_CHECK( wl1.has("W4")); + + BOOST_CHECK( !wl2.has("W1")); + BOOST_CHECK( !wl2.has("W3")); + + BOOST_CHECK( wl3.has("W1")); + BOOST_CHECK( wl3.has("W3")); + } +}