diff --git a/opm/input/eclipse/Schedule/Schedule.hpp b/opm/input/eclipse/Schedule/Schedule.hpp index 91e8a6696..bd75fe3c2 100644 --- a/opm/input/eclipse/Schedule/Schedule.hpp +++ b/opm/input/eclipse/Schedule/Schedule.hpp @@ -731,11 +731,13 @@ namespace Opm void handleWCONPROD (HandlerContext&); void handleWECON (HandlerContext&); void handleWEFAC (HandlerContext&); + void handleWELCOMPL (HandlerContext&); void handleWELOPEN (HandlerContext&); void handleWELPI (HandlerContext&); void handleWELSEGS (HandlerContext&); void handleWELSPECS (HandlerContext&); void handleWELTARG (HandlerContext&); + void handleWELTRAJ (HandlerContext&); void handleWFOAM (HandlerContext&); void handleWGRUPCON (HandlerContext&); void handleWHISTCTL (HandlerContext&); diff --git a/opm/input/eclipse/Schedule/Well/WellConnections.hpp b/opm/input/eclipse/Schedule/Well/WellConnections.hpp index ba5af1e0d..d22504fc0 100644 --- a/opm/input/eclipse/Schedule/Well/WellConnections.hpp +++ b/opm/input/eclipse/Schedule/Well/WellConnections.hpp @@ -88,6 +88,12 @@ namespace Opm { const std::string& wname, const KeywordLocation& location); + void loadWELCOMPL(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); + + using const_iterator = std::vector< Connection >::const_iterator; + void add(Connection); std::size_t size() const; bool empty() const; @@ -182,6 +188,12 @@ namespace Opm { void orderTRACK(); void orderMSW(); void orderDEPTH(); + + Connection::Order m_ordering = Connection::Order::TRACK; + int headI, headJ; + std::vector< Connection > m_connections; + double x_coordinate; + }; std::optional diff --git a/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp b/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp index dd35e6c7a..7edc3cd0f 100644 --- a/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp +++ b/src/opm/input/eclipse/Schedule/KeywordHandlers.cpp @@ -179,6 +179,83 @@ namespace { } } + void Schedule::handleWELTRAJ(HandlerContext& handlerContext) { + std::unordered_set wells; + for (const auto& record : handlerContext.keyword) { + const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0); + auto wellnames = this->wellNames(wellNamePattern, handlerContext ); + + for (const auto& name : wellnames) { + auto well2 = this->snapshots.back().wells.get(name); + auto connections = std::shared_ptr( new WellConnections( well2.getConnections())); + connections->loadWELTRAJ(record, handlerContext.grid, name, handlerContext.keyword.location()); + //what to do here? need here something like updateTrajectory + //maybe new method WellConnection::addTrajectory? + if (well2.updateConnections(connections, handlerContext.grid)) { + this->snapshots.back().wells.update( well2 ); + wells.insert( name ); + } + + if (connections->empty() && well2.getConnections().empty()) { + const auto& location = handlerContext.keyword.location(); + auto msg = fmt::format("Problem with COMPDAT/{}\n" + "In {} line {}\n" + "Well {} is not connected to grid - will remain SHUT", name, location.filename, location.lineno, name); + OpmLog::warning(msg); + } + this->snapshots.back().wellgroup_events().addEvent( name, ScheduleEvents::COMPLETION_CHANGE); + } + } + this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE); + + // In the case the wells reference depth has been defaulted in the + // WELSPECS keyword we need to force a calculation of the wells + // reference depth exactly when the COMPDAT keyword has been completely + // processed. + // for (const auto& wname : wells) { + // auto& well = this->snapshots.back().wells.get( wname ); + // well.updateRefDepth(); + // this->snapshots.back().wells.update( std::move(well)); + // } + } + void Schedule::handleWELCOMPL(HandlerContext& handlerContext) { + std::unordered_set wells; + for (const auto& record : handlerContext.keyword) { + const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0); + auto wellnames = this->wellNames(wellNamePattern, handlerContext ); + + for (const auto& name : wellnames) { + auto well2 = this->snapshots.back().wells.get(name); + auto connections = std::shared_ptr( new WellConnections( well2.getConnections())); + connections->loadWELCOMPL(record, handlerContext.grid, name, handlerContext.keyword.location()); + // if (well2.updateConnections(connections, handlerContext.grid)) { + // this->snapshots.back().wells.update( well2 ); + // wells.insert( name ); + // } + + // if (connections->empty() && well2.getConnections().empty()) { + // const auto& location = handlerContext.keyword.location(); + // auto msg = fmt::format("Problem with COMPDAT/{}\n" + // "In {} line {}\n" + // "Well {} is not connected to grid - will remain SHUT", name, location.filename, location.lineno, name); + // OpmLog::warning(msg); + // } + // this->snapshots.back().wellgroup_events().addEvent( name, ScheduleEvents::COMPLETION_CHANGE); + } + } + this->snapshots.back().events().addEvent(ScheduleEvents::COMPLETION_CHANGE); + + // In the case the wells reference depth has been defaulted in the + // WELSPECS keyword we need to force a calculation of the wells + // reference depth exactly when the COMPDAT keyword has been completely + // processed. + // for (const auto& wname : wells) { + // auto& well = this->snapshots.back().wells.get( wname ); + // well.updateRefDepth(); + // this->snapshots.back().wells.update( std::move(well)); + // } + } + void Schedule::handleCOMPLUMP(HandlerContext& handlerContext) { for (const auto& record : handlerContext.keyword) { const std::string& wellNamePattern = record.getItem("WELL").getTrimmedString(0); @@ -2298,11 +2375,13 @@ Well{0} entered with disallowed 'FIELD' parent group: { "WCONPROD", &Schedule::handleWCONPROD }, { "WECON" , &Schedule::handleWECON }, { "WEFAC" , &Schedule::handleWEFAC }, + { "WELCOMPL", &Schedule::handleWELCOMPL }, { "WELOPEN" , &Schedule::handleWELOPEN }, { "WELPI" , &Schedule::handleWELPI }, { "WELSEGS" , &Schedule::handleWELSEGS }, { "WELSPECS", &Schedule::handleWELSPECS }, { "WELTARG" , &Schedule::handleWELTARG }, + { "WELTRAJ" , &Schedule::handleWELTRAJ }, { "WFOAM" , &Schedule::handleWFOAM }, { "WGRUPCON", &Schedule::handleWGRUPCON }, { "WHISTCTL", &Schedule::handleWHISTCTL }, diff --git a/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp b/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp index c68ecfde0..846c9a664 100644 --- a/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp +++ b/src/opm/input/eclipse/Schedule/Well/WellConnections.cpp @@ -1,4 +1,4 @@ -/* +/*addConnectioncell Copyright 2013 Statoil ASA. This file is part of the Open Porous Media project (OPM). @@ -46,6 +46,18 @@ #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include //testing #include @@ -441,6 +453,55 @@ namespace Opm { } } } + + void WellConnections::loadWELCOMPL(const DeckRecord& record, + const ScheduleGrid& grid, + const std::string& wname, + const KeywordLocation& location) { + + const std::string& completionNamePattern = record.getItem("COMPLETION").getTrimmedString(0); + + //Connection::State state = Connection::StateFromString( record.getItem("STATE").getTrimmedString(0) ); + //based on the data of wellCOMPL and trajectory data the ijk coordinates should be derived here. + //unclear how to get trajectory data in this method + const auto& ahdepth_upper = record.getItem("AHDEPTH_UPPER"); + const auto& ahdepth_lower = record.getItem("AHDEPTH_LOWER"); + const auto& diameterItem = record.getItem("DIAMETER"); + double skin_factor = record.getItem("SKIN").getSIDouble(0); + + double rw; + if (diameterItem.hasValue(0)) + rw = 0.50 * diameterItem.getSIDouble(0); + 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; + + //const auto& test = grid.cells; + } + + void WellConnections::loadWELTRAJ(const DeckRecord& record, + const ScheduleGrid& grid, + const std::string& wname, + const KeywordLocation& location) { + + //const std::string& completionNamePattern = record.getItem("COMPLETION").getTrimmedString(0); + + //Connection::State state = Connection::StateFromString( record.getItem("STATE").getTrimmedString(0) ); + ////should we use loadWELTRAJ we may assume (?) that only once a trajectory is created? + //(1) how to store data read in here???? + //(2) how to get info from here to loadWELCOMPL??????? + this->x_coordinate = record.getItem("X").getSIDouble(0); + const auto& y_coordinate = record.getItem("Y"); + const int I = 8; + const int J = 8; + const int K = 2; + + const CompletedCells::Cell& cell = grid.get_cell(I, J, K); + } + + std::size_t WellConnections::size() const { return m_connections.size(); diff --git a/src/opm/input/eclipse/share/keywords/900_OPM/W/WELCOMPL b/src/opm/input/eclipse/share/keywords/900_OPM/W/WELCOMPL new file mode 100644 index 000000000..857fa1c00 --- /dev/null +++ b/src/opm/input/eclipse/share/keywords/900_OPM/W/WELCOMPL @@ -0,0 +1,43 @@ +{ + "name": "WELCOMPL", + "sections": [ + "SCHEDULE" + ], + "items": [ + { + "item": 1, + "name": "WELL", + "value_type": "STRING" + }, + { + "item": 2, + "name": "COMPLETION", + "value_type": "STRING" + }, + { + "item": 3, + "name": "AHDEPTH_UPPER", + "value_type": "DOUBLE", + "dimension": "Length" + }, + { + "item": 4, + "name": "AHDEPTH_LOWER", + "value_type": "DOUBLE", + "dimension": "Length" + }, + { + "item": 5, + "name": "DIAMETER", + "value_type": "DOUBLE", + "dimension": "Length" + }, + { + "item": 6, + "name": "SKIN", + "value_type": "DOUBLE", + "dimension": "1" + } + + ] +} diff --git a/src/opm/input/eclipse/share/keywords/900_OPM/W/WELTRAJ b/src/opm/input/eclipse/share/keywords/900_OPM/W/WELTRAJ new file mode 100644 index 000000000..21181be72 --- /dev/null +++ b/src/opm/input/eclipse/share/keywords/900_OPM/W/WELTRAJ @@ -0,0 +1,37 @@ +{ + "name": "WELTRAJ", + "sections": [ + "SCHEDULE" + ], + "items": [ + { + "item": 1, + "name": "WELL", + "value_type": "STRING" + }, + { + "item": 2, + "name": "X", + "value_type": "DOUBLE", + "dimension": "Length" + }, + { + "item": 3, + "name": "Y", + "value_type": "DOUBLE", + "dimension": "Length" + }, + { + "item": 4, + "name": "TVDEPTH", + "value_type": "DOUBLE", + "dimension": "Length" + }, + { + "item": 5, + "name": "AHDEPTH", + "value_type": "DOUBLE", + "dimension": "Length" + } + ] +} diff --git a/src/opm/input/eclipse/share/keywords/keyword_list.cmake b/src/opm/input/eclipse/share/keywords/keyword_list.cmake index 15073c225..0a07a67cb 100644 --- a/src/opm/input/eclipse/share/keywords/keyword_list.cmake +++ b/src/opm/input/eclipse/share/keywords/keyword_list.cmake @@ -1135,6 +1135,8 @@ set( keywords 900_OPM/T/TLPMIXPA 900_OPM/V/VAPWAT 900_OPM/W/WATJT + 900_OPM/W/WELTRAJ + 900_OPM/W/WELCOMPL 900_OPM/W/WMICP 900_OPM/W/WPMITAB 900_OPM/W/WSKPTAB)