From da17ef3174b6b03800d64d841252a38c057b57eb Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 29 Sep 2022 16:35:31 +0200 Subject: [PATCH] adding the parsing support for keyword WINJMULT --- opm/input/eclipse/Schedule/Schedule.hpp | 1 + .../eclipse/Schedule/Well/Connection.hpp | 34 ++++++++++++ opm/input/eclipse/Schedule/Well/Well.hpp | 1 + .../eclipse/Schedule/Well/WellConnections.hpp | 2 + .../eclipse/Schedule/KeywordHandlers.cpp | 19 +++++++ .../eclipse/Schedule/Well/Connection.cpp | 22 ++++++++ src/opm/input/eclipse/Schedule/Well/Well.cpp | 53 +++++++++++++++++++ .../eclipse/Schedule/Well/WellConnections.cpp | 11 ++++ 8 files changed, 143 insertions(+) diff --git a/opm/input/eclipse/Schedule/Schedule.hpp b/opm/input/eclipse/Schedule/Schedule.hpp index b8f12e6c4..d8b42275f 100644 --- a/opm/input/eclipse/Schedule/Schedule.hpp +++ b/opm/input/eclipse/Schedule/Schedule.hpp @@ -746,6 +746,7 @@ namespace Opm void handleWVFPEXP (HandlerContext&); void handleWWPAVE (HandlerContext&); void handleWPIMULT (HandlerContext&); + void handleWINJMULT (HandlerContext&); void handleWPMITAB (HandlerContext&); void handleWPOLYMER (HandlerContext&); void handleWRFT (HandlerContext&); diff --git a/opm/input/eclipse/Schedule/Well/Connection.hpp b/opm/input/eclipse/Schedule/Well/Connection.hpp index fbe5403e3..6f7f5b895 100644 --- a/opm/input/eclipse/Schedule/Well/Connection.hpp +++ b/opm/input/eclipse/Schedule/Well/Connection.hpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace Opm { @@ -76,6 +77,35 @@ namespace RestartIO { Defaulted, }; + enum class InjMultMode { + WREV, + CREV, + CIRR, + NONE, + }; + + static InjMultMode injModeFromString(const std::string& str); + + struct InjMult { + InjMultMode mode {InjMultMode::NONE}; + double fracture_pressure {std::numeric_limits::max()}; + double multiplier_gradient {0.}; + + template + void serializeOp(Serializer& serializer) + { + serializer(mode); + serializer(fracture_pressure); + serializer(multiplier_gradient); + } + + bool operator==( const InjMult& rhs ) const { + return mode == rhs.mode + && fracture_pressure == rhs.fracture_pressure + && multiplier_gradient == rhs.multiplier_gradient; + } + }; + Connection(); Connection(int i, int j , int k , @@ -120,6 +150,8 @@ namespace RestartIO { double connectionLength() const; double skinFactor() const; CTFKind kind() const; + InjMult injmult() const; + void setInjMult(const InjMult& inj_mult); void setState(State state); void setComplnum(int compnum); @@ -163,6 +195,7 @@ namespace RestartIO { serializer(ijk); serializer(m_global_index); serializer(m_ctfkind); + serializer(m_injmult); serializer(m_sort_value); serializer(m_perf_range); serializer(m_defaultSatTabId); @@ -186,6 +219,7 @@ namespace RestartIO { std::array ijk; CTFKind m_ctfkind; + InjMult m_injmult; std::size_t m_global_index; /* The sort_value member is a peculiar quantity. The connections are diff --git a/opm/input/eclipse/Schedule/Well/Well.hpp b/opm/input/eclipse/Schedule/Well/Well.hpp index ce4d37f9e..0b7976052 100644 --- a/opm/input/eclipse/Schedule/Well/Well.hpp +++ b/opm/input/eclipse/Schedule/Well/Well.hpp @@ -472,6 +472,7 @@ public: bool handleWELOPENConnections(const DeckRecord& record, Connection::State status); bool handleCOMPLUMP(const DeckRecord& record); bool handleWPIMULT(const DeckRecord& record); + bool handleWINJMULT(const DeckRecord& record, const KeywordLocation& location); bool applyGlobalWPIMULT(double scale_factor); void filterConnections(const ActiveGridCells& grid); diff --git a/opm/input/eclipse/Schedule/Well/WellConnections.hpp b/opm/input/eclipse/Schedule/Well/WellConnections.hpp index 62fc1a63d..f918f9d04 100644 --- a/opm/input/eclipse/Schedule/Well/WellConnections.hpp +++ b/opm/input/eclipse/Schedule/Well/WellConnections.hpp @@ -153,6 +153,8 @@ namespace Opm { void applyWellPIScaling(const double scaleFactor, std::vector& scalingApplicable); + bool underWREVInjMultMode() const; + template void serializeOp(Serializer& serializer) { diff --git a/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp b/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp index 08606c924..c92e9068f 100644 --- a/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp +++ b/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp @@ -1950,6 +1950,24 @@ Well{0} entered with 'FIELD' parent group: } } + void Schedule::handleWINJMULT(Opm::Schedule::HandlerContext& handlerContext) { + for (const auto& record : handlerContext.keyword) { + const std::string& wellNamePattern = record.getItem("WELL_NAME").getTrimmedString(0); + const auto well_names = wellNames(wellNamePattern); + + for (const auto& well_name : well_names) { + auto well = this->snapshots.back().wells( well_name ); + if (well.isProducer()) { + const std::string reason = fmt::format("Keyword WINJMULT can only apply to injectors," + " but Well {} is a producer", well_name); + throw OpmInputError(reason, handlerContext.keyword.location()); + } + if (well.handleWINJMULT(record, handlerContext.keyword.location())) + this->snapshots.back().wells.update( std::move(well)); + } + } + } + void Schedule::handleWPMITAB(HandlerContext& handlerContext) { for (const auto& record : handlerContext.keyword) { const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0); @@ -2478,6 +2496,7 @@ Well{0} entered with 'FIELD' parent group: { "WVFPEXP" , &Schedule::handleWVFPEXP }, { "WWPAVE" , &Schedule::handleWWPAVE }, { "WPIMULT" , &Schedule::handleWPIMULT }, + { "WINJMULT", &Schedule::handleWINJMULT }, { "WPMITAB" , &Schedule::handleWPMITAB }, { "WPOLYMER", &Schedule::handleWPOLYMER }, { "WRFT" , &Schedule::handleWRFT }, diff --git a/src/opm/input/eclipse/Schedule/Well/Connection.cpp b/src/opm/input/eclipse/Schedule/Well/Connection.cpp index 6c2f0e335..a821eaaed 100644 --- a/src/opm/input/eclipse/Schedule/Well/Connection.cpp +++ b/src/opm/input/eclipse/Schedule/Well/Connection.cpp @@ -311,6 +311,7 @@ const std::optional>& Connection::perf_range() const { && this->m_re == rhs.m_re && this->m_connection_length == rhs.m_connection_length && this->m_skin_factor == rhs.m_skin_factor + && this->m_injmult == rhs.m_injmult && this->m_Kh == rhs.m_Kh && this->sat_tableId == rhs.sat_tableId && this->open_state == rhs.open_state @@ -354,6 +355,19 @@ Connection::State Connection::StateFromString( const std::string& stringValue ) throw std::invalid_argument("Unknown enum state string: " + stringValue ); } +Connection::InjMultMode Connection::injModeFromString(const std::string& str) { + if (str == "WREV") + return Connection::InjMultMode::WREV; + else if (str == "CREV") + return Connection::InjMultMode::CREV; + else if (str == "CIRR") + return Connection::InjMultMode::CIRR; + else if (str == "NONE") + return Connection::InjMultMode::NONE; + else + throw std::invalid_argument("Unknow enum INJMultMode string: " + str); +} + std::string Connection::Direction2String(const Direction enumValue) { @@ -442,4 +456,12 @@ Connection::CTFKind Connection::kind() const { return m_ctfkind; } +Connection::InjMult Connection::injmult() const { + return m_injmult; +} + +void Connection::setInjMult(const Connection::InjMult& inj_mult) { + m_injmult = inj_mult; +} + } diff --git a/src/opm/input/eclipse/Schedule/Well/Well.cpp b/src/opm/input/eclipse/Schedule/Well/Well.cpp index c2681977c..86c69bd43 100644 --- a/src/opm/input/eclipse/Schedule/Well/Well.cpp +++ b/src/opm/input/eclipse/Schedule/Well/Well.cpp @@ -1300,6 +1300,59 @@ bool Well::handleWPIMULT(const DeckRecord& record) { } +bool Well::handleWINJMULT(const Opm::DeckRecord& record, const KeywordLocation& location) { + // TODO: the this keyword, defaulted means it <=0. + // We need to check how the following works + auto match = [=] ( const Connection& c) -> bool { + if (!match_eq(c.getI() , record, "I", -1)) return false; + if (!match_eq(c.getJ() , record, "J", -1)) return false; + if (!match_eq(c.getK() , record, "K", -1)) return false; + + return true; + }; + + // if this record using WREV, with the current ideas, we will rewrite the information to all the connectios regarding + // using the WINJMULT record information + // if this record use CREV or CIRR, and previoiusly, the well is using WREV, we need to discard the WREV setup for + // all the connections. For the connections not specified in the record, the injmult information will be reset. + const std::string mode = record.getItem("MODE").getTrimmedString(0); + const double fracture_pressure = record.getItem("FRACTURING_PRESSURE").get(0); + const double multiple_gradient = record.getItem("MULTIPLIER_GRADIENT").get(0); + auto new_connections = std::make_shared(this->connections->ordering(), this->headI, this->headJ); + const Connection::InjMult inj_mult {Connection::injModeFromString(mode), fracture_pressure, multiple_gradient}; + + if (mode == "WREV") { + // all the connections will share the same INJMULT setup + for (auto c : *this->connections) { + c.setInjMult(inj_mult); + new_connections->add(c); + } + } else if (mode == "CREV" || mode == "CIRR"){ + // check whether it was under WREV previously. + // if yes, we need to reset all the connections for injmult operation + const bool is_prev_wrev = this->connections->underWREVInjMultMode(); + for (auto c : *this->connections) { + if (match(c)) { + c.setInjMult(inj_mult); + } else { + if (is_prev_wrev) { + // reset the injMult information for this connection + c.setInjMult({}); + } + } + new_connections->add(c); + } + } else { + const std::string msg = fmt::format("unknown WINJMULT operation mode {} with keyword {}" + "at line {} in file {}", mode, location.keyword, + location.lineno, location.filename); + throw std::logic_error(msg); + } + + return this->updateConnections(std::move(new_connections), false); +} + + bool Opm::Well::applyGlobalWPIMULT(const double scaling_factor) { auto new_connections = std::make_shared(this->connections->ordering(), this->headI, this->headJ); diff --git a/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp b/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp index 32e39b641..1dc7bbfd0 100644 --- a/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp +++ b/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp @@ -284,6 +284,17 @@ namespace Opm { } } + bool WellConnections::underWREVInjMultMode() const { + // TODO: if the first connection is under WREV, all the connections should be under WREV + // how we can guarantee that? + // and hesitate to add extra member to this class + if (this->m_connections.empty()) { + return false; + } + const bool first_con_wrev = this->m_connections[0].injmult().mode == Connection::InjMultMode::WREV; + return first_con_wrev; + } + void WellConnections::addConnection(const int i, const int j, const int k, const std::size_t global_index, const int complnum,