diff --git a/opm/autodiff/BlackoilWellModel_impl.hpp b/opm/autodiff/BlackoilWellModel_impl.hpp index f49934fe7..7d3d704c2 100644 --- a/opm/autodiff/BlackoilWellModel_impl.hpp +++ b/opm/autodiff/BlackoilWellModel_impl.hpp @@ -954,7 +954,7 @@ namespace Opm { prepareGroupControl(); for (const auto& well : well_container_) { - well->checkWellOperability(ebosSimulator_); + well->checkWellOperability(ebosSimulator_, well_state_); } // since the controls are all updated, we should update well_state accordingly diff --git a/opm/autodiff/MultisegmentWell.hpp b/opm/autodiff/MultisegmentWell.hpp index c3613ff98..318d06609 100644 --- a/opm/autodiff/MultisegmentWell.hpp +++ b/opm/autodiff/MultisegmentWell.hpp @@ -332,7 +332,8 @@ namespace Opm // checking the operability of the well based on current reservoir condition // it is not implemented for multisegment well yet - virtual void checkWellOperability(const Simulator& ebos_simulator); + virtual void checkWellOperability(const Simulator& ebos_simulator, + const WellState& well_state) override; void updateWellStateFromPrimaryVariables(WellState& well_state) const; diff --git a/opm/autodiff/MultisegmentWell_impl.hpp b/opm/autodiff/MultisegmentWell_impl.hpp index e101e21af..fd3a1362e 100644 --- a/opm/autodiff/MultisegmentWell_impl.hpp +++ b/opm/autodiff/MultisegmentWell_impl.hpp @@ -1645,7 +1645,8 @@ namespace Opm template void MultisegmentWell:: - checkWellOperability(const Simulator& ebos_simulator) + checkWellOperability(const Simulator& /* ebos_simulator */, + const WellState& /* well_state */) { const std::string msg = "Support of well operatability checking for mutlisegment wells is not implemented " "yet, checkWellOperability() for " + name() + " will do nothing"; diff --git a/opm/autodiff/StandardWell.hpp b/opm/autodiff/StandardWell.hpp index 4d9e36cb8..b5ff47380 100644 --- a/opm/autodiff/StandardWell.hpp +++ b/opm/autodiff/StandardWell.hpp @@ -350,7 +350,8 @@ namespace Opm // check whether the well is operable under the current reservoir condition // mostly related to BHP limit and THP limit - virtual void checkWellOperability(const Simulator& ebos_simulator) override; + virtual void checkWellOperability(const Simulator& ebos_simulator, + const WellState& well_state) override; // check whether the well is operable under BHP limit with current reservoir condition void checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator); @@ -369,6 +370,10 @@ namespace Opm // be able to produce/inject . bool allDrawDownWrongDirection(const Simulator& ebos_simulator) const; + // whether the well can produce / inject based on the current well state (bhp) + bool canProduceInjectWithCurrentBhp(const Simulator& ebos_simulator, + const WellState& well_state); + // turn on crossflow to avoid singular well equations // when the well is banned from cross-flow and the BHP is not properly initialized, // we turn on crossflow to avoid singular well equations. It can result in wrong-signed diff --git a/opm/autodiff/StandardWell_impl.hpp b/opm/autodiff/StandardWell_impl.hpp index b7983f411..5d944b626 100644 --- a/opm/autodiff/StandardWell_impl.hpp +++ b/opm/autodiff/StandardWell_impl.hpp @@ -440,7 +440,7 @@ namespace Opm WellState& well_state) { - checkWellOperability(ebosSimulator); + checkWellOperability(ebosSimulator, well_state); if (!this->isOperable()) return; @@ -1293,7 +1293,8 @@ namespace Opm template void StandardWell:: - checkWellOperability(const Simulator& ebos_simulator) + checkWellOperability(const Simulator& ebos_simulator, + const WellState& well_state) { // focusing on PRODUCER for now if (well_type_ == INJECTOR) { @@ -1315,13 +1316,12 @@ namespace Opm // checking whether the well can operate under the THP constraints. if (this->wellHasTHPConstraints()) { + this->operability_status_.has_thp_constaint = true; checkOperabilityUnderTHPLimitProducer(ebos_simulator); + this->operability_status_.can_produce_inject_with_current_bhp = + canProduceInjectWithCurrentBhp(ebos_simulator, well_state); } - // checking whether the well can not produce/inject - this->operability_status_.existing_drawdown_correct_direction = - ! allDrawDownWrongDirection(ebos_simulator); - const bool well_operable = this->operability_status_.isOperable(); if (!well_operable && old_well_operable) { @@ -1458,6 +1458,40 @@ namespace Opm + template + bool + StandardWell:: + canProduceInjectWithCurrentBhp(const Simulator& ebos_simulator, + const WellState& well_state) + { + const double bhp = well_state.bhp()[index_of_well_]; + std::vector well_rates; + computeWellRatesWithBhp(ebos_simulator, bhp, well_rates); + + const double sign = (well_type_ == PRODUCER) ? -1. : 1.; + const double threshold = sign * std::numeric_limits::min(); + + bool can_produce_inject = false; + for (const auto value : well_rates) { + if (well_type_ == PRODUCER && value < threshold) { + can_produce_inject = true; + break; + } else if (well_type_ == INJECTOR && value > threshold) { + can_produce_inject = true; + break; + } + } + + if (!can_produce_inject) { + OpmLog::debug(" well " + name() + " CANNOT produce or inejct "); + } + + return can_produce_inject; + } + + + + template bool diff --git a/opm/autodiff/WellInterface.hpp b/opm/autodiff/WellInterface.hpp index 546a556e3..272809588 100644 --- a/opm/autodiff/WellInterface.hpp +++ b/opm/autodiff/WellInterface.hpp @@ -223,7 +223,7 @@ namespace Opm void updatePerforatedCell(std::vector& is_cell_perforated); - virtual void checkWellOperability(const Simulator& ebos_simulator) = 0; + virtual void checkWellOperability(const Simulator& ebos_simulator, const WellState& well_state) = 0; // whether the well is operable bool isOperable() const; @@ -391,8 +391,8 @@ namespace Opm if (!operable_under_only_bhp_limit) { return false; } else { - return existing_drawdown_correct_direction && - (isOperableUnderBHPLimit() || isOperableUnderTHPLimit()); + return ( (isOperableUnderBHPLimit() || isOperableUnderTHPLimit()) && + !(has_thp_constaint && !can_produce_inject_with_current_bhp) ); } } @@ -409,8 +409,8 @@ namespace Opm obey_thp_limit_under_bhp_limit = true; can_obtain_bhp_with_thp_limit = true; obey_bhp_limit_with_thp_limit = true; - // TODO: the following one might need to be treated differently - existing_drawdown_correct_direction = true; + can_produce_inject_with_current_bhp = true; + has_thp_constaint = false; } // whether the well can be operated under bhp limit @@ -425,13 +425,14 @@ namespace Opm // whether the well obey bhp limit when operated under thp limit bool obey_bhp_limit_with_thp_limit = true; - // there is some drawdown with correct sign/direction - // if all the drawdown are with wrong sign/direction, it means producer can not produce - // and injector can not inject. - // TODO: even there exist some drawdown with correct direction, it is still possible that - // producer can not produce and injector can not inject if the crossflow is allowed, since - // the well rate is the sum of the rates from all the perofrations - bool existing_drawdown_correct_direction = true; + // TODO: the following criterion is based on the current state of + // the well, we consider it is a numerical criterion. + // at the moment, we only apply it with well has THP constraint. + // whether the well can produce / inject with the current bhp of the well + // it might be updated with other criterion with investigation with more cases. + bool can_produce_inject_with_current_bhp = true; + // whether the well has a THP constraint + bool has_thp_constaint = false; }; }