From dabf988aa7c13879078a6b03aa901457377c075a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 19 Oct 2020 00:57:43 +0200 Subject: [PATCH 1/7] Split WELPI Application Into Two Parts First part, implemented in a new member function Well::getWellPIScalingFactor calculates a CTF scaling factor from stored WELPI information and a dynamically calculated well-level PI value. The second part, using the original name applyWellProdIndexScaling, applies an externally calculate CTF scaling factor to all eligble connections. This is needed to enable applying multiple scalings across the time direction. Update unit tests accordingly. --- .../EclipseState/Schedule/Well/Well.hpp | 1 + .../EclipseState/Schedule/Well/Well.cpp | 22 +++++++++++-- tests/parser/ScheduleTests.cpp | 10 ++++-- tests/parser/WellTests.cpp | 33 ++++++++++++++----- 4 files changed, 52 insertions(+), 14 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp index ba3090422..51f4ba4ef 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp @@ -600,6 +600,7 @@ public: bool operator==(const Well& data) const; void setInsertIndex(std::size_t index); void applyWellProdIndexScaling(const double currentEffectivePI); + double getWellPIScalingFactor(const double currentEffectivePI) const; template void serializeOp(Serializer& serializer) diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp index 858f48d50..96acf41b0 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp @@ -826,7 +826,23 @@ void Well::setInsertIndex(std::size_t index) { this->insert_index = index; } -void Well::applyWellProdIndexScaling(const double currentEffectivePI) { +double Well::getWellPIScalingFactor(const double currentEffectivePI) const { + if (this->connections->empty()) + // No connections for this well. Unexpected. + return 1.0; + + if (!this->productivity_index) + // WELPI not activated. Nothing to do. + return 1.0; + + if (this->productivity_index->pi_value == currentEffectivePI) + // No change in scaling. + return 1.0; + + return this->productivity_index->pi_value / currentEffectivePI; +} + +void Well::applyWellProdIndexScaling(const double scalingFactor) { if (this->connections->empty()) // No connections for this well. Unexpected. return; @@ -835,11 +851,11 @@ void Well::applyWellProdIndexScaling(const double currentEffectivePI) { // WELPI not activated. Nothing to do. return; - if (this->productivity_index->pi_value == currentEffectivePI) + if (scalingFactor == 1.0) // No change in scaling. return; - this->connections->applyWellPIScaling(this->productivity_index->pi_value / currentEffectivePI); + this->connections->applyWellPIScaling(scalingFactor); } const WellConnections& Well::getConnections() const { diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index b9f78cd90..838b6841f 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -3790,7 +3790,10 @@ END const auto expectCF = (200.0 / 100.0) * 100.0*cp_rm3_per_db(); auto wellP = sched.getWell("P", 1); - wellP.applyWellProdIndexScaling(100.0*liquid_PI_unit()); + const auto scalingFactor = wellP.getWellPIScalingFactor(100.0*liquid_PI_unit()); + BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); + + wellP.applyWellProdIndexScaling(scalingFactor); for (const auto& conn : wellP.getConnections()) { BOOST_CHECK_CLOSE(conn.CF(), expectCF, 1.0e-10); } @@ -3801,7 +3804,10 @@ END const auto expectCF = (200.0 / 100.0) * 100.0*cp_rm3_per_db(); auto wellP = sched.getWell("P", 2); - wellP.applyWellProdIndexScaling(100.0*liquid_PI_unit()); + const auto scalingFactor = wellP.getWellPIScalingFactor(100.0*liquid_PI_unit()); + BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); + + wellP.applyWellProdIndexScaling(scalingFactor); const auto& connP = wellP.getConnections(); BOOST_CHECK_CLOSE(connP[0].CF(), expectCF , 1.0e-10); BOOST_CHECK_CLOSE(connP[1].CF(), 50*cp_rm3_per_db(), 1.0e-10); diff --git a/tests/parser/WellTests.cpp b/tests/parser/WellTests.cpp index 8ee1f505e..94947a348 100644 --- a/tests/parser/WellTests.cpp +++ b/tests/parser/WellTests.cpp @@ -1229,15 +1229,25 @@ END "Second call to updateWellProductivityIndex() must NOT be a state change"); // Want PI=2, but actual/effective PI=1 => scale CF by 2.0/1.0. - wellP.applyWellProdIndexScaling(1.0); - for (const auto& conn : wellP.getConnections()) { - BOOST_CHECK_CLOSE(conn.CF(), 2.0*expectCF, 1.0e-10); + { + const auto scalingFactor = wellP.getWellPIScalingFactor(1.0); + BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); + + wellP.applyWellProdIndexScaling(scalingFactor); + for (const auto& conn : wellP.getConnections()) { + BOOST_CHECK_CLOSE(conn.CF(), 2.0*expectCF, 1.0e-10); + } } // Repeated application of WELPI multiplies scaling factors. - wellP.applyWellProdIndexScaling(1.0); - for (const auto& conn : wellP.getConnections()) { - BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10); + { + const auto scalingFactor = wellP.getWellPIScalingFactor(1.0); + BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); + + wellP.applyWellProdIndexScaling(scalingFactor); + for (const auto& conn : wellP.getConnections()) { + BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10); + } } // New WELPI record does not reset the scaling factors @@ -1247,9 +1257,14 @@ END } // Effective PI=desired PI => no scaling change - wellP.applyWellProdIndexScaling(3.0); - for (const auto& conn : wellP.getConnections()) { - BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10); + { + const auto scalingFactor = wellP.getWellPIScalingFactor(3.0); + BOOST_CHECK_CLOSE(scalingFactor, 1.0, 1.0e-10); + + wellP.applyWellProdIndexScaling(scalingFactor); + for (const auto& conn : wellP.getConnections()) { + BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10); + } } BOOST_CHECK_MESSAGE(wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::OIL }), From 338a48708ab626c0a632acd28dda44d39247deb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 19 Oct 2020 01:24:11 +0200 Subject: [PATCH 2/7] Add Special Predicate to Check if Two Wells Have Same Connections This commit adds a new special purpose predicate member function bool Well::hasSameConnectionsPointers which checks if the internal WellConnections pointers of two Well objects (*this and the input argument) point to the same object. This, in turn, enables identifying when to apply dynamic WELPI CTF scaling across the time direction the internalized connection information. --- .../EclipseState/Schedule/Well/Well.hpp | 1 + .../EclipseState/Schedule/Well/Well.cpp | 7 +++ tests/parser/WellTests.cpp | 62 ++++++++++++++++++- 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp index 51f4ba4ef..c9f0617b8 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp @@ -598,6 +598,7 @@ public: bool updateHasProduced(); bool cmp_structure(const Well& other) const; bool operator==(const Well& data) const; + bool hasSameConnectionsPointers(const Well& other) const; void setInsertIndex(std::size_t index); void applyWellProdIndexScaling(const double currentEffectivePI); double getWellPIScalingFactor(const double currentEffectivePI) const; diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp index 96acf41b0..3681cbea0 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp @@ -821,6 +821,13 @@ const std::string& Well::name() const { return this->wname; } +bool Well::hasSameConnectionsPointers(const Well& other) const +{ + // Note: This is *supposed* to be a pointer comparison. We need to know + // if the two connection structures represent the exact same object, not + // just if they have the same value. + return this->connections == other.connections; +} void Well::setInsertIndex(std::size_t index) { this->insert_index = index; diff --git a/tests/parser/WellTests.cpp b/tests/parser/WellTests.cpp index 94947a348..b19a576c8 100644 --- a/tests/parser/WellTests.cpp +++ b/tests/parser/WellTests.cpp @@ -17,9 +17,11 @@ along with OPM. If not, see . */ -#include #include +#include #include +#include +#include #define BOOST_TEST_MODULE WellTest #include @@ -1272,3 +1274,61 @@ END BOOST_CHECK_MESSAGE(!wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::OIL }), "Fifth call to updateWellProductivityIndex() must NOT be a state change"); } + +BOOST_AUTO_TEST_CASE(Has_Same_Connections_Pointers) { + const auto deck = Parser{}.parseString(R"(RUNSPEC +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 / + +PERMX + 300*100.0 / +PERMY + 300*100.0 / +PERMZ + 300*10.0 / +PORO + 300*0.3 / + +SCHEDULE +WELSPECS + 'P' 'G' 10 10 2005 'LIQ' / +/ +COMPDAT + 'P' 0 0 1 3 OPEN 1 100 / +/ + +END +)"); + + const auto es = EclipseState{ deck }; + const auto sched = Schedule{ deck, es }; + + const auto wellP = sched.getWell("P", 0); + auto wellQ = wellP; + + BOOST_CHECK_MESSAGE(wellP.hasSameConnectionsPointers(wellQ), + "P and Q must have the same internal connections pointers"); + + auto connQ = std::make_shared(wellP.getConnections()); + wellQ.forceUpdateConnections(std::move(connQ)); + BOOST_CHECK_MESSAGE(! wellP.hasSameConnectionsPointers(wellQ), + "P and Q must NOT have the same internal connections pointers " + "after forcibly updating the connections structure"); + + BOOST_CHECK_MESSAGE(wellP.getConnections() == wellQ.getConnections(), + "P and Q must have same WellConnections VALUE"); +} From cfa5dd80ccce0dff5838cec9817ef02a51a5f88c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 19 Oct 2020 01:46:38 +0200 Subject: [PATCH 3/7] Enable Applying WELPI CTF Scaling Across Time Direction This commit adds a new in/out parameter, scalingApplicable, to the applyWellProdIndexScaling functions. This parameter carries time (history) information on whether or not a particular connection is eligible for WELPI-based CTF scaling. Entries are marked ineligible (false) and left untouched on subsequent calls if the corresponding connection is ineligible at any point--e.g., as a result of new COMPDAT entries. This ability enables implementing WELPI CTF scaling at the Schedule level which is the only level that has sufficient time information to identify all the unique Well/WellConnections object combinations. --- .../EclipseState/Schedule/Well/Connection.hpp | 2 +- .../EclipseState/Schedule/Well/Well.hpp | 3 +- .../Schedule/Well/WellConnections.hpp | 9 ++- .../EclipseState/Schedule/Well/Connection.cpp | 5 +- .../EclipseState/Schedule/Well/Well.cpp | 4 +- .../Schedule/Well/WellConnections.cpp | 13 +++- tests/parser/ConnectionTests.cpp | 70 +++++++++++++------ tests/parser/ScheduleTests.cpp | 21 +++++- tests/parser/WellTests.cpp | 34 +++++++-- 9 files changed, 118 insertions(+), 43 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.hpp b/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.hpp index 49cc4c34f..ccf7a5513 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.hpp @@ -123,7 +123,7 @@ namespace RestartIO { void setComplnum(int compnum); void scaleWellPi(double wellPi); bool prepareWellPIScaling(); - void applyWellPIScaling(const double scaleFactor); + bool applyWellPIScaling(const double scaleFactor); void updateSegmentRST(int segment_number_arg, double center_depth_arg); void updateSegment(int segment_number_arg, diff --git a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp index c9f0617b8..de20113d1 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Well/Well.hpp @@ -600,8 +600,9 @@ public: bool operator==(const Well& data) const; bool hasSameConnectionsPointers(const Well& other) const; void setInsertIndex(std::size_t index); - void applyWellProdIndexScaling(const double currentEffectivePI); double getWellPIScalingFactor(const double currentEffectivePI) const; + void applyWellProdIndexScaling(const double scalingFactor, + std::vector& scalingApplicable); template void serializeOp(Serializer& serializer) diff --git a/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp b/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp index 4871c6028..2efa11759 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.hpp @@ -111,8 +111,13 @@ namespace Opm { /// Scale pertinent connections' CF value by supplied value. Scaling /// factor typically derived from 'WELPI' input keyword and a dynamic - /// productivity index calculation. - void applyWellPIScaling(const double scaleFactor); + /// productivity index calculation. Applicability array specifies + /// whether or not a particular connection is exempt from scaling. + /// Empty array means "apply scaling to all eligible connections". + /// This array is updated on return (entries set to 'false' if + /// corresponding connection is not eligible). + void applyWellPIScaling(const double scaleFactor, + std::vector& scalingApplicable); template void serializeOp(Serializer& serializer) diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.cpp index 72c2d5285..e7448222e 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Connection.cpp @@ -256,11 +256,12 @@ const std::optional>& Connection::perf_range() const { return update; } - void Connection::applyWellPIScaling(const double scaleFactor) { + bool Connection::applyWellPIScaling(const double scaleFactor) { if (! this->m_subject_to_welpi) - return; + return false; this->scaleWellPi(scaleFactor); + return true; } std::string Connection::str() const { diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp index 3681cbea0..fac690927 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Well/Well.cpp @@ -849,7 +849,7 @@ double Well::getWellPIScalingFactor(const double currentEffectivePI) const { return this->productivity_index->pi_value / currentEffectivePI; } -void Well::applyWellProdIndexScaling(const double scalingFactor) { +void Well::applyWellProdIndexScaling(const double scalingFactor, std::vector& scalingApplicable) { if (this->connections->empty()) // No connections for this well. Unexpected. return; @@ -862,7 +862,7 @@ void Well::applyWellProdIndexScaling(const double scalingFactor) { // No change in scaling. return; - this->connections->applyWellPIScaling(scalingFactor); + this->connections->applyWellPIScaling(scalingFactor, scalingApplicable); } const WellConnections& Well::getConnections() const { diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.cpp index 2b8b0e819..70b41771a 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Well/WellConnections.cpp @@ -195,10 +195,17 @@ inline std::array< size_t, 3> directionIndices(const Opm::Connection::Direction return update; } - void WellConnections::applyWellPIScaling(const double scaleFactor) + void WellConnections::applyWellPIScaling(const double scaleFactor, + std::vector& scalingApplicable) { - for (auto& conn : this->m_connections) - conn.applyWellPIScaling(scaleFactor); + scalingApplicable.resize(std::max(scalingApplicable.size(), this->m_connections.size()), true); + + auto i = std::size_t{0}; + for (auto& conn : this->m_connections) { + if (scalingApplicable[i]) + scalingApplicable[i] = conn.applyWellPIScaling(scaleFactor); + ++i; + } } void WellConnections::addConnection(int i, int j , int k , diff --git a/tests/parser/ConnectionTests.cpp b/tests/parser/ConnectionTests.cpp index 57f379b0f..65f5ff795 100644 --- a/tests/parser/ConnectionTests.cpp +++ b/tests/parser/ConnectionTests.cpp @@ -408,17 +408,26 @@ END BOOST_CHECK_CLOSE(conn.CF(), expectCF, 1.0e-10); } - connP.applyWellPIScaling(2.0); // No "prepare" -> no change. - for (const auto& conn : connP) { - BOOST_CHECK_CLOSE(conn.CF(), expectCF, 1.0e-10); + { + std::vector scalingApplicable; + + connP.applyWellPIScaling(2.0, scalingApplicable); // No "prepare" -> no change. + for (const auto& conn : connP) { + BOOST_CHECK_CLOSE(conn.CF(), expectCF, 1.0e-10); + } } // All CFs scaled by factor 2. BOOST_CHECK_MESSAGE( connP.prepareWellPIScaling(), "First call to prepareWellPIScaling must be a state change"); BOOST_CHECK_MESSAGE(!connP.prepareWellPIScaling(), "Second call to prepareWellPIScaling must NOT be a state change"); - connP.applyWellPIScaling(2.0); - for (const auto& conn : connP) { - BOOST_CHECK_CLOSE(conn.CF(), 2.0*expectCF, 1.0e-10); + + { + std::vector scalingApplicable; + + connP.applyWellPIScaling(2.0, scalingApplicable); // No "prepare" -> no change. + for (const auto& conn : connP) { + BOOST_CHECK_CLOSE(conn.CF(), 2.0*expectCF, 1.0e-10); + } } // Reset CF -- simulating COMPDAT record (inactive cell) @@ -440,20 +449,27 @@ END BOOST_CHECK_CLOSE(connP[2].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); // Should not apply to connection whose CF was manually specified - connP.applyWellPIScaling(2.0); + { + std::vector scalingApplicable; + connP.applyWellPIScaling(2.0, scalingApplicable); - BOOST_CHECK_CLOSE(connP[0].CF(), 4.0*expectCF , 1.0e-10); - BOOST_CHECK_CLOSE(connP[1].CF(), 4.0*expectCF , 1.0e-10); - BOOST_CHECK_CLOSE(connP[2].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(connP[0].CF(), 4.0*expectCF , 1.0e-10); + BOOST_CHECK_CLOSE(connP[1].CF(), 4.0*expectCF , 1.0e-10); + BOOST_CHECK_CLOSE(connP[2].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + } // Prepare new scaling. Simulating new WELPI record. // New scaling applies to all connections. BOOST_CHECK_MESSAGE(connP.prepareWellPIScaling(), "Third call to prepareWellPIScaling must be a state change"); - connP.applyWellPIScaling(2.0); - BOOST_CHECK_CLOSE(connP[0].CF(), 8.0*expectCF , 1.0e-10); - BOOST_CHECK_CLOSE(connP[1].CF(), 8.0*expectCF , 1.0e-10); - BOOST_CHECK_CLOSE(connP[2].CF(), 100.0*cp_rm3_per_db(), 1.0e-10); + { + std::vector scalingApplicable; + connP.applyWellPIScaling(2.0, scalingApplicable); + + BOOST_CHECK_CLOSE(connP[0].CF(), 8.0*expectCF , 1.0e-10); + BOOST_CHECK_CLOSE(connP[1].CF(), 8.0*expectCF , 1.0e-10); + BOOST_CHECK_CLOSE(connP[2].CF(), 100.0*cp_rm3_per_db(), 1.0e-10); + } // Reset CF -- simulating COMPDAT record (active cell) connP.addConnection(8, 9, 1, // 10, 10, 2 @@ -468,12 +484,16 @@ END 1); BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{4}); - connP.applyWellPIScaling(2.0); - BOOST_CHECK_CLOSE(connP[0].CF(), 16.0*expectCF , 1.0e-10); - BOOST_CHECK_CLOSE(connP[1].CF(), 16.0*expectCF , 1.0e-10); - BOOST_CHECK_CLOSE(connP[2].CF(), 200.0*cp_rm3_per_db(), 1.0e-10); - BOOST_CHECK_CLOSE(connP[3].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + { + std::vector scalingApplicable; + connP.applyWellPIScaling(2.0, scalingApplicable); + + BOOST_CHECK_CLOSE(connP[0].CF(), 16.0*expectCF , 1.0e-10); + BOOST_CHECK_CLOSE(connP[1].CF(), 16.0*expectCF , 1.0e-10); + BOOST_CHECK_CLOSE(connP[2].CF(), 200.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(connP[3].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + } const auto& grid = es.getInputGrid(); const auto actCells = Opm::ActiveGridCells { @@ -489,8 +509,12 @@ END BOOST_CHECK_CLOSE(connP[1].CF(), 16.0*expectCF , 1.0e-10); BOOST_CHECK_CLOSE(connP[2].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); - connP.applyWellPIScaling(2.0); - BOOST_CHECK_CLOSE(connP[0].CF(), 32.0*expectCF , 1.0e-10); - BOOST_CHECK_CLOSE(connP[1].CF(), 32.0*expectCF , 1.0e-10); - BOOST_CHECK_CLOSE(connP[2].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + { + std::vector scalingApplicable; + + connP.applyWellPIScaling(2.0, scalingApplicable); + BOOST_CHECK_CLOSE(connP[0].CF(), 32.0*expectCF , 1.0e-10); + BOOST_CHECK_CLOSE(connP[1].CF(), 32.0*expectCF , 1.0e-10); + BOOST_CHECK_CLOSE(connP[2].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + } } diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index 838b6841f..a713dbe13 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -3779,10 +3779,15 @@ END const auto expectCF = 100.0*cp_rm3_per_db(); auto wellP = sched.getWell("P", 0); - wellP.applyWellProdIndexScaling(2.7182818); + std::vector scalingApplicable; + wellP.applyWellProdIndexScaling(2.7182818, scalingApplicable); for (const auto& conn : wellP.getConnections()) { BOOST_CHECK_CLOSE(conn.CF(), expectCF, 1.0e-10); } + + for (const bool applicable : scalingApplicable) { + BOOST_CHECK_MESSAGE(! applicable, "No connection must be eligible for WELPI scaling"); + } } // Apply WELPI after seeing WELPI data. @@ -3793,10 +3798,15 @@ END const auto scalingFactor = wellP.getWellPIScalingFactor(100.0*liquid_PI_unit()); BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); - wellP.applyWellProdIndexScaling(scalingFactor); + std::vector scalingApplicable; + wellP.applyWellProdIndexScaling(scalingFactor, scalingApplicable); for (const auto& conn : wellP.getConnections()) { BOOST_CHECK_CLOSE(conn.CF(), expectCF, 1.0e-10); } + + for (const bool applicable : scalingApplicable) { + BOOST_CHECK_MESSAGE(applicable, "All connections must be eligible for WELPI scaling"); + } } // Apply WELPI after new COMPDAT. @@ -3807,11 +3817,16 @@ END const auto scalingFactor = wellP.getWellPIScalingFactor(100.0*liquid_PI_unit()); BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); - wellP.applyWellProdIndexScaling(scalingFactor); + std::vector scalingApplicable; + wellP.applyWellProdIndexScaling(scalingFactor, scalingApplicable); const auto& connP = wellP.getConnections(); BOOST_CHECK_CLOSE(connP[0].CF(), expectCF , 1.0e-10); BOOST_CHECK_CLOSE(connP[1].CF(), 50*cp_rm3_per_db(), 1.0e-10); BOOST_CHECK_CLOSE(connP[2].CF(), expectCF , 1.0e-10); + + BOOST_CHECK_MESSAGE(bool(scalingApplicable[0]), "Connection[0] must be eligible for WELPI scaling"); + BOOST_CHECK_MESSAGE(! scalingApplicable[1] , "Connection[1] must NOT be eligible for WELPI scaling"); + BOOST_CHECK_MESSAGE(bool(scalingApplicable[0]), "Connection[2] must be eligible for WELPI scaling"); } BOOST_CHECK_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 0), diff --git a/tests/parser/WellTests.cpp b/tests/parser/WellTests.cpp index b19a576c8..e98978b55 100644 --- a/tests/parser/WellTests.cpp +++ b/tests/parser/WellTests.cpp @@ -1213,9 +1213,16 @@ END } // Simulate applying WELPI before WELPI keyword. No effect. - wellP.applyWellProdIndexScaling(2.7182818); - for (const auto& conn : wellP.getConnections()) { - BOOST_CHECK_CLOSE(conn.CF(), expectCF, 1.0e-10); + { + std::vector scalingApplicable; + wellP.applyWellProdIndexScaling(2.7182818, scalingApplicable); + for (const auto& conn : wellP.getConnections()) { + BOOST_CHECK_CLOSE(conn.CF(), expectCF, 1.0e-10); + } + + for (const bool applicable : scalingApplicable) { + BOOST_CHECK_MESSAGE(! applicable, "No connection must be eligible for WELPI scaling"); + } } // Simulate applying WELPI after seeing @@ -1235,10 +1242,15 @@ END const auto scalingFactor = wellP.getWellPIScalingFactor(1.0); BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); - wellP.applyWellProdIndexScaling(scalingFactor); + std::vector scalingApplicable; + wellP.applyWellProdIndexScaling(scalingFactor, scalingApplicable); for (const auto& conn : wellP.getConnections()) { BOOST_CHECK_CLOSE(conn.CF(), 2.0*expectCF, 1.0e-10); } + + for (const bool applicable : scalingApplicable) { + BOOST_CHECK_MESSAGE(applicable, "All connections must be eligible for WELPI scaling"); + } } // Repeated application of WELPI multiplies scaling factors. @@ -1246,10 +1258,15 @@ END const auto scalingFactor = wellP.getWellPIScalingFactor(1.0); BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); - wellP.applyWellProdIndexScaling(scalingFactor); + std::vector scalingApplicable; + wellP.applyWellProdIndexScaling(scalingFactor, scalingApplicable); for (const auto& conn : wellP.getConnections()) { BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10); } + + for (const bool applicable : scalingApplicable) { + BOOST_CHECK_MESSAGE(applicable, "All connections must be eligible for WELPI scaling"); + } } // New WELPI record does not reset the scaling factors @@ -1263,10 +1280,15 @@ END const auto scalingFactor = wellP.getWellPIScalingFactor(3.0); BOOST_CHECK_CLOSE(scalingFactor, 1.0, 1.0e-10); - wellP.applyWellProdIndexScaling(scalingFactor); + std::vector scalingApplicable; + wellP.applyWellProdIndexScaling(scalingFactor, scalingApplicable); for (const auto& conn : wellP.getConnections()) { BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10); } + + for (const bool applicable : scalingApplicable) { + BOOST_CHECK_MESSAGE(applicable, "All connections must be eligible for WELPI scaling"); + } } BOOST_CHECK_MESSAGE(wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::OIL }), From 26ef5d01a2824402ae94e8fae086d052deb6b662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 19 Oct 2020 01:56:10 +0200 Subject: [PATCH 4/7] Apply WELPI CTF Scaling at Schedule Level This commit adds a new member function applyWellProdIndexScaling(well_name, report_step, scalingFactor) which applies WELPI-based CTF scaling (by scalingFactor) for all pertinent report steps from 'report_step' and until the end of the simulation run. We use the 'scalingApplicable' array to communicate connection eligibility between report steps and only apply the scaling if the internal connections pointers differ between report steps. --- .../EclipseState/Schedule/Schedule.hpp | 1 + .../EclipseState/Schedule/Schedule.cpp | 36 +- tests/parser/ScheduleTests.cpp | 309 +++++++++++++++++- 3 files changed, 343 insertions(+), 3 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp index 642ab7d72..67c2bda88 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp @@ -272,6 +272,7 @@ namespace Opm RestartConfig& restart(); void applyAction(std::size_t reportStep, const Action::ActionX& action, const Action::Result& result); + void applyWellProdIndexScaling(const std::string& well_name, const std::size_t reportStep, const double scalingFactor); int getNupcol(std::size_t reportStep) const; diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index f800ad638..80b5367db 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -17,16 +17,17 @@ along with OPM. If not, see . */ +#include #include - #include +#include #include #include #include #include #include +#include #include -#include #include @@ -1499,6 +1500,37 @@ private: } } + void Schedule::applyWellProdIndexScaling(const std::string& well_name, const std::size_t reportStep, const double scalingFactor) { + auto wstat = this->wells_static.find(well_name); + if (wstat == this->wells_static.end()) + return; + + auto uwell = wstat->second.unique(); + auto end = uwell.end(); + auto start = std::lower_bound(uwell.begin(), end, reportStep, + [](const auto& time_well_pair, const auto lookup) -> bool + { + // time < reportStep + return time_well_pair.first < lookup; + }); + + if (start == end) + // Report step after last? + return; + + // Relies on wells_static being OrderedMap>> + // which means uwell is a vector>> + std::vector scalingApplicable; + auto wellPtr = start->second; + wellPtr->applyWellProdIndexScaling(scalingFactor, scalingApplicable); + + for (; start != end; ++start) + if (! wellPtr->hasSameConnectionsPointers(*start->second)) { + wellPtr = start->second; + wellPtr->applyWellProdIndexScaling(scalingFactor, scalingApplicable); + } + } + RestartConfig& Schedule::restart() { return this->restart_config; } diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index a713dbe13..07c090b0c 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -3845,6 +3846,313 @@ END "Must have WELL_PRODUCTIVITY_INDEX event at report step 1"); } +BOOST_AUTO_TEST_CASE(Schedule_ApplyWellProdIndexScaling) { + const auto deck = Parser{}.parseString(R"(RUNSPEC +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 / + +PERMX + 300*100.0 / +PERMY + 300*100.0 / +PERMZ + 300*10.0 / +PORO + 300*0.3 / + +SCHEDULE +WELSPECS -- 0 + 'P' 'G' 10 10 2005 'LIQ' / +/ +COMPDAT + 'P' 0 0 1 3 OPEN 1 100 / +/ + +TSTEP -- 1 + 10 +/ + +WELPI -- 1 + 'P' 200.0 / +/ + +TSTEP -- 2 + 10 +/ + +COMPDAT -- 2 + 'P' 0 0 2 2 OPEN 1 50 / +/ + +TSTEP -- 3 + 10 +/ + +WELPI --3 + 'P' 50.0 / +/ + +TSTEP -- 4 + 10 +/ + +COMPDAT -- 4 + 'P' 10 9 2 2 OPEN 1 100 1.0 3* 'Y' / + 'P' 10 8 2 2 OPEN 1 75 1.0 3* 'Y' / + 'P' 10 7 2 2 OPEN 1 25 1.0 3* 'Y' / +/ + +TSTEP -- 5 + 10 +/ + +END +)"); + + const auto es = EclipseState{ deck }; + auto sched = Schedule{ deck, es }; + + BOOST_REQUIRE_EQUAL(sched.getTimeMap().size(), std::size_t{6}); + BOOST_REQUIRE_EQUAL(sched.getTimeMap().numTimesteps(), std::size_t{5}); + BOOST_REQUIRE_EQUAL(sched.getTimeMap().last(), std::size_t{5}); + + BOOST_REQUIRE_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX, 1), + "Schedule must have WELL_PRODUCTIVITY_INDEX Event at report step 1"); + + BOOST_REQUIRE_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX, 3), + "Schedule must have WELL_PRODUCTIVITY_INDEX Event at report step 3"); + + auto getScalingFactor = [&sched](const std::size_t report_step, const double wellPI) -> double + { + return sched.getWell("P", report_step).getWellPIScalingFactor(wellPI); + }; + + auto applyWellPIScaling = [&sched](const std::size_t report_step, const double scalingFactor) + { + sched.applyWellProdIndexScaling("P", report_step, scalingFactor); + }; + + auto getConnections = [&sched](const std::size_t report_step) + { + return sched.getWell("P", report_step).getConnections(); + }; + + // Apply WELPI scaling after end of time series => no change to CTFs + { + const auto report_step = std::size_t{1}; + const auto scalingFactor = getScalingFactor(report_step, 100.0*liquid_PI_unit()); + + BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); + + applyWellPIScaling(1729, scalingFactor); + + { + const auto expectCF = 100.0*cp_rm3_per_db(); + + const auto& conns = getConnections(0); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 100.0*cp_rm3_per_db(); + + const auto& conns = getConnections(1); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 100.0*cp_rm3_per_db(); + + const auto& conns = getConnections(2); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 100.0*cp_rm3_per_db(); + + const auto& conns = getConnections(3); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto& conns = getConnections(4); + BOOST_REQUIRE_EQUAL(conns.size(), 6); + + BOOST_CHECK_CLOSE(conns[0].CF(), 100.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), 100.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[3].CF(), 100.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[4].CF(), 75.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[5].CF(), 25.0*cp_rm3_per_db(), 1.0e-10); + } + } + + // Apply WELPI scaling after first WELPI specification + { + const auto report_step = std::size_t{1}; + const auto scalingFactor = getScalingFactor(report_step, 100.0*liquid_PI_unit()); + + BOOST_CHECK_CLOSE(scalingFactor, 2.0, 1.0e-10); + + applyWellPIScaling(report_step, scalingFactor); + + { + const auto expectCF = 100.0*cp_rm3_per_db(); + + const auto& conns = getConnections(0); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 200.0*cp_rm3_per_db(); + + const auto& conns = getConnections(1); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 200.0*cp_rm3_per_db(); + + const auto& conns = getConnections(2); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 200.0*cp_rm3_per_db(); + + const auto& conns = getConnections(3); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 200.0*cp_rm3_per_db(); + + const auto& conns = getConnections(4); + BOOST_REQUIRE_EQUAL(conns.size(), 6); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[3].CF(), 100.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[4].CF(), 75.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[5].CF(), 25.0*cp_rm3_per_db(), 1.0e-10); + } + } + + // Apply WELPI scaling after second WELPI specification + { + const auto report_step = std::size_t{3}; + const auto scalingFactor = getScalingFactor(report_step, 200.0*liquid_PI_unit()); + + BOOST_CHECK_CLOSE(scalingFactor, 0.25, 1.0e-10); + + applyWellPIScaling(report_step, scalingFactor); + + { + const auto expectCF = 100.0*cp_rm3_per_db(); + + const auto& conns = getConnections(0); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 200.0*cp_rm3_per_db(); + + const auto& conns = getConnections(1); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 200.0*cp_rm3_per_db(); + + const auto& conns = getConnections(2); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 50.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 50.0*cp_rm3_per_db(); + + const auto& conns = getConnections(3); + BOOST_REQUIRE_EQUAL(conns.size(), 3); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 0.25*expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + } + + { + const auto expectCF = 50.0*cp_rm3_per_db(); + + const auto& conns = getConnections(4); + BOOST_REQUIRE_EQUAL(conns.size(), 6); + + BOOST_CHECK_CLOSE(conns[0].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[1].CF(), 0.25*expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[2].CF(), expectCF, 1.0e-10); + BOOST_CHECK_CLOSE(conns[3].CF(), 100.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[4].CF(), 75.0*cp_rm3_per_db(), 1.0e-10); + BOOST_CHECK_CLOSE(conns[5].CF(), 25.0*cp_rm3_per_db(), 1.0e-10); + } + } +} void cmp_vector(const std::vector&v1, const std::vector& v2) { BOOST_CHECK_EQUAL(v1.size(), v2.size()); @@ -3869,4 +4177,3 @@ BOOST_AUTO_TEST_CASE(VFPPROD_SCALING) { cmp_vector(gfr, vfp_table.getGFRAxis()); cmp_vector(alq, vfp_table.getALQAxis()); } - From 5b4a1c0badb8f4796102941871cbe0f3df6948fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 19 Oct 2020 02:01:24 +0200 Subject: [PATCH 5/7] Remove WELL_CONNECTIONS_UPDATED Event With the introduction of Schedule::applyWellProdIndexScaling(), this special-purpose event type is no longer needed and only causes confusion. --- .../eclipse/EclipseState/Schedule/Events.hpp | 6 ------ .../EclipseState/Schedule/KeywordHandlers.cpp | 6 ++---- .../eclipse/EclipseState/Schedule/Schedule.cpp | 5 ++--- tests/parser/ScheduleTests.cpp | 15 --------------- 4 files changed, 4 insertions(+), 28 deletions(-) diff --git a/opm/parser/eclipse/EclipseState/Schedule/Events.hpp b/opm/parser/eclipse/EclipseState/Schedule/Events.hpp index 0496f3968..25d9f93bb 100644 --- a/opm/parser/eclipse/EclipseState/Schedule/Events.hpp +++ b/opm/parser/eclipse/EclipseState/Schedule/Events.hpp @@ -106,12 +106,6 @@ namespace Opm * New explicit well productivity/injectivity assignment. */ WELL_PRODUCTIVITY_INDEX = (1 << 16), - - /* - * Well's internal WellConnections structure changed. - * Rerun WELPI scaling if applicable. - */ - WELL_CONNECTIONS_UPDATED = (1 << 17), }; } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp index 53541a907..ffcb1c664 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/KeywordHandlers.cpp @@ -154,10 +154,8 @@ namespace { 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"))) { - this->updateWell(well2, handlerContext.currentStep); - this->addWellGroupEvent(name, ScheduleEvents::WELL_CONNECTIONS_UPDATED, handlerContext.currentStep); - } + if (well2->updateConnections(connections, handlerContext.grid, handlerContext.fieldPropsManager.get_int("PVTNUM"))) + this->updateWell(std::move(well2), handlerContext.currentStep); this->addWellGroupEvent(name, ScheduleEvents::COMPLETION_CHANGE, handlerContext.currentStep); } diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index 80b5367db..dba036fb5 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -667,10 +667,9 @@ private: { auto& dynamic_state = this->wells_static.at(wname); auto well_ptr = std::make_shared( *dynamic_state[currentStep] ); - if (well_ptr->handleWELOPEN(record, comp_status, action_mode)) { + if (well_ptr->handleWELOPEN(record, comp_status, action_mode)) // The updateWell call breaks test at line 825 and 831 in ScheduleTests - this->updateWell(well_ptr, currentStep); - } + this->updateWell(std::move(well_ptr), currentStep); } m_events.addEvent( ScheduleEvents::COMPLETION_CHANGE, currentStep ); diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index 07c090b0c..c91f4efd1 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -3829,21 +3829,6 @@ END BOOST_CHECK_MESSAGE(! scalingApplicable[1] , "Connection[1] must NOT be eligible for WELPI scaling"); BOOST_CHECK_MESSAGE(bool(scalingApplicable[0]), "Connection[2] must be eligible for WELPI scaling"); } - - BOOST_CHECK_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 0), - "Well P must have WELL_CONNECTIONS_UPDATED event at report step 0"); - - BOOST_CHECK_MESSAGE(!sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 1), - "Well P must NOT have WELL_CONNECTIONS_UPDATED event at report step 1"); - - BOOST_CHECK_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 2), - "Well P must have WELL_CONNECTIONS_UPDATED event at report step 2"); - - BOOST_CHECK_MESSAGE(!sched.hasWellGroupEvent("P", ScheduleEvents::WELL_CONNECTIONS_UPDATED, 3), - "Well P must NOT have WELL_CONNECTIONS_UPDATED event at report step 3"); - - BOOST_CHECK_MESSAGE(sched.hasWellGroupEvent("P", ScheduleEvents::WELL_PRODUCTIVITY_INDEX, 1), - "Must have WELL_PRODUCTIVITY_INDEX event at report step 1"); } BOOST_AUTO_TEST_CASE(Schedule_ApplyWellProdIndexScaling) { From 91bb168ee58d40875c0f2598d4af205d50166767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Mon, 19 Oct 2020 21:16:55 +0200 Subject: [PATCH 6/7] Fix Shadowing Type Alias The local 'WellPI' type alias shadowed the name of the test. --- tests/parser/WellTests.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/parser/WellTests.cpp b/tests/parser/WellTests.cpp index e98978b55..b7288cab7 100644 --- a/tests/parser/WellTests.cpp +++ b/tests/parser/WellTests.cpp @@ -1199,7 +1199,7 @@ COMPDAT END )"); - using WellPI = Well::WellProductivityIndex; + using WellPIType = Well::WellProductivityIndex; const auto es = EclipseState{ deck }; const auto sched = Schedule{ deck, es }; @@ -1232,9 +1232,9 @@ END // / // // (ignoring units of measure) - BOOST_CHECK_MESSAGE(wellP.updateWellProductivityIndex(WellPI{ 2.0, Phase::GAS }), + BOOST_CHECK_MESSAGE(wellP.updateWellProductivityIndex(WellPIType{ 2.0, Phase::GAS }), "First call to updateWellProductivityIndex() must be a state change"); - BOOST_CHECK_MESSAGE(!wellP.updateWellProductivityIndex(WellPI{ 2.0, Phase::GAS }), + BOOST_CHECK_MESSAGE(!wellP.updateWellProductivityIndex(WellPIType{ 2.0, Phase::GAS }), "Second call to updateWellProductivityIndex() must NOT be a state change"); // Want PI=2, but actual/effective PI=1 => scale CF by 2.0/1.0. @@ -1270,7 +1270,7 @@ END } // New WELPI record does not reset the scaling factors - wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::GAS }); + wellP.updateWellProductivityIndex(WellPIType{ 3.0, Phase::GAS }); for (const auto& conn : wellP.getConnections()) { BOOST_CHECK_CLOSE(conn.CF(), 4.0*expectCF, 1.0e-10); } @@ -1291,9 +1291,9 @@ END } } - BOOST_CHECK_MESSAGE(wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::OIL }), + BOOST_CHECK_MESSAGE(wellP.updateWellProductivityIndex(WellPIType{ 3.0, Phase::OIL }), "Fourth call to updateWellProductivityIndex() must be a state change"); - BOOST_CHECK_MESSAGE(!wellP.updateWellProductivityIndex(WellPI{ 3.0, Phase::OIL }), + BOOST_CHECK_MESSAGE(!wellP.updateWellProductivityIndex(WellPIType{ 3.0, Phase::OIL }), "Fifth call to updateWellProductivityIndex() must NOT be a state change"); } From ab519499093e3970a6fa094a24330914fc4e61f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Tue, 20 Oct 2020 11:14:03 +0200 Subject: [PATCH 7/7] Address Code Review Comments Use more complete object name and fix up a comment. --- .../parser/eclipse/EclipseState/Schedule/Schedule.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp index dba036fb5..7896317c0 100644 --- a/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp +++ b/src/opm/parser/eclipse/EclipseState/Schedule/Schedule.cpp @@ -1504,9 +1504,10 @@ private: if (wstat == this->wells_static.end()) return; - auto uwell = wstat->second.unique(); - auto end = uwell.end(); - auto start = std::lower_bound(uwell.begin(), end, reportStep, + auto unique_well_instances = wstat->second.unique(); + + auto end = unique_well_instances.end(); + auto start = std::lower_bound(unique_well_instances.begin(), end, reportStep, [](const auto& time_well_pair, const auto lookup) -> bool { // time < reportStep @@ -1518,7 +1519,7 @@ private: return; // Relies on wells_static being OrderedMap>> - // which means uwell is a vector>> + // which means unique_well_instances is a vector>> std::vector scalingApplicable; auto wellPtr = start->second; wellPtr->applyWellProdIndexScaling(scalingFactor, scalingApplicable);