23#ifndef OPM_WELLINTERFACE_HEADER_INCLUDED
25#define OPM_WELLINTERFACE_IMPL_HEADER_INCLUDED
26#include <opm/simulators/wells/WellInterface.hpp>
29#include <opm/common/Exceptions.hpp>
31#include <opm/input/eclipse/Schedule/ScheduleTypes.hpp>
32#include <opm/input/eclipse/Schedule/Well/WDFAC.hpp>
34#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
36#include <opm/simulators/wells/GroupState.hpp>
37#include <opm/simulators/wells/TargetCalculator.hpp>
38#include <opm/simulators/wells/WellBhpThpCalculator.hpp>
39#include <opm/simulators/wells/WellHelpers.hpp>
41#include <dune/common/version.hh>
48#include <fmt/format.h>
54 template<
typename TypeTag>
59 const ModelParameters& param,
61 const int pvtRegionIdx,
77 connectionRates_.resize(this->number_of_perforations_);
79 if constexpr (has_solvent || has_zFraction) {
80 if (well.isInjector()) {
83 this->wsolvent_ = this->well_ecl_.getSolventFraction();
90 template<
typename TypeTag>
94 const std::vector<Scalar>& ,
96 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_();
180 template<
typename TypeTag>
181 typename WellInterface<TypeTag>::Scalar
182 WellInterface<TypeTag>::
185 if constexpr (has_micp) {
186 return this->wurea_();
192 template<
typename TypeTag>
194 WellInterface<TypeTag>::
195 updateWellControl(
const Simulator& simulator,
196 const IndividualOrGroup
iog,
205 const auto& summaryState = simulator.vanguard().summaryState();
206 const auto& schedule = simulator.vanguard().schedule();
207 const auto& well = this->well_ecl_;
208 auto&
ws = well_state.well(this->index_of_well_);
210 if (well.isInjector()) {
215 bool oscillating = std::count(this->well_control_log_.begin(),
this->well_control_log_.end(),
from) >= this->param_.max_number_of_well_switches_;
219 bool output = std::count(this->well_control_log_.begin(),
this->well_control_log_.end(),
from) == this->param_.max_number_of_well_switches_;
221 std::ostringstream
ss;
222 ss <<
" The control mode for well " << this->name()
223 <<
" is oscillating\n"
224 <<
" We don't allow for more than "
225 << this->param_.max_number_of_well_switches_
226 <<
" switches. The control is kept at " <<
from;
229 this->well_control_log_.push_back(
from);
234 if (
iog == IndividualOrGroup::Individual) {
236 }
else if (
iog == IndividualOrGroup::Group) {
242 Parallel::Communication
cc = simulator.vanguard().grid().comm();
246 if (well.isInjector()) {
251 std::ostringstream
ss;
252 ss <<
" Switching control mode for well " << this->name()
256 ss <<
" on rank " <<
cc.rank();
260 this->well_control_log_.push_back(
from);
261 updateWellStateWithTarget(simulator, group_state, well_state,
deferred_logger);
268 template<
typename TypeTag>
270 WellInterface<TypeTag>::
271 updateWellControlAndStatusLocalIteration(
const Simulator& simulator,
281 const auto&
summary_state = simulator.vanguard().summaryState();
282 const auto& schedule = simulator.vanguard().schedule();
283 auto&
ws = well_state.well(this->index_of_well_);
285 if (this->isInjector()) {
290 const bool oscillating = std::count(this->well_control_log_.begin(),
this->well_control_log_.end(),
from) >= this->param_.max_number_of_well_switches_;
292 if (
oscillating || this->wellUnderZeroRateTarget(simulator, well_state,
deferred_logger) || !(this->well_ecl_.getStatus() == WellStatus::OPEN)) {
296 const Scalar
sgn = this->isInjector() ? 1.0 : -1.0;
297 if (!this->wellIsStopped()){
312 if (
hasGroupControl && this->param_.check_group_constraints_inner_well_iterations_) {
317 const bool thp_controlled = this->isInjector() ?
ws.injection_cmode == Well::InjectorCMode::THP :
318 ws.production_cmode == Well::ProducerCMode::THP;
321 updateWellStateWithTarget(simulator, group_state, well_state,
deferred_logger);
332 const Scalar bhp = well_state.well(this->index_of_well_).bhp;
337 std::vector<Scalar> rates(this->num_components_);
338 if (this->isInjector()){
339 const Scalar
bhp_thp = WellBhpThpCalculator(*this).
340 calculateBhpFromThp(well_state, rates,
343 this->getRefDensity(),
349 const Scalar
bhp_min = WellBhpThpCalculator(*this).
350 calculateMinimumBhpFromThp(well_state,
353 this->getRefDensity());
362 well_state.well(this->index_of_well_).thp = this->getTHPConstraint(
summary_state);
373 template<
typename TypeTag>
375 WellInterface<TypeTag>::
376 wellTesting(
const Simulator& simulator,
391 initPrimaryVariablesEvaluation();
393 if (this->isProducer()) {
394 const auto& schedule = simulator.vanguard().schedule();
395 const auto report_step = simulator.episodeIndex();
396 const auto&
glo = schedule.glo(report_step);
412 const auto msg = fmt::format(
"WTEST: Well {} is not solvable (physical)", this->name());
419 if ( !this->isOperableAndSolvable() ) {
420 const auto msg = fmt::format(
"WTEST: Well {} is not operable (physical)", this->name());
427 }
catch (
const std::exception&
e) {
428 const std::string
msg = fmt::format(
"well {}: computeWellPotentials() "
429 "failed during testing for re-opening: ",
430 this->name(),
e.what());
435 for (
int p = 0;
p <
np; ++
p) {
459 well_test_state.open_well(this->name());
461 std::string
msg = std::string(
"well ") + this->name() + std::string(
" is re-opened");
467 well_test_state.open_completion(this->name(),
completion.first);
478 template<
typename TypeTag>
480 WellInterface<TypeTag>::
481 iterateWellEquations(
const Simulator& simulator,
487 const auto&
summary_state = simulator.vanguard().summaryState();
488 const auto inj_controls = this->well_ecl_.isInjector() ? this->well_ecl_.injectionControls(
summary_state) : Well::InjectionControls(0);
489 const auto prod_controls = this->well_ecl_.isProducer() ? this->well_ecl_.productionControls(
summary_state) : Well::ProductionControls(0);
490 bool converged =
false;
493 if (!this->param_.local_well_solver_control_switching_){
496 if (this->param_.use_implicit_ipr_ &&
this->well_ecl_.isProducer() &&
this->wellHasTHPConstraints(
summary_state) && (
this->well_ecl_.getStatus() == WellStatus::OPEN)) {
504 const std::string
msg =
"Inner well iterations failed for well " + this->name() +
" Treat the well as unconverged. ";
511 template<
typename TypeTag>
513 WellInterface<TypeTag>::
514 solveWellWithTHPConstraint(
const Simulator& simulator,
522 const auto&
summary_state = simulator.vanguard().summaryState();
524 bool converged =
true;
525 auto&
ws = well_state.well(this->index_of_well_);
527 if (this->wellIsStopped()) {
532 const auto msg = fmt::format(
"estimateOperableBhp: Did not find operable BHP for well {}", this->name());
541 const Scalar bhp = std::max(
bhp_target.value(),
551 const bool isThp =
ws.production_cmode == Well::ProducerCMode::THP;
554 auto rates = well_state.well(this->index_of_well_).surface_rates;
555 this->adaptRatesForVFP(rates);
560 this->operability_status_.use_vfpexplicit =
true;
566 const auto msg = fmt::format(
"Well {} converged to an unstable solution, re-solving", this->name());
578 this->operability_status_.use_vfpexplicit =
true;
589 const Scalar bhp = std::max(
bhp_target.value(),
593 converged = this->iterateWellEqWithSwitching(simulator,
dt,
603 this->operability_status_.can_obtain_bhp_with_thp_limit =
is_operable;
604 this->operability_status_.obey_thp_limit_under_bhp_limit =
is_operable;
608 template<
typename TypeTag>
609 std::optional<typename WellInterface<TypeTag>::Scalar>
610 WellInterface<TypeTag>::
611 estimateOperableBhp(
const Simulator& simulator,
619 Scalar
bhp_min = WellBhpThpCalculator(*this).calculateMinimumBhpFromThp(well_state,
this->well_ecl_,
summary_state,
this->getRefDensity());
622 if (!converged || this->wellIsStopped()) {
626 auto rates = well_state.well(this->index_of_well_).surface_rates;
627 this->adaptRatesForVFP(rates);
628 return WellBhpThpCalculator(*this).estimateStableBhp(well_state,
this->well_ecl_, rates,
this->getRefDensity(),
summary_state);
631 template<
typename TypeTag>
633 WellInterface<TypeTag>::
634 solveWellWithBhp(
const Simulator& simulator,
644 auto&
ws = well_state.well(this->index_of_well_);
647 if (this->isInjector()) {
651 ws.injection_cmode = Well::InjectorCMode::BHP;
656 ws.production_cmode = Well::ProducerCMode::BHP;
667 template<
typename TypeTag>
669 WellInterface<TypeTag>::
670 solveWellWithZeroRate(
const Simulator& simulator,
687 template<
typename TypeTag>
689 WellInterface<TypeTag>::
690 solveWellForTesting(
const Simulator& simulator,
697 const double dt = simulator.timeStepSize();
698 const auto&
summary_state = simulator.vanguard().summaryState();
702 well_state.well(this->indexOfWell()).production_cmode = Well::ProducerCMode::THP;
703 converged = gliftBeginTimeStepWellTestIterateWellEquations(
707 well_state.well(this->indexOfWell()).production_cmode = Well::ProducerCMode::BHP;
708 converged = iterateWellEquations(simulator,
dt, well_state, group_state,
deferred_logger);
711 deferred_logger.debug(
"WellTest: Well equation for well " + this->name() +
" converged");
714 const int max_iter = this->param_.max_welleq_iter_;
715 deferred_logger.debug(
"WellTest: Well equation for well " + this->name() +
" failed converging in "
716 + std::to_string(
max_iter) +
" iterations");
722 template<
typename TypeTag>
724 WellInterface<TypeTag>::
725 solveWellEquation(
const Simulator& simulator,
730 if (!this->isOperableAndSolvable() && !this->wellIsStopped())
735 const double dt = simulator.timeStepSize();
736 bool converged = iterateWellEquations(simulator,
dt, well_state, group_state,
deferred_logger);
746 auto&
ws = well_state.well(this->indexOfWell());
748 if (this->well_ecl_.isInjector()) {
749 thp_control =
ws.injection_cmode == Well::InjectorCMode::THP;
751 ws.injection_cmode = Well::InjectorCMode::BHP;
755 thp_control =
ws.production_cmode == Well::ProducerCMode::THP;
757 ws.production_cmode = Well::ProducerCMode::BHP;
762 const std::string
msg = std::string(
"The newly opened well ") + this->name()
763 + std::string(
" with THP control did not converge during inner iterations, we try again with bhp control");
765 converged = this->iterateWellEquations(simulator,
dt, well_state, group_state,
deferred_logger);
770 const int max_iter = this->param_.max_welleq_iter_;
771 deferred_logger.debug(
"Compute initial well solution for well " + this->name() +
". Failed to converge in "
772 + std::to_string(
max_iter) +
" iterations");
779 template <
typename TypeTag>
781 WellInterface<TypeTag>::
782 assembleWellEq(
const Simulator& simulator,
788 prepareWellBeforeAssembling(simulator,
dt, well_state, group_state,
deferred_logger);
789 assembleWellEqWithoutIteration(simulator,
dt, well_state, group_state,
deferred_logger);
794 template <
typename TypeTag>
796 WellInterface<TypeTag>::
797 assembleWellEqWithoutIteration(
const Simulator& simulator,
803 const auto&
summary_state = simulator.vanguard().summaryState();
804 const auto inj_controls = this->well_ecl_.isInjector() ? this->well_ecl_.injectionControls(
summary_state) : Well::InjectionControls(0);
805 const auto prod_controls = this->well_ecl_.isProducer() ? this->well_ecl_.productionControls(
summary_state) : Well::ProductionControls(0);
813 template<
typename TypeTag>
815 WellInterface<TypeTag>::
816 prepareWellBeforeAssembling(
const Simulator& simulator,
822 const bool old_well_operable = this->operability_status_.isOperableAndSolvable();
824 if (this->param_.check_well_operability_iter_)
828 const int iteration_idx = simulator.model().newtonMethod().numIterations();
830 const auto&
ws = well_state.well(this->indexOfWell());
835 std::any_of(
ws.surface_rates.begin(),
836 ws.surface_rates.begin() + well_state.numPhases(),
837 [](Scalar
rate) { return rate != Scalar(0.0); });
839 this->operability_status_.solvable =
true;
840 bool converged = this->iterateWellEquations(simulator,
dt, well_state, group_state,
deferred_logger);
848 this->operability_status_.resetOperability();
850 deferred_logger.debug(
" " + this->name() +
" is re-opened after being stopped during local solve");
855 if (this->isInjector()) {
862 deferred_logger.debug(
" " + this->name() +
" switched from " +
from +
" to " +
to +
" during local solve");
867 if (this->param_.shut_unsolvable_wells_)
868 this->operability_status_.solvable =
false;
871 if (this->operability_status_.has_negative_potentials) {
876 }
catch (
const std::exception&
e) {
877 const std::string
msg = fmt::format(
"well {}: computeWellPotentials() failed "
878 "during attempt to recompute potentials for well: ",
879 this->name(),
e.what());
881 this->operability_status_.has_negative_potentials =
true;
883 auto&
ws = well_state.well(this->indexOfWell());
884 const int np = well_state.numPhases();
885 for (
int p = 0;
p <
np; ++
p) {
889 this->changed_to_open_this_step_ =
false;
890 const bool well_operable = this->operability_status_.isOperableAndSolvable();
893 deferred_logger.info(
" well " + this->name() +
" gets STOPPED during iteration ");
895 changed_to_stopped_this_step_ =
true;
897 deferred_logger.info(
" well " + this->name() +
" gets REVIVED during iteration ");
899 changed_to_stopped_this_step_ =
false;
900 this->changed_to_open_this_step_ =
true;
904 template<
typename TypeTag>
906 WellInterface<TypeTag>::addCellRates(RateVector& rates,
int cellIdx)
const
908 if(!this->isOperableAndSolvable() && !this->wellIsStopped())
913 for (
int i = 0; i < RateVector::dimension; ++i) {
914 rates[i] += connectionRates_[
perfIdx][i];
920 template<
typename TypeTag>
921 typename WellInterface<TypeTag>::Scalar
922 WellInterface<TypeTag>::volumetricSurfaceRateForConnection(
int cellIdx,
int phaseIdx)
const
926 const unsigned activeCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(
phaseIdx));
931 OPM_THROW(std::invalid_argument,
"The well with name " + this->name()
932 +
" does not perforate cell " + std::to_string(
cellIdx));
939 template<
typename TypeTag>
941 WellInterface<TypeTag>::
942 checkWellOperability(
const Simulator& simulator,
947 if (!this->param_.check_well_operability_) {
951 if (this->wellIsStopped() && !changed_to_stopped_this_step_) {
956 if (!this->operability_status_.isOperableAndSolvable()) {
957 this->operability_status_.use_vfpexplicit =
true;
959 "well not operable, trying with explicit vfp lookup: " + this->name());
964 template<
typename TypeTag>
966 WellInterface<TypeTag>::
967 gliftBeginTimeStepWellTestIterateWellEquations(
const Simulator& simulator,
973 const auto& well_name = this->name();
974 assert(this->wellHasTHPConstraints(simulator.vanguard().summaryState()));
975 const auto& schedule = simulator.vanguard().schedule();
978 if(
glo.active() &&
glo.has_well(well_name)) {
979 const auto increment =
glo.gaslift_increment();
980 auto alq = well_state.getALQ(well_name);
983 well_state.setALQ(well_name, alq);
994 return iterateWellEquations(simulator,
dt, well_state, group_state,
deferred_logger);
998 template<
typename TypeTag>
1000 WellInterface<TypeTag>::
1001 gliftBeginTimeStepWellTestUpdateALQ(
const Simulator& simulator,
1005 const auto&
summary_state = simulator.vanguard().summaryState();
1006 const auto& well_name = this->name();
1008 const std::string
msg = fmt::format(
"GLIFT WTEST: Well {} does not have THP constraints", well_name);
1012 const auto& schedule = simulator.vanguard().schedule();
1015 if (!
glo.has_well(well_name)) {
1016 const std::string
msg = fmt::format(
1017 "GLIFT WTEST: Well {} : Gas Lift not activated: "
1018 "WLIFTOPT is probably missing. Skipping.", well_name);
1029 const auto&
well_ecl = this->wellEcl();
1031 const auto&
table = this->vfpProperties()->getProd()->getTable(
controls.vfp_table_number);
1035 well_state.setALQ(well_name,
max_alq);
1036 const std::string
msg = fmt::format(
1037 "GLIFT WTEST: Well {} : Setting ALQ to max value: {}",
1042 template<
typename TypeTag>
1044 WellInterface<TypeTag>::
1045 updateWellOperability(
const Simulator& simulator,
1049 if (this->param_.local_well_solver_control_switching_) {
1050 const bool success = updateWellOperabilityFromWellEq(simulator, well_state,
deferred_logger);
1054 deferred_logger.debug(
"Operability check using well equations did not converge for well "
1055 + this->name() +
", reverting to classical approach." );
1058 this->operability_status_.resetOperability();
1060 bool thp_controlled = this->isInjector() ? well_state.well(this->index_of_well_).injection_cmode == Well::InjectorCMode::THP:
1061 well_state.well(this->index_of_well_).production_cmode == Well::ProducerCMode::THP;
1062 bool bhp_controlled = this->isInjector() ? well_state.well(this->index_of_well_).injection_cmode == Well::InjectorCMode::BHP:
1063 well_state.well(this->index_of_well_).production_cmode == Well::ProducerCMode::BHP;
1070 checkOperabilityUnderBHPLimit(well_state, simulator,
deferred_logger);
1074 checkOperabilityUnderTHPLimit(simulator, well_state,
deferred_logger);
1078 template<
typename TypeTag>
1080 WellInterface<TypeTag>::
1081 updateWellOperabilityFromWellEq(
const Simulator& simulator,
1086 assert(this->param_.local_well_solver_control_switching_);
1087 this->operability_status_.resetOperability();
1089 const auto& group_state = simulator.problem().wellModel().groupState();
1090 const double dt = simulator.timeStepSize();
1096 template<
typename TypeTag>
1098 WellInterface<TypeTag>::
1099 updateWellStateWithTarget(
const Simulator& simulator,
1106 const auto& well = this->well_ecl_;
1107 const int well_index = this->index_of_well_;
1108 auto&
ws = well_state.well(well_index);
1110 const int np = well_state.numPhases();
1111 const auto& summaryState = simulator.vanguard().summaryState();
1112 const auto& schedule = simulator.vanguard().schedule();
1114 if (this->wellIsStopped()) {
1115 for (
int p = 0;
p<
np; ++
p) {
1116 ws.surface_rates[
p] = 0;
1122 if (this->isInjector() )
1124 const auto&
controls = well.injectionControls(summaryState);
1129 case InjectorType::WATER:
1131 phasePos = pu.phase_pos[BlackoilPhases::Aqua];
1134 case InjectorType::OIL:
1136 phasePos = pu.phase_pos[BlackoilPhases::Liquid];
1139 case InjectorType::GAS:
1141 phasePos = pu.phase_pos[BlackoilPhases::Vapour];
1145 OPM_DEFLOG_THROW(std::runtime_error,
"Expected WATER, OIL or GAS as type for injectors " + this->name(),
deferred_logger );
1148 const auto current =
ws.injection_cmode;
1151 case Well::InjectorCMode::RATE:
1154 if(this->rsRvInj() > 0) {
1155 if (
injectorType == InjectorType::OIL && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
1156 ws.surface_rates[pu.phase_pos[BlackoilPhases::Vapour]] =
controls.surface_rate * this->rsRvInj();
1157 }
else if (
injectorType == InjectorType::GAS && FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1158 ws.surface_rates[pu.phase_pos[BlackoilPhases::Liquid]] =
controls.surface_rate * this->rsRvInj();
1160 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 );
1166 case Well::InjectorCMode::RESV:
1168 std::vector<Scalar>
convert_coeff(this->number_of_phases_, 1.0);
1169 this->rateConverter_.calcCoeff( 0, this->pvtRegionIdx_,
convert_coeff);
1175 case Well::InjectorCMode::THP:
1177 auto rates =
ws.surface_rates;
1178 Scalar bhp = WellBhpThpCalculator(*this).calculateBhpFromThp(well_state,
1182 this->getRefDensity(),
1185 ws.thp = this->getTHPConstraint(summaryState);
1190 Scalar
total_rate = std::accumulate(rates.begin(), rates.end(), 0.0);
1192 ws.surface_rates =
ws.well_potentials;
1196 case Well::InjectorCMode::BHP:
1200 for (
int p = 0;
p<
np; ++
p) {
1207 ws.surface_rates =
ws.well_potentials;
1211 case Well::InjectorCMode::GRUP:
1213 assert(well.isAvailableForGroupControl());
1214 const auto& group = schedule.getGroup(well.groupName(),
this->currentStep());
1216 std::optional<Scalar>
target =
1217 this->getGroupInjectionTargetRate(group,
1229 case Well::InjectorCMode::CMODE_UNDEFINED:
1231 OPM_DEFLOG_THROW(std::runtime_error,
"Well control must be specified for well " + this->name(),
deferred_logger );
1250 const auto current =
ws.production_cmode;
1251 const auto&
controls = well.productionControls(summaryState);
1253 case Well::ProducerCMode::ORAT:
1259 for (
int p = 0;
p<
np; ++
p) {
1263 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1266 for (
int p = 0;
p<
np; ++
p) {
1273 case Well::ProducerCMode::WRAT:
1279 for (
int p = 0;
p<
np; ++
p) {
1283 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1286 for (
int p = 0;
p<
np; ++
p) {
1293 case Well::ProducerCMode::GRAT:
1299 for (
int p = 0;
p<
np; ++
p) {
1303 const std::vector<Scalar >
fractions = initialWellRateFractions(simulator, well_state);
1306 for (
int p = 0;
p<
np; ++
p) {
1315 case Well::ProducerCMode::LRAT:
1318 -
ws.surface_rates[ pu.phase_pos[Oil] ];
1322 for (
int p = 0;
p<
np; ++
p) {
1326 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1329 for (
int p = 0;
p<
np; ++
p) {
1336 case Well::ProducerCMode::CRAT:
1338 OPM_DEFLOG_THROW(std::runtime_error,
1339 fmt::format(
"CRAT control not supported, well {}", this->name()),
1342 case Well::ProducerCMode::RESV:
1344 std::vector<Scalar>
convert_coeff(this->number_of_phases_, 1.0);
1345 this->rateConverter_.calcCoeff( 0, this->pvtRegionIdx_,
ws.surface_rates,
convert_coeff);
1347 for (
int p = 0;
p<
np; ++
p) {
1354 for (
int p = 0;
p<
np; ++
p) {
1358 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1359 for (
int p = 0;
p<
np; ++
p) {
1364 std::vector<Scalar>
hrates(this->number_of_phases_,0.);
1365 if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
1368 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1371 if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
1374 std::vector<Scalar>
hrates_resv(this->number_of_phases_,0.);
1375 this->rateConverter_.calcReservoirVoidageRates( 0, this->pvtRegionIdx_,
hrates,
hrates_resv);
1380 for (
int p = 0;
p<
np; ++
p) {
1384 const std::vector<Scalar>
fractions = initialWellRateFractions(simulator, well_state);
1385 for (
int p = 0;
p<
np; ++
p) {
1392 case Well::ProducerCMode::BHP:
1396 for (
int p = 0;
p<
np; ++
p) {
1403 for (
int p = 0;
p<
np; ++
p) {
1404 ws.surface_rates[
p] = -
ws.well_potentials[
p];
1409 case Well::ProducerCMode::THP:
1417 auto rates =
ws.surface_rates;
1418 this->adaptRatesForVFP(rates);
1419 const Scalar bhp = WellBhpThpCalculator(*this).calculateBhpFromThp(
1422 ws.thp = this->getTHPConstraint(summaryState);
1426 const Scalar
total_rate = -std::accumulate(rates.begin(), rates.end(), 0.0);
1428 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1429 ws.surface_rates[
p] = -
ws.well_potentials[
p];
1435 case Well::ProducerCMode::GRUP:
1437 assert(well.isAvailableForGroupControl());
1438 const auto& group = schedule.getGroup(well.groupName(),
this->currentStep());
1440 Scalar scale = this->getGroupProductionTargetRate(group,
1450 for (
int p = 0;
p<
np; ++
p) {
1451 ws.surface_rates[
p] *= scale;
1453 ws.trivial_target =
false;
1455 ws.trivial_target =
true;
1459 case Well::ProducerCMode::CMODE_UNDEFINED:
1460 case Well::ProducerCMode::NONE:
1462 OPM_DEFLOG_THROW(std::runtime_error,
"Well control must be specified for well " + this->name() ,
deferred_logger);
1473 template<
typename TypeTag>
1475 WellInterface<TypeTag>::
1476 wellUnderZeroRateTarget(
const Simulator& simulator,
1484 const auto& summaryState = simulator.vanguard().summaryState();
1485 return this->wellUnderZeroRateTargetIndividual(summaryState, well_state);
1491 template <
typename TypeTag>
1493 WellInterface<TypeTag>::wellUnderZeroGroupRateTarget(
const Simulator& simulator,
1501 const auto& summaryState = simulator.vanguard().summaryState();
1502 const auto& group_state = simulator.problem().wellModel().groupState();
1503 const auto& schedule = simulator.vanguard().schedule();
1504 return this->zeroGroupRateTarget(summaryState, schedule, well_state, group_state,
deferred_logger);
1509 template<
typename TypeTag>
1511 WellInterface<TypeTag>::
1512 stoppedOrZeroRateTarget(
const Simulator& simulator,
1518 return this->wellIsStopped()
1519 || this->wellUnderZeroRateTarget(simulator, well_state,
deferred_logger);
1522 template<
typename TypeTag>
1523 std::vector<typename WellInterface<TypeTag>::Scalar>
1524 WellInterface<TypeTag>::
1525 initialWellRateFractions(
const Simulator& simulator,
1528 const int np = this->number_of_phases_;
1530 const auto&
ws = well_state.well(this->index_of_well_);
1533 for (
int p = 0;
p<
np; ++
p) {
1537 for (
int p = 0;
p<
np; ++
p) {
1545 const int nperf = this->number_of_perforations_;
1555 for (
int p = 0;
p <
np; ++
p) {
1559 for (
int p = 0;
p <
np; ++
p) {
1569 template <
typename TypeTag>
1578 auto&
ws = well_state.well(this->index_of_well_);
1581 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1598 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1599 ws.surface_rates[
p] =
well_q_s[this->flowPhaseToModelCompIdx(
p)];
1608 for (
int p = 0;
p < this->number_of_phases_; ++
p) {
1610 const int comp_idx = this->flowPhaseToModelCompIdx(
p);
1611 Scalar&
rate =
ws.surface_rates[
p];
1618 template <
typename TypeTag>
1619 std::vector<typename WellInterface<TypeTag>::Scalar>
1629 auto wi = std::vector<Scalar>
1632 if constexpr (! Indices::gasEnabled) {
1636 const auto&
wdfac = this->well_ecl_.getWDFAC();
1638 if (!
wdfac.useDFactor() || (this->well_index_[
perf] == 0.0)) {
1649 const auto&
connection = this->well_ecl_.getConnections()[
ws.perf_data.ecl_index[
perf]];
1652 const unsigned gas_comp_idx = Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx);
1665 const Scalar
r2n =
b*
b + 4*
a*
c;
1667 const Scalar
rn = std::sqrt(
r2n);
1668 const Scalar
xn1 = (
b-
rn)*0.5/
a;
1672 const Scalar
xn2 = (
b+
rn)*0.5/
a;
1679 const Scalar
r2p =
b*
b - 4*
a*
c;
1681 const Scalar
rp = std::sqrt(
r2p);
1682 const Scalar
xp1 = (
rp-
b)*0.5/
a;
1686 const Scalar
xp2 = -(
rp+
b)*0.5/
a;
1696 template <
typename TypeTag>
1698 WellInterface<TypeTag>::
1699 updateConnectionDFactor(
const Simulator& simulator,
1702 if (! this->well_ecl_.getWDFAC().useDFactor()) {
1706 auto&
d_factor =
ws.perf_data.connection_d_factor;
1708 for (
int perf = 0;
perf < this->number_of_perforations_; ++
perf) {
1716 template <
typename TypeTag>
1717 typename WellInterface<TypeTag>::Scalar
1718 WellInterface<TypeTag>::
1719 computeConnectionDFactor(
const int perf,
1724 return FluidSystem::referenceDensity(FluidSystem::gasPhaseIdx,
regIdx);
1729 temperature =
ws.temperature,
1734 const auto&
gasPvt = FluidSystem::gasPvt();
1739 const Scalar
rv_sat =
gasPvt.saturatedOilVaporizationFactor
1751 const auto&
connection = this->well_ecl_.getConnections()
1752 [
ws.perf_data.ecl_index[
perf]];
1758 template <
typename TypeTag>
1760 WellInterface<TypeTag>::
1761 updateConnectionTransmissibilityFactor(
const Simulator& simulator,
1765 &
conns = this->well_ecl_.getConnections()]
1771 auto&
tmult =
ws.perf_data.connection_compaction_tmult;
1772 auto&
ctf =
ws.perf_data.connection_transmissibility_factor;
1774 for (
int perf = 0;
perf < this->number_of_perforations_; ++
perf) {
1777 const auto&
intQuants = simulator.model()
1788 template<
typename TypeTag>
1789 typename WellInterface<TypeTag>::Eval
1790 WellInterface<TypeTag>::getPerfCellPressure(
const typename WellInterface<TypeTag>::FluidState&
fs)
const
1792 if constexpr (Indices::oilEnabled) {
1793 return fs.pressure(FluidSystem::oilPhaseIdx);
1794 }
else if constexpr (Indices::gasEnabled) {
1795 return fs.pressure(FluidSystem::gasPhaseIdx);
1797 return fs.pressure(FluidSystem::waterPhaseIdx);
1801 template <
typename TypeTag>
1802 template<
class Value,
class Callback>
1804 WellInterface<TypeTag>::
1805 getMobility(
const Simulator& simulator,
1807 std::vector<Value>&
mob,
1813 if constexpr (std::is_same_v<Value, Scalar>) {
1814 return std::array<Scalar,3>{};
1816 return std::array<Eval,3>{};
1822 const auto& materialLawManager = simulator.problem().materialLawManager();
1826 const int satid = this->saturation_table_number_[
perf] - 1;
1830 if (!FluidSystem::phaseIsActive(
phaseIdx)) {
1834 const unsigned activeCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(
phaseIdx));
1837 if constexpr (has_solvent) {
1838 mob[Indices::contiSolventEqIdx] = extendEval(
intQuants.solventMobility());
1850 if (!FluidSystem::phaseIsActive(
phaseIdx)) {
1854 const unsigned activeCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(
phaseIdx));
1859 if constexpr (has_solvent) {
1860 OPM_DEFLOG_THROW(std::runtime_error,
"individual mobility for wells does not work in combination with solvent",
deferred_logger);
1864 if (this->isInjector() && !this->inj_fc_multiplier_.empty()) {
1866 const auto&
connections = this->well_ecl_.getConnections();
1870 val *= this->inj_fc_multiplier_[
perf];
1877 template<
typename TypeTag>
1879 WellInterface<TypeTag>::
1880 updateWellStateWithTHPTargetProd(
const Simulator& simulator,
1884 const auto&
summary_state = simulator.vanguard().summaryState();
1889 std::vector<Scalar> rates(this->number_of_phases_, 0.0);
1890 if (thp_update_iterations) {
1897 auto&
ws = well_state.well(this->name());
1898 ws.surface_rates = rates;
1907 template <
typename TypeTag>
1909 WellInterface<TypeTag>::
1910 computeConnLevelProdInd(
const FluidState&
fs,
1911 const std::function<Scalar(
const Scalar)>&
connPICalc,
1912 const std::vector<Scalar>& mobility,
1916 const int np = this->number_of_phases_;
1917 for (
int p = 0;
p <
np; ++
p) {
1921 mobility[this->flowPhaseToModelCompIdx(
p)]
1922 *
fs.invB(this->flowPhaseToModelPhaseIdx(
p)).value();
1927 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
1928 FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx))
1930 const auto io = pu.phase_pos[Oil];
1931 const auto ig = pu.phase_pos[Gas];
1942 template <
typename TypeTag>
1944 WellInterface<TypeTag>::
1945 computeConnLevelInjInd(
const FluidState&
fs,
1947 const std::function<Scalar(
const Scalar)>&
connIICalc,
1948 const std::vector<Scalar>& mobility,
1957 phase_pos = pu.phase_pos[Gas];
1960 phase_pos = pu.phase_pos[Oil];
1963 phase_pos = pu.phase_pos[Water];
1967 fmt::format(
"Unsupported Injector Type ({}) "
1968 "for well {} during connection I.I. calculation",
1973 const auto mt = std::accumulate(mobility.begin(), mobility.end(), 0.0);
Definition DeferredLogger.hpp:57
Class encapsulating some information about parallel wells.
Definition ParallelWellInfo.hpp:186
Definition SingleWellState.hpp:42
Definition WellInterfaceIndices.hpp:34
Definition WellInterface.hpp:71
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_components, const int num_phases, const int index_of_well, const std::vector< PerforationData< Scalar > > &perf_data)
Constructor.
Definition WellInterface_impl.hpp:56
void updateWellStateRates(const Simulator &simulator, WellState< Scalar > &well_state, DeferredLogger &deferred_logger) const
Modify the well_state's rates if there is only one nonzero rate.
Definition WellInterface_impl.hpp:1572
The state of a set of wells, tailored for use by the fully implicit blackoil simulator.
Definition WellState.hpp:62
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition blackoilboundaryratevector.hh:37
PhaseUsage phaseUsage(const Phases &phases)
Determine the active phases.
Definition phaseUsageFromDeck.cpp:37
constexpr auto getPropValue()
get the value data member of a property
Definition propertysystem.hh:242
Static data associated with a well perforation.
Definition PerforationData.hpp:30
Definition BlackoilPhases.hpp:46