From b9bd1598d7f15e430efe17f90a3a381603f7f3b7 Mon Sep 17 00:00:00 2001 From: Joakim Hove Date: Thu, 22 Oct 2020 17:04:40 +0200 Subject: [PATCH] Changes to well reference depth 1. The well reference depth should *not* be updated when new connections are added with COMPDAT. 2. The well reference depth should be recalculated when the well is updated with the WELSPECS keyword. --- .../EclipseState/Schedule/Schedule.hpp | 2 +- .../EclipseState/Schedule/Well/Well.hpp | 7 +- .../EclipseState/Schedule/KeywordHandlers.cpp | 28 +++-- .../EclipseState/Schedule/Schedule.cpp | 12 +- .../EclipseState/Schedule/Well/Well.cpp | 23 ++-- tests/parser/WellTests.cpp | 108 ++++++++++++++++++ 6 files changed, 153 insertions(+), 27 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index 67c2bda88..9505020f5 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -376,7 +376,7 @@ namespace Opm int headI, int headJ, Phase preferredPhase, - double refDepth, + const std::optional& refDepth, double drainageRadius, bool allowCrossFlow, bool automaticShutIn, diff --git a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp index de20113d1..e3add6ecb 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp @@ -463,7 +463,7 @@ public: std::size_t insert_index, int headI, int headJ, - double ref_depth, + const std::optional& ref_depth, const WellType& wtype_arg, ProducerCMode whistctl_cmode, Connection::Order ordering, @@ -552,7 +552,8 @@ public: bool updateCrossFlow(bool allow_cross_flow); bool updatePVTTable(int pvt_table); bool updateHead(int I, int J); - bool updateRefDepth(double ref_dpeth); + void updateRefDepth(); + bool updateRefDepth(const std::optional& ref_dpeth); bool updateDrainageRadius(double drainage_radius); void updateSegments(std::shared_ptr segments_arg); bool updateConnections(std::shared_ptr connections); @@ -651,7 +652,7 @@ private: std::size_t insert_index; int headI; int headJ; - double ref_depth; + std::optional ref_depth; double drainage_radius; bool allow_cross_flow; bool automatic_shutin; diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp index de9f54823..b3e9ef685 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp @@ -143,6 +143,7 @@ namespace { } void Schedule::handleCOMPDAT(const HandlerContext& handlerContext, const ParseContext& parseContext, ErrorGuard& errors) { + std::unordered_set wells; for (const auto& record : handlerContext.keyword) { const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0); auto wellnames = this->wellNames(wellNamePattern, handlerContext.currentStep); @@ -153,14 +154,24 @@ namespace { auto well2 = std::shared_ptr(new Well( this->getWell(name, handlerContext.currentStep))); auto connections = std::shared_ptr( new WellConnections( well2->getConnections())); connections->loadCOMPDAT(record, handlerContext.grid, handlerContext.fieldPropsManager); - - if (well2->updateConnections(connections, handlerContext.grid, handlerContext.fieldPropsManager.get_int("PVTNUM"))) + if (well2->updateConnections(connections, handlerContext.grid, handlerContext.fieldPropsManager.get_int("PVTNUM"))) { this->updateWell(std::move(well2), handlerContext.currentStep); - + wells.insert( name ); + } this->addWellGroupEvent(name, ScheduleEvents::COMPLETION_CHANGE, handlerContext.currentStep); } } m_events.addEvent(ScheduleEvents::COMPLETION_CHANGE, handlerContext.currentStep); + + // In the case the wells reference depth has been defaulted in the + // WELSPECS keyword we need to force a calculation of the wells + // reference depth exactly when the COMPDAT keyword has been completely + // processed. + for (const auto& wname : wells) { + const auto& dynamic_state = this->wells_static.at(wname); + auto& well_ptr = dynamic_state.get(handlerContext.currentStep); + well_ptr->updateRefDepth(); + } } void Schedule::handleCOMPLUMP(const HandlerContext& handlerContext, const ParseContext&, ErrorGuard&) { @@ -1200,18 +1211,19 @@ namespace { const auto& refDepthItem = record.getItem(); int pvt_table = record.getItem().get(0); double drainageRadius = record.getItem().getSIDouble(0); - double refDepth = refDepthItem.hasValue(0) - ? refDepthItem.getSIDouble(0) - : -1.0; + std::optional ref_depth; + if (refDepthItem.hasValue(0)) + ref_depth = refDepthItem.getSIDouble(0); { bool update = false; auto well2 = std::shared_ptr(new Well( this->getWell(wellName, handlerContext.currentStep))); - update = well2->updateHead(headI, headJ); - update |= well2->updateRefDepth(refDepth); + update = well2->updateHead(headI, headJ); + update |= well2->updateRefDepth(ref_depth); update |= well2->updateDrainageRadius(drainageRadius); update |= well2->updatePVTTable(pvt_table); if (update) { + well2->updateRefDepth(); this->updateWell(std::move(well2), handlerContext.currentStep); this->addWellGroupEvent(wellName, ScheduleEvents::WELL_WELSPECS_UPDATE, handlerContext.currentStep); } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index cdb71be3a..b38884c61 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -799,9 +799,9 @@ private: } } const auto& refDepthItem = record.getItem("REF_DEPTH"); - double refDepth = refDepthItem.hasValue( 0 ) - ? refDepthItem.getSIDouble( 0 ) - : -1.0; + std::optional ref_depth; + if (refDepthItem.hasValue( 0 )) + ref_depth = refDepthItem.getSIDouble( 0 ); double drainageRadius = record.getItem( "D_RADIUS" ).getSIDouble(0); @@ -825,7 +825,7 @@ private: headI, headJ, preferredPhase, - refDepth, + ref_depth, drainageRadius, allowCrossFlow, automaticShutIn, @@ -854,7 +854,7 @@ private: int headI, int headJ, Phase preferredPhase, - double refDepth, + const std::optional& ref_depth, double drainageRadius, bool allowCrossFlow, bool automaticShutIn, @@ -869,7 +869,7 @@ private: timeStep, 0, headI, headJ, - refDepth, + ref_depth, WellType(preferredPhase), this->global_whistctl_mode[timeStep], wellConnectionOrder, diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp index 8d07de25a..3394dc26c 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp @@ -309,7 +309,7 @@ Well::Well(const std::string& wname_arg, std::size_t insert_index_arg, int headI_arg, int headJ_arg, - double ref_depth_arg, + const std::optional& ref_depth_arg, const WellType& wtype_arg, ProducerCMode whistctl_cmode, Connection::Order ordering_arg, @@ -638,7 +638,7 @@ bool Well::updateStatus(Status well_state, bool update_connections) { } -bool Well::updateRefDepth(double ref_depth_arg) { +bool Well::updateRefDepth(const std::optional& ref_depth_arg) { if (this->ref_depth != ref_depth_arg) { this->ref_depth = ref_depth_arg; return true; @@ -798,16 +798,21 @@ bool Well::getAllowCrossFlow() const { } double Well::getRefDepth() const { - if( this->ref_depth >= 0.0 ) - return this->ref_depth; + if (!this->ref_depth.has_value()) + throw std::logic_error(fmt::format("Well: {} - tried to access not initialized well reference depth", this->name())); + return *this->ref_depth; +} - // ref depth was defaulted and we get the depth of the first completion - if( this->connections->empty() ) { - throw std::invalid_argument( "No completions defined for well: " - + name() +void Well::updateRefDepth() { + if( !this->ref_depth ) { + // ref depth was defaulted and we get the depth of the first completion + + if( this->connections->empty() ) + throw std::invalid_argument( "No completions defined for well: " + + name() + ". Can not infer reference depth" ); + this->ref_depth = this->connections->get(0).depth(); } - return this->connections->get(0).depth(); } diff --git a/tests/parser/WellTests.cpp b/tests/parser/WellTests.cpp index b7288cab7..a56620a0e 100644 --- a/tests/parser/WellTests.cpp +++ b/tests/parser/WellTests.cpp @@ -1354,3 +1354,111 @@ END BOOST_CHECK_MESSAGE(wellP.getConnections() == wellQ.getConnections(), "P and Q must have same WellConnections VALUE"); } + + + +BOOST_AUTO_TEST_CASE(REPERF) { + const auto deck = Parser{}.parseString(R"(RUNSPEC +START +7 OCT 2020 / + +DIMENS + 10 10 4 / + +GRID +DXV + 10*100.0 / +DYV + 10*100.0 / +DZV + 4*10.0 / + +DEPTHZ + 121*2000.0 / + +PERMX + 400*100.0 / +PERMY + 400*100.0 / +PERMZ + 400*10.0 / +PORO + 400*0.3 / + +SCHEDULE + +WELSPECS + 'W1' 'G' 1 1 1* 'OIL' 2* 'STOP' 4* / +/ + +COMPDAT + 'W1' 1 1 4 4 'OPEN' 1* 34.720 0.216 3095.832 2* 'Y' 12.828 / + 'W1' 1 1 3 3 'OPEN' 1* 34.720 0.216 3095.832 2* 'Y' 12.828 / +/ +-- W0 + +TSTEP + 1 / + +COMPDAT + 'W1' 1 1 2 2 'OPEN' 1* 25.620 0.216 2086.842 2* 'Y' 8.486 / +/ + +-- W1 +TSTEP + 1 / + + + +WELSPECS + 'W1' 'G' 1 1 2005 'LIQ' / +/ + +-- W2 + +TSTEP +1 / + +WELSPECS + 'W1' 'G' 1 1 1* 'LIQ' / +/ +-- W3 + +TSTEP +1 / + + +COMPDAT + 'W1' 1 1 1 1 'OPEN' 1* 25.620 0.216 2086.842 2* 'Y' 8.486 / +/ +-- W4 +TSTEP +1 / + +WELSPECS + 'W1' 'G' 1 1 1* 'LIQ' / +/ +-- W5 + +END +)"); + + const auto es = EclipseState{ deck }; + const auto& grid = es.getInputGrid(); + const auto sched = Schedule{ deck, es }; + + const auto& w0 = sched.getWell("W1", 0); + const auto& w1 = sched.getWell("W1", 1); + const auto& w2 = sched.getWell("W1", 2); + const auto& w3 = sched.getWell("W1", 3); + const auto& w4 = sched.getWell("W1", 4); + const auto& w5 = sched.getWell("W1", 5); + + + BOOST_CHECK_EQUAL(w0.getRefDepth(), grid.getCellDepth(0,0,2)); + BOOST_CHECK_EQUAL(w1.getRefDepth(), w0.getRefDepth()); + BOOST_CHECK_EQUAL(w2.getRefDepth(), 2005 ); + BOOST_CHECK_EQUAL(w3.getRefDepth(), grid.getCellDepth(0,0,1)); + BOOST_CHECK_EQUAL(w4.getRefDepth(), w3.getRefDepth()); + BOOST_CHECK_EQUAL(w5.getRefDepth(), grid.getCellDepth(0,0,0)); +}