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;
}
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,
DeferredLogger& deferred_logger);
bool guideRateUpdateIsNeeded() const;
// create the well container
virtual void createWellContainer(const int time_step) = 0;
virtual void initWellContainer() = 0;

View File

@ -840,6 +840,18 @@ namespace Opm {
}
OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger, "assemble() failed: ",
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_.assemble_time_well += perfTimer.stop();
}
@ -1343,7 +1355,8 @@ namespace Opm {
// and updated only if sucessfull. i.e. the potentials are zero for exceptions
auto& ws = this->wellState().well(well->indexOfWell());
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);
}
// solve the well equation initially to improve the initial solution of the well model
if (param_.solve_welleq_initially_) {
well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), deferred_logger);
if (param_.solve_welleq_initially_ && well->isOperableAndSolvable()) {
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);

View File

@ -112,6 +112,11 @@ computeWellRates_(
-potentials[this->water_pos_]);
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>

View File

@ -253,6 +253,7 @@ namespace Opm
if (this->wellIsStopped()) {
return;
}
this->operability_status_.has_non_positive_potentials = false;
// If the well is pressure controlled the potential equals the rate.
bool thp_controlled_well = false;
@ -285,9 +286,20 @@ namespace Opm
// 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.
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){
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;
}
}
@ -302,6 +314,20 @@ namespace Opm
}
deferred_logger.debug("Cost in iterations of finding well potential for well "
+ 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;
}
this->operability_status_.has_non_positive_potentials = false;
// If the well is pressure controlled the potential equals the rate.
bool thp_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
// opened well and we therefore make the affort of computing the potentials anyway.
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){
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;
}
@ -1917,6 +1928,20 @@ namespace Opm
// the well has a THP related constraint
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;
bool changedToOpenThisStep() const {
return this->changed_to_open_this_step_;
}
protected:
bool getAllowCrossFlow() const;
double mostStrictBhpFromBhpLimits(const SummaryState& summaryState) const;
@ -186,7 +189,7 @@ protected:
// definition of the struct OperabilityStatus
struct OperabilityStatus {
bool isOperableAndSolvable() const {
if (!operable_under_only_bhp_limit || !solvable) {
if (!operable_under_only_bhp_limit || !solvable || has_non_positive_potentials) {
return false;
} else {
return ( (isOperableUnderBHPLimit() || isOperableUnderTHPLimit()) );
@ -221,6 +224,8 @@ protected:
bool obey_bhp_limit_with_thp_limit = true;
// the well is solveable
bool solvable = true;
// the well have non positive potentials
bool has_non_positive_potentials = false;
};
OperabilityStatus operability_status_;
@ -308,6 +313,8 @@ protected:
const GuideRate* guide_rate_;
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();
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->closeCompletions(welltest_state_temp);
@ -482,7 +482,23 @@ namespace Opm
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();
if (!well_operable && old_well_operable) {
if (this->well_ecl_.getAutomaticShutIn()) {
@ -498,6 +514,7 @@ namespace Opm
deferred_logger.info(" well " + this->name() + " gets REVIVED during iteration ");
this->openWell();
changed_to_stopped_this_step_ = false;
this->changed_to_open_this_step_ = true;
}
const auto& summary_state = ebosSimulator.vanguard().summaryState();