Merge pull request #1394 from joakim-hove/schedule-update-well
Schedule update well
This commit is contained in:
@@ -210,6 +210,9 @@ namespace Opm
|
||||
const Well& getWellatEnd(const std::string& well_name) const;
|
||||
std::vector<Well> getWells(size_t timeStep) const;
|
||||
std::vector<Well> getWellsatEnd() const;
|
||||
void shut_well(const std::string& well_name, std::size_t report_step);
|
||||
void stop_well(const std::string& well_name, std::size_t report_step);
|
||||
void open_well(const std::string& well_name, std::size_t report_step);
|
||||
|
||||
std::vector<const Group*> getChildGroups2(const std::string& group_name, size_t timeStep) const;
|
||||
std::vector<Well> getChildWells2(const std::string& group_name, size_t timeStep) const;
|
||||
@@ -310,7 +313,7 @@ namespace Opm
|
||||
void updateGroup(std::shared_ptr<Group> group, size_t reportStep);
|
||||
bool checkGroups(const ParseContext& parseContext, ErrorGuard& errors);
|
||||
void updateUDQActive( std::size_t timeStep, std::shared_ptr<UDQActive> udq );
|
||||
bool updateWellStatus( const std::string& well, size_t reportStep , Well::Status status);
|
||||
bool updateWellStatus( const std::string& well, size_t reportStep , Well::Status status, bool update_connections);
|
||||
void addWellToGroup( const std::string& group_name, const std::string& well_name , size_t timeStep);
|
||||
void iterateScheduleSection(const ParseContext& parseContext , ErrorGuard& errors, const SCHEDULESection& , const EclipseGrid& grid,
|
||||
const FieldPropsManager& fp,
|
||||
|
||||
@@ -497,7 +497,7 @@ public:
|
||||
bool updateRefDepth(double ref_dpeth);
|
||||
bool updateDrainageRadius(double drainage_radius);
|
||||
bool updateConnections(const std::shared_ptr<WellConnections> connections);
|
||||
bool updateStatus(Status status);
|
||||
bool updateStatus(Status status, bool update_connections);
|
||||
bool updateGroup(const std::string& group);
|
||||
bool updateProducer(bool is_producer);
|
||||
bool updateWellGuideRate(bool available, double guide_rate, GuideRateTarget guide_phase, double scale_factor);
|
||||
|
||||
@@ -96,6 +96,9 @@ void python::common::export_Schedule(py::module& module) {
|
||||
.def_property_readonly( "start", &get_start_time )
|
||||
.def_property_readonly( "end", &get_end_time )
|
||||
.def_property_readonly( "timesteps", &get_timesteps )
|
||||
.def( "shut_well", &Schedule::shut_well)
|
||||
.def( "open_well", &Schedule::open_well)
|
||||
.def( "stop_well", &Schedule::stop_well)
|
||||
.def( "get_wells", &Schedule::getWells)
|
||||
.def( "get_well", &get_well)
|
||||
.def( "__contains__", &has_well )
|
||||
|
||||
@@ -57,6 +57,17 @@ class TestSchedule(unittest.TestCase):
|
||||
with self.assertRaises(ValueError):
|
||||
self.sch.group('foo', 0)
|
||||
|
||||
def test_open_shut(self):
|
||||
deck = Parser().parse(test_path('spe3/SPE3CASE1.DATA'))
|
||||
state = EclipseState(deck)
|
||||
sch = Schedule( deck, state )
|
||||
prod = sch.get_well("PROD", 1)
|
||||
self.assertEqual(prod.status(), "OPEN")
|
||||
|
||||
sch.shut_well("PROD", 10)
|
||||
prod = sch.get_well("PROD", 10)
|
||||
self.assertEqual(prod.status(), "SHUT")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
@@ -813,7 +813,7 @@ namespace {
|
||||
invalidNamePattern(wellNamePattern, parseContext, errors, keyword);
|
||||
|
||||
for( const auto& well_name : well_names) {
|
||||
updateWellStatus( well_name , currentStep , status );
|
||||
updateWellStatus( well_name , currentStep , status, false );
|
||||
{
|
||||
auto& dynamic_state = this->wells_static.at(well_name);
|
||||
auto well2 = std::make_shared<Well>(*dynamic_state[currentStep]);
|
||||
@@ -856,7 +856,7 @@ namespace {
|
||||
"Well " + well2->name() + " is a history matched well with zero rate where crossflow is banned. " +
|
||||
"This well will be closed at " + std::to_string ( m_timeMap.getTimePassedUntil(currentStep) / (60*60*24) ) + " days";
|
||||
OpmLog::note(msg);
|
||||
updateWellStatus( well_name, currentStep, Well::Status::SHUT );
|
||||
updateWellStatus( well_name, currentStep, Well::Status::SHUT, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -877,7 +877,7 @@ namespace {
|
||||
|
||||
for( const auto& well_name : well_names) {
|
||||
|
||||
updateWellStatus( well_name , currentStep , status );
|
||||
updateWellStatus( well_name , currentStep , status, false );
|
||||
{
|
||||
auto& dynamic_state = this->wells_static.at(well_name);
|
||||
auto well2 = std::make_shared<Well>(*dynamic_state[currentStep]);
|
||||
@@ -917,6 +917,18 @@ namespace {
|
||||
}
|
||||
|
||||
|
||||
void Schedule::shut_well(const std::string& well_name, std::size_t report_step) {
|
||||
this->updateWellStatus(well_name, report_step, Well::Status::SHUT, true);
|
||||
}
|
||||
|
||||
void Schedule::open_well(const std::string& well_name, std::size_t report_step) {
|
||||
this->updateWellStatus(well_name, report_step, Well::Status::OPEN, true);
|
||||
}
|
||||
|
||||
void Schedule::stop_well(const std::string& well_name, std::size_t report_step) {
|
||||
this->updateWellStatus(well_name, report_step, Well::Status::STOP, true);
|
||||
}
|
||||
|
||||
void Schedule::updateWell(std::shared_ptr<Well> well, size_t reportStep) {
|
||||
auto& dynamic_state = this->wells_static.at(well->name());
|
||||
dynamic_state.update(reportStep, well);
|
||||
@@ -927,19 +939,17 @@ namespace {
|
||||
Function is quite dangerous - because if this is called while holding a
|
||||
Well pointer that will go stale and needs to be refreshed.
|
||||
*/
|
||||
bool Schedule::updateWellStatus( const std::string& well_name, size_t reportStep , Well::Status status) {
|
||||
bool Schedule::updateWellStatus( const std::string& well_name, size_t reportStep , Well::Status status, bool update_connections) {
|
||||
bool update = false;
|
||||
{
|
||||
auto& dynamic_state = this->wells_static.at(well_name);
|
||||
auto well2 = std::make_shared<Well>(*dynamic_state[reportStep]);
|
||||
if (well2->updateStatus(status)) {
|
||||
m_events.addEvent( ScheduleEvents::WELL_STATUS_CHANGE, reportStep );
|
||||
this->addWellGroupEvent( well2->name(), ScheduleEvents::WELL_STATUS_CHANGE, reportStep);
|
||||
this->updateWell(well2, reportStep);
|
||||
update = true;
|
||||
if (status == Well::Status::OPEN)
|
||||
this->rft_config.addWellOpen(well_name, reportStep);
|
||||
}
|
||||
auto& dynamic_state = this->wells_static.at(well_name);
|
||||
auto well2 = std::make_shared<Well>(*dynamic_state[reportStep]);
|
||||
if (well2->updateStatus(status, update_connections)) {
|
||||
m_events.addEvent( ScheduleEvents::WELL_STATUS_CHANGE, reportStep );
|
||||
this->addWellGroupEvent( well2->name(), ScheduleEvents::WELL_STATUS_CHANGE, reportStep);
|
||||
this->updateWell(well2, reportStep);
|
||||
update = true;
|
||||
if (status == Well::Status::OPEN)
|
||||
this->rft_config.addWellOpen(well_name, reportStep);
|
||||
}
|
||||
return update;
|
||||
}
|
||||
@@ -973,7 +983,7 @@ namespace {
|
||||
|
||||
for( const auto& well_name : well_names ) {
|
||||
Well::Status status = Well::StatusFromString( record.getItem("STATUS").getTrimmedString(0));
|
||||
updateWellStatus( well_name , currentStep , status );
|
||||
updateWellStatus( well_name , currentStep , status, false );
|
||||
{
|
||||
bool update_well = false;
|
||||
auto& dynamic_state = this->wells_static.at(well_name);
|
||||
@@ -1006,14 +1016,14 @@ namespace {
|
||||
if (injection->surfaceInjectionRate.is<double>()) {
|
||||
if (injection->hasInjectionControl(Well::InjectorCMode::RATE) && injection->surfaceInjectionRate.zero()) {
|
||||
OpmLog::note(msg);
|
||||
updateWellStatus( well_name, currentStep, Well::Status::SHUT );
|
||||
updateWellStatus( well_name, currentStep, Well::Status::SHUT, false );
|
||||
}
|
||||
}
|
||||
|
||||
if (injection->reservoirInjectionRate.is<double>()) {
|
||||
if (injection->hasInjectionControl(Well::InjectorCMode::RESV) && injection->reservoirInjectionRate.zero()) {
|
||||
OpmLog::note(msg);
|
||||
updateWellStatus( well_name, currentStep, Well::Status::SHUT );
|
||||
updateWellStatus( well_name, currentStep, Well::Status::SHUT, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1036,7 +1046,7 @@ namespace {
|
||||
invalidNamePattern( wellNamePattern, parseContext, errors, keyword);
|
||||
|
||||
for (const auto& well_name : well_names) {
|
||||
updateWellStatus( well_name, currentStep, status );
|
||||
updateWellStatus( well_name, currentStep, status, false );
|
||||
{
|
||||
bool update_well = false;
|
||||
auto& dynamic_state = this->wells_static.at(well_name);
|
||||
@@ -1064,7 +1074,7 @@ namespace {
|
||||
"Well " + well_name + " is an injector with zero rate where crossflow is banned. " +
|
||||
"This well will be closed at " + std::to_string ( m_timeMap.getTimePassedUntil(currentStep) / (60*60*24) ) + " days";
|
||||
OpmLog::note(msg);
|
||||
updateWellStatus( well_name, currentStep, Well::Status::SHUT );
|
||||
updateWellStatus( well_name, currentStep, Well::Status::SHUT, false );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1466,7 +1476,7 @@ namespace {
|
||||
+ std::to_string( days ) + " days";
|
||||
OpmLog::note(msg);
|
||||
} else {
|
||||
this->updateWellStatus( wname, currentStep, well_status );
|
||||
this->updateWellStatus( wname, currentStep, well_status, false );
|
||||
if (well_status == open)
|
||||
this->rft_config.addWellOpen(wname, currentStep);
|
||||
|
||||
@@ -2062,7 +2072,7 @@ namespace {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Schedule::handleWSEGVALV( const DeckKeyword& keyword, size_t currentStep) {
|
||||
const std::map<std::string, std::vector<std::pair<int, Valve> > > valves = Valve::fromWSEGVALV(keyword);
|
||||
|
||||
@@ -2697,7 +2707,7 @@ void Schedule::handleGRUPTREE( const DeckKeyword& keyword, size_t currentStep, c
|
||||
const auto& well = this->getWell(wname, timeStep);
|
||||
const auto& connections = well.getConnections();
|
||||
if (connections.allConnectionsShut())
|
||||
this->updateWellStatus( well.name(), timeStep, Well::Status::SHUT);
|
||||
this->updateWellStatus( well.name(), timeStep, Well::Status::SHUT, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -379,13 +379,41 @@ bool Well::updateHead(int I, int J) {
|
||||
}
|
||||
|
||||
|
||||
bool Well::updateStatus(Status status_arg) {
|
||||
if (this->status != status_arg) {
|
||||
this->status = status_arg;
|
||||
return true;
|
||||
bool Well::updateStatus(Status well_state, bool update_connections) {
|
||||
bool update = false;
|
||||
if (update_connections) {
|
||||
Connection::State connection_state;
|
||||
|
||||
switch (well_state) {
|
||||
case Status::OPEN:
|
||||
connection_state = Connection::State::OPEN;
|
||||
break;
|
||||
case Status::SHUT:
|
||||
connection_state = Connection::State::SHUT;
|
||||
break;
|
||||
case Status::AUTO:
|
||||
connection_state = Connection::State::AUTO;
|
||||
break;
|
||||
case Status::STOP:
|
||||
connection_state = Connection::State::SHUT;
|
||||
break;
|
||||
}
|
||||
|
||||
auto new_connections = std::make_shared<WellConnections>(this->headI, this->headJ);
|
||||
for (auto c : *this->connections) {
|
||||
c.setState(connection_state);
|
||||
new_connections->add(c);
|
||||
}
|
||||
|
||||
update = this->updateConnections(new_connections);
|
||||
}
|
||||
|
||||
return false;
|
||||
if (this->status != well_state) {
|
||||
this->status = well_state;
|
||||
update = true;
|
||||
}
|
||||
|
||||
return update;
|
||||
}
|
||||
|
||||
|
||||
@@ -627,7 +655,7 @@ Phase Well::getPreferredPhase() const {
|
||||
When all connections of a well are closed with the WELOPEN keywords, the well
|
||||
itself should also be SHUT. In the main parsing code this is handled by the
|
||||
function checkIfAllConnectionsIsShut() which is called at the end of every
|
||||
report step in Schedule::iterateScheduleSection(). This is donn in this way
|
||||
report step in Schedule::iterateScheduleSection(). This is done in this way
|
||||
because there is some twisted logic aggregating connection changes over a
|
||||
complete report step.
|
||||
|
||||
@@ -666,6 +694,10 @@ bool Well::handleWELOPEN(const DeckRecord& record, Connection::State state_arg,
|
||||
return this->updateConnections(new_connections);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
bool Well::handleCOMPLUMP(const DeckRecord& record) {
|
||||
|
||||
auto match = [=]( const Connection &c) -> bool {
|
||||
|
||||
@@ -3351,9 +3351,9 @@ BOOST_AUTO_TEST_CASE(WELL_STATIC) {
|
||||
BOOST_CHECK(ws.updateRefDepth(1.0));
|
||||
BOOST_CHECK(!ws.updateRefDepth(1.0));
|
||||
|
||||
ws.updateStatus(Well::Status::OPEN);
|
||||
BOOST_CHECK(!ws.updateStatus(Well::Status::OPEN));
|
||||
BOOST_CHECK(ws.updateStatus(Well::Status::SHUT));
|
||||
ws.updateStatus(Well::Status::OPEN, false);
|
||||
BOOST_CHECK(!ws.updateStatus(Well::Status::OPEN, false));
|
||||
BOOST_CHECK(ws.updateStatus(Well::Status::SHUT, false));
|
||||
|
||||
const auto& connections = ws.getConnections();
|
||||
BOOST_CHECK_EQUAL(connections.size(), 0);
|
||||
|
||||
@@ -78,13 +78,13 @@ BOOST_AUTO_TEST_CASE(WTEST_STATE2) {
|
||||
std::vector<Well> wells;
|
||||
wells.emplace_back("WELL_NAME", "A", 0, 0, 1, 1, 200., Phase::OIL, Well::ProducerCMode::NONE, Connection::Order::TRACK, us, 0.);
|
||||
{
|
||||
wells[0].updateStatus(Well::Status::SHUT);
|
||||
wells[0].updateStatus(Well::Status::SHUT, false);
|
||||
auto shut_wells = st.updateWells(wc, wells, 5000);
|
||||
BOOST_CHECK_EQUAL(shut_wells.size(), 0);
|
||||
}
|
||||
|
||||
{
|
||||
wells[0].updateStatus(Well::Status::OPEN);
|
||||
wells[0].updateStatus(Well::Status::OPEN, false);
|
||||
auto shut_wells = st.updateWells(wc, wells, 5000);
|
||||
BOOST_CHECK_EQUAL( shut_wells.size(), 1);
|
||||
}
|
||||
@@ -115,12 +115,12 @@ BOOST_AUTO_TEST_CASE(WTEST_STATE) {
|
||||
|
||||
WellTestConfig wc;
|
||||
{
|
||||
wells[0].updateStatus(Well::Status::SHUT);
|
||||
wells[0].updateStatus(Well::Status::SHUT, false);
|
||||
auto shut_wells = st.updateWells(wc, wells, 110. * day);
|
||||
BOOST_CHECK_EQUAL(shut_wells.size(), 0);
|
||||
}
|
||||
{
|
||||
wells[0].updateStatus(Well::Status::OPEN);
|
||||
wells[0].updateStatus(Well::Status::OPEN, false);
|
||||
auto shut_wells = st.updateWells(wc, wells, 110. * day);
|
||||
BOOST_CHECK_EQUAL(shut_wells.size(), 0);
|
||||
}
|
||||
@@ -151,10 +151,10 @@ BOOST_AUTO_TEST_CASE(WTEST_STATE) {
|
||||
wc.add_well("WELL_NAME", WellTestConfig::Reason::PHYSICAL, 1000. * day, 3, 0, 5);
|
||||
|
||||
|
||||
wells[0].updateStatus(Well::Status::SHUT);
|
||||
wells[0].updateStatus(Well::Status::SHUT, false);
|
||||
BOOST_CHECK_EQUAL( st.updateWells(wc, wells, 4100. * day).size(), 0);
|
||||
|
||||
wells[0].updateStatus(Well::Status::OPEN);
|
||||
wells[0].updateStatus(Well::Status::OPEN, false);
|
||||
BOOST_CHECK_EQUAL( st.updateWells(wc, wells, 4100. * day).size(), 1);
|
||||
|
||||
BOOST_CHECK_EQUAL( st.updateWells(wc, wells, 5200. * day).size(), 1);
|
||||
@@ -182,9 +182,9 @@ BOOST_AUTO_TEST_CASE(WTEST_STATE_COMPLETIONS) {
|
||||
const UnitSystem us{};
|
||||
std::vector<Well> wells;
|
||||
wells.emplace_back("WELL_NAME", "A", 0, 0, 1, 1, 200., Phase::OIL, Well::ProducerCMode::NONE, Connection::Order::TRACK, us, 0.);
|
||||
wells[0].updateStatus(Well::Status::OPEN);
|
||||
wells[0].updateStatus(Well::Status::OPEN, false);
|
||||
wells.emplace_back("WELLX", "A", 0, 0, 2, 2, 200., Phase::OIL, Well::ProducerCMode::NONE, Connection::Order::TRACK, us, 0.);
|
||||
wells[1].updateStatus(Well::Status::OPEN);
|
||||
wells[1].updateStatus(Well::Status::OPEN, false);
|
||||
|
||||
auto closed_completions = st.updateWells(wc, wells, 5000);
|
||||
BOOST_CHECK_EQUAL( closed_completions.size(), 0);
|
||||
|
||||
Reference in New Issue
Block a user