Changes to Well status implementation

o The status of a well is maintened as a small object which is managed by a new
   std::shared_ptr member in the well objects. The consequence of this is that
   several well objects can share the same underlying status object. The
   advantage of this is that runtime (i.e. ACTIONX) updates of well status will
   affect the correct set of wells.

 o The general Schedule::updateWell() will use the DynamicState::upadte_equal()
This commit is contained in:
Joakim Hove
2020-12-04 16:04:40 +01:00
parent 85e2c641d3
commit 2e832f0fbe
9 changed files with 316 additions and 74 deletions

View File

@@ -573,20 +573,20 @@ private:
}
void Schedule::shut_well(const std::string& well_name, std::size_t report_step) {
this->updateWellStatus(well_name, report_step, Well::Status::SHUT, true);
this->updateWellStatus(well_name, report_step, true, Well::Status::SHUT, false);
}
void Schedule::open_well(const std::string& well_name, std::size_t report_step) {
this->updateWellStatus(well_name, report_step, Well::Status::OPEN, true);
this->updateWellStatus(well_name, report_step, true, Well::Status::OPEN, false);
}
void Schedule::stop_well(const std::string& well_name, std::size_t report_step) {
this->updateWellStatus(well_name, report_step, Well::Status::STOP, true);
this->updateWellStatus(well_name, report_step, true, Well::Status::STOP, false);
}
void Schedule::updateWell(std::shared_ptr<Well> well, std::size_t reportStep) {
auto& dynamic_state = this->wells_static.at(well->name());
dynamic_state.update(reportStep, std::move(well));
dynamic_state.update_equal(reportStep, std::move(well));
}
@@ -594,7 +594,7 @@ private:
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, std::size_t reportStep , Well::Status status, bool update_connections, std::optional<KeywordLocation> location) {
bool Schedule::updateWellStatus( const std::string& well_name, std::size_t reportStep , bool runtime, Well::Status status, bool update_connections, std::optional<KeywordLocation> location) {
auto& dynamic_state = this->wells_static.at(well_name);
auto well2 = std::make_shared<Well>(*dynamic_state[reportStep]);
if (well2->getConnections().empty() && status == Well::Status::OPEN) {
@@ -608,14 +608,26 @@ private:
return false;
}
auto old_status = well2->getStatus();
bool update = false;
if (well2->updateStatus(status, update_connections)) {
m_events.addEvent( ScheduleEvents::WELL_STATUS_CHANGE, reportStep );
this->addWellGroupEvent( well2->name(), ScheduleEvents::WELL_STATUS_CHANGE, reportStep);
if (well2->updateStatus(status, runtime, update_connections)) {
this->updateWell(well2, reportStep);
update = true;
if (status == Well::Status::OPEN)
this->rft_config.addWellOpen(well_name, reportStep);
/*
The Well::updateStatus() will always return true because a new
WellStatus object should be created. But the new object might have
the same value as the previous object; therefor we need to check
for an actual status change before we emit a WELL_STATUS_CHANGE
event.
*/
if (old_status != status) {
this->m_events.addEvent( ScheduleEvents::WELL_STATUS_CHANGE, reportStep );
this->addWellGroupEvent( well2->name(), ScheduleEvents::WELL_STATUS_CHANGE, reportStep);
}
update = true;
}
return update;
}
@@ -654,7 +666,7 @@ private:
}
}
void Schedule::applyWELOPEN(const DeckKeyword& keyword, std::size_t currentStep, const ParseContext& parseContext, ErrorGuard& errors, const std::vector<std::string>& matching_wells) {
void Schedule::applyWELOPEN(const DeckKeyword& keyword, std::size_t currentStep, bool runtime, const ParseContext& parseContext, ErrorGuard& errors, const std::vector<std::string>& matching_wells) {
auto conn_defaulted = []( const DeckRecord& rec ) {
auto defaulted = []( const DeckItem& item ) {
@@ -665,7 +677,6 @@ private:
};
constexpr auto open = Well::Status::OPEN;
bool action_mode = !matching_wells.empty();
for (const auto& record : keyword) {
const auto& wellNamePattern = record.getItem( "WELL" ).getTrimmedString(0);
@@ -690,7 +701,7 @@ private:
+ std::to_string( days ) + " days";
OpmLog::note(msg);
} else {
this->updateWellStatus( wname, currentStep, well_status, false );
this->updateWellStatus( wname, currentStep, runtime, well_status, false );
if (well_status == open)
this->rft_config.addWellOpen(wname, currentStep);
}
@@ -705,7 +716,7 @@ private:
{
auto& dynamic_state = this->wells_static.at(wname);
auto well_ptr = std::make_shared<Well>( *dynamic_state[currentStep] );
if (well_ptr->handleWELOPEN(record, comp_status, action_mode))
if (well_ptr->handleWELOPEN(record, comp_status, runtime))
// The updateWell call breaks test at line 825 and 831 in ScheduleTests
this->updateWell(std::move(well_ptr), currentStep);
}
@@ -876,7 +887,7 @@ private:
const std::string wname = well.name();
m_events.addEvent( ScheduleEvents::NEW_WELL , report_step );
wellgroup_events.insert( std::make_pair(wname, Events(this->m_timeMap)));
this->wellgroup_events.insert( std::make_pair(wname, Events(this->m_timeMap)));
this->addWellGroupEvent(wname, ScheduleEvents::NEW_WELL, report_step);
well.setInsertIndex(this->wells_static.size());
@@ -1372,7 +1383,7 @@ private:
"All completions in well " + well.name() + " is shut at " + std::to_string ( m_timeMap.getTimePassedUntil(timeStep) / (60*60*24) ) + " days. \n" +
"The well is therefore also shut.";
OpmLog::note(msg);
this->updateWellStatus( well.name(), timeStep, Well::Status::SHUT, false);
this->updateWellStatus( well.name(), timeStep, false, Well::Status::SHUT, false);
}
}
}
@@ -1533,7 +1544,7 @@ private:
this->updateUDQ(keyword, reportStep);
if (keyword.name() == "WELOPEN")
this->applyWELOPEN(keyword, reportStep, parseContext, errors, result.wells());
this->applyWELOPEN(keyword, reportStep, true, parseContext, errors, result.wells());
/*
The WELPI functionality is implemented as a two-step process