From 73c58dba48c674a85d4448632b7dad221f54ad8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A5rd=20Skaflestad?= Date: Fri, 10 Nov 2023 12:05:46 +0100 Subject: [PATCH] Extract CTF Input Data to Separate Structure This commit creates a new helper structure, Opm::Connection::CTFProperties that holds all of the individual items which go into calculating the final connection transmissibility factor (CTF). These include the 'Kh' product, the pressure equivalent radius ('r0'), the well-bore radius ('rw'), and the skin factor. We reimplement the Connection constructor in terms of this new helper structure and this changes the API of the constructor. As an additional helper for the implementation, and with a view towards simulation restart support, we also store the value of the Peaceman formula denominator in CTFProperties as double CTFProperties::peaceman_denom This, in turn, simplifies the implementation of CSKIN. It also fixes a latent problem in the current CSKIN implementation which would ignore any explicitly input CTF values in favour of the pressure equivalent radius. By updating the explicit denominator with a new skin factor instead we do not need to recompute the logarithmic term involving 'r0' as part of CSKIN handling. --- .../eclipse/Schedule/Well/Connection.hpp | 304 +++--- opm/input/eclipse/Schedule/Well/Well.hpp | 2 +- .../eclipse/Schedule/Well/WellConnections.hpp | 58 +- .../eclipse/Schedule/KeywordHandlers.cpp | 18 +- .../eclipse/Schedule/Well/Connection.cpp | 629 +++++++----- src/opm/input/eclipse/Schedule/Well/Well.cpp | 84 +- .../eclipse/Schedule/Well/WellConnections.cpp | 921 +++++++++--------- tests/parser/ConnectionTests.cpp | 207 ++-- tests/parser/MultisegmentWellTests.cpp | 176 ++-- tests/parser/ScheduleTests.cpp | 908 +++++++++-------- tests/parser/WellSolventTests.cpp | 359 +++---- tests/parser/WellTracerTests.cpp | 243 ++--- .../integration/ScheduleCreateFromDeck.cpp | 62 +- tests/test_PAvgCalculator.cpp | 54 +- tests/test_Serialization.cpp | 1 + 15 files changed, 2263 insertions(+), 1763 deletions(-) diff --git a/opm/input/eclipse/Schedule/Well/Connection.hpp b/opm/input/eclipse/Schedule/Well/Connection.hpp index 431a13cb3..4be15fbf2 100644 --- a/opm/input/eclipse/Schedule/Well/Connection.hpp +++ b/opm/input/eclipse/Schedule/Well/Connection.hpp @@ -17,91 +17,167 @@ along with OPM. If not, see . */ - #ifndef COMPLETION_HPP_ #define COMPLETION_HPP_ +#include +#include + #include #include #include #include #include +#include #include #include #include -#include -#include - namespace Opm { - -namespace RestartIO { - struct RstConnection; -} - class DeckKeyword; class DeckRecord; class ScheduleGrid; class FieldPropsManager; +} // namespace Opm - class Connection { +namespace Opm { namespace RestartIO { + struct RstConnection; +}} // namespace Opm::RestartIO + +namespace Opm { + + class Connection + { public: enum class State { OPEN = 1, SHUT = 2, - AUTO = 3 // Seems like the AUTO state can not be serialized to restart files. + AUTO = 3, // Seems like the AUTO state can not be serialized to restart files. }; - static const std::string State2String( State enumValue ); - static State StateFromString( const std::string& stringValue ); + static std::string State2String(State enumValue); + static State StateFromString(std::string_view stringValue); - enum class Direction{ + enum class Direction { X = 1, Y = 2, - Z = 3 + Z = 3, }; static std::string Direction2String(const Direction enumValue); - static Direction DirectionFromString(const std::string& stringValue); + static Direction DirectionFromString(std::string_view stringValue); enum class Order { - DEPTH, - INPUT, - TRACK + DEPTH, + INPUT, + TRACK, }; - static const std::string Order2String( Order enumValue ); - static Order OrderFromString(const std::string& comporderStringValue); + static std::string Order2String(Order enumValue); + static Order OrderFromString(std::string_view comporderStringValue); + enum class CTFKind { DeckValue, Defaulted, }; - Connection(); - Connection(int i, int j , int k , - std::size_t global_index, - int complnum, - double depth, - State state, - double CF, - double Kh, - double rw, - double r0, - double re, - double connection_length, - double skin_factor, - double d_factor, - double Ke, - const int satTableId, - const Direction direction, - const CTFKind ctf_kind, - const std::size_t sort_value, - const bool defaultSatTabId); - Connection(const RestartIO::RstConnection& rst_connection, const ScheduleGrid& grid, const FieldPropsManager& fp); + /// Quantities that go into calculating the connection + /// transmissibility factor. + struct CTFProperties + { + /// Static connection transmissibility factor calculated from + /// input quantities. + double CF{}; + + /// Static 'Kh' product + double Kh{}; + + /// Effective permeability. + double Ke{}; + + /// Connection's wellbore radius + double rw{}; + + /// Connection's pressure equivalent radius + double r0{}; + + /// Connection's area equivalent radius--mostly for use by the + /// polymer code. + double re{}; + + /// Length of connection's perfororation interval + double connection_length{}; + + /// Connection's skin factor. + double skin_factor{}; + + /// Connection's D factor-i.e., the flow-dependent skin factor + /// for gas. + double d_factor{}; + + /// Denominator in peaceman's formula-i.e., log(r0/rw) + skin. + double peaceman_denom{}; + + /// Serialisation test object. + static CTFProperties serializationTestObject(); + + /// Equality operator + /// + /// \param[in] that Property object to which \c *this will be compared. + bool operator==(const CTFProperties& that) const; + + /// Inequality operator + /// + /// \param[in] that Property object to which \c *this will be compared. + bool operator!=(const CTFProperties& that) const + { + return ! (*this == that); + } + + /// Serialisation operator + /// + /// \tparam Serializer Protocol for serialising and + /// deserialising objects between memory and character + /// buffers. + /// + /// \param[in,out] serializer Serialisation object. + template + void serializeOp(Serializer& serializer) + { + serializer(this->CF); + serializer(this->Kh); + serializer(this->Ke); + serializer(this->rw); + serializer(this->r0); + serializer(this->re); + serializer(this->connection_length); + serializer(this->skin_factor); + serializer(this->d_factor); + serializer(this->peaceman_denom); + } + }; + + + Connection() = default; + Connection(int i, int j, int k, + std::size_t global_index, + int complnum, + State state, + Direction direction, + CTFKind ctf_kind, + const int satTableId, + double depth, + const CTFProperties& ctf_properties, + const std::size_t sort_value, + const bool defaultSatTabId); + + Connection(const RestartIO::RstConnection& rst_connection, + const ScheduleGrid& grid, + const FieldPropsManager& fp); static Connection serializationTestObject(); @@ -117,104 +193,104 @@ namespace RestartIO { int satTableId() const; int complnum() const; int segment() const; - double CF() const; double wpimult() const; + double CF() const; double Kh() const; + double Ke() const; double rw() const; double r0() const; double re() const; double connectionLength() const; double skinFactor() const; double dFactor() const; - double Ke() const; CTFKind kind() const; const InjMult& injmult() const; bool activeInjMult() const; - void setInjMult(const InjMult& inj_mult); - void setFilterCake(const FilterCake& filter_cake); const FilterCake& getFilterCake() const; bool filterCakeActive() const; double getFilterCakeRadius() const; double getFilterCakeArea() const; + const CTFProperties& ctfProperties() const + { + return this->ctf_properties_; + } + + std::size_t sort_value() const; + bool getDefaultSatTabId() const; + const std::optional>& perf_range() const; + std::string str() const; + + bool ctfAssignedFromInput() const + { + return this->m_ctfkind == CTFKind::DeckValue; + } + + bool operator==(const Connection&) const; + bool operator!=(const Connection& that) const + { + return ! (*this == that); + } + + void setInjMult(const InjMult& inj_mult); + void setFilterCake(const FilterCake& filter_cake); void setState(State state); void setComplnum(int compnum); void setSkinFactor(double skin_factor); void setDFactor(double d_factor); void setKe(double Ke); void setCF(double CF); + void setDefaultSatTabId(bool id); + void scaleWellPi(double wellPi); bool prepareWellPIScaling(); bool applyWellPIScaling(const double scaleFactor); + void updateSegmentRST(int segment_number_arg, double center_depth_arg); void updateSegment(int segment_number_arg, double center_depth_arg, std::size_t compseg_insert_index, const std::optional>& perf_range); - std::size_t sort_value() const; - const bool& getDefaultSatTabId() const; - void setDefaultSatTabId(bool id); - const std::optional>& perf_range() const; - std::string str() const; - bool ctfAssignedFromInput() const - { - return this->m_ctfkind == CTFKind::DeckValue; - } - - bool operator==( const Connection& ) const; - bool operator!=( const Connection& ) const; template void serializeOp(Serializer& serializer) { - serializer(direction); - serializer(center_depth); - serializer(open_state); - serializer(sat_tableId); - serializer(m_complnum); - serializer(m_CF); - serializer(m_Kh); - serializer(m_rw); - serializer(m_r0); - serializer(m_re); - serializer(m_connection_length); - serializer(m_skin_factor); - serializer(m_d_factor); - serializer(m_Ke); - serializer(ijk); - serializer(m_global_index); - serializer(m_ctfkind); - serializer(m_injmult); - serializer(m_sort_value); - serializer(m_perf_range); - serializer(m_defaultSatTabId); - serializer(segment_number); - serializer(m_subject_to_welpi); - serializer(m_filter_cake); - serializer(m_wpimult); + serializer(this->direction); + serializer(this->center_depth); + serializer(this->open_state); + serializer(this->sat_tableId); + serializer(this->m_complnum); + serializer(this->ctf_properties_); + serializer(this->ijk); + serializer(this->m_ctfkind); + serializer(this->m_global_index); + serializer(this->m_injmult); + serializer(this->m_sort_value); + serializer(this->m_perf_range); + serializer(this->m_defaultSatTabId); + serializer(this->segment_number); + serializer(this->m_wpimult); + serializer(this->m_subject_to_welpi); + serializer(this->m_filter_cake); } private: - Direction direction; - double center_depth; - State open_state; - int sat_tableId; - int m_complnum; - double m_CF; - double m_Kh; - double m_rw; - double m_r0; - double m_re; - double m_connection_length; - double m_skin_factor; - double m_d_factor; - double m_Ke; + // Note to maintainer: If you add new members to this list, then + // please also update the operator==(), serializeOp(), and + // serializationTestObject() member functions. + Direction direction { Direction::Z }; + double center_depth { 0.0 }; + State open_state { State::SHUT }; + int sat_tableId { -1 }; + int m_complnum { -1 }; + CTFProperties ctf_properties_{}; + + std::array ijk{}; + CTFKind m_ctfkind { CTFKind::DeckValue }; + std::optional m_injmult{}; + std::size_t m_global_index{}; - std::array ijk; - CTFKind m_ctfkind; - std::optional m_injmult; - std::size_t m_global_index; /* The sort_value member is a peculiar quantity. The connections are assembled in the WellConnections class. During the lifetime of the @@ -266,26 +342,26 @@ namespace RestartIO { explicitly, so the truth is probably that the storage order during simulation makes no difference? */ + std::size_t m_sort_value{}; - std::size_t m_sort_value; - std::optional> m_perf_range; - bool m_defaultSatTabId; + std::optional> m_perf_range{}; + bool m_defaultSatTabId{true}; - // related segment number - // 0 means the completion is not related to segment - int segment_number = 0; + // Associate segment number + // + // 0 means the connection is not associated to a segment. + int segment_number { 0 }; + + double m_wpimult { 1.0 }; // Whether or not this Connection is subject to WELPI scaling. - bool m_subject_to_welpi = false; + bool m_subject_to_welpi { false }; - // For applying last known WPIMULT to when calculating connection transmissibilty factor in CSKIN - double m_wpimult = 1.0; - - std::optional m_filter_cake; + std::optional m_filter_cake{}; static std::string CTFKindToString(const CTFKind); }; -} -#endif /* COMPLETION_HPP_ */ +} // namespace Opm +#endif // COMPLETION_HPP_ diff --git a/opm/input/eclipse/Schedule/Well/Well.hpp b/opm/input/eclipse/Schedule/Well/Well.hpp index 4aca23351..3855582f9 100644 --- a/opm/input/eclipse/Schedule/Well/Well.hpp +++ b/opm/input/eclipse/Schedule/Well/Well.hpp @@ -527,7 +527,7 @@ public: bool handleWELSEGS(const DeckKeyword& keyword); bool handleCOMPSEGS(const DeckKeyword& keyword, const ScheduleGrid& grid, const ParseContext& parseContext, ErrorGuard& errors); bool handleWELOPENConnections(const DeckRecord& record, Connection::State status); - bool handleCSKINConnections(const DeckRecord& record); + bool handleCSKIN(const DeckRecord& record, const KeywordLocation& location); bool handleCOMPLUMP(const DeckRecord& record); bool handleWPIMULT(const DeckRecord& record); bool handleWINJCLN(const DeckRecord& record, const KeywordLocation& location); diff --git a/opm/input/eclipse/Schedule/Well/WellConnections.hpp b/opm/input/eclipse/Schedule/Well/WellConnections.hpp index 3ed188439..052a9054e 100644 --- a/opm/input/eclipse/Schedule/Well/WellConnections.hpp +++ b/opm/input/eclipse/Schedule/Well/WellConnections.hpp @@ -23,9 +23,11 @@ #include #include +#include #include #include #include +#include #include #include @@ -33,10 +35,10 @@ namespace Opm { class ActiveGridCells; class DeckRecord; + class EclipseGrid; class FieldPropsManager; class KeywordLocation; class ScheduleGrid; - class EclipseGrid; } // namespace Opm namespace Opm { @@ -67,19 +69,16 @@ namespace Opm { } } + void add(const Connection& conn) + { + this->m_connections.push_back(conn); + } + void addConnection(const int i, const int j, const int k, const std::size_t global_index, - const double depth, const Connection::State state, - const double CF, - const double Kh, - const double rw, - const double r0, - const double re, - const double connection_length, - const double skin_factor, - const double d_factor, - const double Ke, + const double depth, + const Connection::CTFProperties& ctf_props, const int satTableId, const Connection::Direction direction = Connection::Direction::Z, const Connection::CTFKind ctf_kind = Connection::CTFKind::DeckValue, @@ -91,14 +90,20 @@ namespace Opm { const std::string& wname, const KeywordLocation& location); - void loadCOMPTRAJ(const DeckRecord& record, const ScheduleGrid& grid, const std::string& wname, const KeywordLocation& location, external::cvf::ref& cellSearchTree); + void loadCOMPTRAJ(const DeckRecord& record, + const ScheduleGrid& grid, + const std::string& wname, + const KeywordLocation& location, + external::cvf::ref& cellSearchTree); - void loadWELTRAJ(const DeckRecord& record, const ScheduleGrid& grid, const std::string& wname, const KeywordLocation& location); + void loadWELTRAJ(const DeckRecord& record, + const ScheduleGrid& grid, + const std::string& wname, + const KeywordLocation& location); int getHeadI() const; int getHeadJ() const; const std::vector& getMD() const; - void add(Connection); std::size_t size() const; bool empty() const; std::size_t num_open() const; @@ -165,39 +170,32 @@ namespace Opm { serializer(this->coord); serializer(this->md); } + private: Connection::Order m_ordering { Connection::Order::TRACK }; int headI{0}; int headJ{0}; std::vector m_connections{}; - std::vector> coord{3, std::vector(0, 0.0) }; + + std::array, 3> coord{}; std::vector md{}; void addConnection(const int i, const int j, const int k, const std::size_t global_index, const int complnum, - const double depth, const Connection::State state, - const double CF, - const double Kh, - const double rw, - const double r0, - const double re, - const double connection_length, - const double skin_factor, - const double d_factor, - const double Ke, + const double depth, + const Connection::CTFProperties& ctf_props, const int satTableId, - const Connection::Direction direction = Connection::Direction::Z, - const Connection::CTFKind ctf_kind = Connection::CTFKind::DeckValue, - const std::size_t seqIndex = 0, - const bool defaultSatTabId = true); + const Connection::Direction direction, + const Connection::CTFKind ctf_kind, + const std::size_t seqIndex, + const bool defaultSatTabId); size_t findClosestConnection(int oi, int oj, double oz, size_t start_pos); void orderTRACK(); void orderMSW(); void orderDEPTH(); - }; std::optional diff --git a/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp b/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp index 3390b6bed..e475ce6f6 100644 --- a/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp +++ b/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp @@ -377,23 +377,29 @@ File {} line {}.)", wname, location.keyword, location.filename, location.lineno) handlerContext.compsegs_handled(wname); } - void Schedule::handleCSKIN(HandlerContext& handlerContext) { + void Schedule::handleCSKIN(HandlerContext& handlerContext) + { + using Kw = ParserKeywords::CSKIN; + // Get CSKIN keyword info and current step const auto& keyword = handlerContext.keyword; const auto& currentStep = handlerContext.currentStep; // Loop over records in CSKIN - for (const auto& record: keyword) { + for (const auto& record : keyword) { // Get well names - const auto& wellNamePattern = record.getItem( "WELL" ).getTrimmedString(0); + const auto wellNamePattern = record.getItem().getTrimmedString(0); const auto well_names = this->wellNames(wellNamePattern, handlerContext); // Loop over well(s) in record for (const auto& wname : well_names) { - // Get well information, modify connection skin factor, and update well + // Get well information, modify connection skin factor, and + // update well. auto well = this->snapshots[currentStep].wells.get(wname); - well.handleCSKINConnections(record); - this->snapshots[currentStep].wells.update( std::move(well) ); + + if (well.handleCSKIN(record, handlerContext.keyword.location())) { + this->snapshots[currentStep].wells.update(std::move(well)); + } } } } diff --git a/src/opm/input/eclipse/Schedule/Well/Connection.cpp b/src/opm/input/eclipse/Schedule/Well/Connection.cpp index b7f0958f3..58673416b 100644 --- a/src/opm/input/eclipse/Schedule/Well/Connection.cpp +++ b/src/opm/input/eclipse/Schedule/Well/Connection.cpp @@ -17,125 +17,157 @@ along with OPM. If not, see . */ +#include + +#include + +#include + +#include +#include + +#include +#include +#include + #include #include #include #include #include +#include +#include #include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Opm { - - - Connection::Connection(int i, int j , int k , - std::size_t global_index, - int compnum, - double depth, - State stateArg , - double CF, - double Kh, - double rw, - double r0, - double re, - double connection_length, - double skin_factor, - double d_factor, - double Ke, - const int satTableId, - const Direction directionArg, - const CTFKind ctf_kind, - const std::size_t sort_value, - const bool defaultSatTabId) - : direction(directionArg), - center_depth(depth), - open_state(stateArg), - sat_tableId(satTableId), - m_complnum( compnum ), - m_CF(CF), - m_Kh(Kh), - m_rw(rw), - m_r0(r0), - m_re(re), - m_connection_length(connection_length), - m_skin_factor(skin_factor), - m_d_factor(d_factor), - m_Ke(Ke), - ijk({i,j,k}), - m_ctfkind(ctf_kind), - m_global_index(global_index), - m_sort_value(sort_value), - m_defaultSatTabId(defaultSatTabId) - { - } - namespace { -constexpr bool defaultSatTabId = true; + constexpr bool restartDefaultSatTabId = true; + + Opm::Connection::CTFProperties + collectCTFProps(const Opm::RestartIO::RstConnection& rst_conn) + { + auto props = Opm::Connection::CTFProperties{}; + + props.CF = rst_conn.cf; + props.Kh = rst_conn.kh; + props.Ke = 0.0; + props.rw = rst_conn.diameter / 2; + props.r0 = rst_conn.r0; + props.re = 0.0; + props.connection_length = 0.0; + props.skin_factor = rst_conn.skin_factor; + props.d_factor = 0.0; + + return props; + } } -Connection::Connection(const RestartIO::RstConnection& rst_connection, const ScheduleGrid& grid, const FieldPropsManager& fp) : - direction(rst_connection.dir), - center_depth(rst_connection.depth), - open_state(rst_connection.state), - sat_tableId(rst_connection.drain_sat_table), - m_complnum(rst_connection.completion), - m_CF(rst_connection.cf), - m_Kh(rst_connection.kh), - m_rw(rst_connection.diameter / 2), - m_r0(rst_connection.r0), - m_re(0.0), - m_connection_length(0.0), - m_skin_factor(rst_connection.skin_factor), - m_d_factor(0.0), - m_Ke(0.0), - ijk(rst_connection.ijk), - m_ctfkind(rst_connection.cf_kind), - m_global_index(grid.get_cell(this->ijk[0], this->ijk[1], this->ijk[2]).global_index), - m_sort_value(rst_connection.rst_index), - m_defaultSatTabId(defaultSatTabId), - segment_number(rst_connection.segment) +namespace Opm +{ + + Connection::CTFProperties + Connection::CTFProperties::serializationTestObject() + { + auto props = Opm::Connection::CTFProperties{}; + + props.CF = 1.0; + props.Kh = 2.0; + props.Ke = 3.0; + props.rw = 4.0; + props.r0 = 5.0; + props.re = 6.0; + props.connection_length = 7.0; + props.skin_factor = 8.0; + props.d_factor = 9.0; + props.peaceman_denom = 10.0; + + return props; + } + + bool Connection::CTFProperties::operator==(const CTFProperties& that) const + { + return (this->CF == that.CF) + && (this->Kh == that.Kh) + && (this->Ke == that.Ke) + && (this->rw == that.rw) + && (this->r0 == that.r0) + && (this->re == that.re) + && (this->connection_length == that.connection_length) + && (this->skin_factor == that.skin_factor) + && (this->d_factor == that.d_factor) + && (this->peaceman_denom == that.peaceman_denom) + ; + } + + // ========================================================================= + + Connection::Connection(const int i, const int j, const int k, + const std::size_t global_index, + const int complnum, + const State stateArg, + const Direction directionArg, + const CTFKind ctf_kind, + const int satTableId, + const double depth, + const CTFProperties& ctf_props, + const std::size_t sort_value, + const bool defaultSatTabId) + : direction (directionArg) + , center_depth (depth) + , open_state (stateArg) + , sat_tableId (satTableId) + , m_complnum (complnum) + , ctf_properties_ { ctf_props } + , ijk { i, j, k } + , m_ctfkind (ctf_kind) + , m_global_index (global_index) + , m_sort_value (sort_value) + , m_defaultSatTabId(defaultSatTabId) + {} + + Connection::Connection(const RestartIO::RstConnection& rst_connection, + const ScheduleGrid& grid, + const FieldPropsManager& fp) + : direction (rst_connection.dir) + , center_depth (rst_connection.depth) + , open_state (rst_connection.state) + , sat_tableId (rst_connection.drain_sat_table) + , m_complnum (rst_connection.completion) + , ctf_properties_ (collectCTFProps(rst_connection)) + , ijk (rst_connection.ijk) + , m_ctfkind (rst_connection.cf_kind) + , m_global_index (grid.get_cell(this->ijk[0], this->ijk[1], this->ijk[2]).global_index) + , m_sort_value (rst_connection.rst_index) + , m_defaultSatTabId(restartDefaultSatTabId) + , segment_number (rst_connection.segment) { if (this->m_defaultSatTabId) { - const auto& satnum = fp.get_int("SATNUM"); - auto active_index = grid.get_cell(this->ijk[0], this->ijk[1], this->ijk[2]).active_index(); - this->sat_tableId = satnum[active_index]; + const auto active_index = grid + .get_cell(this->ijk[0], this->ijk[1], this->ijk[2]) + .active_index(); + + this->sat_tableId = fp.get_int("SATNUM")[active_index]; + } + + if (this->segment_number > 0) { + this->m_perf_range = std::make_pair(rst_connection.segdist_start, + rst_connection.segdist_end); } - if (this->segment_number > 0) - this->m_perf_range = std::make_pair(rst_connection.segdist_start, rst_connection.segdist_end); //TODO recompute re and perf_length from the grid } - Connection::Connection() - : Connection(0, 0, 0, 0, 0, 0.0, State::SHUT, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, - 0, Direction::X, CTFKind::DeckValue, 0, false) - {} - Connection Connection::serializationTestObject() { Connection result; + result.direction = Direction::Y; result.center_depth = 1.0; result.open_state = State::OPEN; result.sat_tableId = 2; result.m_complnum = 3; - result.m_CF = 4.0; - result.m_Kh = 5.0; - result.m_rw = 6.0; - result.m_r0 = 7.0; - result.m_re = 7.1; - result.m_connection_length = 7.2; - result.m_skin_factor = 8.0; - result.m_d_factor = 8.5; - result.m_Ke = 8.9; + + result.ctf_properties_ = CTFProperties::serializationTestObject(); + result.ijk = {9, 10, 11}; result.m_ctfkind = CTFKind::Defaulted; result.m_global_index = 12; @@ -144,144 +176,181 @@ Connection::Connection(const RestartIO::RstConnection& rst_connection, const Sch result.m_sort_value = 14; result.m_defaultSatTabId = true; result.segment_number = 16; + result.m_wpimult = 0.123; result.m_subject_to_welpi = true; result.m_filter_cake = FilterCake::serializationTestObject(); return result; } - bool Connection::sameCoordinate(const int i, const int j, const int k) const { - if ((ijk[0] == i) && (ijk[1] == j) && (ijk[2] == k)) { - return true; - } else { - return false; - } + bool Connection::sameCoordinate(const int i, const int j, const int k) const + { + return this->ijk == std::array { i, j, k }; } - int Connection::getI() const { + int Connection::getI() const + { return ijk[0]; } - int Connection::getJ() const { + int Connection::getJ() const + { return ijk[1]; } - int Connection::getK() const { + int Connection::getK() const + { return ijk[2]; } - std::size_t Connection::global_index() const { + std::size_t Connection::global_index() const + { return this->m_global_index; } - bool Connection::attachedToSegment() const { - return (segment_number > 0); + bool Connection::attachedToSegment() const + { + return this->segment_number > 0; } - std::size_t Connection::sort_value() const { + std::size_t Connection::sort_value() const + { return m_sort_value; } - const bool& Connection::getDefaultSatTabId() const { + bool Connection::getDefaultSatTabId() const + { return m_defaultSatTabId; } - Connection::Direction Connection::dir() const { + Connection::Direction Connection::dir() const + { return this->direction; } -const std::optional>& Connection::perf_range() const { + const std::optional>& + Connection::perf_range() const + { return this->m_perf_range; } - void Connection::setDefaultSatTabId(bool id) { + void Connection::setDefaultSatTabId(bool id) + { m_defaultSatTabId = id; } - double Connection::depth() const { + double Connection::depth() const + { return this->center_depth; } - Connection::State Connection::state() const { + Connection::State Connection::state() const + { return this->open_state; } - int Connection::satTableId() const { + int Connection::satTableId() const + { return this->sat_tableId; } - int Connection::complnum() const { + int Connection::complnum() const + { return this->m_complnum; } - void Connection::setComplnum(int complnum) { + void Connection::setComplnum(int complnum) + { this->m_complnum = complnum; } - void Connection::setSkinFactor(double skin_factor) { - this->m_skin_factor = skin_factor; + void Connection::setSkinFactor(double skin_factor) + { + auto& ctf_p = this->ctf_properties_; + + const auto peaceman_denom = ctf_p.peaceman_denom + - ctf_p.skin_factor + skin_factor; + + ctf_p.skin_factor = skin_factor; + ctf_p.CF *= ctf_p.peaceman_denom / peaceman_denom; + ctf_p.peaceman_denom = peaceman_denom; } - void Connection::setDFactor(double d_factor) { - this->m_d_factor = d_factor; + void Connection::setDFactor(double d_factor) + { + this->ctf_properties_.d_factor = d_factor; } - void Connection::setKe(double Ke) { - this->m_Ke = Ke; + void Connection::setKe(double Ke) + { + this->ctf_properties_.Ke = Ke; } - void Connection::setCF(double CF) { - this->m_CF = CF; + void Connection::setCF(double CF) + { + this->ctf_properties_.CF = CF; } - double Connection::CF() const { - return this->m_CF; - } - - double Connection::wpimult() const { + double Connection::wpimult() const + { return this->m_wpimult; } - double Connection::Kh() const { - return this->m_Kh; + double Connection::CF() const + { + return this->ctf_properties_.CF; } - double Connection::rw() const { - return this->m_rw; + double Connection::Kh() const + { + return this->ctf_properties_.Kh; } - double Connection::r0() const { - return this->m_r0; + double Connection::rw() const + { + return this->ctf_properties_.rw; } - double Connection::re() const { - return this->m_re; + double Connection::r0() const + { + return this->ctf_properties_.r0; } - double Connection::connectionLength() const { - return this->m_connection_length; + double Connection::re() const + { + return this->ctf_properties_.re; } - double Connection::skinFactor() const { - return this->m_skin_factor; + double Connection::connectionLength() const + { + return this->ctf_properties_.connection_length; } - double Connection::dFactor() const { - return this->m_d_factor; + double Connection::skinFactor() const + { + return this->ctf_properties_.skin_factor; } - double Connection::Ke() const { - return this->m_Ke; + double Connection::dFactor() const + { + return this->ctf_properties_.d_factor; } - void Connection::setState(State state) { + double Connection::Ke() const + { + return this->ctf_properties_.Ke; + } + + void Connection::setState(State state) + { this->open_state = state; } - void Connection::updateSegment(int segment_number_arg, - double center_depth_arg, - std::size_t compseg_insert_index, - const std::optional>& perf_range) { + void Connection::updateSegment(const int segment_number_arg, + const double center_depth_arg, + const std::size_t compseg_insert_index, + const std::optional>& perf_range) + { this->segment_number = segment_number_arg; this->center_depth = center_depth_arg; this->m_sort_value = compseg_insert_index; @@ -289,124 +358,137 @@ const std::optional>& Connection::perf_range() const { } void Connection::updateSegmentRST(int segment_number_arg, - double center_depth_arg) { + double center_depth_arg) + { this->segment_number = segment_number_arg; this->center_depth = center_depth_arg; } - int Connection::segment() const { + int Connection::segment() const + { return this->segment_number; } - void Connection::scaleWellPi(double wellPi) { + void Connection::scaleWellPi(double wellPi) + { this->m_wpimult *= wellPi; - this->m_CF *= wellPi; + this->ctf_properties_.CF *= wellPi; } - bool Connection::prepareWellPIScaling() { + bool Connection::prepareWellPIScaling() + { const auto update = !this->m_subject_to_welpi; this->m_subject_to_welpi = true; return update; } - - bool Connection::applyWellPIScaling(const double scaleFactor) { - if (! this->m_subject_to_welpi) + bool Connection::applyWellPIScaling(const double scaleFactor) + { + if (! this->m_subject_to_welpi) { return false; + } this->scaleWellPi(scaleFactor); return true; } - std::string Connection::str() const { + std::string Connection::str() const + { std::stringstream ss; - ss << "ijk: " << this->ijk[0] << "," << this->ijk[1] << "," << this->ijk[2] << std::endl; - ss << "COMPLNUM " << this->m_complnum << std::endl; - ss << "CF " << this->m_CF << std::endl; - ss << "RW " << this->m_rw << std::endl; - ss << "R0 " << this->m_r0 << std::endl; - ss << "Re " << this->m_re << std::endl; - ss << "connection length " << this->m_connection_length << std::endl; - ss << "skinf " << this->m_skin_factor << std::endl; - ss << "dfactor " << this->m_d_factor << std::endl; - ss << "Ke " << this->m_Ke << std::endl; - ss << "kh " << this->m_Kh << std::endl; - ss << "sat_tableId " << this->sat_tableId << std::endl; - ss << "open_state " << Connection::State2String(this->open_state) << std::endl; - ss << "direction " << Connection::Direction2String(this->direction) << std::endl; - ss << "CTF Source " << Connection::CTFKindToString(this->m_ctfkind) << '\n'; - 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 << "ijk: " << this->ijk[0] << ',' << this->ijk[1] << ',' << this->ijk[2] << '\n' + << "COMPLNUM " << this->m_complnum << '\n' + << "CF " << this->CF() << '\n' + << "RW " << this->rw() << '\n' + << "R0 " << this->r0() << '\n' + << "Re " << this->re() << '\n' + << "connection length " << this->connectionLength() << '\n' + << "skinf " << this->skinFactor() << '\n' + << "dfactor " << this->dFactor() << '\n' + << "Ke " << this->Ke() << '\n' + << "kh " << this->Kh() << '\n' + << "sat_tableId " << this->sat_tableId << '\n' + << "open_state " << Connection::State2String(this->open_state) << '\n' + << "direction " << Connection::Direction2String(this->direction) << '\n' + << "CTF Source " << Connection::CTFKindToString(this->m_ctfkind) << '\n' + << "segment_nr " << this->segment_number << '\n' + << "center_depth " << this->center_depth << '\n' + << "sort_value" << this->m_sort_value<< '\n'; + if (this->m_injmult.has_value()) { - ss << "INJMULT " << InjMult::InjMultToString(this->m_injmult.value()) << std::endl; + ss << "INJMULT " << InjMult::InjMultToString(this->m_injmult.value()) << '\n'; } + if (this->m_filter_cake.has_value()) { - ss << "FilterCake " << FilterCake::filterCakeToString(this->m_filter_cake.value()) << std::endl; + ss << "FilterCake " << FilterCake::filterCakeToString(this->m_filter_cake.value()) << '\n'; } return ss.str(); -} - - bool Connection::operator==( const Connection& rhs ) const { - return this->ijk == rhs.ijk - && this->m_global_index == rhs.m_global_index - && this->m_complnum == rhs.m_complnum - && this->m_CF == rhs.m_CF - && this->m_rw == rhs.m_rw - && this->m_r0 == rhs.m_r0 - && this->m_re == rhs.m_re - && this->m_connection_length == rhs.m_connection_length - && this->m_skin_factor == rhs.m_skin_factor - && this->m_d_factor == rhs.m_d_factor - && this->m_Ke == rhs.m_Ke - && this->m_injmult == rhs.m_injmult - && this->m_Kh == rhs.m_Kh - && this->sat_tableId == rhs.sat_tableId - && this->open_state == rhs.open_state - && this->direction == rhs.direction - && this->segment_number == rhs.segment_number - && this->center_depth == rhs.center_depth - && this->m_sort_value == rhs.m_sort_value - && this->m_subject_to_welpi == rhs.m_subject_to_welpi - && this->m_filter_cake == rhs.m_filter_cake; } - bool Connection::operator!=( const Connection& rhs ) const { - return !( *this == rhs ); + bool Connection::operator==(const Connection& that) const + { + return (this->direction == that.direction) + && (this->open_state == that.open_state) + && (this->sat_tableId == that.sat_tableId) + && (this->m_complnum == that.m_complnum) + && (this->m_ctfkind == that.m_ctfkind) + && (this->m_global_index == that.m_global_index) + && (this->m_sort_value == that.m_sort_value) + && (this->m_defaultSatTabId == that.m_defaultSatTabId) + && (this->segment_number == that.segment_number) + && (this->m_subject_to_welpi == that.m_subject_to_welpi) + && (this->ijk == that.ijk) + && (this->m_injmult == that.m_injmult) + && (this->center_depth == that.center_depth) + && (this->m_perf_range == that.m_perf_range) + && (this->ctf_properties_ == that.ctf_properties_) + && (this->m_filter_cake == that.m_filter_cake) + ; } - -const std::string Connection::State2String( State enumValue ) { - switch( enumValue ) { +std::string Connection::State2String(State enumValue) +{ + switch (enumValue) { case State::OPEN: return "OPEN"; + case State::AUTO: return "AUTO"; + case State::SHUT: return "SHUT"; + default: - throw std::invalid_argument("Unhandled enum value"); + throw std::invalid_argument { + "Unhandled Connection::State value " + + std::to_string(static_cast(enumValue)) + }; } } - -Connection::State Connection::StateFromString( const std::string& stringValue ) { +Connection::State +Connection::StateFromString(std::string_view stringValue) +{ if (stringValue == "OPEN") return State::OPEN; - else if (stringValue == "SHUT") - return State::SHUT; - else if (stringValue == "STOP") - return State::SHUT; - else if (stringValue == "AUTO") - return State::AUTO; - else - throw std::invalid_argument("Unknown enum state string: " + stringValue ); -} + if (stringValue == "SHUT") + return State::SHUT; + + if (stringValue == "STOP") + return State::SHUT; + + if (stringValue == "AUTO") + return State::AUTO; + + throw std::invalid_argument { + "Unknown Connection::State string: " + std::string { stringValue } + }; +} std::string Connection::Direction2String(const Direction enumValue) @@ -434,8 +516,7 @@ std::string Connection::Direction2String(const Direction enumValue) return stringValue; } - -Connection::Direction Connection::DirectionFromString(const std::string& s ) +Connection::Direction Connection::DirectionFromString(std::string_view s) { Direction direction; @@ -443,47 +524,61 @@ Connection::Direction Connection::DirectionFromString(const std::string& s ) else if ((s == "Y") || (s == "y")) { direction = Direction::Y; } else if ((s == "Z") || (s == "z")) { direction = Direction::Z; } else { - std::string msg = "Unsupported completion direction " + s; - throw std::invalid_argument(msg); + throw std::invalid_argument { + "Unsupported completion direction " + + std::string { s } + }; } return direction; } -const std::string Connection::Order2String( Order enumValue ) { - switch( enumValue ) { +std::string Connection::Order2String(Order enumValue) +{ + switch (enumValue) { case Order::DEPTH: return "DEPTH"; + case Order::INPUT: return "INPUT"; + case Order::TRACK: return "TRACK"; + default: - throw std::invalid_argument("Unhandled enum value"); + throw std::invalid_argument { + "Unhandled Connection::Order value " + + std::to_string(static_cast(enumValue)) + }; } } - -Connection::Order Connection::OrderFromString(const std::string& stringValue ) { +Connection::Order Connection::OrderFromString(std::string_view stringValue) +{ if (stringValue == "DEPTH") return Order::DEPTH; - else if (stringValue == "INPUT") + + if (stringValue == "INPUT") return Order::INPUT; - else if (stringValue == "TRACK") + + if (stringValue == "TRACK") return Order::TRACK; - else - throw std::invalid_argument("Unknown enum state string: " + stringValue ); + + throw std::invalid_argument { + "Unknown Connection::Order string: " + std::string { stringValue } + }; } + std::string Connection::CTFKindToString(const CTFKind ctf_kind) { switch (ctf_kind) { - case CTFKind::DeckValue: - return "DeckValue"; + case CTFKind::DeckValue: + return "DeckValue"; - case CTFKind::Defaulted: - return "Defaulted"; + case CTFKind::Defaulted: + return "Defaulted"; } throw std::invalid_argument { @@ -492,58 +587,62 @@ std::string Connection::CTFKindToString(const CTFKind ctf_kind) }; } -Connection::CTFKind Connection::kind() const { +Connection::CTFKind Connection::kind() const +{ return m_ctfkind; } -const InjMult& Connection::injmult() const { +const InjMult& Connection::injmult() const +{ assert(this->activeInjMult()); return m_injmult.value(); } -bool Connection::activeInjMult() const { +bool Connection::activeInjMult() const +{ return this->m_injmult.has_value(); } -void Connection::setInjMult(const InjMult& inj_mult) { +void Connection::setInjMult(const InjMult& inj_mult) +{ m_injmult = inj_mult; } - -void Connection::setFilterCake(const FilterCake& filter_cake) { - this->m_filter_cake = filter_cake; +void Connection::setFilterCake(const FilterCake& filter_cake) +{ + this->m_filter_cake = filter_cake; } -bool Connection::filterCakeActive() const { +bool Connection::filterCakeActive() const +{ return this->m_filter_cake.has_value(); } -const FilterCake& Connection::getFilterCake() const { - assert(this->filterCakeActive()); - return this->m_filter_cake.value(); +const FilterCake& Connection::getFilterCake() const +{ + assert(this->filterCakeActive()); + return this->m_filter_cake.value(); } - -double Connection::getFilterCakeRadius() const { - if (this->getFilterCake().radius.has_value()) { - return this->getFilterCake().radius.value(); - } else { - return this->m_rw; +double Connection::getFilterCakeRadius() const +{ + if (const auto& radius = this->getFilterCake().radius; radius.has_value()) { + return *radius; + } + else { + return this->rw(); } } - -double Connection::getFilterCakeArea() const { - if (this->getFilterCake().flow_area.has_value()) { - return this->getFilterCake().flow_area.value(); - } else { - const double radius = this->getFilterCakeRadius(); - const double length = this->m_connection_length; - constexpr double pi = 3.14159265; - return 2. * pi * radius * length; +double Connection::getFilterCakeArea() const +{ + if (const auto& flow_area = this->getFilterCake().flow_area; flow_area.has_value()) { + return *flow_area; + } + else { + constexpr double two_pi = 2 * 3.14159265358979323846264; + return two_pi * this->getFilterCakeRadius() * this->connectionLength(); } } - - } // end of namespace Opm diff --git a/src/opm/input/eclipse/Schedule/Well/Well.cpp b/src/opm/input/eclipse/Schedule/Well/Well.cpp index 37d77dfaa..84ef0354d 100644 --- a/src/opm/input/eclipse/Schedule/Well/Well.cpp +++ b/src/opm/input/eclipse/Schedule/Well/Well.cpp @@ -40,13 +40,12 @@ #include #include - - #include #include #include +#include #include #include @@ -1300,42 +1299,60 @@ bool Well::handleWELOPENConnections(const DeckRecord& record, Connection::State return this->updateConnections(std::move(new_connections), false); } -bool Well::handleCSKINConnections(const DeckRecord& record) { - // Lambda expression to check if record coordinates match connection coordinates - 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_ge(c.getK(), record, "K_UPPER", -1)) return false; - if (!match_le(c.getK(), record, "K_LOWER", -1)) return false; +bool Well::handleCSKIN(const DeckRecord& record, + const KeywordLocation& location) +{ + using Kw = ParserKeywords::CSKIN; - return true; + auto need_skin_adjustment = [&record](const Connection &c) { + const auto value_shift = -1; + + return match_eq(c.getI(), record, Kw::I::itemName, value_shift) + && match_eq(c.getJ(), record, Kw::J::itemName, value_shift) + && match_ge(c.getK(), record, Kw::K_UPPER::itemName, value_shift) + && match_le(c.getK(), record, Kw::K_LOWER::itemName, value_shift); }; - // Generate a new connection which will be updated with new connection skin factor - auto new_connections = std::make_shared(this->connections->ordering(), this->headI, this->headJ); + // New connection set which will be updated with new connection level + // skin factors. + auto new_connections = std::make_shared + (this->connections->ordering(), this->headI, this->headJ); - // Update skin factor - double skin_factor = record.getItem("CONNECTION_SKIN_FACTOR").get(0); - const double angle = 6.2831853071795864769252867665590057683943387987502116419498; - for (auto c : *this->connections) { - if (match(c)) { - // Check for potential negative new CF - if ((std::log(c.r0() / std::min(c.rw(), c.r0())) + skin_factor) < 0.0) { - throw std::runtime_error("Negative connection transmissibility factor produced by CSKIN for well " - + name()); - } - - // Calculate new connection transmissibility factor - double CF = angle * c.Kh() / (std::log(c.r0() / std::min(c.rw(), c.r0())) + skin_factor); - - // Apply last known WPIMULT (defaulted to 1.0) - CF *= c.wpimult(); - - // Set skin factor and connection factor - c.setSkinFactor(skin_factor); - c.setCF(CF); + const auto skin_factor = record.getItem().getSIDouble(0); + for (const auto& connection : *this->connections) { + if (! need_skin_adjustment(connection)) { + // No CSKIN adjustment needed here. Include connection as-is + // into new connection set. + new_connections->add(connection); + continue; } - new_connections->add(c); + + // If we get here, we must make the connection's skin factor be + // 'skin_factor'. + // + // First guard against this adjustment making the CTF go negative, + // typically because the 'skin_factor' value is large and negative + // itself. + if (const auto& ctf_props = connection.ctfProperties(); + ctf_props.peaceman_denom + skin_factor - ctf_props.skin_factor < 0.0) + { + throw OpmInputError { + fmt::format("Negative connection transmissibility " + "factor generated by skin factor {} " + "in connection ({},{},{}) for well {}.", + skin_factor, + connection.getI() + 1, + connection.getJ() + 1, + connection.getK() + 1, + this->name()), + location + }; + } + + auto connection_copy = connection; + connection_copy.setSkinFactor(skin_factor); + + new_connections->add(connection_copy); } return this->updateConnections(std::move(new_connections), false); @@ -1390,6 +1407,7 @@ bool Well::handleWPIMULT(const DeckRecord& record) { new_connections->add(c); } + return this->updateConnections(std::move(new_connections), false); } diff --git a/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp b/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp index 582ac9cd6..38ffcb58b 100644 --- a/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp +++ b/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp @@ -19,22 +19,32 @@ #include +#include + #include #include #include - -#include +#include #include -#include #include -#include +#include + #include +#include +#include +#include #include #include +#include +#include +#include +#include +#include + #include #include #include @@ -46,28 +56,9 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - #include -#include -#include -#include -#include -#include -#include +#include namespace { @@ -150,50 +141,72 @@ namespace { return 0.28 * (num / den); } + double peacemanDenominator(const double r0, + const double rw, + const double skin_factor) + { + return std::log(r0 / std::min(rw, r0)) + skin_factor; + } + + double peacemanDenominator(const Opm::Connection::CTFProperties& ctf_props) + { + return peacemanDenominator(ctf_props.r0, ctf_props.rw, ctf_props.skin_factor); + } + // Calculate permeability thickness Kh for line segment in a cell for x,y,z directions std::array - permThickness(const external::cvf::Vec3d& connection_vector, + permThickness(const external::cvf::Vec3d& effective_connection, const std::array& cell_perm, const double ntg) { - std::array perm_thickness; - Opm::Connection::Direction direction[3] = {Opm::Connection::DirectionFromString("X"), - Opm::Connection::DirectionFromString("Y"), - Opm::Connection::DirectionFromString("Z")}; - external::cvf::Vec3d effective_connection = connection_vector; - effective_connection[2] *= ntg; - for (size_t i = 0; i < 3; ++i) - { - const auto& K = permComponents(direction[i], cell_perm); - perm_thickness[i] = std::sqrt(K[0] * K[1]) * effective_connection[i]; + auto perm_thickness = std::array { + effective_connection[0], + effective_connection[1], + effective_connection[2] * ntg, + }; + + const auto direction = std::array { + Opm::Connection::Direction::X, + Opm::Connection::Direction::Y, + Opm::Connection::Direction::Z, + }; + + for (size_t i = 0; i < 3; ++i) { + const auto K = permComponents(direction[i], cell_perm); + perm_thickness[i] *= std::sqrt(K[0] * K[1]); } + return perm_thickness; } // Calculate directional (x,y,z) peaceman connection factors CFx, CFy, CFz std::array - connectionFactor(const external::cvf::Vec3d& connection_vector, - const std::array& cell_perm, - std::array cell_size, + connectionFactor(const std::array& cell_perm, + const std::array& cell_size, const double ntg, - const std::array Kh, + const std::array& Kh, const double rw, const double skin_factor) { - std::array connection_factor; - Opm::Connection::Direction direction[3] = {Opm::Connection::DirectionFromString("X"), - Opm::Connection::DirectionFromString("Y"), - Opm::Connection::DirectionFromString("Z")}; - external::cvf::Vec3d effective_connection = connection_vector; - effective_connection[2] *= ntg; - for (size_t i = 0; i < 3; ++i) - { - const double angle = 6.2831853071795864769252867665590057683943387987502116419498; - const auto& K = permComponents(direction[i], cell_perm); - const auto& D = effectiveExtent(direction[i], ntg, cell_size); - const auto& r0 = effectiveRadius(K,D); - connection_factor[i] = angle * Kh[i] / (std::log(r0 / std::min(rw, r0)) + skin_factor); + auto connection_factor = std::array{}; + + const auto direction = std::array { + Opm::Connection::Direction::X, + Opm::Connection::Direction::Y, + Opm::Connection::Direction::Z, + }; + + const double angle = 6.2831853071795864769252867665590057683943387987502116419498; + + for (size_t i = 0; i < 3; ++i) { + const auto K = permComponents(direction[i], cell_perm); + const auto D = effectiveExtent(direction[i], ntg, cell_size); + const auto r0 = effectiveRadius(K, D); + + connection_factor[i] = angle * Kh[i] + / peacemanDenominator(r0, rw, skin_factor); } + return connection_factor; } @@ -285,61 +298,40 @@ namespace Opm { } void WellConnections::addConnection(const int i, const int j, const int k, - const std::size_t global_index, - const int complnum, - const double depth, - const Connection::State state, - const double CF, - const double Kh, - const double rw, - const double r0, - const double re, - const double connection_length, - const double skin_factor, - const double d_factor, - const double Ke, - const int satTableId, - const Connection::Direction direction, - const Connection::CTFKind ctf_kind, - const std::size_t seqIndex, - const bool defaultSatTabId) + const std::size_t global_index, + const int complnum, + const Connection::State state, + const double depth, + const Connection::CTFProperties& ctf_props, + const int satTableId, + const Connection::Direction direction, + const Connection::CTFKind ctf_kind, + const std::size_t seqIndex, + const bool defaultSatTabId) { const int conn_i = (i < 0) ? this->headI : i; const int conn_j = (j < 0) ? this->headJ : j; - Connection conn(conn_i, conn_j, k, - global_index, complnum, - depth, state, CF, Kh, rw, r0, re, connection_length, - skin_factor, d_factor, Ke, satTableId, direction, ctf_kind, - seqIndex, defaultSatTabId); - - this->add(conn); + this->m_connections.emplace_back(conn_i, conn_j, k, global_index, complnum, + state, direction, ctf_kind, satTableId, + depth, ctf_props, seqIndex, defaultSatTabId); } void WellConnections::addConnection(const int i, const int j, const int k, - const std::size_t global_index, - const double depth, - const Connection::State state, - const double CF, - const double Kh, - const double rw, - const double r0, - const double re, - const double connection_length, - const double skin_factor, - const double d_factor, - const double Ke, - const int satTableId, - const Connection::Direction direction, - const Connection::CTFKind ctf_kind, - const std::size_t seqIndex, - const bool defaultSatTabId) + const std::size_t global_index, + const Connection::State state, + const double depth, + const Connection::CTFProperties& ctf_props, + const int satTableId, + const Connection::Direction direction, + const Connection::CTFKind ctf_kind, + const std::size_t seqIndex, + const bool defaultSatTabId) { - const int complnum = (this->m_connections.size() + 1); + const auto complnum = static_cast(this->m_connections.size()) + 1; - this->addConnection(i, j, k, global_index, complnum, - depth, state, CF, Kh, rw, r0, re, - connection_length, skin_factor, d_factor, Ke, + this->addConnection(i, j, k, global_index, complnum, state, + depth, ctf_props, satTableId, direction, ctf_kind, seqIndex, defaultSatTabId); } @@ -349,435 +341,431 @@ namespace Opm { const std::string& wname, const KeywordLocation& location) { + const auto& itemI = record.getItem("I"); + const auto defaulted_I = itemI.defaultApplied(0) || (itemI.get(0) == 0); + const auto I = !defaulted_I ? itemI.get(0) - 1 : this->headI; - const auto& itemI = record.getItem( "I" ); - const auto defaulted_I = itemI.defaultApplied( 0 ) || itemI.get< int >( 0 ) == 0; - const int I = !defaulted_I ? itemI.get< int >( 0 ) - 1 : this->headI; + const auto& itemJ = record.getItem("J"); + const auto defaulted_J = itemJ.defaultApplied(0) || (itemJ.get(0) == 0); + const auto J = !defaulted_J ? itemJ.get(0) - 1 : this->headJ; - const auto& itemJ = record.getItem( "J" ); - const auto defaulted_J = itemJ.defaultApplied( 0 ) || itemJ.get< int >( 0 ) == 0; - const int J = !defaulted_J ? itemJ.get< int >( 0 ) - 1 : this->headJ; + const auto K1 = record.getItem("K1").get(0) - 1; + const auto K2 = record.getItem("K2").get(0) - 1; + const auto state = Connection::StateFromString(record.getItem("STATE").getTrimmedString(0)); - int K1 = record.getItem("K1").get< int >(0) - 1; - int K2 = record.getItem("K2").get< int >(0) - 1; - Connection::State state = Connection::StateFromString( record.getItem("STATE").getTrimmedString(0) ); - - int satTableId = -1; - bool defaultSatTable = true; const auto& r0Item = record.getItem("PR"); const auto& CFItem = record.getItem("CONNECTION_TRANSMISSIBILITY_FACTOR"); const auto& diameterItem = record.getItem("DIAMETER"); const auto& KhItem = record.getItem("Kh"); const auto& satTableIdItem = record.getItem("SAT_TABLE"); const auto direction = Connection::DirectionFromString(record.getItem("DIR").getTrimmedString(0)); - double skin_factor = record.getItem("SKIN").getSIDouble(0); - - double d_factor = record.getItem("D_FACTOR").getSIDouble(0); - double rw; + const auto skin_factor = record.getItem("SKIN").getSIDouble(0); + const auto d_factor = record.getItem("D_FACTOR").getSIDouble(0); - if (satTableIdItem.hasValue(0) && satTableIdItem.get < int > (0) > 0) - { - satTableId = satTableIdItem.get< int >(0); + int satTableId = -1; + bool defaultSatTable = true; + if (satTableIdItem.hasValue(0) && (satTableIdItem.get(0) > 0)) { + satTableId = satTableIdItem.get(0); defaultSatTable = false; } - if (diameterItem.hasValue(0)) - rw = 0.50 * diameterItem.getSIDouble(0); - else + double rw{}; + if (diameterItem.hasValue(0)) { + rw = diameterItem.getSIDouble(0) / 2; + } + else { // The Eclipse100 manual does not specify a default value for the wellbore // diameter, but the Opm codebase has traditionally implemented a default // value of one foot. The same default value is used by Eclipse300. rw = 0.5*unit::feet; + } - for (int k = K1; k <= K2; k++) { - const CompletedCells::Cell& cell = grid.get_cell(I, J, k); + // Angle of completion exposed to flow. We assume centre + // placement so there's complete exposure (= 2\pi). + const auto angle = 6.2831853071795864769252867665590057683943387987502116419498; + + for (int k = K1; k <= K2; ++k) { + const auto& cell = grid.get_cell(I, J, k); if (!cell.is_active()) { - auto msg = fmt::format("Problem with COMPDAT keyword\n" - "In {} line {}\n" - "The cell ({},{},{}) in well {} is not active and the connection will be ignored", location.filename, location.lineno, I,J,k, wname); + auto msg = fmt::format(R"(Problem with COMPDAT keyword +In {} line {} +The cell ({},{},{}) in well {} is not active and the connection will be ignored)", + location.filename, location.lineno, + I + 1, J + 1, k + 1, wname); + OpmLog::warning(msg); continue; } + const auto& props = cell.props; - double CF = -1; - double Kh = -1; - double r0 = -1; - auto ctf_kind = ::Opm::Connection::CTFKind::DeckValue; - if (defaultSatTable) + auto ctf_props = ::Opm::Connection::CTFProperties{}; + ctf_props.rw = rw; + ctf_props.skin_factor = skin_factor; + ctf_props.d_factor = d_factor; + + if (defaultSatTable) { satTableId = props->satnum; + } - auto same_ijk = [&]( const Connection& c ) { - return c.sameCoordinate( I,J,k ); - }; + ctf_props.r0 = -1.0; + if (r0Item.hasValue(0)) { + ctf_props.r0 = r0Item.getSIDouble(0); + } - if (r0Item.hasValue(0)) - r0 = r0Item.getSIDouble(0); + ctf_props.Kh = -1.0; + if (KhItem.hasValue(0) && (KhItem.getSIDouble(0) > 0.0)) { + ctf_props.Kh = KhItem.getSIDouble(0); + } - if (KhItem.hasValue(0) && KhItem.getSIDouble(0) > 0.0) - Kh = KhItem.getSIDouble(0); + ctf_props.CF = -1.0; + if (CFItem.hasValue(0) && (CFItem.getSIDouble(0) > 0.0)) { + ctf_props.CF = CFItem.getSIDouble(0); + } - if (CFItem.hasValue(0) && CFItem.getSIDouble(0) > 0.0) - CF = CFItem.getSIDouble(0); + const auto D = effectiveExtent(direction, props->ntg, cell.dimensions); + const auto K = permComponents(direction, { props->permx, props->permy, props->permz }); + ctf_props.Ke = std::sqrt(K[0] * K[1]); - // Angle of completion exposed to flow. We assume centre - // placement so there's complete exposure (= 2\pi). - const double angle = 6.2831853071795864769252867665590057683943387987502116419498; - std::array cell_size = cell.dimensions; - const auto& D = effectiveExtent(direction, props->ntg, cell_size); + const auto ctf_kind = (ctf_props.CF < 0.0) + ? ::Opm::Connection::CTFKind::Defaulted + : ::Opm::Connection::CTFKind::DeckValue; - std::array cell_perm = {{ props->permx, - props->permy, - props->permz}}; - const auto& K = permComponents(direction, cell_perm); - double Ke = std::sqrt(K[0] * K[1]); - - /* We start with the absolute happy path; both CF and Kh are explicitly given in the deck. */ - if (CF > 0 && Kh > 0) + // We start with the absolute happy path; both CF and Kh are + // explicitly given in the deck. + if ((ctf_props.CF > 0.0) && (ctf_props.Kh > 0.0)) { + ctf_props.peaceman_denom = angle * ctf_props.Kh / ctf_props.CF; goto CF_done; + } - /* We must calculate CF and Kh from the items in the COMPDAT record and cell properties. */ + // We must calculate CF and Kh from the items in the COMPDAT + // record and cell properties. + if (ctf_props.r0 < 0.0) { + ctf_props.r0 = effectiveRadius(K, D); + } + + if (const auto peaceman_denom = peacemanDenominator(ctf_props); + ctf_props.Kh > 0.0) { - if (r0 < 0) - r0 = effectiveRadius(K,D); - if (CF < 0) { - if (Kh < 0) - Kh = Ke * D[2]; - CF = angle * Kh / (std::log(r0 / std::min(rw, r0)) + skin_factor); - ctf_kind = ::Opm::Connection::CTFKind::Defaulted; - } else { - if (KhItem.defaultApplied(0) || KhItem.getSIDouble(0) < 0) { - Kh = CF * (std::log(r0 / std::min(r0, rw)) + skin_factor) / angle; - } else { - if (Kh < 0) { - Kh = Ke * D[2]; - - // Compute r0 to be consistent with other parameters - r0 = RestartIO::RstConnection::inverse_peaceman(CF, Kh, rw, skin_factor); - } - } + // CF < 0 + ctf_props.CF = angle * ctf_props.Kh / peaceman_denom; + ctf_props.peaceman_denom = peaceman_denom; + } + else if (ctf_props.CF > 0.0) { // Kh < 0 + if (KhItem.defaultApplied(0) || (KhItem.get(0) < 0.0)) { + // Kh explicitly defaulted. Derive compatible Kh value + // from specified CTF, r0, rw, and skin factor. + ctf_props.Kh = ctf_props.CF * peaceman_denom / angle; } + else { + // Kh = 0 entered in item 10 of COMPDAT. Compute Kh + // from permeability and length of perforation interval + // and request a compatible pressure equivalent radius + // (r0) be calculated. + ctf_props.Kh = ctf_props.Ke * D[2]; + + // Defer r0 calculation to CF_done: r0 < 0 case. + ctf_props.r0 = -1.0; + } + + ctf_props.peaceman_denom = angle * ctf_props.Kh / ctf_props.CF; + } + else { // (CF < 0) && (Kh < 0) + ctf_props.Kh = ctf_props.Ke * D[2]; + ctf_props.CF = angle * ctf_props.Kh / peaceman_denom; + ctf_props.peaceman_denom = peaceman_denom; } CF_done: - if (r0 < 0) - r0 = RestartIO::RstConnection::inverse_peaceman(CF, Kh, rw, skin_factor); + if (ctf_props.r0 < 0.0) { + ctf_props.r0 = RestartIO::RstConnection:: + inverse_peaceman(ctf_props.CF, ctf_props.Kh, + ctf_props.rw, + ctf_props.skin_factor); + } - // used by the PolymerMW module - double re = std::sqrt(D[0] * D[1] / angle * 2); // area equivalent radius of the grid block - double connection_length = D[2]; // the length of the well perforation + // Length of the well perforation interval. + ctf_props.connection_length = ctf_props.Kh / ctf_props.Ke; + + // Area equivalent radius of the grid block. Used by the + // PolymerMW module. + ctf_props.re = std::sqrt(D[0] * D[1] / angle * 2); + + auto prev = std::find_if(this->m_connections.begin(), + this->m_connections.end(), + [I, J, k](const Connection& c) + { + return c.sameCoordinate(I, J, k); + }); - auto prev = std::find_if( this->m_connections.begin(), - this->m_connections.end(), - same_ijk ); if (prev == this->m_connections.end()) { - std::size_t noConn = this->m_connections.size(); - this->addConnection(I,J,k, - cell.global_index, - cell.depth, - state, - CF, - Kh, - rw, - r0, - re, - connection_length, - skin_factor, - d_factor, - Ke, - satTableId, - direction, - ctf_kind, - noConn, - defaultSatTable); - } else { - std::size_t css_ind = prev->sort_value(); - int conSegNo = prev->segment(); - const auto& perf_range = prev->perf_range(); - double depth = cell.depth; - *prev = Connection(I,J,k, - cell.global_index, - prev->complnum(), - depth, - state, - CF, - Kh, - rw, - r0, - re, - connection_length, - skin_factor, - d_factor, - Ke, - satTableId, - direction, - ctf_kind, - prev->sort_value(), - defaultSatTable); + const std::size_t noConn = this->m_connections.size(); + this->addConnection(I, J, k, cell.global_index, state, + cell.depth, ctf_props, satTableId, + direction, ctf_kind, + noConn, defaultSatTable); + } + else { + const auto compl_num = prev->complnum(); + const auto css_ind = prev->sort_value(); + const auto conSegNo = prev->segment(); + const auto perf_range = prev->perf_range(); - prev->updateSegment(conSegNo, - depth, - css_ind, - perf_range); + *prev = Connection { + I, J, k, cell.global_index, compl_num, + state, direction, ctf_kind, satTableId, + cell.depth, ctf_props, + css_ind, defaultSatTable + }; + + prev->updateSegment(conSegNo, cell.depth, css_ind, perf_range); } } } - - void WellConnections::loadCOMPTRAJ(const DeckRecord& record, - const ScheduleGrid& grid, - const std::string& wname, - const KeywordLocation& location, - external::cvf::ref& cellSearchTree) { - // const std::string& completionNamePattern = record.getItem("BRANCH_NUMBER").getTrimmedString(0); + void WellConnections::loadCOMPTRAJ(const DeckRecord& record, + const ScheduleGrid& grid, + const std::string& wname, + const KeywordLocation& location, + external::cvf::ref& cellSearchTree) + { const auto& perf_top = record.getItem("PERF_TOP"); const auto& perf_bot = record.getItem("PERF_BOT"); const auto& CFItem = record.getItem("CONNECTION_TRANSMISSIBILITY_FACTOR"); const auto& diameterItem = record.getItem("DIAMETER"); const auto& KhItem = record.getItem("Kh"); - double skin_factor = record.getItem("SKIN").getSIDouble(0); - double d_factor = record.getItem("D_FACTOR").getSIDouble(0); + const auto skin_factor = record.getItem("SKIN").getSIDouble(0); + const auto d_factor = record.getItem("D_FACTOR").getSIDouble(0); const auto& satTableIdItem = record.getItem("SAT_TABLE"); - Connection::State state = Connection::StateFromString(record.getItem("STATE").getTrimmedString(0)); + const auto state = Connection::StateFromString(record.getItem("STATE").getTrimmedString(0)); int satTableId = -1; bool defaultSatTable = true; - if (satTableIdItem.hasValue(0) && satTableIdItem.get < int > (0) > 0) - { - satTableId = satTableIdItem.get< int >(0); + if (satTableIdItem.hasValue(0) && (satTableIdItem.get(0) > 0)) { + satTableId = satTableIdItem.get(0); defaultSatTable = false; } - double rw; - if (diameterItem.hasValue(0)) - rw = 0.50 * diameterItem.getSIDouble(0); - else + double rw{}; + if (diameterItem.hasValue(0)) { + rw = diameterItem.getSIDouble(0) / 2; + } + else { // The Eclipse100 manual does not specify a default value for the wellbore // diameter, but the Opm codebase has traditionally implemented a default // value of one foot. The same default value is used by Eclipse300. rw = 0.5*unit::feet; + } - // Get the grid - auto ecl_grid = grid.get_grid(); + // Get the grid + const auto& ecl_grid = grid.get_grid(); // Calulate the x,y,z coordinates of the begin and end of a perforation external::cvf::Vec3d p_top; external::cvf::Vec3d p_bot; for (size_t i = 0; i < 3 ; ++i) { - p_top[i] = Opm::linearInterpolation(this->md, this->coord[i], perf_top.getSIDouble(0)); - p_bot[i] = Opm::linearInterpolation(this->md, this->coord[i], perf_bot.getSIDouble(0)); + p_top[i] = linearInterpolation(this->md, this->coord[i], perf_top.getSIDouble(0)); + p_bot[i] = linearInterpolation(this->md, this->coord[i], perf_bot.getSIDouble(0)); } std::vector points{p_top, p_bot}; std::vector md_interval{perf_top.getSIDouble(0), perf_bot.getSIDouble(0)}; - - external::cvf::ref wellPathGeometry = new external::RigWellPath; + + external::cvf::ref wellPathGeometry { new external::RigWellPath }; wellPathGeometry->setWellPathPoints(points); wellPathGeometry->setMeasuredDepths(md_interval); - external::cvf::ref e = new external::RigEclipseWellLogExtractor(wellPathGeometry.p(), *ecl_grid, cellSearchTree); - - // Keep the AABB search tree of the grid to avoid redoing an expensive calulation + + external::cvf::ref e { + new external::RigEclipseWellLogExtractor { + wellPathGeometry.p(), *ecl_grid, cellSearchTree + } + }; + + // Keep the AABB search tree of the grid to avoid redoing an + // expensive calulation. cellSearchTree = e->getCellSearchTree(); - // This gives the intersected grid cells IJK, cell face entrance & exit cell face point and connection length + // This gives the intersected grid cells IJK, cell face entrance & + // exit cell face point and connection length. auto intersections = e->cellIntersectionInfosAlongWellPath(); - int I{0}; - int J{0}; - int k{0}; - for (size_t is = 0; is < intersections.size(); ++is){ - auto ijk = std::array{}; - ijk = ecl_grid->getIJK(intersections[is].globCellIndex); - I = ijk[0]; - J = ijk[1]; - k = ijk[2]; + for (size_t is = 0; is < intersections.size(); ++is) { + const auto ijk = ecl_grid->getIJK(intersections[is].globCellIndex); - // When using WELTRAJ & COMPTRAJ one may use default settings in WELSPECS for headI/J and let the - // headI/J be calculated by the trajectory data. - // If these defaults are used the headI/J are set to the first intersection. + // When using WELTRAJ & COMPTRAJ one may use default settings in + // WELSPECS for headI/J and let the headI/J be calculated by the + // trajectory data. + // + // If these defaults are used the headI/J are set to the first + // intersection. if (is == 0) { - if (this->headI == -1) - this->headI = I; - if (this->headJ == -1) - this->headJ = J; + if (this->headI < 0) { this->headI = ijk[0]; } + if (this->headJ < 0) { this->headJ = ijk[1]; } } - external::cvf::Vec3d connection_vector = intersections[is].intersectionLengthsInCellCS; + const auto& cell = grid.get_cell(ijk[0], ijk[1], ijk[2]); - const CompletedCells::Cell& cell = grid.get_cell(I, J, k); - - if (!cell.is_active()) { - auto msg = fmt::format("Problem with COMPTRAJ keyword\n" - "In {} line {}\n" - "The cell ({},{},{}) in well {} is not active and the connection will be ignored", location.filename, location.lineno, I,J,k, wname); + if (!cell.is_active()) { + const auto msg = fmt::format(R"(Problem with COMPTRAJ keyword +In {} line {} +The cell ({},{},{}) in well {} is not active and the connection will be ignored)", + location.filename, + location.lineno, + ijk[0] + 1, + ijk[1] + 1, + ijk[2] + 1, wname); OpmLog::warning(msg); + continue; } + const auto& props = cell.props; - double CF = -1; - double Kh = -1; - double r0 = -1; - auto ctf_kind = ::Opm::Connection::CTFKind::DeckValue; - if (defaultSatTable) - satTableId = props->satnum; + auto ctf_props = Connection::CTFProperties{}; + ctf_props.rw = rw; + ctf_props.skin_factor = skin_factor; + ctf_props.d_factor = d_factor; - auto same_ijk = [I, J, k]( const Connection& c ) { - return c.sameCoordinate( I,J,k ); + ctf_props.r0 = -1.0; + ctf_props.Kh = -1.0; + if (KhItem.hasValue(0) && (KhItem.getSIDouble(0) > 0.0)) { + ctf_props.Kh = KhItem.getSIDouble(0); + } + + ctf_props.CF = -1.0; + if (CFItem.hasValue(0) && (CFItem.getSIDouble(0) > 0.0)) { + ctf_props.CF = CFItem.getSIDouble(0); + } + + const auto cell_perm = std::array { + props->permx, props->permy, props->permz }; - if (KhItem.hasValue(0) && KhItem.getSIDouble(0) > 0.0) - Kh = KhItem.getSIDouble(0); - - if (CFItem.hasValue(0) && CFItem.getSIDouble(0) > 0.0) - CF = CFItem.getSIDouble(0); - - std::array cell_size = cell.dimensions; - - std::array cell_perm = {{ props->permx, - props->permy, - props->permz}}; - - if (CF < 0 && Kh < 0) { - /* We must calculate CF and Kh from the items in the COMPTRAJ record and cell properties. */ + auto ctf_kind = ::Opm::Connection::CTFKind::DeckValue; + if ((ctf_props.CF < 0.0) && (ctf_props.Kh < 0.0)) { + // We must calculate CF and Kh from the items in the + // COMPTRAJ record and cell properties. ctf_kind = ::Opm::Connection::CTFKind::Defaulted; + const auto& connection_vector = + intersections[is].intersectionLengthsInCellCS; - const auto& perm_thickness = permThickness(connection_vector, - cell_perm, - props->ntg); + const auto perm_thickness = + permThickness(connection_vector, cell_perm, props->ntg); - const auto& connection_factor = connectionFactor(connection_vector, - cell_perm, - cell_size, - props->ntg, - perm_thickness, - rw, - skin_factor); + const auto connection_factor = + connectionFactor(cell_perm, cell.dimensions, props->ntg, + perm_thickness, rw, skin_factor); - CF = std::sqrt(std::pow(connection_factor[0],2)+ std::pow(connection_factor[1],2)+std::pow(connection_factor[2],2)); - // std::cout<<"CF: " << CF << "; CFx: " << connection_factor[0] << " CFy: " << connection_factor[1] << " CFz: " << connection_factor[2] << "\n" < 0.0) && (ctf_props.Kh > 0.0))) { + auto msg = fmt::format(R"(Problem with COMPTRAJ keyword +In {} line {} +CF and Kh items for well {} must both be specified or both defaulted/negative)", + location.filename, location.lineno, wname); + + throw std::logic_error(msg); + } + + // Todo: check what needs to be done for polymerMW module, see + // loadCOMPDAT used by the PolymerMW module + + const auto direction = ::Opm::Connection::Direction::Z; + + ctf_props.re = -1; + + { + const auto K = permComponents(direction, cell_perm); + ctf_props.Ke = std::sqrt(K[0] * K[1]); + } + + auto prev = std::find_if(this->m_connections.begin(), + this->m_connections.end(), + [&ijk](const Connection& c) + { return c.sameCoordinate(ijk[0], ijk[1], ijk[2]); }); + + if (prev == this->m_connections.end()) { + const std::size_t noConn = this->m_connections.size(); + this->addConnection(ijk[0], ijk[1], ijk[2], + cell.global_index, state, + cell.depth, ctf_props, satTableId, + direction, ctf_kind, + noConn, defaultSatTable); } else { - if (! (CF > 0 && Kh > 0) ){ - auto msg = fmt::format("Problem with COMPTRAJ keyword\n" - "In {} line {}\n" - "CF and Kh items for well {} must both be specified or both defaulted/negative", - location.filename, location.lineno, wname); - throw std::logic_error(msg); - } - } + const auto compl_num = prev->complnum(); + const auto css_ind = prev->sort_value(); + const auto conSegNo = prev->segment(); + const auto perf_range = prev->perf_range(); - // Todo: check what needs to be done for polymerMW module, see loadCOMPDAT - // used by the PolymerMW module - // double re = std::sqrt(D[0] * D[1] / angle * 2); // area equivalent radius of the grid block - // double connection_length = D[2]; // the length of the well perforation - - const auto direction = Connection::DirectionFromString("Z"); - double re = -1; - double connection_length = connection_vector.length(); - const auto& K = permComponents(direction, cell_perm); - double Ke = std::sqrt(K[0] * K[1]); + *prev = Connection { + ijk[0], ijk[1], ijk[2], + cell.global_index, compl_num, + state, direction, ctf_kind, satTableId, + cell.depth, ctf_props, + css_ind, defaultSatTable + }; - auto prev = std::find_if( this->m_connections.begin(), - this->m_connections.end(), - same_ijk ); - if (prev == this->m_connections.end()) { - std::size_t noConn = this->m_connections.size(); - this->addConnection(I,J,k, - cell.global_index, - cell.depth, - state, - CF, - Kh, - rw, - r0, - re, - connection_length, - skin_factor, - d_factor, - Ke, - satTableId, - direction, - ctf_kind, - noConn, - defaultSatTable); - } else { - std::size_t css_ind = prev->sort_value(); - int conSegNo = prev->segment(); - const auto& perf_range = prev->perf_range(); - double depth = cell.depth; - *prev = Connection(I,J,k, - cell.global_index, - prev->complnum(), - depth, - state, - CF, - Kh, - rw, - r0, - re, - connection_length, - skin_factor, - d_factor, - Ke, - satTableId, - direction, - ctf_kind, - prev->sort_value(), - defaultSatTable); - - prev->updateSegment(conSegNo, - depth, - css_ind, - *perf_range); + prev->updateSegment(conSegNo, cell.depth, css_ind, *perf_range); } } } void WellConnections::loadWELTRAJ(const DeckRecord& record, - const ScheduleGrid& grid, - const std::string& wname, - const KeywordLocation& location) { - (void) grid; //surpress unused argument compile warning - (void) wname; - (void) location; + [[maybe_unused]] const ScheduleGrid& grid, + [[maybe_unused]] const std::string& wname, + [[maybe_unused]] const KeywordLocation& location) + { this->coord[0].push_back(record.getItem("X").getSIDouble(0)); - this->coord[1].push_back(record.getItem("Y").getSIDouble(0)), + this->coord[1].push_back(record.getItem("Y").getSIDouble(0)); this->coord[2].push_back(record.getItem("TVD").getSIDouble(0)); + this->md.push_back(record.getItem("MD").getSIDouble(0)); } - std::size_t WellConnections::size() const { + std::size_t WellConnections::size() const + { return m_connections.size(); } - std::size_t WellConnections::num_open() const { + std::size_t WellConnections::num_open() const + { return std::count_if(this->m_connections.begin(), this->m_connections.end(), [] (const Connection& c) { return c.state() == Connection::State::OPEN; }); } - bool WellConnections::empty() const { + bool WellConnections::empty() const + { return this->size() == size_t{0}; } - const Connection& WellConnections::get(size_t index) const { + const Connection& WellConnections::get(size_t index) const + { return (*this)[index]; } - const Connection& WellConnections::operator[](size_t index) const { + const Connection& WellConnections::operator[](size_t index) const + { return this->m_connections.at(index); } - const Connection& WellConnections::lowest() const { - if (this->m_connections.empty()) + const Connection& WellConnections::lowest() const + { + if (this->m_connections.empty()) { throw std::logic_error("Tried to get lowest connection from empty set"); + } const auto max_iter = std::max_element(this->m_connections.begin(), this->m_connections.end(), @@ -789,79 +777,92 @@ namespace Opm { return *max_iter; } - bool WellConnections::hasGlobalIndex(std::size_t global_index) const { - auto conn_iter = std::find_if(this->begin(), this->end(), - [global_index] (const Connection& conn) {return conn.global_index() == global_index;}); - return (conn_iter != this->end()); + bool WellConnections::hasGlobalIndex(std::size_t global_index) const + { + return std::any_of(this->begin(), this->end(), + [global_index](const Connection& conn) + { + return conn.global_index() == global_index; + }); } - const Connection& WellConnections::getFromIJK(const int i, const int j, const int k) const { + const Connection& + WellConnections::getFromIJK(const int i, const int j, const int k) const + { for (size_t ic = 0; ic < size(); ++ic) { if (get(ic).sameCoordinate(i, j, k)) { return get(ic); } } + throw std::runtime_error(" the connection is not found! \n "); } - const Connection& WellConnections::getFromGlobalIndex(std::size_t global_index) const { - auto conn_iter = std::find_if(this->begin(), this->end(), - [global_index] (const Connection& conn) {return conn.global_index() == global_index;}); + const Connection& WellConnections::getFromGlobalIndex(std::size_t global_index) const + { + auto conn_iter = + std::find_if(this->begin(), this->end(), + [global_index] (const Connection& conn) + { return conn.global_index() == global_index; }); - if (conn_iter == this->end()) + if (conn_iter == this->end()) { throw std::logic_error(fmt::format("No connection with global index {}", global_index)); + } + return *conn_iter; } - Connection& WellConnections::getFromIJK(const int i, const int j, const int k) { - for (size_t ic = 0; ic < size(); ++ic) { - if (get(ic).sameCoordinate(i, j, k)) { - return this->m_connections[ic]; - } - } - throw std::runtime_error(" the connection is not found! \n "); - } - - void WellConnections::add(Connection connection) + Connection& WellConnections::getFromIJK(const int i, const int j, const int k) { - this->m_connections.push_back(std::move(connection)); + for (size_t ic = 0; ic < size(); ++ic) { + if (get(ic).sameCoordinate(i, j, k)) { + return this->m_connections[ic]; + } + } + + throw std::runtime_error(" the connection is not found! \n "); } - bool WellConnections::allConnectionsShut( ) const { - if (this->empty()) + bool WellConnections::allConnectionsShut() const + { + if (this->empty()) { return false; + } - - auto shut = []( const Connection& c ) { - return c.state() == Connection::State::SHUT; - }; - - return std::all_of( this->m_connections.begin(), - this->m_connections.end(), - shut ); + return std::all_of(this->m_connections.begin(), + this->m_connections.end(), + [](const Connection& c) + { return c.state() == Connection::State::SHUT; }); } void WellConnections::order() { - if (m_connections.empty()) + if (m_connections.empty()) { return; + } - if (this->m_connections[0].attachedToSegment()) + if (this->m_connections[0].attachedToSegment()) { this->orderMSW(); - else if (this->m_ordering == Connection::Order::TRACK) + } + else if (this->m_ordering == Connection::Order::TRACK) { this->orderTRACK(); - else if (this->m_ordering == Connection::Order::DEPTH) + } + else if (this->m_ordering == Connection::Order::DEPTH) { this->orderDEPTH(); + } } - void WellConnections::orderMSW() { - std::sort(this->m_connections.begin(), this->m_connections.end(), [](const Opm::Connection& conn1, const Opm::Connection& conn2) + void WellConnections::orderMSW() + { + std::sort(this->m_connections.begin(), this->m_connections.end(), + [](const Opm::Connection& conn1, const Opm::Connection& conn2) { return conn1.sort_value() < conn2.sort_value(); }); } - void WellConnections::orderTRACK() { + void WellConnections::orderTRACK() + { // Find the first connection and swap it into the 0-position. const double surface_z = 0.0; size_t first_index = findClosestConnection(this->headI, this->headJ, surface_z, 0); @@ -870,10 +871,12 @@ namespace Opm { // Repeat for remaining connections. // // Note that since findClosestConnection() is O(n), this is an - // O(n^2) algorithm. However, it should be acceptable since - // the expected number of connections is fairly low (< 100). + // O(n^2) algorithm. However, it should be acceptable since the + // expected number of connections is fairly low (< 100). - if( this->m_connections.empty() ) return; + if (this->m_connections.empty()) { + return; + } for (size_t pos = 1; pos < m_connections.size() - 1; ++pos) { const auto& prev = m_connections[pos - 1]; @@ -912,27 +915,31 @@ namespace Opm { return closest; } - void WellConnections::orderDEPTH() { - std::sort(this->m_connections.begin(), this->m_connections.end(), [](const Opm::Connection& conn1, const Opm::Connection& conn2) + void WellConnections::orderDEPTH() + { + std::sort(this->m_connections.begin(), this->m_connections.end(), + [](const Opm::Connection& conn1, const Opm::Connection& conn2) { return conn1.depth() < conn2.depth(); }); - } - bool WellConnections::operator==( const WellConnections& rhs ) const { - return this->size() == rhs.size() && - this->m_ordering == rhs.m_ordering && - this->coord == rhs.coord && - this->md == rhs.md && - std::equal( this->begin(), this->end(), rhs.begin() ); + bool WellConnections::operator==(const WellConnections& rhs) const + { + return (this->size() == rhs.size()) + && (this->m_ordering == rhs.m_ordering) + && (this->coord == rhs.coord) + && (this->md == rhs.md) + && std::equal( this->begin(), this->end(), rhs.begin()); } - bool WellConnections::operator!=( const WellConnections& rhs ) const { - return !( *this == rhs ); + bool WellConnections::operator!=(const WellConnections& rhs) const + { + return ! (*this == rhs); } - void WellConnections::filter(const ActiveGridCells& grid) { + void WellConnections::filter(const ActiveGridCells& grid) + { auto isInactive = [&grid](const Connection& c) { return !grid.cellActive(c.getI(), c.getJ(), c.getK()); }; @@ -941,7 +948,8 @@ namespace Opm { m_connections.erase(new_end, m_connections.end()); } - double WellConnections::segment_perf_length(int segment) const { + double WellConnections::segment_perf_length(int segment) const + { double perf_length = 0; for (const auto& conn : this->m_connections) { if (conn.segment() == segment) { @@ -949,18 +957,22 @@ namespace Opm { perf_length += end - start; } } + return perf_length; } - int WellConnections::getHeadI() const { + int WellConnections::getHeadI() const + { return this->headI; } - int WellConnections::getHeadJ() const { + int WellConnections::getHeadJ() const + { return this->headJ; } - const std::vector& WellConnections::getMD() const { + const std::vector& WellConnections::getMD() const + { return this->md; } @@ -974,9 +986,10 @@ namespace Opm { return conn.global_index() == global_index; }); - if (connPos == connections.end()) + if (connPos == connections.end()) { // No connection exists with the requisite 'global_index' return {}; + } return { connPos->complnum() }; } diff --git a/tests/parser/ConnectionTests.cpp b/tests/parser/ConnectionTests.cpp index 0f261a337..0fe009226 100644 --- a/tests/parser/ConnectionTests.cpp +++ b/tests/parser/ConnectionTests.cpp @@ -17,32 +17,38 @@ along with OPM. If not, see . */ -#include -#include -#include - #define BOOST_TEST_MODULE CompletionTests #include -#include -#include -#include -#include - #include -#include -#include + +#include + +#include + #include #include -#include #include -#include -#include +#include +#include #include +#include +#include +#include + #include #include +#include + +#include + +#include + +#include +#include +#include namespace { double cp_rm3_per_db() @@ -51,20 +57,31 @@ namespace { / (Opm::unit::day * Opm::unit::barsa); } -Opm::WellConnections loadCOMPDAT(const std::string& compdat_keyword) { - Opm::EclipseGrid grid(10,10,10); - Opm::TableManager tables; - Opm::Parser parser; - const auto deck = parser.parseString(compdat_keyword); - Opm::FieldPropsManager field_props(deck, Opm::Phases{true, true, true}, grid, Opm::TableManager()); - const auto& keyword = deck["COMPDAT"][0]; - Opm::WellConnections connections(Opm::Connection::Order::TRACK, 10,10); - Opm::CompletedCells cells(grid); - for (const auto& rec : keyword) - connections.loadCOMPDAT(rec, Opm::ScheduleGrid(grid, field_props, cells), "WELL", {}); + Opm::WellConnections + loadCOMPDAT(const std::string& compdat_keyword) + { + Opm::WellConnections connections { + Opm::Connection::Order::TRACK, 10, 10 + }; - return connections; -} + const auto deck = Opm::Parser{}.parseString(compdat_keyword); + const auto loc = Opm::KeywordLocation{}; + + const Opm::EclipseGrid grid { 10, 10, 10 }; + const Opm::FieldPropsManager field_props { + deck, Opm::Phases{true, true, true}, grid, Opm::TableManager{} + }; + + // Must be mutable. + Opm::CompletedCells completed_cells(grid); + const auto sg = Opm::ScheduleGrid { grid, field_props, completed_cells }; + + for (const auto& rec : deck["COMPDAT"][0]) { + connections.loadCOMPDAT(rec, sg, "WELL", loc); + } + + return connections; + } } namespace Opm { @@ -94,12 +111,22 @@ BOOST_AUTO_TEST_CASE(CreateWellConnectionsOK) { -BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect) { - auto dir = Opm::Connection::Direction::Z; +BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect) +{ + const auto dir = Opm::Connection::Direction::Z; const auto kind = Opm::Connection::CTFKind::DeckValue; + const auto depth = 0.0; + + auto ctf_props = Opm::Connection::CTFProperties{}; + + ctf_props.CF = 99.88; + ctf_props.Kh = 355.113; + ctf_props.rw = 0.25; + + const auto completion1 = Opm::Connection { 10,10,10, 100, 1, Opm::Connection::State::OPEN, dir, kind, 0, depth, ctf_props, 0, true }; + const auto completion2 = Opm::Connection { 10,10,11, 102, 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true }; + Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 1,1); - Opm::Connection completion1( 10,10,10, 100, 1, 0.0, Opm::Connection::State::OPEN , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true); - Opm::Connection completion2( 10,10,11, 102, 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true); completionSet.add( completion1 ); BOOST_CHECK_EQUAL( 1U , completionSet.size() ); BOOST_CHECK_MESSAGE( !completionSet.empty(), "Non-empty completion set must not be empty" ); @@ -111,11 +138,21 @@ BOOST_AUTO_TEST_CASE(AddCompletionSizeCorrect) { } -BOOST_AUTO_TEST_CASE(WellConnectionsGetOutOfRangeThrows) { - auto dir = Opm::Connection::Direction::Z; +BOOST_AUTO_TEST_CASE(WellConnectionsGetOutOfRangeThrows) +{ + const auto dir = Opm::Connection::Direction::Z; const auto kind = Opm::Connection::CTFKind::DeckValue; - Opm::Connection completion1( 10,10,10, 100, 1, 0.0, Opm::Connection::State::OPEN , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0,true); - Opm::Connection completion2( 10,10,11, 102, 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0,true); + const auto depth = 0.0; + + auto ctf_props = Opm::Connection::CTFProperties{}; + + ctf_props.CF = 99.88; + ctf_props.Kh = 355.113; + ctf_props.rw = 0.25; + + const auto completion1 = Opm::Connection { 10,10,10, 100, 1, Opm::Connection::State::OPEN, dir, kind, 0, depth, ctf_props, 0, true }; + const auto completion2 = Opm::Connection { 10,10,11, 102, 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true }; + Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 1,1); completionSet.add( completion1 ); BOOST_CHECK_EQUAL( 1U , completionSet.size() ); @@ -148,15 +185,23 @@ BOOST_AUTO_TEST_CASE(Compdat_Direction) { } -BOOST_AUTO_TEST_CASE(AddCompletionCopy) { - Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 10,10); - auto dir = Opm::Connection::Direction::Z; +BOOST_AUTO_TEST_CASE(AddCompletionCopy) +{ + const auto dir = Opm::Connection::Direction::Z; const auto kind = Opm::Connection::CTFKind::DeckValue; + const auto depth = 0.0; - Opm::Connection completion1( 10,10,10, 100, 1, 0.0, Opm::Connection::State::OPEN , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true); - Opm::Connection completion2( 10,10,11, 101, 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true); - Opm::Connection completion3( 10,10,12, 102, 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true); + auto ctf_props = Opm::Connection::CTFProperties{}; + ctf_props.CF = 99.88; + ctf_props.Kh = 355.113; + ctf_props.rw = 0.25; + + const auto completion1 = Opm::Connection { 10,10,10, 100, 1, Opm::Connection::State::OPEN, dir, kind, 0, depth, ctf_props, 0, true }; + const auto completion2 = Opm::Connection { 10,10,11, 101, 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true }; + const auto completion3 = Opm::Connection { 10,10,12, 102, 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true }; + + Opm::WellConnections completionSet(Opm::Connection::Order::TRACK, 10,10); completionSet.add( completion1 ); completionSet.add( completion2 ); completionSet.add( completion3 ); @@ -171,31 +216,43 @@ BOOST_AUTO_TEST_CASE(AddCompletionCopy) { } -BOOST_AUTO_TEST_CASE(ActiveCompletions) { - Opm::EclipseGrid grid(10,20,20); - auto dir = Opm::Connection::Direction::Z; - const auto kind = Opm::Connection::CTFKind::Defaulted; - Opm::WellConnections completions(Opm::Connection::Order::TRACK, 10,10); - Opm::Connection completion1( 0,0,0, grid.getGlobalIndex(0,0,0), 1, 0.0, Opm::Connection::State::OPEN , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true); - Opm::Connection completion2( 0,0,1, grid.getGlobalIndex(0,0,1), 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true); - Opm::Connection completion3( 0,0,2, grid.getGlobalIndex(0,0,2), 1, 0.0, Opm::Connection::State::SHUT , 99.88, 355.113, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true); +BOOST_AUTO_TEST_CASE(ActiveCompletions) +{ + const auto dir = Opm::Connection::Direction::Z; + const auto kind = Opm::Connection::CTFKind::DeckValue; + const auto depth = 0.0; + auto ctf_props = Opm::Connection::CTFProperties{}; + + ctf_props.CF = 99.88; + ctf_props.Kh = 355.113; + ctf_props.rw = 0.25; + + Opm::EclipseGrid grid { 10, 20, 20 }; + + const auto completion1 = Opm::Connection { 0,0,0, grid.getGlobalIndex(0,0,0), 1, Opm::Connection::State::OPEN, dir, kind, 0, depth, ctf_props, 0, true }; + const auto completion2 = Opm::Connection { 0,0,1, grid.getGlobalIndex(0,0,1), 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true }; + const auto completion3 = Opm::Connection { 0,0,2, grid.getGlobalIndex(0,0,2), 1, Opm::Connection::State::SHUT, dir, kind, 0, depth, ctf_props, 0, true }; + + Opm::WellConnections completions(Opm::Connection::Order::TRACK, 10,10); completions.add( completion1 ); completions.add( completion2 ); completions.add( completion3 ); std::vector actnum(grid.getCartesianSize(), 1); actnum[0] = 0; - grid.resetACTNUM( actnum); + grid.resetACTNUM(actnum); - Opm::WellConnections active_completions(completions, grid); + const Opm::WellConnections active_completions(completions, grid); BOOST_CHECK_EQUAL( active_completions.size() , 2U); BOOST_CHECK_EQUAL( completion2, active_completions.get(0)); BOOST_CHECK_EQUAL( completion3, active_completions.get(1)); } -BOOST_AUTO_TEST_CASE(loadCOMPDATTEST) { - Opm::UnitSystem units(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC); // Unit system used in deck FIRST_SIM.DATA. +BOOST_AUTO_TEST_CASE(loadCOMPDATTEST) +{ + const Opm::UnitSystem units(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC); // Unit system used in deck FIRST_SIM.DATA. + { const std::string deck = R"(GRID @@ -212,7 +269,8 @@ COMPDAT -- CF Diam Kh Skin Df 'WELL' 1 1 1 1 'OPEN' 1* 1.168 0.311 107.872 1* 1* 'Z' 21.925 / /)"; - Opm::WellConnections connections = loadCOMPDAT(deck); + + const Opm::WellConnections connections = loadCOMPDAT(deck); const auto& conn0 = connections[0]; BOOST_CHECK_EQUAL(conn0.CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, 1.168)); BOOST_CHECK_EQUAL(conn0.Kh(), units.to_si(Opm::UnitSystem::measure::effective_Kh, 107.872)); @@ -236,7 +294,8 @@ COMPDAT -- CF Diam Kh Skin Df 'WELL' 1 1 1 1 'OPEN' 1* 1.168 0.311 0 1* 1* 'Z' 21.925 / /)"; - Opm::WellConnections connections = loadCOMPDAT(deck); + + const Opm::WellConnections connections = loadCOMPDAT(deck); const auto& conn0 = connections[0]; BOOST_CHECK_EQUAL(conn0.CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, 1.168)); BOOST_CHECK_EQUAL(conn0.Kh(), units.to_si(Opm::UnitSystem::measure::effective_Kh, 0.10 * 1.0)); @@ -460,20 +519,16 @@ END } // Reset CF -- simulating COMPDAT record (inactive cell) + auto ctf_props = Opm::Connection::CTFProperties{}; + ctf_props.CF = 50.0*cp_rm3_per_db(); + ctf_props.Kh = 0.123; + ctf_props.rw = 0.234; + ctf_props.r0 = 0.157; + connP.addConnection(9, 9, 1, // 10, 10, 2 - 199, - 2015.0, - Opm::Connection::State::OPEN, - 50.0*cp_rm3_per_db(), - 0.123, - 0.234, - 0.157, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1); + 199, + Opm::Connection::State::OPEN, + 2015.0, ctf_props, 1); BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{3}); @@ -506,19 +561,9 @@ END // Reset CF -- simulating COMPDAT record (active cell) connP.addConnection(8, 9, 1, // 10, 10, 2 - 198, - 2015.0, - Opm::Connection::State::OPEN, - 50.0*cp_rm3_per_db(), - 0.123, - 0.234, - 0.157, - 0.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1); + 198, + Opm::Connection::State::OPEN, + 2015.0, ctf_props, 1); BOOST_REQUIRE_EQUAL(connP.size(), std::size_t{4}); diff --git a/tests/parser/MultisegmentWellTests.cpp b/tests/parser/MultisegmentWellTests.cpp index 16d8050e9..a7443bfcb 100644 --- a/tests/parser/MultisegmentWellTests.cpp +++ b/tests/parser/MultisegmentWellTests.cpp @@ -55,20 +55,32 @@ #include #include -BOOST_AUTO_TEST_CASE(AICDWellTest) { - - auto dir = Opm::Connection::Direction::Z; +BOOST_AUTO_TEST_CASE(AICDWellTest) +{ + const auto dir_z = Opm::Connection::Direction::Z; + const auto dir_x = Opm::Connection::Direction::X; const auto kind = Opm::Connection::CTFKind::DeckValue; - Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); - Opm::EclipseGrid grid(20,20,20, 1., 1., 25.0, 2500.0); - connection_set.add(Opm::Connection( 19, 0, 0,grid.getGlobalIndex(19,0,0), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 1,grid.getGlobalIndex(19,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 2,grid.getGlobalIndex(19,0,2), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 18, 0, 1,grid.getGlobalIndex(18,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 17, 0, 1,grid.getGlobalIndex(17,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 16, 0, 1,grid.getGlobalIndex(16,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 15, 0, 1,grid.getGlobalIndex(15,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); + const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 }; + + const auto depth = 0.0; + const auto state = Opm::Connection::State::OPEN; + + auto ctf_props = Opm::Connection::CTFProperties{}; + + ctf_props.CF = 200.0; + ctf_props.Kh = 17.29; + ctf_props.rw = 0.25; + + Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); + connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + + connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); BOOST_CHECK_EQUAL( 7U , connection_set.size() ); @@ -212,23 +224,33 @@ WSEGAICD const double center_depth_connection7 = connection7.depth(); BOOST_CHECK_EQUAL(segment_number_connection7, 8); BOOST_CHECK_EQUAL(center_depth_connection7, 2534.5); - } -BOOST_AUTO_TEST_CASE(MultisegmentWellTest) { - - auto dir = Opm::Connection::Direction::Z; +BOOST_AUTO_TEST_CASE(MultisegmentWellTest) +{ + const auto dir_z = Opm::Connection::Direction::Z; + const auto dir_x = Opm::Connection::Direction::X; const auto kind = Opm::Connection::CTFKind::DeckValue; - Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); - Opm::EclipseGrid grid(20,20,20, 1., 1., 25.0, 2500.0); - connection_set.add(Opm::Connection( 19, 0, 0,grid.getGlobalIndex(19,0,0), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 1,grid.getGlobalIndex(19,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 2,grid.getGlobalIndex(19,0,2), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); + const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 }; - connection_set.add(Opm::Connection( 18, 0, 1,grid.getGlobalIndex(18,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 17, 0, 1,grid.getGlobalIndex(17,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 16, 0, 1,grid.getGlobalIndex(16,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 15, 0, 1,grid.getGlobalIndex(15,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); + const auto depth = 0.0; + const auto state = Opm::Connection::State::OPEN; + + auto ctf_props = Opm::Connection::CTFProperties{}; + + ctf_props.CF = 200.0; + ctf_props.Kh = 17.29; + ctf_props.rw = 0.25; + + Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); + connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + + connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); BOOST_CHECK_EQUAL( 7U , connection_set.size() ); @@ -383,19 +405,32 @@ WSEGSICD } -BOOST_AUTO_TEST_CASE(WrongDistanceCOMPSEGS) { - auto dir = Opm::Connection::Direction::Z; +BOOST_AUTO_TEST_CASE(WrongDistanceCOMPSEGS) +{ + const auto dir_z = Opm::Connection::Direction::Z; + const auto dir_x = Opm::Connection::Direction::X; const auto kind = Opm::Connection::CTFKind::DeckValue; - Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); - Opm::EclipseGrid grid(20,20,20, 1., 1., 25., 2500.); - connection_set.add(Opm::Connection( 19, 0, 0, grid.getGlobalIndex(19,0,0),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 1, grid.getGlobalIndex(19,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 2, grid.getGlobalIndex(19,0,2),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 18, 0, 1, grid.getGlobalIndex(18,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 17, 0, 1, grid.getGlobalIndex(17,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 16, 0, 1, grid.getGlobalIndex(16,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 15, 0, 1, grid.getGlobalIndex(15,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); + const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25., 2500.0 }; + + const auto depth = 0.0; + const auto state = Opm::Connection::State::OPEN; + + auto ctf_props = Opm::Connection::CTFProperties{}; + + ctf_props.CF = 200.0; + ctf_props.Kh = 17.29; + ctf_props.rw = 0.25; + + Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); + connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + + connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); BOOST_CHECK_EQUAL( 7U , connection_set.size() ); @@ -452,19 +487,32 @@ BOOST_AUTO_TEST_CASE(WrongDistanceCOMPSEGS) { BOOST_CHECK_NO_THROW(Opm::Compsegs::processCOMPSEGS(compsegs, connection_set, segment_set, Opm::ScheduleGrid(grid, fp, cells), parseContext, errorGuard)); } -BOOST_AUTO_TEST_CASE(NegativeDepthCOMPSEGS) { - auto dir = Opm::Connection::Direction::Z; +BOOST_AUTO_TEST_CASE(NegativeDepthCOMPSEGS) +{ + const auto dir_z = Opm::Connection::Direction::Z; + const auto dir_x = Opm::Connection::Direction::X; const auto kind = Opm::Connection::CTFKind::DeckValue; - Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); - Opm::EclipseGrid grid(20,20,20, 1., 1., 25., 2500.); - connection_set.add(Opm::Connection( 19, 0, 0, grid.getGlobalIndex(19,0,0),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 1, grid.getGlobalIndex(19,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 2, grid.getGlobalIndex(19,0,2),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 18, 0, 1, grid.getGlobalIndex(18,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 17, 0, 1, grid.getGlobalIndex(17,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 16, 0, 1, grid.getGlobalIndex(16,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 15, 0, 1, grid.getGlobalIndex(15,0,1),1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); + const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 }; + + const auto depth = 0.0; + const auto state = Opm::Connection::State::OPEN; + + auto ctf_props = Opm::Connection::CTFProperties{}; + + ctf_props.CF = 200.0; + ctf_props.Kh = 17.29; + ctf_props.rw = 0.25; + + Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); + connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + + connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); BOOST_CHECK_EQUAL( 7U , connection_set.size() ); @@ -521,19 +569,31 @@ BOOST_AUTO_TEST_CASE(NegativeDepthCOMPSEGS) { BOOST_CHECK_NO_THROW( Opm::Compsegs::processCOMPSEGS(compsegs, connection_set, segment_set, Opm::ScheduleGrid(grid, fp, cells), parseContext, errorGuard) ); } -BOOST_AUTO_TEST_CASE(testwsegvalv) { - auto dir = Opm::Connection::Direction::Z; +BOOST_AUTO_TEST_CASE(testwsegvalv) +{ + const auto dir_z = Opm::Connection::Direction::Z; + const auto dir_x = Opm::Connection::Direction::X; const auto kind = Opm::Connection::CTFKind::DeckValue; - Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); - Opm::EclipseGrid grid(20,20,20, 1., 1., 25., 2500.); - connection_set.add(Opm::Connection( 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); - connection_set.add(Opm::Connection( 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, dir, kind, 0, true) ); + const Opm::EclipseGrid grid { 20,20,20, 1.0, 1.0, 25.0, 2500.0 }; - connection_set.add(Opm::Connection( 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); - connection_set.add(Opm::Connection( 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, 0.0, Opm::Connection::State::OPEN , 200, 17.29, 0.25, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, kind, 0, true) ); + const auto depth = 0.0; + const auto state = Opm::Connection::State::OPEN; + + auto ctf_props = Opm::Connection::CTFProperties{}; + + ctf_props.CF = 200.0; + ctf_props.Kh = 17.29; + ctf_props.rw = 0.25; + + Opm::WellConnections connection_set(Opm::Connection::Order::TRACK, 10,10); + connection_set.add({ 19, 0, 0, grid.getGlobalIndex(19,0,0), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 1, grid.getGlobalIndex(19,0,1), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 19, 0, 2, grid.getGlobalIndex(19,0,2), 1, state, dir_z, kind, 0, depth, ctf_props, 0, true }); + + connection_set.add({ 18, 0, 1, grid.getGlobalIndex(18,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 17, 0, 1, grid.getGlobalIndex(17,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 16, 0, 1, grid.getGlobalIndex(16,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); + connection_set.add({ 15, 0, 1, grid.getGlobalIndex(15,0,1), 1, state, dir_x, kind, 0, depth, ctf_props, 0, true }); BOOST_CHECK_EQUAL( 7U , connection_set.size() ); diff --git a/tests/parser/ScheduleTests.cpp b/tests/parser/ScheduleTests.cpp index 3d6469280..bff809685 100644 --- a/tests/parser/ScheduleTests.cpp +++ b/tests/parser/ScheduleTests.cpp @@ -15,16 +15,7 @@ You should have received a copy of the GNU General Public License along with OPM. If not, see . - */ - -#include -#include -#include -#include -#include -#include - -#include +*/ #define BOOST_TEST_MODULE ScheduleTests @@ -37,6 +28,8 @@ #include #endif +#include + #include #include #include @@ -45,49 +38,62 @@ #include #include -#include #include -#include #include +#include #include +#include #include -#include -#include -#include -#include + +#include + +#include #include +#include +#include +#include #include +#include +#include #include -#include #include #include #include +#include +#include +#include #include +#include #include #include -#include -#include + +#include +#include +#include #include #include #include #include + #include #include -#include #include -#include -#include -#include - -#include -#include -#include -#include -#include +#include #include "tests/WorkArea.hpp" +#include +#include +#include +#include +#include +#include +#include +#include + +#include + using namespace Opm; namespace { @@ -100,32 +106,33 @@ namespace { { return UnitSystem::newMETRIC().to_si(UnitSystem::measure::transmissibility, 1.0); } -} -static Schedule make_schedule(const std::string& deck_string) { - const auto& deck = Parser{}.parseString(deck_string); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec (deck); - return Schedule(deck, grid , fp, runspec, python); -} + Schedule make_schedule(const std::string& deck_string) + { + const auto deck = Parser{}.parseString(deck_string); + const EclipseGrid grid(10, 10, 10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); -static std::string createDeck() { - std::string input = R"( + return { deck, grid, fp, runspec, std::make_shared() }; + } + + std::string createDeck() + { + return { R"( START 8 MAR 1998 / SCHEDULE -)"; - return input; -} +)" }; + } -static std::string createDeckWithWells() { - std::string input = R"( + std::string createDeckWithWells() + { + return { R"( START -- 0 10 MAI 2007 / SCHEDULE @@ -143,13 +150,12 @@ WELSPECS 'WX2' 'OP' 30 37 3.33 'OIL' 7* / 'W_3' 'OP' 20 51 3.92 'OIL' 7* / /; -)"; - return input; -} +)" }; + } - -static std::string createDeckWTEST() { - std::string input = R"( + std::string createDeckWTEST() + { + return { R"( START -- 0 10 MAI 2007 / GRID @@ -246,12 +252,12 @@ DATES -- 5 WCONINJH 'BAN' 'WATER' 1* 1.0 / / -)"; - return input; -} +)" }; + } -static std::string createDeckForTestingCrossFlow() { - std::string input = R"( + std::string createDeckForTestingCrossFlow() + { + return { R"( START -- 0 10 MAI 2007 / GRID @@ -318,12 +324,12 @@ DATES -- 4 WCONINJH 'BAN' 'WATER' 1* 1.0 / / -)"; - return input; -} +)" }; + } -static std::string createDeckWithWellsOrdered() { - std::string input = R"( + std::string createDeckWithWellsOrdered() + { + return { R"( START -- 0 10 MAI 2007 / WELLDIMS @@ -334,12 +340,12 @@ WELSPECS 'BW_2' 'BG' 3 3 3.33 'OIL' 7* / 'AW_3' 'AG' 2 5 3.92 'OIL' 7* / / -)"; - return input; -} +)" }; + } -static std::string createDeckWithWellsOrderedGRUPTREE() { - std::string input = R"( + std::string createDeckWithWellsOrderedGRUPTREE() + { + return { R"( START -- 0 10 MAI 2007 / SCHEDULE @@ -355,13 +361,12 @@ WELSPECS 'BW_2' 'CG2' 3 3 3.33 'OIL' 7* / 'AW_3' 'CG2' 2 5 3.92 'OIL' 7* / / -)"; +)" }; + } - return input; -} - -static std::string createDeckWithWellsAndCompletionData() { - std::string input = R"( + std::string createDeckWithWellsAndCompletionData() + { + return { R"( START -- 0 1 NOV 1979 / GRID @@ -398,17 +403,20 @@ DATES -- 2,3 COMPDAT // with defaulted I and J 'OP_1' 0 * 3 9 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 / / -)"; - return input; -} +)" }; + } + bool has_name(const std::vector& names, + const std::string& name) + { + return std::any_of(names.begin(), names.end(), + [&name](const std::string& search) + { + return search == name; + }); + } - -bool has_name(const std::vector& names, const std::string& name) { - auto find_iter = std::find(names.begin(), names.end(), name); - return (find_iter != names.end()); -} - +} // Anonymous namespace BOOST_AUTO_TEST_CASE(CreateScheduleDeckMissingReturnsDefaults) { Deck deck; @@ -448,14 +456,16 @@ BOOST_AUTO_TEST_CASE(CreateScheduleDeckWellsOrdered) { BOOST_CHECK_EQUAL(field_ptr->name(), "FIELD"); } +namespace { -static bool has_well( const std::vector& wells, const std::string& well_name) { +bool has_well( const std::vector& wells, const std::string& well_name) { for (const auto& well : wells ) if (well.name( ) == well_name) return true; return false; } +} // Anonymous namespace BOOST_AUTO_TEST_CASE(CreateScheduleDeckWellsOrderedGRUPTREE) { const auto& schedule = make_schedule( createDeckWithWellsOrderedGRUPTREE() ); @@ -527,7 +537,6 @@ BOOST_AUTO_TEST_CASE(GroupTree2TEST) { } - BOOST_AUTO_TEST_CASE(CreateScheduleDeckWithStart) { const auto& schedule = make_schedule( createDeck() ); BOOST_CHECK_EQUAL( schedule.getStartTime() , asTimeT(TimeStampUTC(1998, 3 , 8 ))); @@ -685,8 +694,11 @@ BOOST_AUTO_TEST_CASE(TestCrossFlowHandling) { BOOST_CHECK(Well::Status::OPEN == schedule.getWell("BAN", 5).getStatus()); } -static std::string createDeckWithWellsAndSkinFactorChanges() { - std::string input = R"( +namespace { + + std::string createDeckWithWellsAndSkinFactorChanges() + { + return { R"(RUNSPEC START -- 0 1 NOV 1979 / GRID @@ -708,40 +720,53 @@ WELSPECS 'OP_3' 'OP' 7 7 1* 'OIL' 1* 1* 1* 1* 1* 1* 1* / / COMPDAT - 'OP_1' 9 9 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 / - 'OP_1' 9 9 2 2 'OPEN' 1* 46.825 0.311 4332.346 1* 1* 'X' 22.123 / - 'OP_2' 8 8 1 3 'OPEN' 1* 1.168 0.311 107.872 1* 1* 'Y' 21.925 / - 'OP_2' 8 7 3 3 'OPEN' 1* 15.071 0.311 1391.859 1* 1* 'Y' 21.920 / - 'OP_2' 8 7 3 6 'OPEN' 1* 6.242 0.311 576.458 1* 1* 'Y' 21.915 / - 'OP_3' 7 7 1 1 'OPEN' 1* 27.412 0.311 2445.337 1* 1* 'Y' 18.521 / - 'OP_3' 7 7 2 2 'OPEN' 1* 55.195 0.311 4923.842 1* 1* 'Y' 18.524 / +-- Well I J K1 K2 Status SATNUM CTF Diam Kh Skin D Dir PER (r0) + 'OP_1' 9 9 1 1 'OPEN' 1* 32.948 0.311 3047.839 1* 1* 'X' 22.100 / + 'OP_1' 9 9 2 2 'OPEN' 1* 46.825 0.311 4332.346 1* 1* 'X' 22.123 / + 'OP_2' 8 8 1 3 'OPEN' 1* 1.168 0.311 107.872 1* 1* 'Y' 21.925 / + 'OP_2' 8 7 3 3 'OPEN' 1* 15.071 0.311 1391.859 1* 1* 'Y' 21.920 / + 'OP_2' 8 7 3 6 'OPEN' 1* 6.242 0.311 576.458 1* 1* 'Y' 21.915 / + 'OP_3' 7 7 1 1 'OPEN' 1* 27.412 0.311 2445.337 1* 1* 'Y' 18.521 / + 'OP_3' 7 7 2 2 'OPEN' 1* 55.195 0.311 4923.842 1* 1* 'Y' 18.524 / / DATES -- 2 10 JUL 2007 / / CSKIN -'OP_1' 9 9 1 1 1.5 / -'OP_2' 4* -1.0 / -'OP_3' 2* 1 2 10.0 / +'OP_1' 9 9 1 1 1.5 / +'OP_2' 4* -1.0 / +'OP_3' 2* 1 2 10.0 / 'OP_3' 7 7 1 1 -1.15 / / -)"; - return input; -} +)" }; + } + +} // Anonymous namespace + +BOOST_AUTO_TEST_CASE(CreateScheduleDeckWellsAndSkinFactorChanges) +{ + auto metricCF = [units = Opm::UnitSystem::newMETRIC()] + (const double ctf) + { + return units.from_si(Opm::UnitSystem::measure::transmissibility, ctf); + }; + + const auto schedule = make_schedule(createDeckWithWellsAndSkinFactorChanges()); -BOOST_AUTO_TEST_CASE(CreateScheduleDeckWellsAndSkinFactorChanges) { - Opm::UnitSystem units(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC); - const auto& schedule = make_schedule(createDeckWithWellsAndSkinFactorChanges()); - // OP_1 { const auto& cs = schedule.getWell("OP_1", 2).getConnections(); BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).skinFactor(), 1.5, 1e-10); - double CF = 25.290608354096133; - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, CF), 1e-5); + + // denom = 2*pi*Kh / CTF = 4.95609889 + // + // New CTF = CTF * denom / (denom + S) = 32.948 * 4.95609889 / (4.95609889 + 1.5) + const double expectCF = 25.292912792; + BOOST_CHECK_CLOSE(metricCF(cs.getFromIJK(8, 8, 0).CF()), expectCF, 1.0e-5); } + // OP_2 { const auto& well = schedule.getWell("OP_2", 2); @@ -749,24 +774,40 @@ BOOST_AUTO_TEST_CASE(CreateScheduleDeckWellsAndSkinFactorChanges) { for (size_t i = 0; i < cs.size(); i++) { BOOST_CHECK_CLOSE(cs.get(i).skinFactor(), -1.0, 1e-10); } - double CF = 7.822338909386947; - BOOST_CHECK_CLOSE(cs.getFromIJK(7, 6, 2).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, CF), 1e-5); + + // denom = 2*pi*Kh / CTF = 4.947899898 + // + // New CTF = CTF * denom / (denom + S) = 6.242 * 4.947899898 / (4.947899898 - 1.0) + const double expectCF = 7.82309378689; + BOOST_CHECK_CLOSE(metricCF(cs.getFromIJK(7, 6, 2).CF()), expectCF, 1.0e-5); } + // OP_3 { const auto& well = schedule.getWell("OP_3", 2); const auto& cs = well.getConnections(); - BOOST_CHECK_CLOSE(cs.getFromIJK(6, 6, 0).skinFactor(), -1.15, 1e-10); - BOOST_CHECK_CLOSE(cs.getFromIJK(6, 6, 1).skinFactor(), 10.0, 1e-10); - double CF1 = 36.09169888375442; - BOOST_CHECK_CLOSE(cs.getFromIJK(6, 6, 0).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, CF1), 1e-5); - double CF2 = 17.848489977420336; - BOOST_CHECK_CLOSE(cs.getFromIJK(6, 6, 1).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, CF2), 1e-5); + BOOST_CHECK_CLOSE(cs.getFromIJK(6, 6, 0).skinFactor(), - 1.15, 1e-10); + BOOST_CHECK_CLOSE(cs.getFromIJK(6, 6, 1).skinFactor(), 10.0, 1e-10); + + // denom = 2*pi*Kh / CTF = 4.7794177751 + // + // New CTF = CTF * denom / (denom + S) = 27.412 * 4.7794177751 / (4.7794177751 - 1.15) + const double expectCF1 = 36.09763553531; + BOOST_CHECK_CLOSE(metricCF(cs.getFromIJK(6, 6, 0).CF()), expectCF1, 1.0e-5); + + // denom = 2*pi*Kh / CTF = 4.7794879307 + // + // New CTF = CTF * denom / (denom + S) = 55.195 * 4.7794879307 / (4.7794879307 + 10) + const double expectCF2 = 17.84932181501; + BOOST_CHECK_CLOSE(metricCF(cs.getFromIJK(6, 6, 1).CF()), expectCF2, 1.0e-5); } } -static std::string createDeckWithWPIMULTandWELPIandCSKIN() { - std::string input = R"( +namespace { + + std::string createDeckWithWPIMULTandWELPIandCSKIN() + { + return { R"( START -- 0 1 NOV 1979 / GRID @@ -848,22 +889,33 @@ CSKIN 'OP_1' 9 9 1 1 -1.0 / / -)"; - return input; -} +)" }; + } -BOOST_AUTO_TEST_CASE(CreateScheduleDeckWPIMULTandWELPIandCSKIN) { - // Setup - Opm::UnitSystem units(Opm::UnitSystem::UnitType::UNIT_TYPE_METRIC); +} // Anonymous namespace + +BOOST_AUTO_TEST_CASE(CreateScheduleDeckWPIMULTandWELPIandCSKIN) +{ + auto metricCF = [units = Opm::UnitSystem::newMETRIC()](const double ctf) + { + return units.from_si(Opm::UnitSystem::measure::transmissibility, ctf); + }; + + // Note: Schedule must be mutable for WELPI scaling. auto schedule = make_schedule(createDeckWithWPIMULTandWELPIandCSKIN()); // Report step 2 { const auto& cs = schedule.getWell("OP_1", 2).getConnections(); - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).skinFactor(), 1.5, 1e-10); - double CF = 25.290608354096133; - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, CF), 1e-5); - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).wpimult(), 1.0, 1e-5); + const auto& conn = cs.getFromIJK(8, 8, 0); + + BOOST_CHECK_CLOSE(conn.skinFactor(), 1.5, 1e-10); + + // denom = 2*pi*Kh / CTF = 4.95609889 + // + // New CTF = CTF * denom / (denom + S) = 32.948 * 4.95609889 / (4.95609889 + 1.5) + const double expectCF = 25.292912792376; + BOOST_CHECK_CLOSE(metricCF(conn.CF()), expectCF, 1.0e-5); } // Report step 3 @@ -871,15 +923,22 @@ BOOST_AUTO_TEST_CASE(CreateScheduleDeckWPIMULTandWELPIandCSKIN) { const auto& cs_prev = schedule.getWell("OP_1", 2).getConnections(); const auto& cs_curr = schedule.getWell("OP_1", 3).getConnections(); BOOST_CHECK_CLOSE(cs_curr.getFromIJK(8, 8, 0).CF() / cs_prev.getFromIJK(8, 8, 0).CF(), 1.3, 1e-5); - BOOST_CHECK_CLOSE(cs_curr.getFromIJK(8, 8, 0).wpimult(), 1.3, 1e-5); } // Report step 4 { const auto& cs = schedule.getWell("OP_1", 4).getConnections(); - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).skinFactor(), 0.5, 1e-10); - double CF = 38.90302007377862; // CF from CSKIN multiplied by 1.3 from WPIMULT - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, CF), 1e-5); + const auto& conn = cs.getFromIJK(8, 8, 0); + + BOOST_CHECK_CLOSE(conn.skinFactor(), 0.5, 1e-10); + + // CF from CSKIN multiplied by 1.3 from WPIMULT + // denom = 2*pi*Kh / CTF = 4.95609889 + // mult = 1.3 + // + // New CTF = mult * CTF * denom / (denom + S) = 1.3 * 32.948 * 4.95609889 / (4.95609889 + 0.5) + const double expectCF = 38.90721454349; + BOOST_CHECK_CLOSE(metricCF(conn.CF()), expectCF, 1e-5); } // Report step 5 @@ -887,49 +946,69 @@ BOOST_AUTO_TEST_CASE(CreateScheduleDeckWPIMULTandWELPIandCSKIN) { const auto& cs_prev = schedule.getWell("OP_1", 4).getConnections(); const auto& cs_curr = schedule.getWell("OP_1", 5).getConnections(); BOOST_CHECK_CLOSE(cs_curr.getFromIJK(8, 8, 0).CF() / cs_prev.getFromIJK(8, 8, 0).CF(), 1.3, 1e-5); - BOOST_CHECK_CLOSE(cs_curr.getFromIJK(8, 8, 0).wpimult(), 1.3 * 1.3, 1e-5); } // Report step 6 { - const auto& cs = schedule.getWell("OP_1", 6).getConnections(); - double init_pi = 100.0; - schedule.applyWellProdIndexScaling("OP_1", 6, units.to_si(Opm::UnitSystem::measure::liquid_productivity_index, init_pi)); - const auto& target_pi = schedule[6].target_wellpi.at("OP_1"); - BOOST_CHECK_CLOSE(target_pi, 50.0, 1e-5); - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).wpimult(), 1.3 * 1.3 * (target_pi / init_pi), 1e-5); + auto cvrtPI = [units = Opm::UnitSystem::newMETRIC()](const double pi) + { + return units.to_si(Opm::UnitSystem::measure::liquid_productivity_index, pi); + }; + + const auto init_pi = cvrtPI(100.0); + schedule.applyWellProdIndexScaling("OP_1", 6, init_pi); + + const auto target_pi = schedule[6].target_wellpi.at("OP_1"); + BOOST_CHECK_CLOSE(target_pi, 50.0, 1.0e-5); } // Report step 7 { - const auto& cs_prev = schedule.getWell("OP_1", 6).getConnections(); - const auto& cs_curr = schedule.getWell("OP_1", 7).getConnections(); - BOOST_CHECK_CLOSE(cs_curr.getFromIJK(8, 8, 0).skinFactor(), 5.0, 1e-10); - double CF = 13.858329011932668; // CF from CSKIN multiplied by 0.845 from WPIMULT and WELPI previous - BOOST_CHECK_CLOSE(cs_curr.getFromIJK(8, 8, 0).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, CF), 1e-5); - BOOST_CHECK_CLOSE(cs_curr.getFromIJK(8, 8, 0).wpimult(), cs_prev.getFromIJK(8, 8, 0).wpimult(), 1e-5); + const auto& cs = schedule.getWell("OP_1", 7).getConnections(); + const auto& conn = cs.getFromIJK(8, 8, 0); + + BOOST_CHECK_CLOSE(conn.skinFactor(), 5.0, 1e-10); + + // denom = 2*pi*Kh / CTF = 4.95609889 + // mult = 1.3 * 1.3 * (50 / 100) = 0.845 + // + // New CTF = mult * CTF * denom / (denom + S) = 0.845 * 32.948 * 4.95609889 / (4.95609889 + 5) + + const auto expectCF = 13.8591478493; + BOOST_CHECK_CLOSE(metricCF(conn.CF()), expectCF, 1.0e-5); } // Report step 8 { const auto& cs = schedule.getWell("OP_1", 8).getConnections(); - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, 32.948), 1e-5); - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).wpimult(), 1.0, 1e-5); + const auto& conn = cs.getFromIJK(8, 8, 0); + + const auto expectCF = 32.948; + BOOST_CHECK_CLOSE(metricCF(conn.CF()), expectCF, 1.0e-5); } // Report step 9 { const auto& cs = schedule.getWell("OP_1", 9).getConnections(); - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).skinFactor(), -1.0, 1e-10); - double CF = 41.27026972084714; // CF from CSKIN with WPIMULT and WELLPI multiplier reset to 1.0 - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).CF(), units.to_si(Opm::UnitSystem::measure::transmissibility, CF), 1e-5); - BOOST_CHECK_CLOSE(cs.getFromIJK(8, 8, 0).wpimult(), 1.0, 1e-5); + const auto& conn = cs.getFromIJK(8, 8, 0); + + BOOST_CHECK_CLOSE(conn.skinFactor(), -1.0, 1e-10); + + // CF from CSKIN with WPIMULT and WELLPI multiplier reset to 1.0 + // + // denom = 2*pi*Kh / CTF = 4.95609889 + // + // New CTF = CTF * denom / (denom + S) = 32.948 * 4.95609889 / (4.95609889 - 1) + const auto expectCF = 41.276406579873; + BOOST_CHECK_CLOSE(metricCF(conn.CF()), expectCF, 1.0e-5); } } +namespace { -static std::string createDeckWithWellsAndConnectionDataWithWELOPEN() { - std::string input = R"( + std::string createDeckWithWellsAndConnectionDataWithWELOPEN() + { + return { R"( START -- 0 1 NOV 1979 / GRID @@ -986,9 +1065,10 @@ DATES -- 5 WELOPEN 'OP_1' SHUT 0 0 0 0 0 / / -)"; - return input; -} +)" }; + } + +} // Anonymous namespace BOOST_AUTO_TEST_CASE(CreateScheduleDeckWellsAndConnectionDataWithWELOPEN) { const auto& schedule = make_schedule(createDeckWithWellsAndConnectionDataWithWELOPEN()); @@ -2617,46 +2697,48 @@ BOOST_AUTO_TEST_CASE(WTEMPINJ_well_template) { } BOOST_AUTO_TEST_CASE( COMPDAT_sets_automatic_complnum ) { - std::string input = R"( - START -- 0 - 19 JUN 2007 / - GRID - PERMX - 1000*0.10/ - COPY - PERMX PERMY / - PERMX PERMZ / - / - SCHEDULE - DATES -- 1 - 10 OKT 2008 / - / - WELSPECS - 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / - / + const auto deck = Parser{}.parseString(R"( +START -- 0 +19 JUN 2007 / +GRID +PORO + 1000*0.3 / +PERMX + 1000*0.10/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +SCHEDULE +DATES -- 1 + 10 OKT 2008 / +/ +WELSPECS + 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / +/ - COMPDAT - 'W1' 0 0 1 1 'SHUT' 1* / -- regular completion (1) - 'W1' 0 0 2 2 'SHUT' 1* / -- regular completion (2) - 'W1' 0 0 3 4 'SHUT' 1* / -- two completions in one record (3, 4) - / +COMPDAT + 'W1' 0 0 1 1 'SHUT' 1* / -- regular completion (1) + 'W1' 0 0 2 2 'SHUT' 1* / -- regular completion (2) + 'W1' 0 0 3 4 'SHUT' 1* / -- two completions in one record (3, 4) +/ - DATES -- 2 - 11 OKT 2008 / - / +DATES -- 2 + 11 OKT 2008 / +/ - COMPDAT - 'W1' 0 0 1 1 'SHUT' 1* / -- respecify, essentially ignore (1) - / - )"; +COMPDAT + 'W1' 0 0 1 1 'SHUT' 1* / -- respecify, essentially ignore (1) +/ +END +)"); + + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); - auto deck = Parser().parseString(input); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec (deck); - Schedule schedule( deck, grid, fp, runspec, python); const auto& cs1 = schedule.getWell( "W1", 1 ).getConnections( ); BOOST_CHECK_EQUAL( 1, cs1.get( 0 ).complnum() ); BOOST_CHECK_EQUAL( 2, cs1.get( 1 ).complnum() ); @@ -2671,43 +2753,44 @@ BOOST_AUTO_TEST_CASE( COMPDAT_sets_automatic_complnum ) { } BOOST_AUTO_TEST_CASE( COMPDAT_multiple_wells ) { - std::string input = R"( - START -- 0 - 19 JUN 2007 / - GRID - PERMX - 1000*0.10/ - COPY - PERMX PERMY / - PERMX PERMZ / - / - SCHEDULE - DATES -- 1 - 10 OKT 2008 / - / - WELSPECS - 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / - 'W2' 'G2' 5 5 1 'OIL' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / - / + const auto deck = Parser{}.parseString(R"( +START -- 0 +19 JUN 2007 / +GRID +PERMX + 1000*0.10/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 1000*0.3 / - COMPDAT - 'W1' 0 0 1 1 'SHUT' 1* / -- regular completion (1) - 'W1' 0 0 2 2 'SHUT' 1* / -- regular completion (2) - 'W1' 0 0 3 4 'SHUT' 1* / -- two completions in one record (3, 4) - 'W2' 0 0 3 3 'SHUT' 1* / -- regular completion (1) - 'W2' 0 0 1 3 'SHUT' 1* / -- two completions (one exist already) (2, 3) - 'W*' 0 0 3 5 'SHUT' 1* / -- two completions, two wells (includes existing - -- and adding for both wells) - / - )"; +SCHEDULE +DATES -- 1 + 10 OKT 2008 / +/ +WELSPECS + 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / + 'W2' 'G2' 5 5 1 'OIL' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / +/ - auto deck = Parser().parseString( input); - auto python = std::make_shared(); - EclipseGrid grid( 10, 10, 10 ); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec (deck); - Schedule schedule( deck, grid, fp, runspec, python); +COMPDAT + 'W1' 0 0 1 1 'SHUT' 1* / -- regular completion (1) + 'W1' 0 0 2 2 'SHUT' 1* / -- regular completion (2) + 'W1' 0 0 3 4 'SHUT' 1* / -- two completions in one record (3, 4) + 'W2' 0 0 3 3 'SHUT' 1* / -- regular completion (1) + 'W2' 0 0 1 3 'SHUT' 1* / -- two completions (one exist already) (2, 3) + 'W*' 0 0 3 5 'SHUT' 1* / -- two completions, two wells (includes existing + -- and adding for both wells) +/ +)"); + + const EclipseGrid grid(10, 10, 10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); { const auto& w1cs = schedule.getWell( "W1", 1 ).getConnections(); @@ -2745,39 +2828,40 @@ BOOST_AUTO_TEST_CASE( COMPDAT_multiple_wells ) { } BOOST_AUTO_TEST_CASE( COMPDAT_multiple_records_same_completion ) { - std::string input = R"( - START -- 0 - 19 JUN 2007 / - GRID - PERMX - 1000*0.10/ - COPY - PERMX PERMY / - PERMX PERMZ / - / - SCHEDULE - DATES -- 1 - 10 OKT 2008 / - / - WELSPECS - 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / - 'W2' 'G2' 5 5 1 'OIL' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / - / + const auto deck = Parser{}.parseString(R"( +START -- 0 +19 JUN 2007 / +GRID +PERMX + 1000*0.10/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 1000*0.3 / +SCHEDULE +DATES -- 1 + 10 OKT 2008 / +/ +WELSPECS + 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / + 'W2' 'G2' 5 5 1 'OIL' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / +/ - COMPDAT - 'W1' 0 0 1 2 'SHUT' 1* / -- multiple completion (1, 2) - 'W1' 0 0 2 2 'SHUT' 1* / -- updated completion (2) - 'W1' 0 0 3 3 'SHUT' 1* / -- regular completion (3) - / - )"; +COMPDAT + 'W1' 0 0 1 2 'SHUT' 1* / -- multiple completion (1, 2) + 'W1' 0 0 2 2 'SHUT' 1* / -- updated completion (2) + 'W1' 0 0 3 3 'SHUT' 1* / -- regular completion (3) +/ +)"); + + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); - auto deck = Parser().parseString(input); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec (deck); - Schedule schedule( deck, grid, fp, runspec, python); const auto& cs = schedule.getWell( "W1", 1 ).getConnections(); BOOST_CHECK_EQUAL( 3U, cs.size() ); BOOST_CHECK_EQUAL( 1, cs.get( 0 ).complnum() ); @@ -2822,56 +2906,57 @@ BOOST_AUTO_TEST_CASE( complump_less_than_1 ) { } BOOST_AUTO_TEST_CASE( complump ) { - std::string input = R"( - START -- 0 - 19 JUN 2007 / - GRID - PERMX - 1000*0.10/ - COPY - PERMX PERMY / - PERMX PERMZ / - / - SCHEDULE + const auto deck = Parser{}.parseString(R"( +START -- 0 +19 JUN 2007 / +GRID +PERMX + 1000*0.10/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 1000*0.3 / - WELSPECS - 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / - 'W2' 'G2' 5 5 1 'OIL' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / - / +SCHEDULE - COMPDAT - 'W1' 0 0 1 2 'SHUT' 1* / Global Index = 23, 123, 223, 323, 423, 523 - 'W1' 0 0 2 3 'SHUT' 1* / - 'W1' 0 0 4 6 'SHUT' 1* / - 'W2' 0 0 3 4 'SHUT' 1* / - 'W2' 0 0 1 4 'SHUT' 1* / - / +WELSPECS + 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / + 'W2' 'G2' 5 5 1 'OIL' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / +/ - COMPLUMP - -- name I J K1 K2 C - -- where C is the completion number of this lump - 'W1' 0 0 1 3 1 / - / +COMPDAT + 'W1' 0 0 1 2 'SHUT' 1* / Global Index = 23, 123, 223, 323, 423, 523 + 'W1' 0 0 2 3 'SHUT' 1* / + 'W1' 0 0 4 6 'SHUT' 1* / + 'W2' 0 0 3 4 'SHUT' 1* / + 'W2' 0 0 1 4 'SHUT' 1* / +/ - DATES -- 1 - 10 OKT 2008 / - / +COMPLUMP + -- name I J K1 K2 C + -- where C is the completion number of this lump + 'W1' 0 0 1 3 1 / +/ - WELOPEN - 'W1' 'OPEN' 0 0 0 1 1 / - / - )"; +DATES -- 1 + 10 OKT 2008 / +/ + +WELOPEN + 'W1' 'OPEN' 0 0 0 1 1 / +/ +)"); constexpr auto open = Connection::State::OPEN; constexpr auto shut = Connection::State::SHUT; - auto deck = Parser().parseString(input); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec (deck); - Schedule schedule( deck, grid, fp, runspec, python); + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); const auto& sc0 = schedule.getWell("W1", 0).getConnections(); /* complnum should be modified by COMPLNUM */ @@ -2932,66 +3017,65 @@ BOOST_AUTO_TEST_CASE( complump ) { BOOST_CHECK_THROW( all_connections.getFromGlobalIndex(100000), std::exception ); } - - BOOST_AUTO_TEST_CASE( COMPLUMP_specific_coordinates ) { - std::string input = R"( - START -- 0 - 19 JUN 2007 / - GRID - PERMX - 1000*0.10/ - COPY - PERMX PERMY / - PERMX PERMZ / - / - SCHEDULE + const auto deck = Parser{}.parseString(R"( +START -- 0 +19 JUN 2007 / +GRID +PERMX + 1000*0.10/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 1000*0.3 / - WELSPECS - 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / - / +SCHEDULE - COMPDAT -- completion number - 'W1' 1 1 1 1 'SHUT' 1* / -- 1 - 'W1' 1 1 2 2 'SHUT' 1* / -- 2 - 'W1' 0 0 1 2 'SHUT' 1* / -- 3, 4 - 'W1' 0 0 2 3 'SHUT' 1* / -- 5 - 'W1' 2 2 1 1 'SHUT' 1* / -- 6 - 'W1' 2 2 4 6 'SHUT' 1* / -- 7, 8, 9 - / +WELSPECS + 'W1' 'G1' 3 3 2873.94 'WATER' 0.00 'STD' 'SHUT' 'NO' 0 'SEG' / +/ - DATES -- 1 - 10 OKT 2008 / - / +COMPDAT -- completion number + 'W1' 1 1 1 1 'SHUT' 1* / -- 1 + 'W1' 1 1 2 2 'SHUT' 1* / -- 2 + 'W1' 0 0 1 2 'SHUT' 1* / -- 3, 4 + 'W1' 0 0 2 3 'SHUT' 1* / -- 5 + 'W1' 2 2 1 1 'SHUT' 1* / -- 6 + 'W1' 2 2 4 6 'SHUT' 1* / -- 7, 8, 9 +/ + +DATES -- 1 + 10 OKT 2008 / +/ - DATES -- 2 - 15 OKT 2008 / - / +DATES -- 2 + 15 OKT 2008 / +/ - COMPLUMP - -- name I J K1 K2 C - -- where C is the completion number of this lump - 'W1' 0 0 2 3 2 / -- all with k = [2 <= k <= 3] -> {2, 4, 5} - 'W1' 2 2 1 5 7 / -- fix'd i,j, k = [1 <= k <= 5] -> {6, 7, 8} - / +COMPLUMP + -- name I J K1 K2 C + -- where C is the completion number of this lump + 'W1' 0 0 2 3 2 / -- all with k = [2 <= k <= 3] -> {2, 4, 5} + 'W1' 2 2 1 5 7 / -- fix'd i,j, k = [1 <= k <= 5] -> {6, 7, 8} +/ - WELOPEN - 'W1' OPEN 0 0 0 2 2 / -- open the new 2 {2, 4, 5} - 'W1' OPEN 0 0 0 5 7 / -- open 5..7 {5, 6, 7, 8} - / - )"; +WELOPEN + 'W1' OPEN 0 0 0 2 2 / -- open the new 2 {2, 4, 5} + 'W1' OPEN 0 0 0 5 7 / -- open 5..7 {5, 6, 7, 8} +/ +)"); constexpr auto open = Connection::State::OPEN; constexpr auto shut = Connection::State::SHUT; - auto deck = Parser().parseString( input); - auto python = std::make_shared(); - EclipseGrid grid( 10, 10, 10 ); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec (deck); - Schedule schedule( deck, grid, fp, runspec, python); + const EclipseGrid grid(10, 10, 10); + const TableManager table (deck ); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); const auto& cs1 = schedule.getWell("W1", 1).getConnections(); const auto& cs2 = schedule.getWell("W1", 2).getConnections(); @@ -3843,9 +3927,16 @@ BOOST_AUTO_TEST_CASE(WTEST_CONFIG) { } -static bool has(const std::vector& l, const std::string& s) { - auto f = std::find(l.begin(), l.end(), s); - return (f != l.end()); +namespace { + + bool has(const std::vector& l, const std::string& s) + { + return std::any_of(l.begin(), l.end(), + [&s](const std::string& search) + { + return search == s; + }); + } } @@ -3883,20 +3974,10 @@ BOOST_AUTO_TEST_CASE(WELL_STATIC) { const auto& connections = ws.getConnections(); BOOST_CHECK_EQUAL(connections.size(), 0U); auto c2 = std::make_shared(Connection::Order::TRACK, 1,1); - c2->addConnection(1,1,1, - grid1.getGlobalIndex(1,1,1), - 100, + c2->addConnection(1, 1, 1, + grid1.getGlobalIndex(1, 1, 1), Connection::State::OPEN, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 10, - 100); + 100.0, Connection::CTFProperties{}, 10); BOOST_CHECK( ws.updateConnections(c2, false) ); BOOST_CHECK( !ws.updateConnections(c2, false) ); @@ -4869,12 +4950,16 @@ END } } +namespace { + void cmp_vector(const std::vector&v1, const std::vector& v2) { BOOST_CHECK_EQUAL(v1.size(), v2.size()); for (std::size_t i = 0; i < v1.size(); i++) BOOST_CHECK_CLOSE(v1[i], v2[i], 1e-4); } +} // Anonymous namespace + BOOST_AUTO_TEST_CASE(VFPPROD_SCALING) { const auto deck = Parser{}.parseFile("VFP_CASE.DATA"); const auto es = EclipseState{ deck }; @@ -5128,6 +5213,8 @@ END BOOST_CHECK_EQUAL( netbalan1.thp_max_iter(), 5 ); } +namespace { + bool compare_dates(const time_point& t, int year, int month, int day) { return t == TimeService::from_time_t( asTimeT( TimeStampUTC(year, month, day))); } @@ -5141,6 +5228,7 @@ std::string dates_msg(const time_point& t, std::array& ymd) { return fmt::format("Different dates: {}-{}-{} != {}-{}-{}", ts.year(), ts.month(), ts.day(), ymd[0], ymd[1], ymd[2]); } +} // Anonymous namespace BOOST_AUTO_TEST_CASE(ScheduleStateDatesTest) { const auto& sched = make_schedule(createDeckWTEST()); @@ -5692,7 +5780,7 @@ END BOOST_AUTO_TEST_CASE(Test_wdfac) { - std::string input = R"( + const auto deck = Parser{}.parseString(R"( DIMENS 10 10 10 / @@ -5718,7 +5806,7 @@ PERMY 1000*10 / PERMZ 1000*10 / - + SCHEDULE DATES -- 1 @@ -5730,10 +5818,10 @@ WELSPECS / COMPDAT - 'W1' 3 3 1 1 'OPEN' 1* 1 0.216 200 1* 1* 'X' / - 'W1' 3 3 2 2 'OPEN' 1* 2 0.216 200 1* 1* 'X' / - 'W1' 3 3 3 3 'OPEN' 1* 3 0.216 200 1* 1* 'X' / - 'W2' 3 3 3 3 'OPEN' 1* 1 0.216 200 1* 11 'X' / + 'W1' 3 3 1 1 'OPEN' 1* 1 0.216 200 1* 1* 'X' / + 'W1' 3 3 2 2 'OPEN' 1* 2 0.216 200 1* 1* 'X' / + 'W1' 3 3 3 3 'OPEN' 1* 3 0.216 200 1* 1* 'X' / + 'W2' 3 3 3 3 'OPEN' 1* 1 0.216 200 1* 11 'X' / / WDFAC @@ -5746,10 +5834,10 @@ DATES -- 2 / COMPDAT - 'W1' 3 3 1 1 'OPEN' 1* 1* 0.216 200 1* 1* 'X' / - 'W1' 3 3 2 2 'OPEN' 1* 1* 0.216 200 1* 1* 'X' / - 'W1' 3 3 3 3 'OPEN' 1* 1* 0.216 200 1* 1* 'X' / - 'W2' 3 3 3 3 'OPEN' 1* 1 0.216 200 1* 11 'X' / + 'W1' 3 3 1 1 'OPEN' 1* 1* 0.216 200 1* 1* 'X' / + 'W1' 3 3 2 2 'OPEN' 1* 1* 0.216 200 1* 1* 'X' / + 'W1' 3 3 3 3 'OPEN' 1* 1* 0.216 200 1* 1* 'X' / + 'W2' 3 3 3 3 'OPEN' 1* 1 0.216 200 1* 11 'X' / / WDFACCOR @@ -5762,57 +5850,65 @@ DATES -- 3 / COMPDAT - 'W1' 3 3 1 1 'OPEN' 1* 1 0.216 200 1* 1* 'X' / - 'W1' 3 3 2 2 'OPEN' 1* 2 0.216 200 1* 0 'X' / - 'W1' 3 3 3 3 'OPEN' 1* 3 0.216 200 1* 11 'X' / - 'W2' 3 3 3 3 'OPEN' 1* 1 0.216 200 1* 11 'X' / + 'W1' 3 3 1 1 'OPEN' 1* 1 0.216 200 1* 1* 'X' / + 'W1' 3 3 2 2 'OPEN' 1* 2 0.216 200 1* 0 'X' / + 'W1' 3 3 3 3 'OPEN' 1* 3 0.216 200 1* 11 'X' / + 'W2' 3 3 3 3 'OPEN' 1* 1 0.216 200 1* 11 'X' / / - END +)"); -)"; - Deck deck = Parser{}.parseString(input); const auto es = EclipseState { deck }; const auto sched = Schedule { deck, es, std::make_shared() }; - const auto& well11 = sched.getWell("W1", 1); - const auto& well21 = sched.getWell("W2", 1); - const auto& wdfac11 = well11.getWDFAC(); - const auto& wdfac21 = well21.getWDFAC(); + const auto dFacUnit = 1*unit::day/unit::cubic(unit::meter); - double rho = 1.0; - double mu = 0.01*Opm::prefix::centi * Opm::unit::Poise; - double phi = 0.3; + const double rho = 1.0; + const double mu = 0.01*prefix::centi*unit::Poise; + const double phi = 0.3; - // WDFAC overwrites D factor in COMDAT - BOOST_CHECK(wdfac11.useDFactor()); + { + const auto& well11 = sched.getWell("W1", 1); + const auto& well21 = sched.getWell("W2", 1); + const auto& wdfac11 = well11.getWDFAC(); + const auto& wdfac21 = well21.getWDFAC(); - // well d factor scaled by connection CF. - BOOST_CHECK_CLOSE(wdfac11.getDFactor(well11.getConnections()[0], mu, rho, phi), 6*1*Opm::unit::day, 1e-12); - BOOST_CHECK_CLOSE(wdfac21.getDFactor(well21.getConnections()[0], mu, rho, phi), 2*Opm::unit::day, 1e-12); - - const auto& well12 = sched.getWell("W1", 2); - const auto& well22 = sched.getWell("W2", 2); - const auto& wdfac12 = well12.getWDFAC(); - const auto& wdfac22 = well22.getWDFAC(); + // WDFAC overwrites D factor in COMDAT + BOOST_CHECK_MESSAGE(wdfac11.useDFactor(), + R"(Well "W1" must use D-Factors at step 1)"); - BOOST_CHECK_CLOSE(wdfac12.getDFactor(well12.getConnections()[0], mu, rho, phi), 5.19e-1, 3); - BOOST_CHECK_CLOSE(wdfac22.getDFactor(well22.getConnections()[0], mu, rho, phi), 2*Opm::unit::day, 1e-12); + // Well-level D-factor scaled by connection transmissibility factor. + BOOST_CHECK_CLOSE(wdfac11.getDFactor(well11.getConnections()[0], mu, rho, phi), 6*1.0*dFacUnit, 1e-12); + BOOST_CHECK_CLOSE(wdfac21.getDFactor(well21.getConnections()[0], mu, rho, phi), 2.0*dFacUnit, 1e-12); + } + { + const auto& well12 = sched.getWell("W1", 2); + const auto& well22 = sched.getWell("W2", 2); + const auto& wdfac12 = well12.getWDFAC(); + const auto& wdfac22 = well22.getWDFAC(); - const auto& well13 = sched.getWell("W1", 3); - const auto& well23 = sched.getWell("W2", 3); - const auto& wdfac13 = well13.getWDFAC(); - const auto& wdfac23 = well23.getWDFAC(); - BOOST_CHECK(wdfac13.useDFactor()); + BOOST_CHECK_CLOSE(wdfac12.getDFactor(well12.getConnections()[0], mu, rho, phi), 5.19e-1, 3); + BOOST_CHECK_CLOSE(wdfac22.getDFactor(well22.getConnections()[0], mu, rho, phi), 2.0*dFacUnit, 1e-12); + } + { + const auto& well13 = sched.getWell("W1", 3); + const auto& well23 = sched.getWell("W2", 3); + const auto& wdfac13 = well13.getWDFAC(); + const auto& wdfac23 = well23.getWDFAC(); - BOOST_CHECK_CLOSE(well13.getConnections()[0].dFactor(), 0*Opm::unit::day, 1e-12); - BOOST_CHECK_CLOSE(well13.getConnections()[1].dFactor(), 0*Opm::unit::day, 1e-12); - BOOST_CHECK_CLOSE(well13.getConnections()[2].dFactor(), 11*Opm::unit::day, 1e-12); - BOOST_CHECK_CLOSE(wdfac13.getDFactor(well13.getConnections()[2], mu, rho, phi), 6/3*11*Opm::unit::day, 1e-12); - BOOST_CHECK_CLOSE(wdfac23.getDFactor(well23.getConnections()[0], mu, rho, phi), 2*Opm::unit::day, 1e-12); + BOOST_CHECK_MESSAGE(wdfac13.useDFactor(), + R"(Well "W1" must use D-Factors at step 3)"); + + BOOST_CHECK_CLOSE(well13.getConnections()[0].dFactor(), 0.0*dFacUnit, 1e-12); + BOOST_CHECK_CLOSE(well13.getConnections()[1].dFactor(), 0.0*dFacUnit, 1e-12); + BOOST_CHECK_CLOSE(well13.getConnections()[2].dFactor(), 11.0*dFacUnit, 1e-12); + + BOOST_CHECK_CLOSE(wdfac13.getDFactor(well13.getConnections()[2], mu, rho, phi), 6.0/3.0*11.0*dFacUnit, 1e-12); + BOOST_CHECK_CLOSE(wdfac23.getDFactor(well23.getConnections()[0], mu, rho, phi), 2.0*dFacUnit, 1e-12); + } } BOOST_AUTO_TEST_CASE(createDeckWithBC) { diff --git a/tests/parser/WellSolventTests.cpp b/tests/parser/WellSolventTests.cpp index 390d404fa..dbe7a83fd 100644 --- a/tests/parser/WellSolventTests.cpp +++ b/tests/parser/WellSolventTests.cpp @@ -22,192 +22,219 @@ #include #include + #include #include #include #include + #include #include + #include #include #include #include + #include #include using namespace Opm; -static Deck createDeckWithOutSolvent() { - Opm::Parser parser; - std::string input = - "GRID\n" - "PERMX\n" - " 1000*0.25/\n" - "COPY\n" - " PERMX PERMY /\n" - " PERMX PERMZ /\n" - "/\n" - "SCHEDULE\n" - "WELSPECS\n" - " 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n" - "/\n" - "COMPDAT\n" - " 'W_1' 2* 1 1 'OPEN' / \n" - "/\n" - "WCONINJE\n" - " 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/\n/\n"; +namespace { - return parser.parseString(input); +Deck createDeckWithOutSolvent() +{ + return Parser{}.parseString(R"( +GRID +PERMX + 1000*0.25/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 1000*0.3 / + +SCHEDULE +WELSPECS + 'W_1' 'OP' 2 2 1* 'OIL' 7* / +/ +COMPDAT + 'W_1' 2* 1 1 'OPEN' / +/ +WCONINJE + 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/ +/ +END +)"); } -static Deck createDeckWithGasInjector() { - Opm::Parser parser; - std::string input = - "GRID\n" - "PERMX\n" - " 1000*0.25/\n" - "COPY\n" - " PERMX PERMY /\n" - " PERMX PERMZ /\n" - "/\n" - "SCHEDULE\n" - "WELSPECS\n" - " 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n" - "/\n" - "COMPDAT\n" - " 'W_1' 2* 1 1 'OPEN' / \n" - "/\n" - "WCONINJE\n" - " 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/\n/\n" - "WSOLVENT\n" - " 'W_1' 1 / \n " - "/\n"; +Deck createDeckWithGasInjector() +{ + return Parser{}.parseString(R"( +GRID +PERMX + 1000*0.25/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 1000*0.3 / - return parser.parseString(input); +SCHEDULE +WELSPECS + 'W_1' 'OP' 1 1 1* 'GAS' 7* / +/ +COMPDAT + 'W_1' 2* 1 1 'OPEN' / +/ +WCONINJE + 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/ +/ +WSOLVENT + 'W_1' 1 / +/ +END +)"); } -static Deck createDeckWithDynamicWSOLVENT() { - Opm::Parser parser; - std::string input = - "START -- 0 \n" - "1 JAN 2000 / \n" - "GRID\n" - "PERMX\n" - " 1000*0.25/\n" - "COPY\n" - " PERMX PERMY /\n" - " PERMX PERMZ /\n" - "/\n" - "SCHEDULE\n" - "WELSPECS\n" - " 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n" - "/\n" - "COMPDAT\n" - " 'W_1' 2* 1 1 'OPEN' / \n" - "/\n" - "WCONINJE\n" - " 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/\n/\n" - "DATES -- 2\n" - " 1 MAY 2000 / \n" - "/\n" - "WSOLVENT\n" - " 'W_1' 1 / \n " - "/\n" - "DATES -- 3,4\n" - " 1 JUL 2000 / \n" - " 1 AUG 2000 / \n" - "/\n" - "WSOLVENT\n" - " 'W_1' 0 / \n " - "/\n"; +Deck createDeckWithDynamicWSOLVENT() +{ + return Parser{}.parseString(R"( +START -- 0 +1 JAN 2000 / +GRID +PERMX + 1000*0.25/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 1000*0.3 / - return parser.parseString(input); +SCHEDULE +WELSPECS + 'W_1' 'OP' 1 1 1* 'GAS' 7* / +/ +COMPDAT + 'W_1' 2* 1 1 'OPEN' / +/ +WCONINJE + 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/ +/ +DATES -- 2 + 1 MAY 2000 / +/ +WSOLVENT + 'W_1' 1 / +/ +DATES -- 3,4 + 1 JUL 2000 / + 1 AUG 2000 / +/ +WSOLVENT + 'W_1' 0 / +/ +END +)"); } -static Deck createDeckWithOilInjector() { - Opm::Parser parser; - std::string input = - "GRID\n" - "PERMX\n" - " 1000*0.25/\n" - "COPY\n" - " PERMX PERMY /\n" - " PERMX PERMZ /\n" - "/\n" - "SCHEDULE\n" - "WELSPECS\n" - " 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n" - "/\n" - "COMPDAT\n" - " 'W_1' 2* 1 1 'OPEN' / \n" - "/\n" - "WCONINJE\n" - " 'W_1' 'OIL' 'OPEN' 'BHP' 1 2 3/\n/\n" - "WSOLVENT\n" - " 'W_1' 1 / \n " - "/\n"; - - return parser.parseString(input); +Deck createDeckWithOilInjector() +{ + return Parser{}.parseString(R"( +GRID +PERMX + 1000*0.25/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +SCHEDULE +WELSPECS + 'W_1' 'OP' 2 2 1* 'OIL' 7* / +/ +COMPDAT + 'W_1' 2* 1 1 'OPEN' / +/ +WCONINJE + 'W_1' 'OIL' 'OPEN' 'BHP' 1 2 3/ +/ +WSOLVENT + 'W_1' 1 / +/ +END +)"); } -static Deck createDeckWithWaterInjector() { - Opm::Parser parser; - std::string input = - "GRID\n" - "PERMX\n" - " 1000*0.25/\n" - "COPY\n" - " PERMX PERMY /\n" - " PERMX PERMZ /\n" - "/\n" - "SCHEDULE\n" - "WELSPECS\n" - " 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n" - "/\n" - "COMPDAT\n" - " 'W_1' 2* 1 1 'OPEN' / \n" - "/\n" - "WCONINJE\n" - " 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/\n/\n" - "WSOLVENT\n" - " 'W_1' 1 / \n " - "/\n"; - - return parser.parseString(input); +Deck createDeckWithWaterInjector() +{ + return Parser{}.parseString(R"( +GRID +PERMX + 1000*0.25/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +SCHEDULE +WELSPECS + 'W_1' 'OP' 2 2 1* \'OIL\' 7* / +/ +COMPDAT + 'W_1' 2* 1 1 'OPEN' / +/ +WCONINJE + 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/ +/ +WSOLVENT + 'W_1' 1 / +/ +END +)"); } -BOOST_AUTO_TEST_CASE(TestNoSolvent) { - auto deck = createDeckWithOutSolvent(); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); - Runspec runspec(deck); - Schedule schedule(deck, grid , fp, runspec, python); + +} // Anonymous namespace + +BOOST_AUTO_TEST_CASE(TestNoSolvent) +{ + const auto deck = createDeckWithOutSolvent(); + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec(deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); + BOOST_CHECK(!deck.hasKeyword("WSOLVENT")); } BOOST_AUTO_TEST_CASE(TestGasInjector) { - auto deck = createDeckWithGasInjector(); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); - Runspec runspec(deck); - Schedule schedule(deck, grid , fp, runspec, python); + const auto deck = createDeckWithGasInjector(); + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec(deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); + BOOST_CHECK(deck.hasKeyword("WSOLVENT")); } -BOOST_AUTO_TEST_CASE(TestDynamicWSOLVENT) { - auto deck = createDeckWithDynamicWSOLVENT(); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); - Runspec runspec(deck); - Schedule schedule(deck, grid , fp, runspec, python); +BOOST_AUTO_TEST_CASE(TestDynamicWSOLVENT) +{ + const auto deck = createDeckWithDynamicWSOLVENT(); + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec(deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); + BOOST_CHECK(deck.hasKeyword("WSOLVENT")); + const auto& keyword = deck["WSOLVENT"].back(); BOOST_CHECK_EQUAL(keyword.size(),1U); + const auto& record = keyword.getRecord(0); const std::string& well_name = record.getItem("WELL").getTrimmedString(0); BOOST_CHECK_EQUAL(well_name, "W_1"); @@ -217,22 +244,24 @@ BOOST_AUTO_TEST_CASE(TestDynamicWSOLVENT) { BOOST_CHECK_EQUAL(schedule.getWell("W_1", 3).getSolventFraction(),0); } -BOOST_AUTO_TEST_CASE(TestOilInjector) { - auto deck = createDeckWithOilInjector(); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); - Runspec runspec(deck); - BOOST_CHECK_THROW (Schedule(deck , grid , fp, runspec, python), std::exception); +BOOST_AUTO_TEST_CASE(TestOilInjector) +{ + const auto deck = createDeckWithOilInjector(); + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec(deck); + + BOOST_CHECK_THROW (Schedule(deck, grid, fp, runspec, std::make_shared()), std::exception); } -BOOST_AUTO_TEST_CASE(TestWaterInjector) { - auto deck = createDeckWithWaterInjector(); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); - Runspec runspec(deck); - BOOST_CHECK_THROW (Schedule(deck, grid , fp, runspec, python), std::exception); +BOOST_AUTO_TEST_CASE(TestWaterInjector) +{ + const auto deck = createDeckWithWaterInjector(); + const EclipseGrid grid(10,10,10); + const TableManager table ( deck ); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec(deck); + + BOOST_CHECK_THROW (Schedule(deck, grid , fp, runspec, std::make_shared()), std::exception); } diff --git a/tests/parser/WellTracerTests.cpp b/tests/parser/WellTracerTests.cpp index 4696bbf29..120e09df7 100644 --- a/tests/parser/WellTracerTests.cpp +++ b/tests/parser/WellTracerTests.cpp @@ -22,141 +22,166 @@ #include #include + #include + #include #include #include #include + #include #include #include + #include #include #include #include + #include using namespace Opm; -static Deck createDeckWithOutTracer() { - Opm::Parser parser; - std::string input = - "GRID\n" - "PERMX\n" - " 1000*0.25/\n" - "COPY\n" - " PERMX PERMY /\n" - " PERMX PERMZ /\n" - "/\n" - "SCHEDULE\n" - "WELSPECS\n" - " 'W_1' 'OP' 2 2 1* \'OIL\' 7* / \n" - "/\n" - "COMPDAT\n" - " 'W_1' 2* 1 1 'OPEN' / \n" - "/\n" - "WCONINJE\n" - " 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/\n/\n"; +namespace { - return parser.parseString(input); +Deck createDeckWithOutTracer() +{ + return Parser{}.parseString(R"( +GRID +PERMX + 1000*0.25/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO +1000*0.3 / + +SCHEDULE +WELSPECS + 'W_1' 'OP' 2 2 1* 'OIL' 7* / +/ +COMPDAT + 'W_1' 2* 1 1 'OPEN' / +/ +WCONINJE + 'W_1' 'WATER' 'OPEN' 'BHP' 1 2 3/ +/ +END +)"); } +Deck createDeckWithDynamicWTRACER() +{ + return Parser{}.parseString(R"( +START -- 0 +1 JAN 2000 / +GRID +PERMX + 1000*0.25/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO +1000*0.3 / -static Deck createDeckWithDynamicWTRACER() { - Opm::Parser parser; - std::string input = - "START -- 0 \n" - "1 JAN 2000 / \n" - "GRID\n" - "PERMX\n" - " 1000*0.25/\n" - "COPY\n" - " PERMX PERMY /\n" - " PERMX PERMZ /\n" - "/\n" - "SCHEDULE\n" - "WELSPECS\n" - " 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n" - "/\n" - "COMPDAT\n" - " 'W_1' 2* 1 1 'OPEN' / \n" - "/\n" - "WCONINJE\n" - " 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/\n/\n" - "DATES -- 1\n" - " 1 MAY 2000 / \n" - "/\n" - "WTRACER\n" - " 'W_1' 'I1' 1 / \n " - " 'W_1' 'I2' 1 / \n " - "/\n" - "DATES -- 2, 3\n" - " 1 JUL 2000 / \n" - " 1 AUG 2000 / \n" - "/\n" - "WTRACER\n" - " 'W_1' 'I1' 0 / \n " - "/\n" - "DATES -- 4\n" - " 1 SEP 2000 / \n" - "/\n"; +SCHEDULE +WELSPECS + 'W_1' 'OP' 1 1 1* 'GAS' 7* / +/ +COMPDAT + 'W_1' 2* 1 1 'OPEN' / +/ +WCONINJE + 'W_1' 'GAS' 'OPEN' 'BHP' 1 2 3/ +/ +DATES -- 1 + 1 MAY 2000 / +/ +WTRACER + 'W_1' 'I1' 1 / + 'W_1' 'I2' 1 / +/ +DATES -- 2, 3 + 1 JUL 2000 / + 1 AUG 2000 / +/ +WTRACER + 'W_1' 'I1' 0 / +/ +DATES -- 4 + 1 SEP 2000 / +/ - return parser.parseString(input); +END +)"); } -static Deck createDeckWithTracerInProducer() { - Opm::Parser parser; - std::string input = - "START -- 0 \n" - "1 JAN 2000 / \n" - "GRID\n" - "PERMX\n" - " 1000*0.25/\n" - "COPY\n" - " PERMX PERMY /\n" - " PERMX PERMZ /\n" - "/\n" - "SCHEDULE\n" - "WELSPECS\n" - " 'W_1' 'OP' 1 1 1* \'GAS\' 7* / \n" - "/\n" - "COMPDAT\n" - " 'W_1' 2* 1 1 'OPEN' / \n" - "/\n" - "WCONPROD\n" - "'W_1' 'OPEN' 'ORAT' 20000 4* 1000 /\n" - "WTRACER\n" - " 'W_1' 'I1' 1 / \n " - " 'W_1' 'I2' 1 / \n " - "/\n"; +Deck createDeckWithTracerInProducer() +{ + return Parser{}.parseString(R"( +START -- 0 +1 JAN 2000 / +GRID +PERMX + 1000*0.25/ +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 1000*0.3 / - return parser.parseString(input); +SCHEDULE +WELSPECS + 'W_1' 'OP' 1 1 1* 'GAS' 7* / +/ +COMPDAT + 'W_1' 2* 1 1 'OPEN' / +/ +WCONPROD + 'W_1' 'OPEN' 'ORAT' 20000 4* 1000 / +WTRACER + 'W_1' 'I1' 1 / + 'W_1' 'I2' 1 / +/ +END +)"); } +} // Anonymous namespace + +BOOST_AUTO_TEST_CASE(TestNoTracer) +{ + const auto deck = createDeckWithOutTracer(); + + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); -BOOST_AUTO_TEST_CASE(TestNoTracer) { - auto deck = createDeckWithOutTracer(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); - auto python = std::make_shared(); - Runspec runspec ( deck ); - Schedule schedule(deck, grid , fp, runspec, python); BOOST_CHECK(!deck.hasKeyword("WTRACER")); } -BOOST_AUTO_TEST_CASE(TestDynamicWTRACER) { - auto deck = createDeckWithDynamicWTRACER(); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec ( deck ); - Schedule schedule(deck, grid , fp, runspec, python); +BOOST_AUTO_TEST_CASE(TestDynamicWTRACER) +{ + const auto deck = createDeckWithDynamicWTRACER(); + + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); + const Schedule schedule(deck, grid, fp, runspec, std::make_shared()); + BOOST_CHECK(deck.hasKeyword("WTRACER")); + const auto& keyword = deck["WTRACER"].back(); BOOST_CHECK_EQUAL(keyword.size(),1U); + const auto& record = keyword.getRecord(0); const std::string& well_name = record.getItem("WELL").getTrimmedString(0); BOOST_CHECK_EQUAL(well_name, "W_1"); @@ -169,13 +194,13 @@ BOOST_AUTO_TEST_CASE(TestDynamicWTRACER) { } -BOOST_AUTO_TEST_CASE(TestTracerInProducerTHROW) { - auto deck = createDeckWithTracerInProducer(); - auto python = std::make_shared(); - EclipseGrid grid(10,10,10); - TableManager table ( deck ); - FieldPropsManager fp( deck, Phases{true, true, true}, grid, table); - Runspec runspec ( deck ); +BOOST_AUTO_TEST_CASE(TestTracerInProducerTHROW) +{ + const auto deck = createDeckWithTracerInProducer(); + const EclipseGrid grid(10,10,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); - BOOST_CHECK_THROW(Schedule(deck, grid, fp, runspec, python), OpmInputError); + BOOST_CHECK_THROW(Schedule(deck, grid, fp, runspec, std::make_shared()), OpmInputError); } diff --git a/tests/parser/integration/ScheduleCreateFromDeck.cpp b/tests/parser/integration/ScheduleCreateFromDeck.cpp index 7e4bbd1bb..b96b6d071 100644 --- a/tests/parser/integration/ScheduleCreateFromDeck.cpp +++ b/tests/parser/integration/ScheduleCreateFromDeck.cpp @@ -518,34 +518,39 @@ BOOST_AUTO_TEST_CASE(WellTestWGRUPCONWellPropertiesSet) { } -BOOST_AUTO_TEST_CASE(TestDefaultedCOMPDATIJ) { - Parser parser; - const char * deckString = "\n\ -START\n\ -\n\ -10 MAI 2007 /\n\ -\n\ -GRID\n\ -PERMX\n\ - 9000*0.25 /\n\ -COPY \n\ - PERMX PERMY /\n\ - PERMX PERMZ /\n\ -/\n\ -SCHEDULE\n\ -WELSPECS \n\ - 'W1' 'OP' 11 21 3.33 'OIL' 7* / \n\ -/\n\ -COMPDAT \n\ - 'W1' 2* 1 1 'OPEN' 1* 32.948 0.311 3047.839 2* 'X' 22.100 /\n\ -/\n"; - auto deck = parser.parseString(deckString); - auto python = std::make_shared(); - EclipseGrid grid(30,30,10); - TableManager table ( deck ); - FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); - Runspec runspec (deck); - Schedule sched(deck, grid , fp, runspec, python); +BOOST_AUTO_TEST_CASE(TestDefaultedCOMPDATIJ) +{ + const auto deck = Parser{}.parseString(R"( +START + +10 MAI 2007 / + +GRID +PERMX + 9000*0.25 / +COPY + PERMX PERMY / + PERMX PERMZ / +/ +PORO + 9000*0.3 / + +SCHEDULE +WELSPECS + 'W1' 'OP' 11 21 3.33 'OIL' 7* / +/ +COMPDAT + 'W1' 2* 1 1 'OPEN' 1* 32.948 0.311 3047.839 2* 'X' 22.100 / +/ +END +)"); + + const EclipseGrid grid(30,30,10); + const TableManager table (deck); + const FieldPropsManager fp(deck, Phases{true, true, true}, grid, table); + const Runspec runspec (deck); + const Schedule sched(deck, grid, fp, runspec, std::make_shared()); + const auto& connections = sched.getWell("W1", 0).getConnections(); BOOST_CHECK_EQUAL( 10 , connections.get(0).getI() ); BOOST_CHECK_EQUAL( 20 , connections.get(0).getJ() ); @@ -907,4 +912,3 @@ BOOST_AUTO_TEST_CASE(TestWellEvents) { BOOST_CHECK( sched[0].wellgroup_events().hasEvent( "W_1", ScheduleEvents::COMPLETION_CHANGE)); BOOST_CHECK( sched[5].wellgroup_events().hasEvent( "W_1", ScheduleEvents::COMPLETION_CHANGE)); } - diff --git a/tests/test_PAvgCalculator.cpp b/tests/test_PAvgCalculator.cpp index 9369ce6ec..22977b91d 100644 --- a/tests/test_PAvgCalculator.cpp +++ b/tests/test_PAvgCalculator.cpp @@ -57,12 +57,22 @@ namespace { const auto j = (dims[1] - 1) - 1; for (auto k = top; k < static_cast(dims.size()); ++k) { + const auto depth = 2000 + (2*k + 1) / static_cast(2); + + auto ctf_props = Opm::Connection::CTFProperties{}; + ctf_props.CF = k / 100.0; + ctf_props.Kh = 1.0; + ctf_props.Ke = 1.0; + ctf_props.rw = 1.0; + ctf_props.r0 = 0.5; + ctf_props.re = 0.5; + ctf_props.connection_length = 1.0; + conns.emplace_back(i, j, k, globIndex({i, j, k}, dims), k, - 2000 + (2*k + 1) / static_cast(2), Opm::Connection::State::OPEN, - k / 100.0, 1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::Z, - Opm::Connection::CTFKind::DeckValue, k, false); + Opm::Connection::CTFKind::DeckValue, + 0, depth, ctf_props, k, false); } return { Opm::Connection::Order::INPUT, i, j, conns }; @@ -87,18 +97,28 @@ namespace { }; for (auto k = topConn; k < kMax; ++k) { + const auto depth = 2000 + (2*k + 1) / static_cast(2); + + auto ctf_props = Opm::Connection::CTFProperties{}; + + // 0.03, 0.0, 0.01, 0.02, 0.03, ... + ctf_props.CF = ((k + 3 - topConn) % 4) / 100.0; + + ctf_props.Kh = 1.0; + ctf_props.Ke = 1.0; + ctf_props.rw = 1.0; + ctf_props.r0 = 0.5; + ctf_props.re = 0.5; + ctf_props.connection_length = 1.0; + conns.emplace_back(i, j, k, globIndex({i, j, k}, dims), k - topConn, - 2000 + (2*k + 1) / static_cast(2), // Open, Shut, Open, Open, Shut, ... state[(k - topConn) % state.size()], - // 0.03, 0.0, 0.01, 0.02, 0.03, ... - ((k + 3 - topConn) % 4) / 100.0, - - 1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::Z, - Opm::Connection::CTFKind::DeckValue, k - topConn, false); + Opm::Connection::CTFKind::DeckValue, + 0, depth, ctf_props, k - topConn, false); } return { Opm::Connection::Order::INPUT, i, j, conns }; @@ -115,12 +135,22 @@ namespace { const auto iMax = std::min(dims[0] - 1, left + numConns); for (auto i = left; i < iMax; ++i) { + const auto depth = 2000 + (2*k + 1) / static_cast(2); + + auto ctf_props = Opm::Connection::CTFProperties{}; + ctf_props.CF = i / 100.0; + ctf_props.Kh = 1.0; + ctf_props.Ke = 1.0; + ctf_props.rw = 1.0; + ctf_props.r0 = 0.5; + ctf_props.re = 0.5; + ctf_props.connection_length = 1.0; + conns.emplace_back(i, j, k, globIndex({i, j, k}, dims), i - left, - 2000 + (2*k + 1) / static_cast(2), Opm::Connection::State::OPEN, - i / 100.0, 1.0, 1.0, 0.5, 0.5, 1.0, 0.0, 0.0, 0.0, 0, Opm::Connection::Direction::X, - Opm::Connection::CTFKind::DeckValue, i - left, false); + Opm::Connection::CTFKind::DeckValue, + 0, depth, ctf_props, i - left, false); } return { Opm::Connection::Order::INPUT, left, j, conns }; diff --git a/tests/test_Serialization.cpp b/tests/test_Serialization.cpp index c9d3710e6..9a6946813 100644 --- a/tests/test_Serialization.cpp +++ b/tests/test_Serialization.cpp @@ -193,6 +193,7 @@ TEST_FOR_TYPE_NAMED(Action::State, ActionState) TEST_FOR_TYPE(BCConfig) TEST_FOR_TYPE(BrineDensityTable) TEST_FOR_TYPE(ColumnSchema) +TEST_FOR_TYPE_NAMED(Connection::CTFProperties, CTFProperties) TEST_FOR_TYPE(Connection) TEST_FOR_TYPE_NAMED_OBJ(data::AquiferData, AquiferData_CarterTracy, serializationTestObjectC) TEST_FOR_TYPE_NAMED_OBJ(data::AquiferData, AquiferData_Fetkovich, serializationTestObjectF)