Merge pull request #3116 from joakim-hove/action-update-ecl-well

Update ecl wells for all matching wells after actionx
This commit is contained in:
Joakim Hove 2021-03-30 07:56:14 +02:00 committed by GitHub
commit 7ea78e9c36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 80 additions and 54 deletions

View File

@ -45,6 +45,7 @@
#include <dune/geometry/referenceelements.hh>
#include <map>
#include <unordered_set>
namespace Opm {
@ -1449,8 +1450,8 @@ protected:
void
updateEclWell(int, const std::string&) {
throw std::logic_error("updateEclWell() method not implemented for class eclpeacemanwell");
updateEclWells(int, const std::unordered_set<std::string>&) {
throw std::logic_error("updateEclWells() method not implemented for class eclpeacemanwell");
}

View File

@ -1377,6 +1377,7 @@ public:
pyaction->run(ecl_state, schedule, reportStep, summaryState);
}
bool commit_wellstate = false;
auto simTime = schedule.simTime(reportStep);
for (const auto& action : actions.pending(actionState, simTime)) {
auto actionResult = action->eval(context);
@ -1393,19 +1394,24 @@ public:
const auto& wellpi = this->fetchWellPI(reportStep, *action, schedule, matching_wells);
schedule.applyAction(reportStep, Opm::TimeService::from_time_t(simTime), *action, actionResult, wellpi);
auto affected_wells = schedule.applyAction(reportStep, Opm::TimeService::from_time_t(simTime), *action, actionResult, wellpi);
actionState.add_run(*action, simTime);
for ( const auto& [wname, _] : wellpi) {
(void)_;
if (this->wellModel_.hasWell(wname))
this->wellModel_.updateEclWell(reportStep, wname);
}
this->wellModel_.updateEclWells(reportStep, affected_wells);
if (!affected_wells.empty())
commit_wellstate = true;
} else {
std::string msg = "The action: " + action->name() + " evaluated to false at " + ts;
Opm::OpmLog::info(msg);
}
}
/*
The well state has been stored in a previous object when the time step
has completed successfully, the action process might have modified the
well state, and to be certain that is not overwritten when starting
the next timestep we must commit it.
*/
if (commit_wellstate)
this->wellModel_.commitWellState();
}

View File

@ -51,6 +51,7 @@
#include <dune/grid/common/gridenums.hh>
#include <map>
#include <unordered_set>
#include <string>
#include <vector>
@ -658,7 +659,7 @@ public:
void
updateEclWell(int, const std::string&) {
updateEclWells(int, const std::unordered_set<std::string>&) {
throw std::logic_error("wellPI() method not implemented for class eclwellmanager");
}

View File

@ -365,8 +365,7 @@ namespace Opm {
/// Returns true if the well was actually found and shut.
bool forceShutWellByNameIfPredictionMode(const std::string& wellname, const double simulation_time);
void updateEclWell(const int timeStepIdx, const int well_index);
void updateEclWell(const int timeStepIdx, const std::string& wname);
void updateEclWells(const int timeStepIdx, const std::unordered_set<std::string>& wells);
bool hasWell(const std::string& wname);
double wellPI(const int well_index) const;
double wellPI(const std::string& well_name) const;

View File

@ -2622,55 +2622,38 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
updateEclWell(const int timeStepIdx, const int well_index)
{
updateEclWells(const int timeStepIdx, const std::unordered_set<std::string>& wells) {
const auto& schedule = this->ebosSimulator_.vanguard().schedule();
const auto& wname = this->wells_ecl_[well_index].name();
this->wells_ecl_[well_index] = schedule.getWell(wname, timeStepIdx);
for (const auto& wname : wells) {
auto well_iter = std::find_if( this->wells_ecl_.begin(), this->wells_ecl_.end(), [wname] (const auto& well) -> bool { return well.name() == wname;});
if (well_iter != this->wells_ecl_.end()) {
auto well_index = std::distance( this->wells_ecl_.begin(), well_iter );
this->wells_ecl_[well_index] = schedule.getWell(wname, timeStepIdx);
const auto& well = this->wells_ecl_[well_index];
auto& pd = this->well_perf_data_[well_index];
auto pdIter = pd.begin();
for (const auto& conn : well.getConnections()) {
if (conn.state() != Connection::State::SHUT) {
pdIter->connection_transmissibility_factor = conn.CF();
++pdIter;
const auto& well = this->wells_ecl_[well_index];
auto& pd = this->well_perf_data_[well_index];
auto pdIter = pd.begin();
for (const auto& conn : well.getConnections()) {
if (conn.state() != Connection::State::SHUT) {
pdIter->connection_transmissibility_factor = conn.CF();
++pdIter;
}
}
this->wellState().updateStatus(well_index, well.getStatus());
this->wellState().resetConnectionTransFactors(well_index, pd);
this->prod_index_calc_[well_index].reInit(well);
}
}
this->wellState().resetConnectionTransFactors(well_index, pd);
this->prod_index_calc_[well_index].reInit(well);
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
updateEclWell(const int timeStepIdx, const std::string& wname)
{
auto well_iter = std::find_if(this->wells_ecl_.begin(), this->wells_ecl_.end(),
[&wname](const auto& well) -> bool
{
return well.name() == wname;
});
if (well_iter == this->wells_ecl_.end()) {
throw std::logic_error { "Could not find well: " + wname };
}
auto well_index = std::distance(this->wells_ecl_.begin(), well_iter);
this->updateEclWell(timeStepIdx, well_index);
}
template<typename TypeTag>
double
BlackoilWellModel<TypeTag>::
@ -2762,6 +2745,26 @@ namespace Opm {
ScheduleEvents::Events::WELL_PRODUCTIVITY_INDEX);
};
auto updateEclWell = [this, timeStepIdx](const int well_index) -> void
{
const auto& schedule = this->schedule();
const auto& wname = this->wells_ecl_[well_index].name();
this->wells_ecl_[well_index] = schedule.getWell(wname, timeStepIdx);
const auto& well = this->wells_ecl_[well_index];
auto& pd = this->well_perf_data_[well_index];
auto pdIter = pd.begin();
for (const auto& conn : well.getConnections()) {
if (conn.state() != Connection::State::SHUT) {
pdIter->connection_transmissibility_factor = conn.CF();
++pdIter;
}
}
this->wellState().resetConnectionTransFactors(well_index, pd);
this->prod_index_calc_[well_index].reInit(well);
};
auto rescaleWellPI =
[this, timeStepIdx](const int well_index,
const double newWellPI) -> void
@ -2770,8 +2773,6 @@ namespace Opm {
auto& schedule = this->ebosSimulator_.vanguard().schedule(); // Mutable
schedule.applyWellProdIndexScaling(wname, timeStepIdx, newWellPI);
this->updateEclWell(timeStepIdx, well_index);
};
// Minimal well setup to compute PI/II values
@ -2797,6 +2798,7 @@ namespace Opm {
for (auto wellID = 0*nw; wellID < nw; ++wellID) {
if (hasWellPIEvent(wellID)) {
rescaleWellPI(wellID, this->wellPI(wellID));
updateEclWell(wellID);
}
}

View File

@ -239,6 +239,22 @@ namespace Opm
this->thp_[well_index] = 0;
}
void updateStatus(int well_index, Well::Status status) {
switch (status) {
case Well::Status::OPEN:
this->openWell(well_index);
break;
case Well::Status::SHUT:
this->shutWell(well_index);
break;
case Well::Status::STOP:
this->stopWell(well_index);
break;
default:
throw std::logic_error("Invalid well status");
}
}
virtual data::Wells
report(const PhaseUsage& pu,
const int* globalCellIdxMap,

View File

@ -66,6 +66,7 @@ namespace Opm
using BaseType :: numWells;
using BaseType :: numPhases;
using BaseType :: resetConnectionTransFactors;
using BaseType :: updateStatus;
/// Allocate and initialize if wells is non-null. Also tries
/// to give useful initial values to the bhp(), wellRates()
@ -166,8 +167,8 @@ namespace Opm
is_producer_[w] = wells_ecl[w].isProducer();
}
current_injection_controls_.resize(nw);
current_production_controls_.resize(nw);
current_injection_controls_.resize(nw, Well::InjectorCMode::CMODE_UNDEFINED);
current_production_controls_.resize(nw, Well::ProducerCMode::CMODE_UNDEFINED);
for (int w = 0; w < nw; ++w) {
if (wells_ecl[w].isProducer()) {
const auto controls = wells_ecl[w].productionControls(summary_state);