From 68e586bf7ab857255cb4c713dfd09df49b4a3da4 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 19 Jun 2023 15:35:12 +0200 Subject: [PATCH 1/2] separating the WINJMULT for well and connections with more testing, it looks like when multiple records are entered. The records with WREV mode and records with CIRR and CREV modes work differently in term of overwriting the previous records. So it is necessary to store them separately. --- CMakeLists_files.cmake | 2 + .../eclipse/Schedule/Well/Connection.hpp | 32 +-------- opm/input/eclipse/Schedule/Well/WINJMULT.hpp | 63 +++++++++++++++++ opm/input/eclipse/Schedule/Well/Well.hpp | 16 ++--- .../eclipse/Schedule/Well/Connection.cpp | 11 ++- .../input/eclipse/Schedule/Well/WINJMULT.cpp | 70 +++++++++++++++++++ src/opm/input/eclipse/Schedule/Well/Well.cpp | 50 +++++-------- 7 files changed, 167 insertions(+), 77 deletions(-) create mode 100644 opm/input/eclipse/Schedule/Well/WINJMULT.hpp create mode 100644 src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index ad6e43ae1..756136d62 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -221,6 +221,7 @@ if(ENABLE_ECL_INPUT) src/opm/input/eclipse/Schedule/Well/WellTestState.cpp src/opm/input/eclipse/Schedule/WellTraj/RigEclipseWellLogExtractor.cpp src/opm/input/eclipse/Schedule/Well/WellTracerProperties.cpp + src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp src/opm/input/eclipse/Schedule/Well/WList.cpp src/opm/input/eclipse/Schedule/Well/WListManager.cpp src/opm/input/eclipse/Schedule/Well/WVFPDP.cpp @@ -1233,6 +1234,7 @@ if(ENABLE_ECL_INPUT) opm/input/eclipse/Schedule/Well/WellMICPProperties.hpp opm/input/eclipse/Schedule/Well/WellPolymerProperties.hpp opm/input/eclipse/Schedule/Well/WellTracerProperties.hpp + opm/input/eclipse/Schedule/Well/WINJMULT.hpp opm/input/eclipse/Schedule/Well/WVFPDP.hpp opm/input/eclipse/Schedule/Well/WVFPEXP.hpp opm/input/eclipse/Schedule/Well/WellTestConfig.hpp diff --git a/opm/input/eclipse/Schedule/Well/Connection.hpp b/opm/input/eclipse/Schedule/Well/Connection.hpp index 0f9575147..2718ff91a 100644 --- a/opm/input/eclipse/Schedule/Well/Connection.hpp +++ b/opm/input/eclipse/Schedule/Well/Connection.hpp @@ -30,6 +30,8 @@ #include #include +#include + namespace Opm { namespace RestartIO { @@ -77,34 +79,6 @@ namespace RestartIO { Defaulted, }; - - - struct InjMult { - bool is_active {false}; - double fracture_pressure {std::numeric_limits::max()}; - double multiplier_gradient {0.}; - - bool active() const - { - return is_active; - } - - template - void serializeOp(Serializer& serializer) - { - serializer(is_active); - serializer(fracture_pressure); - serializer(multiplier_gradient); - } - - bool operator==( const InjMult& rhs ) const { - return is_active == rhs.is_active - && fracture_pressure == rhs.fracture_pressure - && multiplier_gradient == rhs.multiplier_gradient; - } - }; - - Connection(); Connection(int i, int j , int k , std::size_t global_index, @@ -150,8 +124,6 @@ namespace RestartIO { CTFKind kind() const; const InjMult& injmult() const; void setInjMult(const InjMult& inj_mult); - // remove the injMult setting and INJMULT is not active for this connection - void clearInjMult(); void setState(State state); void setComplnum(int compnum); diff --git a/opm/input/eclipse/Schedule/Well/WINJMULT.hpp b/opm/input/eclipse/Schedule/Well/WINJMULT.hpp new file mode 100644 index 000000000..bc60ee1fd --- /dev/null +++ b/opm/input/eclipse/Schedule/Well/WINJMULT.hpp @@ -0,0 +1,63 @@ +/* +Copyright 2023 Equinor. + +This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with OPM. If not, see . +*/ + +#ifndef OPM_WINJMULT_HPP +#define OPM_WINJMULT_HPP + +#include + + +namespace Opm { + +class KeywordLocation; + +struct InjMult { + + enum class InjMultMode { + WREV, + CREV, + CIRR, + NONE, + }; + + bool is_active {false}; + double fracture_pressure {std::numeric_limits::max()}; + double multiplier_gradient {0.}; + + static InjMultMode injMultModeFromString(const std::string& str, const KeywordLocation& location); + + bool active() const; + + template + void serializeOp(Serializer& serializer) + { + serializer(is_active); + serializer(fracture_pressure); + serializer(multiplier_gradient); + } + + bool operator==(const InjMult& rhs) const; + + static InjMult serializationTestObject(); + static std::string InjMultToString(const InjMult&); +}; + +} + +#endif // OPM_WINJMULT_HPP diff --git a/opm/input/eclipse/Schedule/Well/Well.hpp b/opm/input/eclipse/Schedule/Well/Well.hpp index 046bd5162..02aa47f70 100644 --- a/opm/input/eclipse/Schedule/Well/Well.hpp +++ b/opm/input/eclipse/Schedule/Well/Well.hpp @@ -39,6 +39,7 @@ #include #include #include +#include #include namespace Opm { @@ -76,14 +77,10 @@ class Well { public: using Status = WellStatus; - enum class InjMultMode { - WREV, - CREV, - CIRR, - NONE, - }; - - static InjMultMode injMultModeFromString(const std::string& str, const KeywordLocation& location); + /* + * The mode for the keyword WINJMULT. It can have four different values: WREV, CREV, CIRR and NONE. + */ + using InjMultMode = InjMult::InjMultMode; /* The elements in this enum are used as bitmasks to keep track @@ -393,6 +390,7 @@ public: const std::string& groupName() const; Phase getPreferredPhase() const; InjMultMode getInjMultMode() const; + const InjMult& getWellInjMult() const; bool hasConnections() const; const std::vector getConnections(int completion) const; @@ -550,6 +548,7 @@ public: serializer(m_pavg); serializer(well_temperature); serializer(inj_mult_mode); + serializer(well_inj_mult); } private: @@ -597,6 +596,7 @@ private: PAvg m_pavg; double well_temperature; InjMultMode inj_mult_mode = InjMultMode::NONE; + InjMult well_inj_mult; }; std::ostream& operator<<( std::ostream&, const Well::WellInjectionProperties& ); diff --git a/src/opm/input/eclipse/Schedule/Well/Connection.cpp b/src/opm/input/eclipse/Schedule/Well/Connection.cpp index 3e701499d..12c23ffbb 100644 --- a/src/opm/input/eclipse/Schedule/Well/Connection.cpp +++ b/src/opm/input/eclipse/Schedule/Well/Connection.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include namespace Opm { @@ -131,6 +130,7 @@ Connection::Connection(const RestartIO::RstConnection& rst_connection, const Sch result.m_ctfkind = CTFKind::Defaulted; result.m_global_index = 12; result.m_perf_range = std::make_pair(14,15); + result.m_injmult = InjMult::serializationTestObject(); result.m_sort_value = 14; result.m_defaultSatTabId = true; result.segment_number = 16; @@ -297,6 +297,7 @@ const std::optional>& Connection::perf_range() const { ss << "segment_nr " << this->segment_number << std::endl; ss << "center_depth " << this->center_depth << std::endl; ss << "sort_value" << this->m_sort_value<< std::endl; + ss << "INJMULT " << InjMult::InjMultToString(this->m_injmult) << std::endl; return ss.str(); } @@ -444,16 +445,12 @@ Connection::CTFKind Connection::kind() const { return m_ctfkind; } -const Connection::InjMult& Connection::injmult() const { +const InjMult& Connection::injmult() const { return m_injmult; } -void Connection::setInjMult(const Connection::InjMult& inj_mult) { +void Connection::setInjMult(const InjMult& inj_mult) { m_injmult = inj_mult; } -void Connection::clearInjMult() { - this->setInjMult({}); -} - } diff --git a/src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp b/src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp new file mode 100644 index 000000000..3435000c0 --- /dev/null +++ b/src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp @@ -0,0 +1,70 @@ +/* +Copyright 2023 Equinor. + +This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with OPM. If not, see . +*/ + + +#include +#include + +#include + +#include + +namespace Opm { + +InjMult::InjMultMode InjMult::injMultModeFromString(const std::string& str, const KeywordLocation& location) { + if (str == "WREV") + return InjMultMode::WREV; + else if (str == "CREV") + return InjMultMode::CREV; + else if (str == "CIRR") + return InjMultMode::CIRR; + else + throw OpmInputError(fmt::format("Unknown mode {} is specified in WINJMULT keyword", str), location); +} + + +bool InjMult::active() const +{ + return this->is_active; +} + +bool InjMult::operator==(const InjMult& rhs) const +{ + return is_active == rhs.is_active + && fracture_pressure == rhs.fracture_pressure + && multiplier_gradient == rhs.multiplier_gradient; +} + + +InjMult InjMult::serializationTestObject() { + InjMult result; + result.is_active = false; + result.fracture_pressure = 1.e9; + result.multiplier_gradient = 2.; + return result; +} + + +std::string InjMult::InjMultToString(const InjMult& mult) { + std::string ss = fmt::format("active? {}, fracture_pressure {}, multiplier_gradient {}", + mult.is_active, mult.fracture_pressure, mult.multiplier_gradient); + return ss; +} + +} // end of namespace Opm \ No newline at end of file diff --git a/src/opm/input/eclipse/Schedule/Well/Well.cpp b/src/opm/input/eclipse/Schedule/Well/Well.cpp index eefcdc03e..c7bff6f04 100644 --- a/src/opm/input/eclipse/Schedule/Well/Well.cpp +++ b/src/opm/input/eclipse/Schedule/Well/Well.cpp @@ -490,7 +490,6 @@ Well::Well(const std::string& wname_arg, wvfpexp(std::make_shared()), status(Status::SHUT), well_temperature(Metric::TemperatureOffset + ParserKeywords::STCOND::TEMPERATURE::defaultValue) - { auto p = std::make_shared(this->unit_system, this->wname); p->whistctl_cmode = whistctl_cmode; @@ -533,6 +532,7 @@ Well Well::serializationTestObject() result.wvfpexp = std::make_shared(WVFPEXP::serializationTestObject()); result.m_pavg = PAvg(); result.well_temperature = 10.0; + result.well_inj_mult = InjMult::serializationTestObject(); return result; } @@ -565,17 +565,6 @@ bool Well::updateWellGuideRate(double guide_rate_arg) { return false; } -Well::InjMultMode Well::injMultModeFromString(const std::string& str, const KeywordLocation& location) { - if (str == "WREV") - return InjMultMode::WREV; - else if (str == "CREV") - return InjMultMode::CREV; - else if (str == "CIRR") - return InjMultMode::CIRR; - else - throw OpmInputError(fmt::format("Unknown mode {} is specified in WINJMULT keyword", str), location); -} - bool Well::updateFoamProperties(std::shared_ptr foam_properties_arg) { if (this->wtype.producer()) { @@ -1327,11 +1316,8 @@ bool Well::handleWINJMULT(const Opm::DeckRecord& record, const KeywordLocation& return true; }; - // check whether it was under WREV previously. - // if yes, we need to reset all the connections for INJMULT specification - const bool is_prev_wrev = this->inj_mult_mode == InjMultMode::WREV; using Kw = ParserKeywords::WINJMULT; - const InjMultMode mode = injMultModeFromString(record.getItem().getTrimmedString(0), location); + const InjMultMode mode = InjMult::injMultModeFromString(record.getItem().getTrimmedString(0), location); const bool mode_change = (this->inj_mult_mode != mode); if (mode_change) { this->inj_mult_mode = mode; @@ -1339,33 +1325,26 @@ bool Well::handleWINJMULT(const Opm::DeckRecord& record, const KeywordLocation& const double fracture_pressure = record.getItem().getSIDouble(0); const double multiple_gradient = record.getItem().getSIDouble(0); auto new_connections = std::make_shared(this->connections->ordering(), this->headI, this->headJ); - const Connection::InjMult inj_mult {true, fracture_pressure, multiple_gradient}; + const InjMult inj_mult {true, fracture_pressure, multiple_gradient}; + bool connections_update = false; + bool well_inj_update = false; if (mode == InjMultMode::WREV) { - // all the connections will share the same INJMULT setup - for (auto c : *this->connections) { - c.setInjMult(inj_mult); - new_connections->add(c); - } + // all the connections will share the same INJMULT setup when under WREV + // it is stored in the Well object + this->well_inj_mult = inj_mult; + well_inj_update = true; } else if (mode == InjMultMode::CREV || mode == InjMultMode::CIRR){ for (auto c : *this->connections) { if (match(c)) { c.setInjMult(inj_mult); - } else { - // if previously defined with WREV for the well, for all the connections - // not specified in the new CREV or CIRR records, we do not consider they have - // an active WINJMULT setup - if (is_prev_wrev) { - // reset the injMult information for this connection - // basically, disable the injMult for this connection - c.clearInjMult(); - } } new_connections->add(c); } + connections_update = this->updateConnections(std::move(new_connections), false); } - return this->updateConnections(std::move(new_connections), false) || mode_change; + return mode_change || connections_update || well_inj_update; } @@ -1635,6 +1614,7 @@ bool Well::operator==(const Well& data) const { && (this->getInjectionProperties() == data.getInjectionProperties()) && (this->well_temperature == data.well_temperature) && (this->inj_mult_mode == data.inj_mult_mode) + && (this->getWellInjMult() == data.getWellInjMult()) ; } @@ -1719,3 +1699,9 @@ int Opm::Well::eclipseControlMode(const Well& well, Opm::Well::InjMultMode Opm::Well::getInjMultMode() const { return this->inj_mult_mode; } + +const Opm::InjMult& Opm::Well::getWellInjMult() const { + return this->well_inj_mult; +} + + From 9572d5ecf393fcc83e85af9695f1a5ef115d4cb2 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 22 Jun 2023 11:58:52 +0200 Subject: [PATCH 2/2] addressing the reviewing comments for PR #3577 --- opm/input/eclipse/Schedule/Well/Connection.hpp | 3 ++- opm/input/eclipse/Schedule/Well/WINJMULT.hpp | 4 ---- opm/input/eclipse/Schedule/Well/Well.hpp | 3 ++- .../input/eclipse/Schedule/Well/Connection.cpp | 12 ++++++++++-- .../input/eclipse/Schedule/Well/WINJMULT.cpp | 13 +++---------- src/opm/input/eclipse/Schedule/Well/Well.cpp | 18 +++++++++++++----- 6 files changed, 30 insertions(+), 23 deletions(-) diff --git a/opm/input/eclipse/Schedule/Well/Connection.hpp b/opm/input/eclipse/Schedule/Well/Connection.hpp index 2718ff91a..e607b0e30 100644 --- a/opm/input/eclipse/Schedule/Well/Connection.hpp +++ b/opm/input/eclipse/Schedule/Well/Connection.hpp @@ -123,6 +123,7 @@ namespace RestartIO { double skinFactor() const; CTFKind kind() const; const InjMult& injmult() const; + bool activeInjMult() const; void setInjMult(const InjMult& inj_mult); void setState(State state); @@ -191,7 +192,7 @@ namespace RestartIO { std::array ijk; CTFKind m_ctfkind; - InjMult m_injmult; + std::optional 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/WINJMULT.hpp b/opm/input/eclipse/Schedule/Well/WINJMULT.hpp index bc60ee1fd..9e43f04dc 100644 --- a/opm/input/eclipse/Schedule/Well/WINJMULT.hpp +++ b/opm/input/eclipse/Schedule/Well/WINJMULT.hpp @@ -36,18 +36,14 @@ struct InjMult { NONE, }; - bool is_active {false}; double fracture_pressure {std::numeric_limits::max()}; double multiplier_gradient {0.}; static InjMultMode injMultModeFromString(const std::string& str, const KeywordLocation& location); - bool active() const; - template void serializeOp(Serializer& serializer) { - serializer(is_active); serializer(fracture_pressure); serializer(multiplier_gradient); } diff --git a/opm/input/eclipse/Schedule/Well/Well.hpp b/opm/input/eclipse/Schedule/Well/Well.hpp index 02aa47f70..1bc1b9556 100644 --- a/opm/input/eclipse/Schedule/Well/Well.hpp +++ b/opm/input/eclipse/Schedule/Well/Well.hpp @@ -391,6 +391,7 @@ public: Phase getPreferredPhase() const; InjMultMode getInjMultMode() const; const InjMult& getWellInjMult() const; + bool aciveWellInjMult() const; bool hasConnections() const; const std::vector getConnections(int completion) const; @@ -596,7 +597,7 @@ private: PAvg m_pavg; double well_temperature; InjMultMode inj_mult_mode = InjMultMode::NONE; - InjMult well_inj_mult; + std::optional well_inj_mult; }; std::ostream& operator<<( std::ostream&, const Well::WellInjectionProperties& ); diff --git a/src/opm/input/eclipse/Schedule/Well/Connection.cpp b/src/opm/input/eclipse/Schedule/Well/Connection.cpp index 12c23ffbb..da5b0de80 100644 --- a/src/opm/input/eclipse/Schedule/Well/Connection.cpp +++ b/src/opm/input/eclipse/Schedule/Well/Connection.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include namespace Opm { @@ -297,7 +298,9 @@ const std::optional>& Connection::perf_range() const { ss << "segment_nr " << this->segment_number << std::endl; ss << "center_depth " << this->center_depth << std::endl; ss << "sort_value" << this->m_sort_value<< std::endl; - ss << "INJMULT " << InjMult::InjMultToString(this->m_injmult) << std::endl; + if (this->m_injmult.has_value()) { + ss << "INJMULT " << InjMult::InjMultToString(this->m_injmult.value()) << std::endl; + } return ss.str(); } @@ -446,7 +449,12 @@ Connection::CTFKind Connection::kind() const { } const InjMult& Connection::injmult() const { - return m_injmult; + assert(this->activeInjMult()); + return m_injmult.value(); +} + +bool Connection::activeInjMult() const { + return this->m_injmult.has_value(); } void Connection::setInjMult(const InjMult& inj_mult) { diff --git a/src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp b/src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp index 3435000c0..1025ce20c 100644 --- a/src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp +++ b/src/opm/input/eclipse/Schedule/Well/WINJMULT.cpp @@ -39,22 +39,15 @@ InjMult::InjMultMode InjMult::injMultModeFromString(const std::string& str, cons } -bool InjMult::active() const -{ - return this->is_active; -} - bool InjMult::operator==(const InjMult& rhs) const { - return is_active == rhs.is_active - && fracture_pressure == rhs.fracture_pressure + return fracture_pressure == rhs.fracture_pressure && multiplier_gradient == rhs.multiplier_gradient; } InjMult InjMult::serializationTestObject() { InjMult result; - result.is_active = false; result.fracture_pressure = 1.e9; result.multiplier_gradient = 2.; return result; @@ -62,8 +55,8 @@ InjMult InjMult::serializationTestObject() { std::string InjMult::InjMultToString(const InjMult& mult) { - std::string ss = fmt::format("active? {}, fracture_pressure {}, multiplier_gradient {}", - mult.is_active, mult.fracture_pressure, mult.multiplier_gradient); + std::string ss = fmt::format("fracture_pressure {}, multiplier_gradient {}", + mult.fracture_pressure, mult.multiplier_gradient); return ss; } diff --git a/src/opm/input/eclipse/Schedule/Well/Well.cpp b/src/opm/input/eclipse/Schedule/Well/Well.cpp index c7bff6f04..044161548 100644 --- a/src/opm/input/eclipse/Schedule/Well/Well.cpp +++ b/src/opm/input/eclipse/Schedule/Well/Well.cpp @@ -52,6 +52,7 @@ #include "../MSW/Compsegs.hpp" +#include #include #include #include @@ -310,7 +311,8 @@ Well::Well(const RestartIO::RstWell& rst_well, wvfpdp(std::make_shared()), wvfpexp(explicitTHPOptions(rst_well)), status(status_from_int(rst_well.well_status)), - well_temperature(Metric::TemperatureOffset + ParserKeywords::STCOND::TEMPERATURE::defaultValue) + well_temperature(Metric::TemperatureOffset + ParserKeywords::STCOND::TEMPERATURE::defaultValue), + well_inj_mult(std::nullopt) { if (this->wtype.producer()) { auto p = std::make_shared(this->unit_system, wname); @@ -489,7 +491,8 @@ Well::Well(const std::string& wname_arg, wvfpdp(std::make_shared()), wvfpexp(std::make_shared()), status(Status::SHUT), - well_temperature(Metric::TemperatureOffset + ParserKeywords::STCOND::TEMPERATURE::defaultValue) + well_temperature(Metric::TemperatureOffset + ParserKeywords::STCOND::TEMPERATURE::defaultValue), + well_inj_mult(std::nullopt) { auto p = std::make_shared(this->unit_system, this->wname); p->whistctl_cmode = whistctl_cmode; @@ -1325,7 +1328,7 @@ bool Well::handleWINJMULT(const Opm::DeckRecord& record, const KeywordLocation& const double fracture_pressure = record.getItem().getSIDouble(0); const double multiple_gradient = record.getItem().getSIDouble(0); auto new_connections = std::make_shared(this->connections->ordering(), this->headI, this->headJ); - const InjMult inj_mult {true, fracture_pressure, multiple_gradient}; + const InjMult inj_mult {fracture_pressure, multiple_gradient}; bool connections_update = false; bool well_inj_update = false; @@ -1614,7 +1617,7 @@ bool Well::operator==(const Well& data) const { && (this->getInjectionProperties() == data.getInjectionProperties()) && (this->well_temperature == data.well_temperature) && (this->inj_mult_mode == data.inj_mult_mode) - && (this->getWellInjMult() == data.getWellInjMult()) + && (this->well_inj_mult == data.well_inj_mult) ; } @@ -1701,7 +1704,12 @@ Opm::Well::InjMultMode Opm::Well::getInjMultMode() const { } const Opm::InjMult& Opm::Well::getWellInjMult() const { - return this->well_inj_mult; + assert(this->aciveWellInjMult()); + return this->well_inj_mult.value(); +} + +bool Opm::Well::aciveWellInjMult() const { + return this->well_inj_mult.has_value(); }