22#ifndef OPM_WELLINTERFACE_IMPL_HEADER_INCLUDED
23#define OPM_WELLINTERFACE_IMPL_HEADER_INCLUDED
26#ifndef OPM_WELLINTERFACE_HEADER_INCLUDED
28#include <opm/simulators/wells/WellInterface.hpp>
31#include <opm/common/Exceptions.hpp>
33#include <opm/input/eclipse/Schedule/ScheduleTypes.hpp>
34#include <opm/input/eclipse/Schedule/Well/WDFAC.hpp>
36#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
38#include <opm/simulators/wells/GroupState.hpp>
39#include <opm/simulators/wells/TargetCalculator.hpp>
40#include <opm/simulators/wells/WellBhpThpCalculator.hpp>
41#include <opm/simulators/wells/WellHelpers.hpp>
43#include <dune/common/version.hh>
50#include <fmt/format.h>
56 template<
typename TypeTag>
61 const ModelParameters& param,
63 const int pvtRegionIdx,
79 connectionRates_.resize(this->number_of_local_perforations_);
81 if constexpr (has_solvent || has_zFraction) {
82 if (well.isInjector()) {
85 this->wsolvent_ = this->well_ecl_.getSolventFraction();
92 template<
typename TypeTag>
95 init(
const std::vector<Scalar>& ,
97 const std::vector<Scalar>&
B_avg,
108 template<
typename TypeTag>
109 typename WellInterface<TypeTag>::Scalar
110 WellInterface<TypeTag>::
113 if constexpr (has_polymer) {
114 return this->wpolymer_();
124 template<
typename TypeTag>
125 typename WellInterface<TypeTag>::Scalar
126 WellInterface<TypeTag>::
129 if constexpr (has_foam) {
130 return this->wfoam_();
138 template<
typename TypeTag>
139 typename WellInterface<TypeTag>::Scalar
140 WellInterface<TypeTag>::
143 if constexpr (has_brine) {
144 return this->wsalt_();
150 template<
typename TypeTag>
151 typename WellInterface<TypeTag>::Scalar
152 WellInterface<TypeTag>::
155 if constexpr (has_micp) {
156 return this->wmicrobes_();
162 template<
typename TypeTag>
163 typename WellInterface<TypeTag>::Scalar
164 WellInterface<TypeTag>::
167 if constexpr (has_micp) {
168 return this->woxygen_();
174 template<
typename TypeTag>
175 typename WellInterface<TypeTag>::Scalar
176 WellInterface<TypeTag>::
179 if constexpr (has_micp) {
180 return this->wurea_();
186 template<
typename TypeTag>
188 WellInterface<TypeTag>::
189 updateWellControl(
const Simulator& simulator,
190 const IndividualOrGroup
iog,
191 WellStateType& well_state,
200 const auto& summaryState = simulator.vanguard().summaryState();
201 const auto& schedule = simulator.vanguard().schedule();
202 const auto& well = this->well_ecl_;
203 auto&
ws = well_state.well(this->index_of_well_);
206 if (well.isInjector()) {
208 is_grup =
ws.injection_cmode == Well::InjectorCMode::GRUP;
211 is_grup =
ws.production_cmode == Well::ProducerCMode::GRUP;
214 const int episodeIdx = simulator.episodeIndex();
215 const int iterationIdx = simulator.model().newtonMethod().numIterations();
217 const bool oscillating = std::count(this->well_control_log_.begin(),
this->well_control_log_.end(),
from) >= this->param_.max_number_of_well_switches_;
220 const bool output = std::count(this->well_control_log_.begin(),
this->well_control_log_.end(),
from) == this->param_.max_number_of_well_switches_;
222 const auto msg = fmt::format(
" The control mode for well {} is oscillating. \n"
223 "We don't allow for more than {} switches after NUPCOL iterations. (NUPCOL = {}) \n"
224 "The control is kept at {}.",
225 this->name(), this->param_.max_number_of_well_switches_,
nupcol,
from);
228 this->well_control_log_.push_back(
from);
233 if (
iog == IndividualOrGroup::Individual) {
235 }
else if (
iog == IndividualOrGroup::Group) {
236 changed = this->checkGroupConstraints(well_state, group_state, schedule, summaryState,
true,
deferred_logger);
241 Parallel::Communication
cc = simulator.vanguard().grid().comm();
245 if (well.isInjector()) {
250 std::ostringstream
ss;
251 ss <<
" Switching control mode for well " << this->name()
255 ss <<
" on rank " <<
cc.rank();
263 this->well_control_log_.push_back(
from);
265 updateWellStateWithTarget(simulator, group_state, well_state,
deferred_logger);
272 template<
typename TypeTag>
274 WellInterface<TypeTag>::
275 updateWellControlAndStatusLocalIteration(
const Simulator& simulator,
276 WellStateType& well_state,
286 const auto&
summary_state = simulator.vanguard().summaryState();
287 const auto& schedule = simulator.vanguard().schedule();
288 auto&
ws = well_state.well(this->index_of_well_);
290 if (this->isInjector()) {
295 const bool oscillating = std::count(this->well_control_log_.begin(),
this->well_control_log_.end(),
from) >= this->param_.max_number_of_well_switches_;
297 if (
oscillating || this->wellUnderZeroRateTarget(simulator, well_state,
deferred_logger) || !(well_state.well(
this->index_of_well_).status == WellStatus::OPEN)) {
301 const Scalar
sgn = this->isInjector() ? 1.0 : -1.0;
302 if (!this->wellIsStopped()){
315 bool isGroupControl =
ws.production_cmode == Well::ProducerCMode::GRUP ||
ws.injection_cmode == Well::InjectorCMode::GRUP;
316 if (! (
isGroupControl && !this->param_.check_group_constraints_inner_well_iterations_)) {
319 if (
hasGroupControl && this->param_.check_group_constraints_inner_well_iterations_) {
324 const bool thp_controlled = this->isInjector() ?
ws.injection_cmode == Well::InjectorCMode::THP :
325 ws.production_cmode == Well::ProducerCMode::THP;
330 updateWellStateWithTarget(simulator, group_state, well_state,
deferred_logger);
339 const Scalar bhp = well_state.well(this->index_of_well_).bhp;
344 std::vector<Scalar> rates(this->num_conservation_quantities_);
345 if (this->isInjector()){
346 const Scalar
bhp_thp = WellBhpThpCalculator(*this).
347 calculateBhpFromThp(well_state, rates,
350 this->getRefDensity(),
356 const Scalar
bhp_min = WellBhpThpCalculator(*this).
357 calculateMinimumBhpFromThp(well_state,
360 this->getRefDensity());
369 well_state.well(this->index_of_well_).thp = this->getTHPConstraint(
summary_state);
380 template<
typename TypeTag>
382 WellInterface<TypeTag>::
383 wellTesting(
const Simulator& simulator,
385 WellStateType& well_state,
398 const auto&
summary_state = simulator.vanguard().summaryState();
400 if (this->isProducer()) {
401 ws.production_cmode =
has_thp_limit ? Well::ProducerCMode::THP : Well::ProducerCMode::BHP;
403 ws.injection_cmode =
has_thp_limit ? Well::InjectorCMode::THP : Well::InjectorCMode::BHP;
412 if (this->isProducer()) {
413 const auto& schedule = simulator.vanguard().schedule();
414 const auto report_step = simulator.episodeIndex();
415 const auto&
glo = schedule.glo(report_step);
417 gliftBeginTimeStepWellTestUpdateALQ(simulator,
435 const auto msg = fmt::format(
"WTEST: Well {} is not solvable (physical)", this->name());
442 if ( !this->isOperableAndSolvable() ) {
443 const auto msg = fmt::format(
"WTEST: Well {} is not operable (physical)", this->name());
450 }
catch (
const std::exception&
e) {
451 const std::string
msg = fmt::format(
"well {}: computeWellPotentials() "
452 "failed during testing for re-opening: ",
453 this->name(),
e.what());
458 for (
int p = 0;
p <
np; ++
p) {
482 well_test_state.open_well(this->name());
484 std::string
msg = std::string(
"well ") + this->name() + std::string(
" is re-opened");
490 well_test_state.open_completion(this->name(),
completion.first);
493 open_times.try_emplace(this->name(), well_test_state.lastTestTime(
this->name()));
500 template<
typename TypeTag>
502 WellInterface<TypeTag>::
503 iterateWellEquations(
const Simulator& simulator,
505 WellStateType& well_state,
510 const auto&
summary_state = simulator.vanguard().summaryState();
511 const auto inj_controls = this->well_ecl_.isInjector() ? this->well_ecl_.injectionControls(
summary_state) : Well::InjectionControls(0);
512 const auto prod_controls = this->well_ecl_.isProducer() ? this->well_ecl_.productionControls(
summary_state) : Well::ProductionControls(0);
513 const auto&
ws = well_state.well(this->indexOfWell());
516 bool converged =
false;
519 if (!this->param_.local_well_solver_control_switching_){
522 if (this->param_.use_implicit_ipr_ &&
this->well_ecl_.isProducer() && (well_state.well(
this->index_of_well_).status == WellStatus::OPEN)) {
530 const std::string
msg =
"Inner well iterations failed for well " + this->name() +
" Treat the well as unconverged. ";
538 if (this->isInjector()) {
545 const auto msg = fmt::format(
" Well {} switched from {} to {} during local solve", this->name(),
from,
to);
547 const int episodeIdx = simulator.episodeIndex();
548 const int iterationIdx = simulator.model().newtonMethod().numIterations();
549 const auto& schedule = simulator.vanguard().schedule();
555 this->well_control_log_.push_back(
from);
563 template<
typename TypeTag>
565 WellInterface<TypeTag>::
566 solveWellWithOperabilityCheck(
const Simulator& simulator,
570 WellStateType& well_state,
575 const auto&
summary_state = simulator.vanguard().summaryState();
576 bool converged =
true;
577 auto&
ws = well_state.well(this->index_of_well_);
579 if (this->wellIsStopped()) {
584 const auto msg = fmt::format(
"estimateOperableBhp: Did not find operable BHP for well {}", this->name());
590 this->operability_status_.can_obtain_bhp_with_thp_limit =
false;
591 this->operability_status_.obey_thp_limit_under_bhp_limit =
false;
596 const Scalar bhp = std::max(
bhp_target.value(),
605 const bool isThp =
ws.production_cmode == Well::ProducerCMode::THP;
608 auto rates = well_state.well(this->index_of_well_).surface_rates;
609 this->adaptRatesForVFP(rates);
614 this->operability_status_.use_vfpexplicit =
true;
617 const Scalar reltol = 1
e-3;
620 const auto msg = fmt::format(
"Well {} converged to an unstable solution, re-solving", this->name());
632 this->operability_status_.use_vfpexplicit =
true;
640 this->operability_status_.can_obtain_bhp_with_thp_limit =
false;
641 this->operability_status_.obey_thp_limit_under_bhp_limit =
false;
645 const Scalar bhp = std::max(
bhp_target.value(),
649 const auto msg = fmt::format(
"Well {} did not converge, re-solving with explicit fractions for VFP caculations.", this->name());
651 converged = this->iterateWellEqWithSwitching(simulator,
dt,
660 this->operability_status_.can_obtain_bhp_with_thp_limit = !this->wellIsStopped();
661 this->operability_status_.obey_thp_limit_under_bhp_limit = !this->wellIsStopped();
665 template<
typename TypeTag>
666 std::optional<typename WellInterface<TypeTag>::Scalar>
667 WellInterface<TypeTag>::
668 estimateOperableBhp(
const Simulator& simulator,
670 WellStateType& well_state,
677 if (!converged || this->wellIsStopped()) {
686 Scalar
bhp_min = WellBhpThpCalculator(*this).calculateMinimumBhpFromThp(well_state,
this->well_ecl_,
summary_state,
this->getRefDensity());
689 if (!converged || this->wellIsStopped()) {
693 auto rates = well_state.well(this->index_of_well_).surface_rates;
694 this->adaptRatesForVFP(rates);
695 return WellBhpThpCalculator(*this).estimateStableBhp(well_state,
this->well_ecl_, rates,
this->getRefDensity(),
summary_state);
698 template<
typename TypeTag>
700 WellInterface<TypeTag>::
701 solveWellWithBhp(
const Simulator& simulator,
704 WellStateType& well_state,
712 auto&
ws = well_state.well(this->index_of_well_);
715 if (this->isInjector()) {
719 ws.injection_cmode = Well::InjectorCMode::BHP;
724 ws.production_cmode = Well::ProducerCMode::BHP;
735 template<
typename TypeTag>
737 WellInterface<TypeTag>::
738 solveWellWithZeroRate(
const Simulator& simulator,
740 WellStateType& well_state,
756 template<
typename TypeTag>
758 WellInterface<TypeTag>::
759 solveWellForTesting(
const Simulator& simulator,
760 WellStateType& well_state,
765 const double dt = simulator.timeStepSize();
767 const auto&
summary_state = simulator.vanguard().summaryState();
768 auto inj_controls = this->well_ecl_.isInjector() ? this->well_ecl_.injectionControls(
summary_state) : Well::InjectionControls(0);
769 auto prod_controls = this->well_ecl_.isProducer() ? this->well_ecl_.productionControls(
summary_state) : Well::ProductionControls(0);
772 bool converged =
false;
775 if (!this->param_.local_well_solver_control_switching_){
778 if (this->param_.use_implicit_ipr_ &&
this->well_ecl_.isProducer() && (well_state.well(
this->index_of_well_).status == WellStatus::OPEN)) {
786 const std::string
msg =
"Inner well iterations failed for well " + this->name() +
" Treat the well as unconverged. ";
792 deferred_logger.debug(
"WellTest: Well equation for well " + this->name() +
" converged");
795 const int max_iter = this->param_.max_welleq_iter_;
796 deferred_logger.debug(
"WellTest: Well equation for well " + this->name() +
" failed converging in "
797 + std::to_string(
max_iter) +
" iterations");
802 template<
typename TypeTag>
804 WellInterface<TypeTag>::
805 solveWellEquation(
const Simulator& simulator,
806 WellStateType& well_state,
811 if (!this->isOperableAndSolvable() && !this->wellIsStopped())
816 const double dt = simulator.timeStepSize();
817 bool converged = iterateWellEquations(simulator,
dt, well_state, group_state,
deferred_logger);
827 auto&
ws = well_state.well(this->indexOfWell());
829 if (this->well_ecl_.isInjector()) {
830 thp_control =
ws.injection_cmode == Well::InjectorCMode::THP;
832 ws.injection_cmode = Well::InjectorCMode::BHP;
833 if (this->well_control_log_.empty()) {
838 thp_control =
ws.production_cmode == Well::ProducerCMode::THP;
840 ws.production_cmode = Well::ProducerCMode::BHP;
841 if (this->well_control_log_.empty()) {
847 const std::string
msg = std::string(
"The newly opened well ") + this->name()
848 + std::string(
" with THP control did not converge during inner iterations, we try again with bhp control");
850 converged = this->iterateWellEquations(simulator,
dt, well_state, group_state,
deferred_logger);
855 const int max_iter = this->param_.max_welleq_iter_;
856 deferred_logger.debug(
"Compute initial well solution for well " + this->name() +
". Failed to converge in "
857 + std::to_string(
max_iter) +
" iterations");
864 template <
typename TypeTag>
866 WellInterface<TypeTag>::
867 assembleWellEq(
const Simulator& simulator,
869 WellStateType& well_state,
874 prepareWellBeforeAssembling(simulator,
dt, well_state, group_state,
deferred_logger);
875 assembleWellEqWithoutIteration(simulator,
dt, well_state, group_state,
deferred_logger);
880 template <
typename TypeTag>
882 WellInterface<TypeTag>::
883 assembleWellEqWithoutIteration(
const Simulator& simulator,
885 WellStateType& well_state,
890 const auto&
summary_state = simulator.vanguard().summaryState();
891 const auto inj_controls = this->well_ecl_.isInjector() ? this->well_ecl_.injectionControls(
summary_state) : Well::InjectionControls(0);
892 const auto prod_controls = this->well_ecl_.isProducer() ? this->well_ecl_.productionControls(
summary_state) : Well::ProductionControls(0);
900 template<
typename TypeTag>
902 WellInterface<TypeTag>::
903 prepareWellBeforeAssembling(
const Simulator& simulator,
905 WellStateType& well_state,
910 const bool old_well_operable = this->operability_status_.isOperableAndSolvable();
912 if (this->param_.check_well_operability_iter_)
916 const int iteration_idx = simulator.model().newtonMethod().numIterations();
918 const auto&
ws = well_state.well(this->indexOfWell());
920 std::any_of(
ws.surface_rates.begin(),
921 ws.surface_rates.begin() + well_state.numPhases(),
922 [](Scalar rate) { return rate != Scalar(0.0); });
924 this->operability_status_.solvable =
true;
925 if (number_of_well_reopenings_ >= this->param_.max_well_status_switch_) {
927 if (number_of_well_reopenings_ == this->param_.max_well_status_switch_) {
928 const std::string
msg = fmt::format(
"well {} is oscillating between open and stop. \n"
929 "We don't allow for more than {} re-openings "
930 "and the well is therefore kept stopped.",
931 this->name(), number_of_well_reopenings_);
935 changed_to_stopped_this_step_ =
true;
938 this->operability_status_.solvable =
false;
941 number_of_well_reopenings_++;
944 bool converged = this->iterateWellEquations(simulator,
dt, well_state, group_state,
deferred_logger);
952 this->operability_status_.resetOperability();
954 deferred_logger.debug(
" " + this->name() +
" is re-opened after being stopped during local solve");
955 number_of_well_reopenings_++;
959 if (this->param_.shut_unsolvable_wells_) {
960 this->operability_status_.solvable =
false;
964 if (this->operability_status_.has_negative_potentials) {
969 }
catch (
const std::exception&
e) {
970 const std::string
msg = fmt::format(
"well {}: computeWellPotentials() failed "
971 "during attempt to recompute potentials for well: ",
972 this->name(),
e.what());
974 this->operability_status_.has_negative_potentials =
true;
976 auto&
ws = well_state.well(this->indexOfWell());
977 const int np = well_state.numPhases();
978 for (
int p = 0;
p <
np; ++
p) {
982 this->changed_to_open_this_step_ =
false;
983 changed_to_stopped_this_step_ =
false;
985 const bool well_operable = this->operability_status_.isOperableAndSolvable();
989 deferred_logger.debug(
" well " + this->name() +
" gets STOPPED during iteration ");
990 changed_to_stopped_this_step_ =
true;
992 }
else if (well_state.isOpen(
this->name())) {
995 deferred_logger.debug(
" well " + this->name() +
" gets REVIVED during iteration ");
996 this->changed_to_open_this_step_ =
true;
1001 template<
typename TypeTag>
1003 WellInterface<TypeTag>::addCellRates(RateVector& rates,
int cellIdx)
const
1005 if(!this->isOperableAndSolvable() && !this->wellIsStopped())
1010 for (
int i = 0; i < RateVector::dimension; ++i) {
1011 rates[i] += connectionRates_[
perfIdx][i];
1017 template<
typename TypeTag>
1018 typename WellInterface<TypeTag>::Scalar
1019 WellInterface<TypeTag>::volumetricSurfaceRateForConnection(
int cellIdx,
int phaseIdx)
const
1023 const unsigned activeCompIdx = FluidSystem::canonicalToActiveCompIdx(FluidSystem::solventComponentIndex(
phaseIdx));
1028 OPM_THROW(std::invalid_argument,
"The well with name " + this->name()
1029 +
" does not perforate cell " + std::to_string(
cellIdx));
1036 template<
typename TypeTag>
1038 WellInterface<TypeTag>::
1039 checkWellOperability(
const Simulator& simulator,
1040 const WellStateType& well_state,
1044 if (!this->param_.check_well_operability_) {
1048 if (this->wellIsStopped() && !changed_to_stopped_this_step_) {
1053 if (!this->operability_status_.isOperableAndSolvable()) {
1054 this->operability_status_.use_vfpexplicit =
true;
1056 "well not operable, trying with explicit vfp lookup: " + this->name());
1063 template<
typename TypeTag>
1065 WellInterface<TypeTag>::
1066 gliftBeginTimeStepWellTestUpdateALQ(
const Simulator& simulator,
1067 WellStateType& well_state,
1073 const auto&
summary_state = simulator.vanguard().summaryState();
1074 const auto& well_name = this->name();
1076 const std::string
msg = fmt::format(
"GLIFT WTEST: Well {} does not have THP constraints", well_name);
1080 const auto& schedule = simulator.vanguard().schedule();
1083 if (!
glo.has_well(well_name)) {
1084 const std::string
msg = fmt::format(
1085 "GLIFT WTEST: Well {} : Gas lift not activated: "
1086 "WLIFTOPT is probably missing. Skipping.", well_name);
1093 std::unique_ptr<GasLiftSingleWell>
glift =
1103 well_state.well(well_name).alq_state.set(
wtest_alq);
1105 "GLIFT WTEST: Well {} : Setting ALQ to optimized value = {}",
1111 "GLIFT WTEST: Well {} : Gas lift optimization deactivated. Setting ALQ to WLIFTOPT item 3 = {}",
1113 unit_system.from_si(UnitSystem::measure::gas_surface_rate, well_state.well(well_name).alq_state.get()));
1118 "GLIFT WTEST: Well {} : Gas lift optimization failed, no ALQ set.",
1125 template<
typename TypeTag>
1127 WellInterface<TypeTag>::
1128 updateWellOperability(
const Simulator& simulator,
1129 const WellStateType& well_state,
1133 if (this->param_.local_well_solver_control_switching_) {
1134 const bool success = updateWellOperabilityFromWellEq(simulator, well_state,
deferred_logger);
1136 this->operability_status_.solvable =
false;
1137 deferred_logger.debug(
"Operability check using well equations did not converge for well "
1138 + this->name() +
". Mark the well as unsolvable." );
1142 this->operability_status_.resetOperability();
1144 bool thp_controlled = this->isInjector() ? well_state.well(this->index_of_well_).injection_cmode == Well::InjectorCMode::THP:
1145 well_state.well(this->index_of_well_).production_cmode == Well::ProducerCMode::THP;
1146 bool bhp_controlled = this->isInjector() ? well_state.well(this->index_of_well_).injection_cmode == Well::InjectorCMode::BHP:
1147 well_state.well(this->index_of_well_).production_cmode == Well::ProducerCMode::BHP;
1154 checkOperabilityUnderBHPLimit(well_state, simulator,
deferred_logger);
1158 checkOperabilityUnderTHPLimit(simulator, well_state,
deferred_logger);
1162 template<
typename TypeTag>
1164 WellInterface<TypeTag>::
1165 updateWellOperabilityFromWellEq(
const Simulator& simulator,
1166 const WellStateType& well_state,
1171 assert(this->param_.local_well_solver_control_switching_);
1172 this->operability_status_.resetOperability();
1174 const auto& group_state = simulator.problem().wellModel().groupState();
1175 const double dt = simulator.timeStepSize();
1181 template<
typename TypeTag>
1183 WellInterface<TypeTag>::
1184 scaleSegmentRatesAndPressure([[
maybe_unused]] WellStateType& well_state)
const
1189 template<
typename TypeTag>
1191 WellInterface<TypeTag>::
1192 updateWellStateWithTarget(
const Simulator& simulator,
1194 WellStateType& well_state,
1199 const auto& well = this->well_ecl_;
1200 const int well_index = this->index_of_well_;
1201 auto&
ws = well_state.well(well_index);
1202 const int np = well_state.numPhases();
1203 const auto& summaryState = simulator.vanguard().summaryState();
1204 const auto& schedule = simulator.vanguard().schedule();
1208 ws.primaryvar.resize(0);
1210 if (this->wellIsStopped()) {
1211 for (
int p = 0;
p<
np; ++
p) {
1212 ws.surface_rates[
p] = 0;
1218 if (this->isInjector() )
1220 const auto&
controls = well.injectionControls(summaryState);
1225 case InjectorType::WATER:
1227 phasePos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::waterPhaseIdx);
1230 case InjectorType::OIL:
1232 phasePos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::oilPhaseIdx);
1235 case InjectorType::GAS:
1237 phasePos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::gasPhaseIdx);
1241 OPM_DEFLOG_THROW(std::runtime_error,
"Expected WATER, OIL or GAS as type for injectors " + this->name(),
deferred_logger );
1244 const auto current =
ws.injection_cmode;
1247 case Well::InjectorCMode::RATE:
1250 if(this->rsRvInj() > 0) {
1251 if (
injectorType == InjectorType::OIL && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
1252 const int gas_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::gasPhaseIdx);
1254 }
else if (
injectorType == InjectorType::GAS && FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1255 const int oil_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::oilPhaseIdx);
1258 OPM_DEFLOG_THROW(std::runtime_error,
"Expected OIL or GAS as type for injectors when RS/RV (item 10) is non-zero " + this->name(),
deferred_logger );
1264 case Well::InjectorCMode::RESV:
1266 std::vector<Scalar>
convert_coeff(this->number_of_phases_, 1.0);
1267 this->rateConverter_.calcCoeff( 0, this->pvtRegionIdx_,
convert_coeff);
1273 case Well::InjectorCMode::THP:
1275 auto rates =
ws.surface_rates;
1276 Scalar bhp = WellBhpThpCalculator(*this).calculateBhpFromThp(well_state,
1280 this->getRefDensity(),
1283 ws.thp = this->getTHPConstraint(summaryState);
1288 Scalar
total_rate = std::accumulate(rates.begin(), rates.end(), 0.0);
1290 ws.surface_rates =
ws.well_potentials;
1294 case Well::InjectorCMode::BHP:
1298 for (
int p = 0;
p<
np; ++
p) {
1305 ws.surface_rates =
ws.well_potentials;
1309 case Well::InjectorCMode::GRUP:
1311 assert(well.isAvailableForGroupControl());
1312 const auto& group = schedule.getGroup(well.groupName(),
this->currentStep());
1314 well_state[well.name()].efficiency_scaling_factor;
1315 std::optional<Scalar>
target =
1316 this->getGroupInjectionTargetRate(group,
1328 case Well::InjectorCMode::CMODE_UNDEFINED:
1330 OPM_DEFLOG_THROW(std::runtime_error,
"Well control must be specified for well " + this->name(),
deferred_logger );
1349 const auto current =
ws.production_cmode;
1350 const auto&
controls = well.productionControls(summaryState);
1352 case Well::ProducerCMode::ORAT:
1354 const int oil_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::oilPhaseIdx);
1359 for (
int p = 0;
p<
np; ++
p) {
1363 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1366 for (
int p = 0;
p<
np; ++
p) {
1373 case Well::ProducerCMode::WRAT:
1375 const int water_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::waterPhaseIdx);
1380 for (
int p = 0;
p<
np; ++
p) {
1384 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1387 for (
int p = 0;
p<
np; ++
p) {
1394 case Well::ProducerCMode::GRAT:
1396 const int gas_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::gasPhaseIdx);
1401 for (
int p = 0;
p<
np; ++
p) {
1405 const std::vector<Scalar >
fractions = initialWellRateFractions(simulator, well_state);
1408 for (
int p = 0;
p<
np; ++
p) {
1417 case Well::ProducerCMode::LRAT:
1419 const int water_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::waterPhaseIdx);
1420 const int oil_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::oilPhaseIdx);
1426 for (
int p = 0;
p<
np; ++
p) {
1430 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1433 for (
int p = 0;
p<
np; ++
p) {
1440 case Well::ProducerCMode::CRAT:
1442 OPM_DEFLOG_THROW(std::runtime_error,
1443 fmt::format(
"CRAT control not supported, well {}", this->name()),
1446 case Well::ProducerCMode::RESV:
1448 std::vector<Scalar>
convert_coeff(this->number_of_phases_, 1.0);
1449 this->rateConverter_.calcCoeff( 0, this->pvtRegionIdx_,
ws.surface_rates,
convert_coeff);
1451 for (
int p = 0;
p<
np; ++
p) {
1458 for (
int p = 0;
p<
np; ++
p) {
1462 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1463 for (
int p = 0;
p<
np; ++
p) {
1468 std::vector<Scalar>
hrates(this->number_of_phases_,0.);
1469 if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
1470 const int phase_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::waterPhaseIdx);
1473 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1474 const int phase_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::oilPhaseIdx);
1477 if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
1478 const int phase_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::gasPhaseIdx);
1481 std::vector<Scalar>
hrates_resv(this->number_of_phases_,0.);
1482 this->rateConverter_.calcReservoirVoidageRates( 0, this->pvtRegionIdx_,
hrates,
hrates_resv);
1487 for (
int p = 0;
p<
np; ++
p) {
1491 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1492 for (
int p = 0;
p<
np; ++
p) {
1499 case Well::ProducerCMode::BHP:
1503 for (
int p = 0;
p<
np; ++
p) {
1510 for (
int p = 0;
p<
np; ++
p) {
1511 ws.surface_rates[
p] = -
ws.well_potentials[
p];
1516 case Well::ProducerCMode::THP:
1524 auto rates =
ws.surface_rates;
1525 this->adaptRatesForVFP(rates);
1526 const Scalar bhp = WellBhpThpCalculator(*this).calculateBhpFromThp(
1529 ws.thp = this->getTHPConstraint(summaryState);
1533 const Scalar
total_rate = -std::accumulate(rates.begin(), rates.end(), 0.0);
1535 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1536 ws.surface_rates[
p] = -
ws.well_potentials[
p];
1542 case Well::ProducerCMode::GRUP:
1544 assert(well.isAvailableForGroupControl());
1545 const auto& group = schedule.getGroup(well.groupName(),
this->currentStep());
1547 well_state[well.name()].efficiency_scaling_factor;
1548 Scalar scale = this->getGroupProductionTargetRate(group,
1558 for (
int p = 0;
p<
np; ++
p) {
1559 ws.surface_rates[
p] *= scale;
1561 ws.trivial_group_target =
false;
1565 ws.trivial_group_target =
true;
1569 case Well::ProducerCMode::CMODE_UNDEFINED:
1570 case Well::ProducerCMode::NONE:
1572 OPM_DEFLOG_THROW(std::runtime_error,
"Well control must be specified for well " + this->name() ,
deferred_logger);
1583 template<
typename TypeTag>
1585 WellInterface<TypeTag>::
1586 wellUnderZeroRateTarget(
const Simulator& simulator,
1587 const WellStateType& well_state,
1595 const auto& summaryState = simulator.vanguard().summaryState();
1596 return this->wellUnderZeroRateTargetIndividual(summaryState, well_state);
1602 template <
typename TypeTag>
1604 WellInterface<TypeTag>::wellUnderZeroGroupRateTarget(
const Simulator& simulator,
1605 const WellStateType& well_state,
1612 const auto& summaryState = simulator.vanguard().summaryState();
1613 const auto& group_state = simulator.problem().wellModel().groupState();
1614 const auto& schedule = simulator.vanguard().schedule();
1615 return this->zeroGroupRateTarget(summaryState, schedule, well_state, group_state,
deferred_logger);
1620 template<
typename TypeTag>
1622 WellInterface<TypeTag>::
1623 stoppedOrZeroRateTarget(
const Simulator& simulator,
1624 const WellStateType& well_state,
1629 return this->wellIsStopped()
1630 || this->wellUnderZeroRateTarget(simulator, well_state,
deferred_logger);
1633 template<
typename TypeTag>
1634 std::vector<typename WellInterface<TypeTag>::Scalar>
1635 WellInterface<TypeTag>::
1636 initialWellRateFractions(
const Simulator& simulator,
1637 const WellStateType& well_state)
const
1640 const int np = this->number_of_phases_;
1642 const auto&
ws = well_state.well(this->index_of_well_);
1645 for (
int p = 0;
p<
np; ++
p) {
1649 for (
int p = 0;
p<
np; ++
p) {
1657 const int nperf = this->number_of_local_perforations_;
1665 const auto& intQuants = simulator.model().intensiveQuantities(
cell_idx, 0);
1666 const auto& fs = intQuants.fluidState();
1669 for (
int p = 0;
p <
np; ++
p) {
1673 for (
int p = 0;
p <
np; ++
p) {
1683 template <
typename TypeTag>
1690 assert(this->isProducer());
1694 auto&
ws = well_state.well(this->index_of_well_);
1697 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1709 std::vector<Scalar>
well_q_s(this->number_of_phases_, 0.0);
1712 const auto&
summary_state = simulator.vanguard().summaryState();
1719 if (std::any_of(
well_q_s.begin(),
well_q_s.end(), [](Scalar
q) { return q > 0.0; })) {
1727 q = std::min(
q, Scalar{0.0});
1737 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1753 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1765 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1770 template <
typename TypeTag>
1771 std::vector<typename WellInterface<TypeTag>::Scalar>
1774 const IntensiveQuantities& intQuants,
1776 const SingleWellStateType&
ws)
const
1781 if (
static_cast<std::size_t
>(
perf) >= this->well_cells_.size()) {
1782 OPM_THROW(std::invalid_argument,
"The perforation index exceeds the size of the local containers - possibly wellIndex was called with a global instead of a local perforation index!");
1784 auto wi = std::vector<Scalar>
1785 (this->num_conservation_quantities_, this->well_index_[
perf] *
trans_mult);
1787 if constexpr (! Indices::gasEnabled) {
1791 const auto&
wdfac = this->well_ecl_.getWDFAC();
1793 if (!
wdfac.useDFactor() || (this->well_index_[
perf] == 0.0)) {
1797 const Scalar
d = this->computeConnectionDFactor(
perf, intQuants,
ws);
1804 const auto&
connection = this->well_ecl_.getConnections()[
ws.perf_data.ecl_index[
perf]];
1807 const unsigned gas_comp_idx = FluidSystem::canonicalToActiveCompIdx(FluidSystem::gasCompIdx);
1812 const Scalar
invB =
getValue(intQuants.fluidState().invB(FluidSystem::gasPhaseIdx));
1813 const Scalar
mob_g =
getValue(intQuants.mobility(FluidSystem::gasPhaseIdx)) *
invB;
1820 const Scalar
r2n =
b*
b + 4*
a*
c;
1822 const Scalar
rn = std::sqrt(
r2n);
1823 const Scalar
xn1 = (
b-
rn)*0.5/
a;
1827 const Scalar
xn2 = (
b+
rn)*0.5/
a;
1834 const Scalar
r2p =
b*
b - 4*
a*
c;
1836 const Scalar
rp = std::sqrt(
r2p);
1837 const Scalar
xp1 = (
rp-
b)*0.5/
a;
1841 const Scalar
xp2 = -(
rp+
b)*0.5/
a;
1851 template <
typename TypeTag>
1853 WellInterface<TypeTag>::
1854 updateConnectionDFactor(
const Simulator& simulator,
1855 SingleWellStateType&
ws)
const
1857 if (! this->well_ecl_.getWDFAC().useDFactor()) {
1861 auto&
d_factor =
ws.perf_data.connection_d_factor;
1863 for (
int perf = 0;
perf < this->number_of_local_perforations_; ++
perf) {
1865 const auto& intQuants = simulator.model().intensiveQuantities(
cell_idx, 0);
1871 template <
typename TypeTag>
1872 typename WellInterface<TypeTag>::Scalar
1873 WellInterface<TypeTag>::
1874 computeConnectionDFactor(
const int perf,
1875 const IntensiveQuantities& intQuants,
1876 const SingleWellStateType&
ws)
const
1879 return FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx,
regIdx);
1884 temperature =
ws.temperature,
1885 regIdx = this->pvtRegionIdx(), &intQuants]()
1887 const auto rv =
getValue(intQuants.fluidState().Rv());
1889 const auto&
gasPvt = FluidSystem::gasPvt();
1894 const Scalar
rv_sat =
gasPvt.saturatedOilVaporizationFactor
1903 rv,
getValue(intQuants.fluidState().Rvw()));
1906 const auto&
connection = this->well_ecl_.getConnections()
1907 [
ws.perf_data.ecl_index[
perf]];
1913 template <
typename TypeTag>
1915 WellInterface<TypeTag>::
1916 updateConnectionTransmissibilityFactor(
const Simulator& simulator,
1917 SingleWellStateType&
ws)
const
1920 &
conns = this->well_ecl_.getConnections()]
1926 auto&
tmult =
ws.perf_data.connection_compaction_tmult;
1927 auto& ctf =
ws.perf_data.connection_transmissibility_factor;
1929 for (
int perf = 0;
perf < this->number_of_local_perforations_; ++
perf) {
1932 const auto& intQuants = simulator.model()
1943 template<
typename TypeTag>
1944 typename WellInterface<TypeTag>::Eval
1945 WellInterface<TypeTag>::getPerfCellPressure(
const typename WellInterface<TypeTag>::FluidState& fs)
const
1947 if constexpr (Indices::oilEnabled) {
1948 return fs.pressure(FluidSystem::oilPhaseIdx);
1949 }
else if constexpr (Indices::gasEnabled) {
1950 return fs.pressure(FluidSystem::gasPhaseIdx);
1952 return fs.pressure(FluidSystem::waterPhaseIdx);
1956 template <
typename TypeTag>
1957 template<
class Value,
class Callback>
1959 WellInterface<TypeTag>::
1960 getMobility(
const Simulator& simulator,
1962 std::vector<Value>&
mob,
1968 if constexpr (std::is_same_v<Value, Scalar>) {
1969 return std::array<Scalar,3>{};
1971 return std::array<Eval,3>{};
1974 if (
static_cast<std::size_t
>(
local_perf_index) >= this->well_cells_.size()) {
1975 OPM_THROW(std::invalid_argument,
"The perforation index exceeds the size of the local containers - possibly getMobility was called with a global instead of a local perforation index!");
1978 assert (
int(
mob.size()) ==
this->num_conservation_quantities_);
1979 const auto& intQuants = simulator.model().intensiveQuantities(
cell_idx, 0);
1980 const auto& materialLawManager = simulator.problem().materialLawManager();
1988 if (!FluidSystem::phaseIsActive(
phaseIdx)) {
1992 const unsigned activeCompIdx = FluidSystem::canonicalToActiveCompIdx(FluidSystem::solventComponentIndex(
phaseIdx));
1995 if constexpr (has_solvent) {
1996 mob[Indices::contiSolventEqIdx] = extendEval(intQuants.solventMobility());
2008 if (!FluidSystem::phaseIsActive(
phaseIdx)) {
2012 const unsigned activeCompIdx = FluidSystem::canonicalToActiveCompIdx(FluidSystem::solventComponentIndex(
phaseIdx));
2017 if constexpr (has_solvent) {
2018 OPM_DEFLOG_THROW(std::runtime_error,
"individual mobility for wells does not work in combination with solvent",
deferred_logger);
2022 if (this->isInjector() && !this->inj_fc_multiplier_.empty()) {
2024 const auto&
connections = this->well_ecl_.getConnections();
2027 std::transform(
mob.begin(),
mob.end(),
mob.begin(),
2029 { return val * mult; });
2035 template<
typename TypeTag>
2037 WellInterface<TypeTag>::
2038 updateWellStateWithTHPTargetProd(
const Simulator& simulator,
2039 WellStateType& well_state,
2043 const auto&
summary_state = simulator.vanguard().summaryState();
2048 std::vector<Scalar> rates(this->number_of_phases_, 0.0);
2049 if (thp_update_iterations) {
2056 auto&
ws = well_state.well(this->name());
2057 ws.surface_rates = rates;
2066 template <
typename TypeTag>
2068 WellInterface<TypeTag>::
2069 computeConnLevelProdInd(
const FluidState& fs,
2070 const std::function<Scalar(
const Scalar)>&
connPICalc,
2071 const std::vector<Scalar>& mobility,
2074 const int np = this->number_of_phases_;
2075 for (
int p = 0;
p <
np; ++
p) {
2085 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
2086 FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx))
2088 const auto io = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::oilPhaseIdx);
2089 const auto ig = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::gasPhaseIdx);
2100 template <
typename TypeTag>
2102 WellInterface<TypeTag>::
2103 computeConnLevelInjInd(
const FluidState& fs,
2105 const std::function<Scalar(
const Scalar)>&
connIICalc,
2106 const std::vector<Scalar>& mobility,
2112 phase_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::gasPhaseIdx);
2115 phase_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::oilPhaseIdx);
2118 phase_pos = FluidSystem::canonicalToActivePhaseIdx(FluidSystem::waterPhaseIdx);
2122 fmt::format(
"Unsupported Injector Type ({}) "
2123 "for well {} during connection I.I. calculation",
2128 const auto mt = std::accumulate(mobility.begin(), mobility.end(), 0.0);
2133 template<
typename TypeTag>
2134 template<
class GasLiftSingleWell>
2135 std::unique_ptr<GasLiftSingleWell>
2136 WellInterface<TypeTag>::
2137 initializeGliftWellTest_(
const Simulator& simulator,
2138 WellStateType& well_state,
2144 auto& comm = simulator.vanguard().grid().comm();
2145 ecl_well_map.try_emplace(this->name(), &(this->wellEcl()), this->indexOfWell());
2148 simulator.vanguard().schedule(),
2149 simulator.vanguard().summaryState(),
2150 simulator.episodeIndex(),
2151 simulator.model().newtonMethod().numIterations(),
2161 const auto&
summary_state = simulator.vanguard().summaryState();
2162 return std::make_unique<GasLiftSingleWell>(*
this,
Definition DeferredLogger.hpp:57
Class encapsulating some information about parallel wells.
Definition ParallelWellInfo.hpp:198
Definition WellInterfaceIndices.hpp:34
Definition WellInterface.hpp:76
void initializeProducerWellState(const Simulator &simulator, WellStateType &well_state, DeferredLogger &deferred_logger) const
Modify the well_state's rates if there is only one nonzero rate.
Definition WellInterface_impl.hpp:1686
WellInterface(const Well &well, const ParallelWellInfo< Scalar > &pw_info, const int time_step, const ModelParameters ¶m, const RateConverterType &rate_converter, const int pvtRegionIdx, const int num_conservation_quantities, const int num_phases, const int index_of_well, const std::vector< PerforationData< Scalar > > &perf_data)
Constructor.
Definition WellInterface_impl.hpp:58
The state of a set of wells, tailored for use by the fully implicit blackoil simulator.
Definition WellState.hpp:66
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition blackoilbioeffectsmodules.hh:43
constexpr auto getPropValue()
get the value data member of a property
Definition propertysystem.hh:240
Static data associated with a well perforation.
Definition PerforationData.hpp:30