Mark wells with negative and trivial potentials as not operable

The simulator will try to compute potentials at every iterations to
try to reopen the well.
This commit is contained in:
Tor Harald Sandve
2021-11-18 11:57:16 +00:00
parent d163bebcdc
commit b5cdb1048a
8 changed files with 124 additions and 8 deletions

View File

@@ -2374,4 +2374,20 @@ runWellPIScaling(const int timeStepIdx,
this->last_run_wellpi_ = timeStepIdx; this->last_run_wellpi_ = timeStepIdx;
} }
bool
BlackoilWellModelGeneric::
guideRateUpdateIsNeeded() const {
int update = 0;
for (const auto& well : well_container_generic_) {
if (well->changedToOpenThisStep()) {
update = 1;
break;
}
}
update = comm_.max(update);
return update;
}
} }

View File

@@ -396,6 +396,8 @@ protected:
const SummaryConfig& summaryConfig, const SummaryConfig& summaryConfig,
DeferredLogger& deferred_logger); DeferredLogger& deferred_logger);
bool guideRateUpdateIsNeeded() const;
// create the well container // create the well container
virtual void createWellContainer(const int time_step) = 0; virtual void createWellContainer(const int time_step) = 0;
virtual void initWellContainer() = 0; virtual void initWellContainer() = 0;

View File

@@ -840,6 +840,18 @@ namespace Opm {
} }
OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger, "assemble() failed: ", OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger, "assemble() failed: ",
terminal_output_, grid().comm()); terminal_output_, grid().comm());
//update guide rates
if (guideRateUpdateIsNeeded()) {
const int reportStepIdx = ebosSimulator_.episodeIndex();
const double simulationTime = ebosSimulator_.time();
const auto& comm = ebosSimulator_.vanguard().grid().comm();
const auto& summaryState = ebosSimulator_.vanguard().summaryState();
std::vector<double> pot(numPhases(), 0.0);
const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx);
WellGroupHelpers::updateGuideRates(fieldGroup, schedule(), summaryState, this->phase_usage_, reportStepIdx, simulationTime,
this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger);
}
last_report_.converged = true; last_report_.converged = true;
last_report_.assemble_time_well += perfTimer.stop(); last_report_.assemble_time_well += perfTimer.stop();
} }
@@ -1343,7 +1355,8 @@ namespace Opm {
// and updated only if sucessfull. i.e. the potentials are zero for exceptions // and updated only if sucessfull. i.e. the potentials are zero for exceptions
auto& ws = this->wellState().well(well->indexOfWell()); auto& ws = this->wellState().well(well->indexOfWell());
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
ws.well_potentials[p] = std::abs(potentials[p]); // make sure the potentials are positive
ws.well_potentials[p] = std::max(0.0, potentials[p]);
} }
} }
@@ -1424,8 +1437,13 @@ namespace Opm {
events.clearEvent(WellState::event_mask); events.clearEvent(WellState::event_mask);
} }
// solve the well equation initially to improve the initial solution of the well model // solve the well equation initially to improve the initial solution of the well model
if (param_.solve_welleq_initially_) { if (param_.solve_welleq_initially_ && well->isOperableAndSolvable()) {
well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), deferred_logger); try {
well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), deferred_logger);
} catch (const std::exception& e) {
const std::string msg = "Compute initial well solution for " + well->name() + " initially failed. Continue with the privious rates";
deferred_logger.warning("WELL_INITIAL_SOLVE_FAILED", msg);
}
} }
} }
updatePrimaryVariables(deferred_logger); updatePrimaryVariables(deferred_logger);

View File

@@ -112,6 +112,11 @@ computeWellRates_(
-potentials[this->water_pos_]); -potentials[this->water_pos_]);
displayDebugMessage_(msg); displayDebugMessage_(msg);
} }
for (size_t phase = 0; phase < potentials.size(); ++phase){
// make sure the potentials are negative
potentials[phase] = std::min(0.0, potentials[phase]);
}
} }
template<typename TypeTag> template<typename TypeTag>

View File

@@ -253,6 +253,7 @@ namespace Opm
if (this->wellIsStopped()) { if (this->wellIsStopped()) {
return; return;
} }
this->operability_status_.has_non_positive_potentials = false;
// If the well is pressure controlled the potential equals the rate. // If the well is pressure controlled the potential equals the rate.
bool thp_controlled_well = false; bool thp_controlled_well = false;
@@ -285,9 +286,20 @@ namespace Opm
// if the rates are trivial we are most probably looking at the newly // if the rates are trivial we are most probably looking at the newly
// opened well and we therefore make the affort of computing the potentials anyway. // opened well and we therefore make the affort of computing the potentials anyway.
if (std::abs(total_rate) > 0) { if (std::abs(total_rate) > 0) {
const double sign = this->isInjector() ? 1.0:-1.0;
double total_potential = 0.0;
for (int phase = 0; phase < np; ++phase){ for (int phase = 0; phase < np; ++phase){
well_potentials[phase] = ws.surface_rates[phase]; well_potentials[phase] = sign * ws.surface_rates[phase];
total_potential += well_potentials[phase];
} }
if (total_potential <= 0.0) {
// wells with trivial or non-positive potentials
// are not operable
this->operability_status_.has_non_positive_potentials = true;
const std::string msg = std::string("well ") + this->name() + std::string(": has non positive potentials and is not operable");
deferred_logger.info(msg);
}
return; return;
} }
} }
@@ -302,6 +314,20 @@ namespace Opm
} }
deferred_logger.debug("Cost in iterations of finding well potential for well " deferred_logger.debug("Cost in iterations of finding well potential for well "
+ this->name() + ": " + std::to_string(debug_cost_counter_)); + this->name() + ": " + std::to_string(debug_cost_counter_));
const double sign = this->isInjector() ? 1.0:-1.0;
double total_potential = 0.0;
for (int phase = 0; phase < np; ++phase){
well_potentials[phase] *= sign;
total_potential += well_potentials[phase];
}
if (total_potential <= 0.0) {
// wells with trivial or non-positive potentials
// are not operable
this->operability_status_.has_non_positive_potentials = true;
const std::string msg = std::string("well ") + this->name() + std::string(": has non positive potentials is not operable");
deferred_logger.info(msg);
}
} }

View File

@@ -1868,6 +1868,7 @@ namespace Opm
return; return;
} }
this->operability_status_.has_non_positive_potentials = false;
// If the well is pressure controlled the potential equals the rate. // If the well is pressure controlled the potential equals the rate.
bool thp_controlled_well = false; bool thp_controlled_well = false;
bool bhp_controlled_well = false; bool bhp_controlled_well = false;
@@ -1899,8 +1900,18 @@ namespace Opm
// if the rates are trivial we are most probably looking at the newly // if the rates are trivial we are most probably looking at the newly
// opened well and we therefore make the affort of computing the potentials anyway. // opened well and we therefore make the affort of computing the potentials anyway.
if (std::abs(total_rate) > 0) { if (std::abs(total_rate) > 0) {
const double sign = this->isInjector() ? 1.0:-1.0;
double total_potential = 0.0;
for (int phase = 0; phase < np; ++phase){ for (int phase = 0; phase < np; ++phase){
well_potentials[phase] = ws.surface_rates[phase]; well_potentials[phase] = sign * ws.surface_rates[phase];
total_potential += well_potentials[phase];
}
if (total_potential <= 0.0) {
// wells with trivial or non-positive potentials
// are not operable
this->operability_status_.has_non_positive_potentials = true;
const std::string msg = std::string("well ") + this->name() + std::string(": has non positive potentials and is not operable");
deferred_logger.info(msg);
} }
return; return;
} }
@@ -1917,6 +1928,20 @@ namespace Opm
// the well has a THP related constraint // the well has a THP related constraint
well_potentials = computeWellPotentialWithTHP(ebosSimulator, deferred_logger, well_state); well_potentials = computeWellPotentialWithTHP(ebosSimulator, deferred_logger, well_state);
} }
const double sign = this->isInjector() ? 1.0:-1.0;
double total_potential = 0.0;
for (int phase = 0; phase < np; ++phase){
well_potentials[phase] *= sign;
total_potential += well_potentials[phase];
}
if (total_potential <= 0.0) {
// wells with trivial or non-positive potentials
// are not operable
this->operability_status_.has_non_positive_potentials = true;
const std::string msg = std::string("well ") + this->name() + std::string(": has non positive potentials and is not operable");
deferred_logger.info(msg);
}
} }

View File

@@ -174,6 +174,9 @@ public:
void reportWellSwitching(const SingleWellState& ws, DeferredLogger& deferred_logger) const; void reportWellSwitching(const SingleWellState& ws, DeferredLogger& deferred_logger) const;
bool changedToOpenThisStep() const {
return this->changed_to_open_this_step_;
}
protected: protected:
bool getAllowCrossFlow() const; bool getAllowCrossFlow() const;
double mostStrictBhpFromBhpLimits(const SummaryState& summaryState) const; double mostStrictBhpFromBhpLimits(const SummaryState& summaryState) const;
@@ -186,7 +189,7 @@ protected:
// definition of the struct OperabilityStatus // definition of the struct OperabilityStatus
struct OperabilityStatus { struct OperabilityStatus {
bool isOperableAndSolvable() const { bool isOperableAndSolvable() const {
if (!operable_under_only_bhp_limit || !solvable) { if (!operable_under_only_bhp_limit || !solvable || has_non_positive_potentials) {
return false; return false;
} else { } else {
return ( (isOperableUnderBHPLimit() || isOperableUnderTHPLimit()) ); return ( (isOperableUnderBHPLimit() || isOperableUnderTHPLimit()) );
@@ -221,6 +224,8 @@ protected:
bool obey_bhp_limit_with_thp_limit = true; bool obey_bhp_limit_with_thp_limit = true;
// the well is solveable // the well is solveable
bool solvable = true; bool solvable = true;
// the well have non positive potentials
bool has_non_positive_potentials = false;
}; };
OperabilityStatus operability_status_; OperabilityStatus operability_status_;
@@ -308,6 +313,8 @@ protected:
const GuideRate* guide_rate_; const GuideRate* guide_rate_;
std::vector< std::string> well_control_log_; std::vector< std::string> well_control_log_;
bool changed_to_open_this_step_ = false;
}; };
} }

View File

@@ -349,7 +349,7 @@ namespace Opm
} }
const int np = well_state_copy.numPhases(); const int np = well_state_copy.numPhases();
for (int p = 0; p < np; ++p) { for (int p = 0; p < np; ++p) {
ws.well_potentials[p] = std::abs(potentials[p]); ws.well_potentials[p] = std::max(0.0, potentials[p]);
} }
this->updateWellTestState(well_state_copy.well(this->indexOfWell()), simulation_time, /*writeMessageToOPMLog=*/ false, welltest_state_temp, deferred_logger); this->updateWellTestState(well_state_copy.well(this->indexOfWell()), simulation_time, /*writeMessageToOPMLog=*/ false, welltest_state_temp, deferred_logger);
this->closeCompletions(welltest_state_temp); this->closeCompletions(welltest_state_temp);
@@ -482,7 +482,23 @@ namespace Opm
this->operability_status_.solvable = false; this->operability_status_.solvable = false;
} }
} }
if (this->operability_status_.has_non_positive_potentials) {
auto well_state_copy = well_state;
std::vector<double> potentials;
try {
computeWellPotentials(ebosSimulator, well_state_copy, potentials, deferred_logger);
} catch (const std::exception& e) {
const std::string msg = std::string("well ") + this->name() + std::string(": computeWellPotentials() failed during for re-computing: ") + e.what();
deferred_logger.info(msg);
this->operability_status_.has_non_positive_potentials = true;
}
auto& ws = well_state.well(this->indexOfWell());
const int np = well_state.numPhases();
for (int p = 0; p < np; ++p) {
ws.well_potentials[p] = std::max(0.0, potentials[p]);
}
}
this->changed_to_open_this_step_ = false;
const bool well_operable = this->operability_status_.isOperableAndSolvable(); const bool well_operable = this->operability_status_.isOperableAndSolvable();
if (!well_operable && old_well_operable) { if (!well_operable && old_well_operable) {
if (this->well_ecl_.getAutomaticShutIn()) { if (this->well_ecl_.getAutomaticShutIn()) {
@@ -498,6 +514,7 @@ namespace Opm
deferred_logger.info(" well " + this->name() + " gets REVIVED during iteration "); deferred_logger.info(" well " + this->name() + " gets REVIVED during iteration ");
this->openWell(); this->openWell();
changed_to_stopped_this_step_ = false; changed_to_stopped_this_step_ = false;
this->changed_to_open_this_step_ = true;
} }
const auto& summary_state = ebosSimulator.vanguard().summaryState(); const auto& summary_state = ebosSimulator.vanguard().summaryState();