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)