From 969448b0cb11a3ee4d20a7f1e22e5b82cb694a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20H=C3=A6gland?= Date: Sun, 23 Nov 2025 20:44:48 +0100 Subject: [PATCH] Refactor TargetCalculator Refactor TargetCalculator::groupTarget() to WellGroupHelper::getProductionGroupTarget(), and don't pass Group::ProductionControls as a parameter. Since TargetCalculator only works for a given group, passing control as a parameter is confusing and can be error prone if being passed a control for a different group than the TargetCalculator was constructed for. --- .../wells/BlackoilWellModelNldd_impl.hpp | 4 +- .../wells/BlackoilWellModel_impl.hpp | 35 +- opm/simulators/wells/GroupStateHelper.cpp | 376 ++++++++++-------- opm/simulators/wells/GroupStateHelper.hpp | 11 +- opm/simulators/wells/MultisegmentWell.hpp | 11 +- .../wells/MultisegmentWellAssemble.cpp | 46 +-- .../wells/MultisegmentWellAssemble.hpp | 7 +- .../wells/MultisegmentWell_impl.hpp | 61 ++- opm/simulators/wells/StandardWell.hpp | 17 +- opm/simulators/wells/StandardWellAssemble.cpp | 23 +- opm/simulators/wells/StandardWellAssemble.hpp | 7 +- opm/simulators/wells/StandardWell_impl.hpp | 75 ++-- opm/simulators/wells/TargetCalculator.cpp | 180 ++------- opm/simulators/wells/TargetCalculator.hpp | 44 +- opm/simulators/wells/WellAssemble.cpp | 42 +- opm/simulators/wells/WellAssemble.hpp | 12 +- opm/simulators/wells/WellGroupControls.cpp | 97 ++--- opm/simulators/wells/WellGroupControls.hpp | 17 +- opm/simulators/wells/WellInterface.hpp | 25 +- .../wells/WellInterfaceFluidSystem.cpp | 43 +- .../wells/WellInterfaceFluidSystem.hpp | 17 +- opm/simulators/wells/WellInterface_impl.hpp | 52 +-- 22 files changed, 505 insertions(+), 697 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModelNldd_impl.hpp b/opm/simulators/wells/BlackoilWellModelNldd_impl.hpp index b54dce8bf16..afce943b89e 100644 --- a/opm/simulators/wells/BlackoilWellModelNldd_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModelNldd_impl.hpp @@ -118,6 +118,7 @@ recoverWellSolutionAndUpdateWellState(const BVector& x, } well->recoverWellSolutionAndUpdateWellState(wellModel_.simulator(), x_local_, + wellModel_.groupStateHelper(), wellModel_.wellState(), local_deferredLogger); } @@ -143,8 +144,7 @@ getWellConvergence(const Domain& domain, for (const auto& well : wellModel_.localNonshutWells()) { if ((this->well_domain().at(well->name()) == domain.index)) { if (well->isOperableAndSolvable() || well->wellIsStopped()) { - report += well->getWellConvergence(wellModel_.simulator(), - wellModel_.wellState(), + report += well->getWellConvergence(wellModel_.groupStateHelper(), B_avg, local_deferredLogger, relax_tolerance); diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 30bd08e4da9..13ec21e7d36 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -513,9 +513,9 @@ namespace Opm { if (event || dyn_status_change) { try { well->scaleSegmentRatesAndPressure(this->wellState()); - well->calculateExplicitQuantities(simulator_, this->wellState(), local_deferredLogger); + well->calculateExplicitQuantities(simulator_, this->groupStateHelper(), local_deferredLogger); well->updateWellStateWithTarget(simulator_, this->groupStateHelper(), this->wellState(), local_deferredLogger); - well->updatePrimaryVariables(simulator_, this->wellState(), local_deferredLogger); + well->updatePrimaryVariables(this->groupStateHelper(), local_deferredLogger); well->solveWellEquation( simulator_, this->groupStateHelper(), this->wellState(), local_deferredLogger ); @@ -1168,7 +1168,7 @@ namespace Opm { OPM_BEGIN_PARALLEL_TRY_CATCH(); for (auto& well : this->well_container_) { - well->solveEqAndUpdateWellState(simulator_, well_state, deferred_logger); + well->solveEqAndUpdateWellState(simulator_, this->groupStateHelper(), well_state, deferred_logger); } OPM_END_PARALLEL_TRY_CATCH("BlackoilWellModel::doPreStepNetworkRebalance() failed: ", this->simulator_.vanguard().grid().comm()); @@ -1402,9 +1402,6 @@ namespace Opm { //TODO: Auto choke combined with RESV control is not supported std::vector resv_coeff(Indices::numPhases, 1.0); - Scalar gratTargetFromSales = 0.0; - if (group_state.has_grat_sales_target(group.name())) - gratTargetFromSales = group_state.grat_sales_target(group.name()); const auto ctrl = group.productionControls(summary_state); auto cmode_tmp = ctrl.cmode; @@ -1417,7 +1414,7 @@ namespace Opm { const Scalar efficiencyFactor = 1.0; const Group& parentGroup = this->schedule().getGroup(group.parent(), reportStepIdx); auto target = WellGroupControls::getAutoChokeGroupProductionTargetRate( - group.name(), + group, parentGroup, this->groupStateHelper(), this->schedule(), @@ -1430,16 +1427,12 @@ namespace Opm { target_tmp = target.first; cmode_tmp = target.second; } - const auto cmode = cmode_tmp; - using TargetCalculatorType = GroupStateHelpers -::TargetCalculator; - TargetCalculatorType tcalc(cmode, FluidSystem::phaseUsage(), resv_coeff, - gratTargetFromSales, nodeName, group_state, - group.has_gpmaint_control(cmode)); + using TargetCalculatorType = GroupStateHelpers::TargetCalculator; + TargetCalculatorType tcalc{this->groupStateHelper(), resv_coeff, group}; if (!fld_none) { // Target is set for the autochoke group itself - target_tmp = tcalc.groupTarget(ctrl, local_deferredLogger); + target_tmp = tcalc.groupTarget(local_deferredLogger); } const Scalar orig_target = target_tmp; @@ -1777,7 +1770,7 @@ ::TargetCalculator; x_local_[i] = x[cells[i]]; } well->recoverWellSolutionAndUpdateWellState(simulator_, x_local_, - this->wellState(), local_deferredLogger); + this->groupStateHelper(), this->wellState(), local_deferredLogger); } } OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger, @@ -1812,7 +1805,7 @@ ::TargetCalculator; for (const auto& well : well_container_) { if (well->isOperableAndSolvable() || well->wellIsStopped()) { local_report += well->getWellConvergence( - simulator_, this->wellState(), B_avg, local_deferredLogger, + this->groupStateHelper(), B_avg, local_deferredLogger, iterationIdx > param_.strict_outer_iter_wells_); } else { ConvergenceReport report; @@ -1858,7 +1851,7 @@ ::TargetCalculator; { // TODO: checking isOperableAndSolvable() ? for (auto& well : well_container_) { - well->calculateExplicitQuantities(simulator_, this->wellState(), deferred_logger); + well->calculateExplicitQuantities(simulator_, this->groupStateHelper(), deferred_logger); } } @@ -2101,9 +2094,7 @@ ::TargetCalculator; this->groupStateHelper(), local_deferredLogger); const bool under_zero_target = - well->wellUnderZeroGroupRateTarget(this->simulator_, - this->wellState(), - local_deferredLogger); + well->wellUnderZeroGroupRateTarget(this->groupStateHelper(), local_deferredLogger); well->updateWellTestState(this->wellState().well(wname), simulationTime, /*writeMessageToOPMLog=*/ true, @@ -2280,7 +2271,7 @@ ::TargetCalculator; well->updateWellStateWithTarget( simulator_, this->groupStateHelper(), this->wellState(), deferred_logger ); - well->updatePrimaryVariables(simulator_, this->wellState(), deferred_logger); + well->updatePrimaryVariables(this->groupStateHelper(), deferred_logger); // There is no new well control change input within a report step, // so next time step, the well does not consider to have effective events anymore. events.clearEvent(WellState::event_mask); @@ -2364,7 +2355,7 @@ ::TargetCalculator; updatePrimaryVariables(DeferredLogger& deferred_logger) { for (const auto& well : well_container_) { - well->updatePrimaryVariables(simulator_, this->wellState(), deferred_logger); + well->updatePrimaryVariables(this->groupStateHelper(), deferred_logger); } } diff --git a/opm/simulators/wells/GroupStateHelper.cpp b/opm/simulators/wells/GroupStateHelper.cpp index 5cc62fe0aae..590f3208c5d 100644 --- a/opm/simulators/wells/GroupStateHelper.cpp +++ b/opm/simulators/wells/GroupStateHelper.cpp @@ -121,33 +121,20 @@ GroupStateHelper::checkGroupConstraintsInj(const std::strin // If we are here, we are at the topmost group to be visited in the recursion. // This is the group containing the control we will check against. - Scalar sales_target = 0; - if (this->schedule_[this->report_step_].gconsale().has(group.name())) { - const auto& gconsale - = this->schedule_[this->report_step_].gconsale().get(group.name(), this->summary_state_); - sales_target = gconsale.sales_target; - } - GroupStateHelpers -::InjectionTargetCalculator tcalc { - current_group_control, - this->phase_usage_info_, - resv_coeff, - group.name(), - sales_target, - this->groupState(), - injection_phase, - group.has_gpmaint_control(injection_phase, current_group_control), - deferred_logger}; - - GroupStateHelpers -::FractionCalculator fcalc {this->schedule_, - *this, - this->summary_state_, - this->report_step_, - &this->guide_rate_, - tcalc.guideTargetMode(), - /*is_production_group=*/false, - injection_phase}; + GroupStateHelpers::InjectionTargetCalculator tcalc {*this, + resv_coeff, + group, + injection_phase, + deferred_logger}; + + GroupStateHelpers::FractionCalculator fcalc {this->schedule_, + *this, + this->summary_state_, + this->report_step_, + &this->guide_rate_, + tcalc.guideTargetMode(), + /*is_production_group=*/false, + injection_phase}; auto local_fraction_lambda = [&](const std::string& child) { return fcalc.localFraction(child, name); }; @@ -209,12 +196,7 @@ ::FractionCalculator fcalc {this->schedule_, return std::make_pair(current_well_rate_available > group_target_rate_available, scale); } - std::optional ctrl; - if (!group.has_gpmaint_control(injection_phase, current_group_control)) - ctrl = group.injectionControls(injection_phase, this->summary_state_); - - - const Scalar orig_target = tcalc.groupTarget(ctrl, deferred_logger); + const Scalar orig_target = tcalc.groupTarget(deferred_logger); // Assume we have a chain of groups as follows: BOTTOM -> MIDDLE -> TOP. // Then ... // TODO finish explanation. @@ -299,30 +281,18 @@ GroupStateHelper::checkGroupConstraintsProd(const std::stri // If we are here, we are at the topmost group to be visited in the recursion. // This is the group containing the control we will check against. - // gconsale may adjust the grat target. - // the adjusted rates is send to the targetCalculator - Scalar grat_target_from_sales = 0.0; - if (this->groupState().has_grat_sales_target(group.name())) - grat_target_from_sales = this->groupState().grat_sales_target(group.name()); - - GroupStateHelpers -::TargetCalculator tcalc {current_group_control, - this->phase_usage_info_, - resv_coeff, - grat_target_from_sales, - group.name(), - this->groupState(), - group.has_gpmaint_control(current_group_control)}; - - GroupStateHelpers -::FractionCalculator fcalc {this->schedule_, - *this, - this->summary_state_, - this->report_step_, - &this->guide_rate_, - tcalc.guideTargetMode(), - /*is_production_group=*/true, - /*injection_phase=*/Phase::OIL}; + GroupStateHelpers::TargetCalculator tcalc {*this, + resv_coeff, + group}; + + GroupStateHelpers::FractionCalculator fcalc {this->schedule_, + *this, + this->summary_state_, + this->report_step_, + &this->guide_rate_, + tcalc.guideTargetMode(), + /*is_production_group=*/true, + /*injection_phase=*/Phase::OIL}; auto local_fraction_lambda = [&](const std::string& child) { return fcalc.localFraction(child, name); }; @@ -337,11 +307,7 @@ ::FractionCalculator fcalc {this->schedule_, return tcalc.calcModeRateFromRates(group_surface_rates); }; - std::optional ctrl; - if (!group.has_gpmaint_control(current_group_control)) - ctrl = group.productionControls(this->summary_state_); - - const Scalar orig_target = tcalc.groupTarget(ctrl, deferred_logger); + const Scalar orig_target = tcalc.groupTarget(deferred_logger); // Assume we have a chain of groups as follows: BOTTOM -> MIDDLE -> TOP. // Then ... // TODO finish explanation. @@ -636,6 +602,78 @@ GroupStateHelper::getGuideRate(const std::string& name, return total_guide_rate; } +template +Scalar +GroupStateHelper:: +getInjectionGroupTarget( + const Group& group, + const Phase& injection_phase, + const std::vector& resv_coeff, + DeferredLogger& deferred_logger) const +{ + const auto& pu = this->phaseUsageInfo(); + const int pos = this->phaseToActivePhaseIdx(injection_phase); + Group::InjectionCMode cmode = this->groupState().injection_control(group.name(), injection_phase); + Group::InjectionControls ctrl = group.injectionControls(injection_phase, this->summary_state_); + bool use_gpmaint = group.has_gpmaint_control(injection_phase, cmode) + && this->groupState().has_gpmaint_target(group.name()); + switch (cmode) { + case Group::InjectionCMode::RATE: + if (use_gpmaint) { + return this->groupState().gpmaint_target(group.name()); + } + return ctrl.surface_max_rate; + case Group::InjectionCMode::RESV: + if (use_gpmaint) + return this->groupState().gpmaint_target(group.name()) / resv_coeff[pos]; + + return ctrl.resv_max_rate / resv_coeff[pos]; + case Group::InjectionCMode::REIN: { + Scalar production_rate = this->groupState().injection_rein_rates(ctrl.reinj_group)[pos]; + return ctrl.target_reinj_fraction * production_rate; + } + case Group::InjectionCMode::VREP: { + // We use the injection_reservoir_rates directly instead of the reduction rates here to account for the + // possibility that the group in question has both a VREP control and another injection control for a different phase. + const std::vector& group_injection_reservoir_rates = + this->groupState().injection_reservoir_rates(group.name()); + Scalar voidage_rate = this->groupState().injection_vrep_rate(ctrl.voidage_group) * ctrl.target_void_fraction; + if (ctrl.phase != Phase::WATER) { + const int water_pos = pu.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); + voidage_rate -= group_injection_reservoir_rates[water_pos]; + } + if (ctrl.phase != Phase::OIL) { + const int oil_pos = pu.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); + voidage_rate -= group_injection_reservoir_rates[oil_pos]; + } + if (ctrl.phase != Phase::GAS) { + const int gas_pos = pu.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx); + voidage_rate -= group_injection_reservoir_rates[gas_pos]; + } + return voidage_rate / resv_coeff[pos]; + } + case Group::InjectionCMode::SALE: { + assert(pos == pu.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx) ); + Scalar sales_target = 0; + if (this->schedule_[this->report_step_].gconsale().has(group.name())) { + const auto& gconsale + = this->schedule_[this->report_step_].gconsale().get(group.name(), this->summary_state_); + sales_target = gconsale.sales_target; + } + // Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate; + // Gas import and consumption is already included in the REIN rates + Scalar inj_rate = this->groupState().injection_rein_rates(group.name())[pos]; + inj_rate -= sales_target; + return inj_rate; + } + default: + OPM_DEFLOG_THROW(std::logic_error, + "Invalid Group::InjectionCMode in getInjectionGroupTarget", + deferred_logger); + return 0.0; + } +} + template GuideRate::RateVector GroupStateHelper::getProductionGroupRateVector(const std::string& group_name) const @@ -643,6 +681,48 @@ GroupStateHelper::getProductionGroupRateVector(const std::s return this->getGuideRateVector_(this->groupState().production_rates(group_name)); } +template +Scalar +GroupStateHelper:: +getProductionGroupTarget(const Group& group, DeferredLogger& deferred_logger) const +{ + Group::ProductionCMode cmode = this->groupState().production_control(group.name()); + Group::ProductionControls ctrl = group.productionControls(this->summary_state_); + switch (cmode) { + case Group::ProductionCMode::ORAT: + return ctrl.oil_target; + case Group::ProductionCMode::WRAT: + return ctrl.water_target; + case Group::ProductionCMode::GRAT: + { + Scalar grat_target_from_sales = 0.0; + if (this->groupState().has_grat_sales_target(group.name())) { + grat_target_from_sales = this->groupState().grat_sales_target(group.name()); + } + // gas target may have been adjusted by GCONSALE + if (grat_target_from_sales > 0) + return grat_target_from_sales; + + return ctrl.gas_target; + } + case Group::ProductionCMode::LRAT: + return ctrl.liquid_target; + case Group::ProductionCMode::RESV: + { + bool use_gpmaint = group.has_gpmaint_control(cmode); + if (use_gpmaint && this->groupState().has_gpmaint_target(group.name())) + return this->groupState().gpmaint_target(group.name()); + + return ctrl.resv_target; + } + default: + OPM_DEFLOG_THROW(std::logic_error, + "Invalid Group::ProductionCMode in getProductionGroupTarget", + deferred_logger); + return 0.0; + } +} + template std::optional GroupStateHelper::getWellGroupTargetInjector(const std::string& name, @@ -688,33 +768,20 @@ GroupStateHelper::getWellGroupTargetInjector(const std::str // If we are here, we are at the topmost group to be visited in the recursion. // This is the group containing the control we will check against. - Scalar sales_target = 0; - if (this->schedule_[this->report_step_].gconsale().has(group.name())) { - const auto& gconsale - = this->schedule_[this->report_step_].gconsale().get(group.name(), this->summary_state_); - sales_target = gconsale.sales_target; - } - GroupStateHelpers -::InjectionTargetCalculator tcalc { - current_group_control, - this->phase_usage_info_, - resv_coeff, - group.name(), - sales_target, - this->groupState(), - injection_phase, - group.has_gpmaint_control(injection_phase, current_group_control), - deferred_logger}; - - GroupStateHelpers -::FractionCalculator fcalc {this->schedule_, - *this, - this->summary_state_, - this->report_step_, - &this->guide_rate_, - tcalc.guideTargetMode(), - /*is_production_group=*/false, - injection_phase}; + GroupStateHelpers::InjectionTargetCalculator tcalc{*this, + resv_coeff, + group, + injection_phase, + deferred_logger}; + + GroupStateHelpers::FractionCalculator fcalc {this->schedule_, + *this, + this->summary_state_, + this->report_step_, + &this->guide_rate_, + tcalc.guideTargetMode(), + /*is_production_group=*/false, + injection_phase}; auto local_fraction_lambda = [&](const std::string& child, const std::string& always_incluced_name) { return fcalc.localFraction(child, always_incluced_name); @@ -726,12 +793,7 @@ ::FractionCalculator fcalc {this->schedule_, return tcalc.calcModeRateFromRates(group_target_reductions); }; - std::optional ctrl; - if (!group.has_gpmaint_control(injection_phase, current_group_control)) - ctrl = group.injectionControls(injection_phase, this->summary_state_); - - - const Scalar orig_target = tcalc.groupTarget(ctrl, deferred_logger); + const Scalar orig_target = tcalc.groupTarget(deferred_logger); // Assume we have a chain of groups as follows: BOTTOM -> MIDDLE -> TOP. // Then ... // TODO finish explanation. @@ -825,30 +887,18 @@ GroupStateHelper::getWellGroupTargetProducer(const std::str // If we are here, we are at the topmost group to be visited in the recursion. // This is the group containing the control we will check against. - // gconsale may adjust the grat target. - // the adjusted rates is sent to the targetCalculator - Scalar grat_target_from_sales = 0.0; - if (this->groupState().has_grat_sales_target(group.name())) - grat_target_from_sales = this->groupState().grat_sales_target(group.name()); - - GroupStateHelpers -::TargetCalculator tcalc {current_group_control, - this->phase_usage_info_, - resv_coeff, - grat_target_from_sales, - group.name(), - this->groupState(), - group.has_gpmaint_control(current_group_control)}; - - GroupStateHelpers -::FractionCalculator fcalc {this->schedule_, - *this, - this->summary_state_, - this->report_step_, - &this->guide_rate_, - tcalc.guideTargetMode(), - true, - Phase::OIL}; + GroupStateHelpers::TargetCalculator tcalc{*this, + resv_coeff, + group}; + + GroupStateHelpers::FractionCalculator fcalc {this->schedule_, + *this, + this->summary_state_, + this->report_step_, + &this->guide_rate_, + tcalc.guideTargetMode(), + /*is_production_group=*/true, + /*injection_phase=*/Phase::OIL}; auto local_fraction_lambda = [&](const std::string& child, const std::string& always_incluced_name) { return fcalc.localFraction(child, always_incluced_name); }; @@ -859,11 +909,7 @@ ::FractionCalculator fcalc {this->schedule_, return tcalc.calcModeRateFromRates(group_target_reductions); }; - std::optional ctrl; - if (!group.has_gpmaint_control(current_group_control)) - ctrl = group.productionControls(this->summary_state_); - - const Scalar orig_target = tcalc.groupTarget(ctrl, deferred_logger); + const Scalar orig_target = tcalc.groupTarget(deferred_logger); // Assume we have a chain of groups as follows: BOTTOM -> MIDDLE -> TOP. // Then ... // TODO finish explanation. @@ -966,6 +1012,35 @@ GroupStateHelper::groupControlledWells(const std::string& g return num_wells; } +template +int +GroupStateHelper::phaseToActivePhaseIdx(const Phase phase) const +{ + const auto& pu = this->phase_usage_info_; + int phase_pos = -1; + switch (phase) { + case Phase::GAS: + if (pu.phaseIsActive(IndexTraits::gasPhaseIdx)) { + phase_pos = pu.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx); + } + break; + case Phase::OIL: + if (pu.phaseIsActive(IndexTraits::oilPhaseIdx)) { + phase_pos = pu.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); + } + break; + case Phase::WATER: + if (pu.phaseIsActive(IndexTraits::waterPhaseIdx)) { + phase_pos = pu.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); + } + break; + default: + // just to avoid warning + throw std::invalid_argument("unhandled phase enum"); + } + return phase_pos; +} + template void GroupStateHelper::setCmodeGroup(const Group& group) @@ -1164,7 +1239,7 @@ GroupStateHelper::sumWellSurfaceRates(const Group& group, // type depends on types from derived classes (e.g., AverageRegionalPressure). // // Historical Note: -// - The original implementation in WellGroupHelpers.cpp (static utility class) could keep +// - The original implementation in GroupStateHelpers.cpp (static utility class) could keep // the implementation in the .cpp file because it hard-coded BlackOilFluidSystem // and used explicit template instantiation for that specific type. // - As a member-based class, GroupStateHelper must support whatever FluidSystem the TypeTag @@ -1611,35 +1686,6 @@ GroupStateHelper::isInGroupChainTopBot_(const std::string& return true; } -template -int -GroupStateHelper::phaseToActivePhaseIdx_(const Phase phase) const -{ - const auto& pu = this->phase_usage_info_; - int phase_pos = -1; - switch (phase) { - case Phase::GAS: - if (pu.phaseIsActive(IndexTraits::gasPhaseIdx)) { - phase_pos = pu.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx); - } - break; - case Phase::OIL: - if (pu.phaseIsActive(IndexTraits::oilPhaseIdx)) { - phase_pos = pu.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); - } - break; - case Phase::WATER: - if (pu.phaseIsActive(IndexTraits::waterPhaseIdx)) { - phase_pos = pu.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); - } - break; - default: - // just to avoid warning - throw std::invalid_argument("unhandled phase enum"); - } - return phase_pos; -} - template Scalar GroupStateHelper::satelliteInjectionRate_(const ScheduleState& sched, @@ -1779,28 +1825,16 @@ GroupStateHelper::updateGroupControlledWellsRecursive_( // Get the ancestor of the auto choke group that has group control (cmode != FLD, NONE) const auto& control_group_name = this->controlGroup_(group); const auto& control_group = this->schedule_.getGroup(control_group_name, this->report_step_); - const auto& ctrl = control_group.productionControls(this->summary_state_); - const auto& control_group_cmode = ctrl.cmode; const auto& group_guide_rate = group.productionControls(this->summary_state_).guide_rate; if (group_guide_rate > 0) { // Guide rate is not default for the auto choke group - Scalar grat_target_from_sales = 0.0; - if (this->groupState().has_grat_sales_target(control_group_name)) - grat_target_from_sales = this->groupState().grat_sales_target(control_group_name); - std::vector resv_coeff(num_phases, 1.0); - GroupStateHelpers -::TargetCalculator tcalc { - control_group_cmode, - this->phase_usage_info_, - resv_coeff, - grat_target_from_sales, - group.name(), - this->groupState(), - group.has_gpmaint_control(control_group_cmode)}; - const auto& control_group_target = tcalc.groupTarget(ctrl, deferred_logger); + GroupStateHelpers::TargetCalculator tcalc{*this, + resv_coeff, + control_group}; + const auto& control_group_target = tcalc.groupTarget(deferred_logger); // Calculates the guide rate of the parent group with control. // It is allowed that the guide rate of this group is defaulted. The guide rate will be @@ -1853,7 +1887,7 @@ GroupStateHelper::updateGroupTargetReductionRecursive_( if (is_injector) { const Phase all[] = {Phase::WATER, Phase::OIL, Phase::GAS}; for (Phase phase : all) { - const auto phase_pos = this->phaseToActivePhaseIdx_(phase); + const auto phase_pos = this->phaseToActivePhaseIdx(phase); // the phase is not present if (phase_pos == -1) continue; diff --git a/opm/simulators/wells/GroupStateHelper.hpp b/opm/simulators/wells/GroupStateHelper.hpp index 6348c50988a..ce837812e35 100644 --- a/opm/simulators/wells/GroupStateHelper.hpp +++ b/opm/simulators/wells/GroupStateHelper.hpp @@ -150,6 +150,13 @@ class GroupStateHelper Scalar getGuideRate(const std::string& name, const GuideRateModel::Target target) const; + Scalar getInjectionGroupTarget(const Group& group, + const Phase& injection_phase, + const std::vector& resv_coeff, + DeferredLogger& deferred_logger) const; + + Scalar getProductionGroupTarget(const Group& group, DeferredLogger& deferred_logger) const; + GuideRate::RateVector getProductionGroupRateVector(const std::string& group_name) const; std::optional getWellGroupTargetInjector(const std::string& name, @@ -215,6 +222,8 @@ class GroupStateHelper return this->guide_rate_; } + int phaseToActivePhaseIdx(const Phase phase) const; + const PhaseUsageInfo& phaseUsage() const { return this->phase_usage_info_; } @@ -331,8 +340,6 @@ class GroupStateHelper /// check if well/group bottom is a sub well/group of the group top bool isInGroupChainTopBot_(const std::string& bottom, const std::string& top) const; - int phaseToActivePhaseIdx_(const Phase phase) const; - Scalar satelliteInjectionRate_(const ScheduleState& sched, const Group& group, const int phase_pos, diff --git a/opm/simulators/wells/MultisegmentWell.hpp b/opm/simulators/wells/MultisegmentWell.hpp index 9064f566269..4aeb3b28ade 100644 --- a/opm/simulators/wells/MultisegmentWell.hpp +++ b/opm/simulators/wells/MultisegmentWell.hpp @@ -99,8 +99,7 @@ namespace Opm { void scaleSegmentRatesAndPressure(WellStateType& well_state) const override; /// check whether the well equations get converged for this well - ConvergenceReport getWellConvergence(const Simulator& simulator, - const WellStateType& well_state, + ConvergenceReport getWellConvergence(const GroupStateHelperType& groupStateHelper, const std::vector& B_avg, DeferredLogger& deferred_logger, const bool relax_tolerance) const override; @@ -114,6 +113,7 @@ namespace Opm { /// xw to update Well State void recoverWellSolutionAndUpdateWellState(const Simulator& simulator, const BVector& x, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) override; @@ -124,16 +124,16 @@ namespace Opm { std::vector& well_potentials, DeferredLogger& deferred_logger) override; - void updatePrimaryVariables(const Simulator& simulator, - const WellStateType& well_state, + void updatePrimaryVariables(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) override; void solveEqAndUpdateWellState(const Simulator& simulator, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) override; // const? void calculateExplicitQuantities(const Simulator& simulator, - const WellStateType& well_state, + const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) override; // should be const? void updateIPRImplicit(const Simulator& simulator, @@ -185,6 +185,7 @@ namespace Opm { // updating the well_state based on well solution dwells void updateWellState(const Simulator& simulator, const BVectorWell& dwells, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger, const Scalar relaxation_factor = 1.0); diff --git a/opm/simulators/wells/MultisegmentWellAssemble.cpp b/opm/simulators/wells/MultisegmentWellAssemble.cpp index 43d432430f4..cc27434b372 100644 --- a/opm/simulators/wells/MultisegmentWellAssemble.cpp +++ b/opm/simulators/wells/MultisegmentWellAssemble.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -82,10 +83,7 @@ class MultisegmentWellEquationAccess { template void MultisegmentWellAssemble:: -assembleControlEq(const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, +assembleControlEq(const GroupStateHelperType& groupStateHelper, const Well::InjectionControls& inj_controls, const Well::ProductionControls& prod_controls, const Scalar rho, @@ -94,6 +92,8 @@ assembleControlEq(const WellState& well_state, const bool stopped_or_zero_target, DeferredLogger& deferred_logger) const { + const auto& well_state = groupStateHelper.wellState(); + const auto& summary_state = groupStateHelper.summaryState(); /* This function assembles the control equation, similar as for StandardWells. It does *not* need communication. @@ -155,21 +155,18 @@ assembleControlEq(const WellState& well_state, return WellBhpThpCalculator(well_).calculateBhpFromThp(well_state, rates, well, - summaryState, + summary_state, rho, deferred_logger); }; // Call generic implementation. - WellAssemble(well_).assembleControlEqInj(well_state, - group_state, - schedule, - summaryState, - inj_controls, - primary_variables.getBhp(), - injection_rate, - bhp_from_thp, - control_eq, - deferred_logger); + WellAssemble(well_).template assembleControlEqInj(groupStateHelper, + inj_controls, + primary_variables.getBhp(), + injection_rate, + bhp_from_thp, + control_eq, + deferred_logger); } else { // Find rates. const auto rates = getRates(); @@ -178,21 +175,18 @@ assembleControlEq(const WellState& well_state, return WellBhpThpCalculator(well_).calculateBhpFromThp(well_state, rates, well, - summaryState, + summary_state, rho, deferred_logger); }; // Call generic implementation. - WellAssemble(well_).assembleControlEqProd(well_state, - group_state, - schedule, - summaryState, - prod_controls, - primary_variables.getBhp(), - rates, - bhp_from_thp, - control_eq, - deferred_logger); + WellAssemble(well_).template assembleControlEqProd(groupStateHelper, + prod_controls, + primary_variables.getBhp(), + rates, + bhp_from_thp, + control_eq, + deferred_logger); } MultisegmentWellEquationAccess eqns(eqns1); diff --git a/opm/simulators/wells/MultisegmentWellAssemble.hpp b/opm/simulators/wells/MultisegmentWellAssemble.hpp index 1270f3d9ba5..395a208ce78 100644 --- a/opm/simulators/wells/MultisegmentWellAssemble.hpp +++ b/opm/simulators/wells/MultisegmentWellAssemble.hpp @@ -37,6 +37,7 @@ class Schedule; class SummaryState; template class WellInterfaceIndices; template class WellState; +template class GroupStateHelper; //! \brief Class handling assemble of the equation system for MultisegmentWell. template @@ -56,6 +57,7 @@ class MultisegmentWellAssemble using IndexTraits = typename FluidSystem::IndexTraitsType; using Equations = MultisegmentWellEquations; using EvalWell = DenseAd::Evaluation; + using GroupStateHelperType = GroupStateHelper; //! \brief Constructor initializes reference to well. explicit MultisegmentWellAssemble(const WellInterfaceIndices& well) @@ -63,10 +65,7 @@ class MultisegmentWellAssemble {} //! \brief Assemble control equation. - void assembleControlEq(const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + void assembleControlEq(const GroupStateHelperType& groupStateHelper, const Well::InjectionControls& inj_controls, const Well::ProductionControls& prod_controls, const Scalar rho, diff --git a/opm/simulators/wells/MultisegmentWell_impl.hpp b/opm/simulators/wells/MultisegmentWell_impl.hpp index 28668958e94..a75a9d19da0 100644 --- a/opm/simulators/wells/MultisegmentWell_impl.hpp +++ b/opm/simulators/wells/MultisegmentWell_impl.hpp @@ -154,11 +154,11 @@ namespace Opm template void MultisegmentWell:: - updatePrimaryVariables(const Simulator& simulator, - const WellStateType& well_state, + updatePrimaryVariables(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) { - const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger); + const auto& well_state = groupStateHelper.wellState(); + const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(groupStateHelper, deferred_logger); this->primary_variables_.update(well_state, stop_or_zero_rate_target); } @@ -201,12 +201,12 @@ namespace Opm template ConvergenceReport MultisegmentWell:: - getWellConvergence(const Simulator& /* simulator */, - const WellStateType& well_state, + getWellConvergence(const GroupStateHelperType& groupStateHelper, const std::vector& B_avg, DeferredLogger& deferred_logger, const bool relax_tolerance) const { + const auto& well_state = groupStateHelper.wellState(); return this->MSWEval::getWellConvergence(well_state, B_avg, deferred_logger, @@ -264,6 +264,7 @@ namespace Opm MultisegmentWell:: recoverWellSolutionAndUpdateWellState(const Simulator& simulator, const BVector& x, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) { @@ -275,7 +276,7 @@ namespace Opm BVectorWell xw(1); this->linSys_.recoverSolutionWell(x, xw); - updateWellState(simulator, xw, well_state, deferred_logger); + updateWellState(simulator, xw, groupStateHelper, well_state, deferred_logger); } catch (const NumericalProblem& exp) { // Add information about the well and log to deferred logger @@ -463,7 +464,7 @@ namespace Opm this->segments_.perforations(), well_state_copy); - well_copy.calculateExplicitQuantities(simulator, well_state_copy, deferred_logger); + well_copy.calculateExplicitQuantities(simulator, groupStateHelper_copy, deferred_logger); const double dt = simulator.timeStepSize(); // iterate to get a solution at the given bhp. well_copy.iterateWellEqWithControl(simulator, dt, inj_controls, prod_controls, groupStateHelper_copy, @@ -583,7 +584,7 @@ namespace Opm this->segments_.perforations(), well_state_copy); - well_copy.calculateExplicitQuantities(simulator, well_state_copy, deferred_logger); + well_copy.calculateExplicitQuantities(simulator, groupStateHelper_copy, deferred_logger); const double dt = simulator.timeStepSize(); // solve equations bool converged = false; @@ -615,6 +616,7 @@ namespace Opm void MultisegmentWell:: solveEqAndUpdateWellState(const Simulator& simulator, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) { @@ -624,7 +626,7 @@ namespace Opm // which is why we do not put the assembleWellEq here. try{ const BVectorWell dx_well = this->linSys_.solve(); - updateWellState(simulator, dx_well, well_state, deferred_logger); + updateWellState(simulator, dx_well, groupStateHelper, well_state, deferred_logger); } catch(const NumericalProblem& exp) { // Add information about the well and log to deferred logger @@ -721,6 +723,7 @@ namespace Opm MultisegmentWell:: updateWellState(const Simulator& simulator, const BVectorWell& dwells, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger, const Scalar relaxation_factor) @@ -730,7 +733,7 @@ namespace Opm const Scalar dFLimit = this->param_.dwell_fraction_max_; const Scalar max_pressure_change = this->param_.max_pressure_change_ms_wells_; const bool stop_or_zero_rate_target = - this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger); + this->stoppedOrZeroRateTarget(groupStateHelper, deferred_logger); this->primary_variables_.updateNewton(dwells, relaxation_factor, dFLimit, @@ -759,10 +762,10 @@ namespace Opm void MultisegmentWell:: calculateExplicitQuantities(const Simulator& simulator, - const WellStateType& well_state, + const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) { - updatePrimaryVariables(simulator, well_state, deferred_logger); + updatePrimaryVariables(groupStateHelper, deferred_logger); computePerfCellPressDiffs(simulator); computeInitialSegmentFluids(simulator, deferred_logger); } @@ -1541,7 +1544,7 @@ namespace Opm return false; } - updatePrimaryVariables(simulator, well_state, deferred_logger); + updatePrimaryVariables(groupStateHelper, deferred_logger); std::vector > residual_history; std::vector measure_history; @@ -1562,7 +1565,7 @@ namespace Opm well_state, deferred_logger, /*solving_with_zero_rate=*/false); - const auto report = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, relax_convergence); + const auto report = getWellConvergence(groupStateHelper, Base::B_avg_, deferred_logger, relax_convergence); if (report.converged()) { converged = true; break; @@ -1584,7 +1587,7 @@ namespace Opm bool min_relaxation_reached = this->update_relaxation_factor(measure_history, relaxation_factor, this->regularize_, deferred_logger); if (min_relaxation_reached || this->repeatedStagnation(measure_history, this->regularize_, deferred_logger)) { // try last attempt with relaxed tolerances - const auto reportStag = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, true); + const auto reportStag = getWellConvergence(groupStateHelper, Base::B_avg_, deferred_logger, true); if (reportStag.converged()) { converged = true; std::string message = fmt::format("Well stagnates/oscillates but {} manages to get converged with relaxed tolerances in {} inner iterations." @@ -1599,7 +1602,7 @@ namespace Opm BVectorWell dx_well; try{ dx_well = this->linSys_.solve(); - updateWellState(simulator, dx_well, well_state, deferred_logger, relaxation_factor); + updateWellState(simulator, dx_well, groupStateHelper, well_state, deferred_logger, relaxation_factor); } catch(const NumericalProblem& exp) { // Add information about the well and log to deferred logger @@ -1667,7 +1670,7 @@ namespace Opm return false; } - updatePrimaryVariables(simulator, well_state, deferred_logger); + updatePrimaryVariables(groupStateHelper, deferred_logger); std::vector > residual_history; std::vector measure_history; @@ -1695,7 +1698,7 @@ namespace Opm // don't allow opening wells that has a stopped well status const bool allow_open = well_state.well(this->index_of_well_).status == WellStatus::OPEN; // don't allow switcing for wells under zero rate target or requested fixed status and control - const bool allow_switching = !this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger) && + const bool allow_switching = !this->wellUnderZeroRateTarget(groupStateHelper, deferred_logger) && (!fixed_control || !fixed_status) && allow_open; bool final_check = false; // well needs to be set operable or else solving/updating of re-opened wells is skipped @@ -1738,7 +1741,7 @@ namespace Opm well_state, deferred_logger, solving_with_zero_rate); - const auto report = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, relax_convergence); + const auto report = getWellConvergence(groupStateHelper, Base::B_avg_, deferred_logger, relax_convergence); converged = report.converged(); if (this->parallel_well_info_.communication().size() > 1 && this->parallel_well_info_.communication().max(converged) != this->parallel_well_info_.communication().min(converged)) { @@ -1780,7 +1783,7 @@ namespace Opm } try{ const BVectorWell dx_well = this->linSys_.solve(); - updateWellState(simulator, dx_well, well_state, deferred_logger, relaxation_factor); + updateWellState(simulator, dx_well, groupStateHelper, well_state, deferred_logger, relaxation_factor); } catch(const NumericalProblem& exp) { // Add information about the well and log to deferred logger @@ -1979,25 +1982,21 @@ namespace Opm // the fourth equation, the pressure drop equation if (seg == 0) { // top segment, pressure equation is the control equation - const auto& summaryState = simulator.vanguard().summaryState(); - const Schedule& schedule = simulator.vanguard().schedule(); - const bool stopped_or_zero_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger); + const bool stopped_or_zero_target = this->stoppedOrZeroRateTarget(groupStateHelper, deferred_logger); // When solving with zero rate (well isolation), use empty group_state to isolate // from group constraints in assembly. // Otherwise use real group state from groupStateHelper. - const GroupState empty_group_state; - const auto& group_state = solving_with_zero_rate + GroupState empty_group_state; + auto& group_state = solving_with_zero_rate ? empty_group_state : groupStateHelper.groupState(); - + GroupStateHelperType groupStateHelper_copy = groupStateHelper; + auto group_guard = groupStateHelper_copy.pushGroupState(group_state); MultisegmentWellAssemble(*this). - assembleControlEq(well_state, - group_state, - schedule, - summaryState, + assembleControlEq(groupStateHelper_copy, inj_controls, prod_controls, - getRefDensity(), + this->getRefDensity(), this->primary_variables_, this->linSys_, stopped_or_zero_target, diff --git a/opm/simulators/wells/StandardWell.hpp b/opm/simulators/wells/StandardWell.hpp index 67f773c763b..6d45c588b7c 100644 --- a/opm/simulators/wells/StandardWell.hpp +++ b/opm/simulators/wells/StandardWell.hpp @@ -141,8 +141,7 @@ namespace Opm const bool changed_to_open_this_step) override; /// check whether the well equations get converged for this well - virtual ConvergenceReport getWellConvergence(const Simulator& simulator, - const WellStateType& well_state, + virtual ConvergenceReport getWellConvergence(const GroupStateHelperType& groupStateHelper, const std::vector& B_avg, DeferredLogger& deferred_logger, const bool relax_tolerance) const override; @@ -156,6 +155,7 @@ namespace Opm /// xw to update Well State void recoverWellSolutionAndUpdateWellState(const Simulator& simulator, const BVector& x, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) override; @@ -166,17 +166,17 @@ namespace Opm std::vector& well_potentials, DeferredLogger& deferred_logger) /* const */ override; - void updatePrimaryVariables(const Simulator& simulator, - const WellStateType& well_state, + void updatePrimaryVariables(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) override; void solveEqAndUpdateWellState(const Simulator& simulator, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) override; void calculateExplicitQuantities(const Simulator& simulator, - const WellStateType& well_state, - DeferredLogger& deferred_logger) override; // should be const? + const GroupStateHelperType& groupStateHelper, + DeferredLogger& deferred_logger) override; // should be const? void updateProductivityIndex(const Simulator& simulator, const WellProdIndexCalculator& wellPICalc, @@ -265,6 +265,7 @@ namespace Opm // updating the well_state based on well solution dwells void updateWellState(const Simulator& simulator, const BVectorWell& dwells, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger); @@ -277,12 +278,12 @@ namespace Opm const WellStateType& well_state) const; void computeWellConnectionDensitesPressures(const Simulator& simulator, - const WellStateType& well_state, + const GroupStateHelperType& groupStateHelper, const WellConnectionProps& props, DeferredLogger& deferred_logger); void computeWellConnectionPressures(const Simulator& simulator, - const WellStateType& well_state, + const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger); template diff --git a/opm/simulators/wells/StandardWellAssemble.cpp b/opm/simulators/wells/StandardWellAssemble.cpp index 6065cacf97c..64cdafeb404 100644 --- a/opm/simulators/wells/StandardWellAssemble.cpp +++ b/opm/simulators/wells/StandardWellAssemble.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -83,10 +84,7 @@ class StandardWellEquationAccess { template void StandardWellAssemble:: -assembleControlEq(const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, +assembleControlEq(const GroupStateHelperType& groupStateHelper, const Well::InjectionControls& inj_controls, const Well::ProductionControls& prod_controls, const PrimaryVariables& primary_variables, @@ -95,6 +93,9 @@ assembleControlEq(const WellState& well_state, const bool stopped_or_zero_target, DeferredLogger& deferred_logger) const { + const auto& well_state = groupStateHelper.wellState(); + const auto& summary_state = groupStateHelper.summaryState(); + static constexpr int Water = FluidSystem::waterPhaseIdx; static constexpr int Oil = FluidSystem::oilPhaseIdx; static constexpr int Gas = FluidSystem::gasPhaseIdx; @@ -130,16 +131,13 @@ assembleControlEq(const WellState& well_state, return WellBhpThpCalculator(well_).calculateBhpFromThp(well_state, rates, well, - summaryState, + summary_state, rho, deferred_logger); }; WellAssemble(well_). - assembleControlEqInj(well_state, - group_state, - schedule, - summaryState, + assembleControlEqInj(groupStateHelper, inj_controls, primary_variables.eval(PrimaryVariables::Bhp), injection_rate, @@ -154,15 +152,12 @@ assembleControlEq(const WellState& well_state, return WellBhpThpCalculator(well_).calculateBhpFromThp(well_state, rates, well, - summaryState, + summary_state, rho, deferred_logger); }; WellAssemble(well_). - assembleControlEqProd(well_state, - group_state, - schedule, - summaryState, + assembleControlEqProd(groupStateHelper, prod_controls, primary_variables.eval(PrimaryVariables::Bhp), rates, diff --git a/opm/simulators/wells/StandardWellAssemble.hpp b/opm/simulators/wells/StandardWellAssemble.hpp index 30e5126e410..28b483837c0 100644 --- a/opm/simulators/wells/StandardWellAssemble.hpp +++ b/opm/simulators/wells/StandardWellAssemble.hpp @@ -36,6 +36,7 @@ template class StandardWellPrimaryVariables; class SummaryState; template class WellInterfaceFluidSystem; template class WellState; +template class GroupStateHelper; //! \brief Class handling assemble of the equation system for StandardWell. template @@ -47,6 +48,7 @@ class StandardWellAssemble using EvalWell = typename PrimaryVariables::EvalWell; using IndexTraits = typename FluidSystem::IndexTraitsType; using StandardWellEquationsType = StandardWellEquations; + using GroupStateHelperType = GroupStateHelper; //! \brief Constructor initializes reference to well. explicit StandardWellAssemble(const WellInterfaceFluidSystem& well) @@ -54,10 +56,7 @@ class StandardWellAssemble {} //! \brief Assemble control equation. - void assembleControlEq(const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + void assembleControlEq(const GroupStateHelperType& groupStateHelper, const Well::InjectionControls& inj_controls, const Well::ProductionControls& prod_controls, const PrimaryVariables& primary_variables, diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 6dc55b60166..b119b9200bc 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -467,20 +467,19 @@ namespace Opm this->linSys_); } - const auto& summaryState = simulator.vanguard().summaryState(); - const Schedule& schedule = simulator.vanguard().schedule(); - const bool stopped_or_zero_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger); + const bool stopped_or_zero_target = this->stoppedOrZeroRateTarget(groupStateHelper, deferred_logger); { // When solving_with_zero_rate=true (called from solveWellWithZeroRate), // we use an empty GroupState to isolate the well from group constraints during assembly. // This allows us to solve the well equations independently of group controls/targets. - const GroupState empty_group_state; - const auto& group_state = solving_with_zero_rate + GroupState empty_group_state; + auto& group_state = solving_with_zero_rate ? empty_group_state : groupStateHelper.groupState(); + GroupStateHelperType groupStateHelper_copy = groupStateHelper; + auto group_guard = groupStateHelper_copy.pushGroupState(group_state); StandardWellAssemble(*this). - assembleControlEq(well_state, group_state, - schedule, summaryState, + assembleControlEq(groupStateHelper_copy, inj_controls, prod_controls, this->primary_variables_, this->getRefDensity(), @@ -759,12 +758,13 @@ namespace Opm StandardWell:: updateWellState(const Simulator& simulator, const BVectorWell& dwells, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) { if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; - const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger); + const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(groupStateHelper, deferred_logger); updatePrimaryVariablesNewton(dwells, stop_or_zero_rate_target, deferred_logger); const auto& summary_state = simulator.vanguard().summaryState(); @@ -1218,8 +1218,7 @@ namespace Opm template ConvergenceReport StandardWell:: - getWellConvergence(const Simulator& simulator, - const WellStateType& well_state, + getWellConvergence(const GroupStateHelperType& groupStateHelper, const std::vector& B_avg, DeferredLogger& deferred_logger, const bool relax_tolerance) const @@ -1233,14 +1232,14 @@ namespace Opm constexpr Scalar stopped_factor = 1.e-4; // use stricter tolerance for dynamic thp to ameliorate network convergence constexpr Scalar dynamic_thp_factor = 1.e-1; - if (this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger)) { + if (this->stoppedOrZeroRateTarget(groupStateHelper, deferred_logger)) { tol_wells = tol_wells*stopped_factor; } else if (this->getDynamicThpLimit()) { tol_wells = tol_wells*dynamic_thp_factor; } std::vector res; - ConvergenceReport report = this->StdWellEval::getWellConvergence(well_state, + ConvergenceReport report = this->StdWellEval::getWellConvergence(groupStateHelper.wellState(), B_avg, this->param_.max_residual_allowed_, tol_wells, @@ -1338,10 +1337,11 @@ namespace Opm template void StandardWell:: computeWellConnectionDensitesPressures(const Simulator& simulator, - const WellStateType& well_state, + const GroupStateHelperType& groupStateHelper, const WellConnectionProps& props, DeferredLogger& deferred_logger) { + const auto& well_state = groupStateHelper.wellState(); // Cell level dynamic property call-back functions as fall-back // option for calculating connection level mixture densities in // stopped or zero-rate producer wells. @@ -1374,7 +1374,7 @@ namespace Opm }; const auto stopped_or_zero_rate_target = this-> - stoppedOrZeroRateTarget(simulator, well_state, deferred_logger); + stoppedOrZeroRateTarget(groupStateHelper, deferred_logger); this->connections_ .computeProperties(stopped_or_zero_rate_target, well_state, @@ -1394,13 +1394,14 @@ namespace Opm void StandardWell:: computeWellConnectionPressures(const Simulator& simulator, - const WellStateType& well_state, + const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) { + const auto& well_state = groupStateHelper.wellState(); const auto props = computePropertiesForWellConnectionPressures (simulator, well_state); - computeWellConnectionDensitesPressures(simulator, well_state, + computeWellConnectionDensitesPressures(simulator, groupStateHelper, props, deferred_logger); } @@ -1412,6 +1413,7 @@ namespace Opm void StandardWell:: solveEqAndUpdateWellState(const Simulator& simulator, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) { @@ -1423,7 +1425,7 @@ namespace Opm dx_well[0].resize(this->primary_variables_.numWellEq()); this->linSys_.solve( dx_well); - updateWellState(simulator, dx_well, well_state, deferred_logger); + updateWellState(simulator, dx_well, groupStateHelper, well_state, deferred_logger); } @@ -1434,11 +1436,11 @@ namespace Opm void StandardWell:: calculateExplicitQuantities(const Simulator& simulator, - const WellStateType& well_state, + const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) { - updatePrimaryVariables(simulator, well_state, deferred_logger); - computeWellConnectionPressures(simulator, well_state, deferred_logger); + updatePrimaryVariables(groupStateHelper, deferred_logger); + computeWellConnectionPressures(simulator, groupStateHelper, deferred_logger); this->computeAccumWell(); } @@ -1481,6 +1483,7 @@ namespace Opm StandardWell:: recoverWellSolutionAndUpdateWellState(const Simulator& simulator, const BVector& x, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) { @@ -1490,7 +1493,7 @@ namespace Opm xw[0].resize(this->primary_variables_.numWellEq()); this->linSys_.recoverSolutionWell(x, xw); - updateWellState(simulator, xw, well_state, deferred_logger); + updateWellState(simulator, xw, groupStateHelper, well_state, deferred_logger); } @@ -1595,7 +1598,7 @@ namespace Opm well_state_copy.wellRates(this->index_of_well_)[phase] = sign * ws.well_potentials[phase]; } - well_copy.updatePrimaryVariables(simulator, well_state_copy, deferred_logger); + well_copy.updatePrimaryVariables(groupStateHelper_copy, deferred_logger); well_copy.computeAccumWell(); const double dt = simulator.timeStepSize(); @@ -1607,8 +1610,8 @@ namespace Opm " potentials are computed based on unconverged solution"; deferred_logger.debug(msg); } - well_copy.updatePrimaryVariables(simulator, well_state_copy, deferred_logger); - well_copy.computeWellConnectionPressures(simulator, well_state_copy, deferred_logger); + well_copy.updatePrimaryVariables(groupStateHelper_copy, deferred_logger); + well_copy.computeWellConnectionPressures(simulator, groupStateHelper_copy, deferred_logger); well_copy.computeWellRatesWithBhp(simulator, bhp, well_flux, deferred_logger); } @@ -1703,7 +1706,7 @@ namespace Opm } } - well_copy.calculateExplicitQuantities(simulator, well_state_copy, deferred_logger); + well_copy.calculateExplicitQuantities(simulator, groupStateHelper_copy, deferred_logger); const double dt = simulator.timeStepSize(); // iterate to get a solution at the given bhp. bool converged = false; @@ -1810,7 +1813,7 @@ namespace Opm // for newly opened wells we dont compute the potentials implicit // group controlled wells with defaulted guiderates will have zero targets as // the potentials are used to compute the well fractions. - if (this->param_.local_well_solver_control_switching_ && !(this->changed_to_open_this_step_ && this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger))) { + if (this->param_.local_well_solver_control_switching_ && !(this->changed_to_open_this_step_ && this->wellUnderZeroRateTarget(groupStateHelper, deferred_logger))) { converged_implicit = computeWellPotentialsImplicit( simulator, groupStateHelper, well_potentials, deferred_logger ); @@ -1871,13 +1874,13 @@ namespace Opm template void StandardWell:: - updatePrimaryVariables(const Simulator& simulator, - const WellStateType& well_state, + updatePrimaryVariables(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) { if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; - const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger); + const auto& well_state = groupStateHelper.wellState(); + const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(groupStateHelper, deferred_logger); this->primary_variables_.update(well_state, stop_or_zero_rate_target, deferred_logger); // other primary variables related to polymer injection @@ -2415,7 +2418,7 @@ namespace Opm WellStateType& well_state, DeferredLogger& deferred_logger) { - updatePrimaryVariables(simulator, well_state, deferred_logger); + updatePrimaryVariables(groupStateHelper, deferred_logger); const int max_iter = this->param_.max_inner_iter_wells_; int it = 0; @@ -2431,7 +2434,7 @@ namespace Opm this->regularize_ = true; } - auto report = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, relax_convergence); + auto report = getWellConvergence(groupStateHelper, Base::B_avg_, deferred_logger, relax_convergence); converged = report.converged(); if (converged) { @@ -2439,7 +2442,7 @@ namespace Opm } ++it; - solveEqAndUpdateWellState(simulator, well_state, deferred_logger); + solveEqAndUpdateWellState(simulator, groupStateHelper, well_state, deferred_logger); // TODO: when this function is used for well testing purposes, will need to check the controls, so that we will obtain convergence // under the most restrictive control. Based on this converged results, we can check whether to re-open the well. Either we refactor @@ -2481,7 +2484,7 @@ namespace Opm const bool fixed_status /*false*/, const bool solving_with_zero_rate /*false*/) { - updatePrimaryVariables(simulator, well_state, deferred_logger); + updatePrimaryVariables(groupStateHelper, deferred_logger); const int max_iter = this->param_.max_inner_iter_wells_; int it = 0; @@ -2507,7 +2510,7 @@ namespace Opm const bool allow_open = well_state.well(this->index_of_well_).status == WellStatus::OPEN; // don't allow switcing for wells under zero rate target or requested fixed status and control const bool allow_switching = - !this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger) && + !this->wellUnderZeroRateTarget(groupStateHelper, deferred_logger) && (!fixed_control || !fixed_status) && allow_open; bool changed = false; @@ -2549,7 +2552,7 @@ namespace Opm this->regularize_ = true; } - auto report = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, relax_convergence); + auto report = getWellConvergence(groupStateHelper, Base::B_avg_, deferred_logger, relax_convergence); converged = report.converged(); if (converged) { @@ -2564,7 +2567,7 @@ namespace Opm } ++it; - solveEqAndUpdateWellState(simulator, well_state, deferred_logger); + solveEqAndUpdateWellState(simulator, groupStateHelper, well_state, deferred_logger); } while (it < max_iter); diff --git a/opm/simulators/wells/TargetCalculator.cpp b/opm/simulators/wells/TargetCalculator.cpp index 057c52e1785..73d0b958c79 100644 --- a/opm/simulators/wells/TargetCalculator.cpp +++ b/opm/simulators/wells/TargetCalculator.cpp @@ -28,30 +28,22 @@ #include #include #include +#include #include #include namespace Opm::GroupStateHelpers - { - +{ template TargetCalculator:: -TargetCalculator(const Group::ProductionCMode cmode, - const PhaseUsageInfo& pu, +TargetCalculator(const Opm::GroupStateHelper& groupStateHelper, const std::vector& resv_coeff, - const Scalar group_grat_target_from_sales, - const std::string& group_name, - const GroupState& group_state, - const bool use_gpmaint) - : cmode_(cmode) - , pu_(pu) - , resv_coeff_(resv_coeff) - , group_grat_target_from_sales_(group_grat_target_from_sales) - , group_name_(group_name) - , group_state_(group_state) - , use_gpmaint_(use_gpmaint) - + const Group& group) + : cmode_{groupStateHelper.groupState().production_control(group.name())} + , groupStateHelper_{groupStateHelper} + , resv_coeff_{resv_coeff} + , group_{group} { } @@ -59,35 +51,36 @@ template template RateType TargetCalculator::calcModeRateFromRates(const RateType* rates) const { - switch (cmode_) { + const auto& pu = this->groupStateHelper_.phaseUsageInfo(); + switch (this->cmode_) { case Group::ProductionCMode::ORAT: { - assert(pu_.phaseIsActive(IndexTraits::oilPhaseIdx)); - const int pos = pu_.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); + assert(pu.phaseIsActive(IndexTraits::oilPhaseIdx)); + const int pos = pu.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); return rates[pos]; } case Group::ProductionCMode::WRAT: { - assert(pu_.phaseIsActive(IndexTraits::waterPhaseIdx)); - const int pos = pu_.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); + assert(pu.phaseIsActive(IndexTraits::waterPhaseIdx)); + const int pos = pu.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); return rates[pos]; } case Group::ProductionCMode::GRAT: { - assert(pu_.phaseIsActive(IndexTraits::gasPhaseIdx)); - const int pos = pu_.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx); + assert(pu.phaseIsActive(IndexTraits::gasPhaseIdx)); + const int pos = pu.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx); return rates[pos]; } case Group::ProductionCMode::LRAT: { // TODO: do need both oil and water activate to use LRAT? - assert(pu_.phaseIsActive(IndexTraits::oilPhaseIdx)); - assert(pu_.phaseIsActive(IndexTraits::waterPhaseIdx)); - const int opos = pu_.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); - const int wpos = pu_.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); + assert(pu.phaseIsActive(IndexTraits::oilPhaseIdx)); + assert(pu.phaseIsActive(IndexTraits::waterPhaseIdx)); + const int opos = pu.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); + const int wpos = pu.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); return rates[opos] + rates[wpos]; } case Group::ProductionCMode::RESV: { - auto mode_rate = rates[0] * resv_coeff_[0]; - const int num_phases = pu_.numActivePhases(); + auto mode_rate = rates[0] * this->resv_coeff_[0]; + const int num_phases = pu.numActivePhases(); for (int phase = 1; phase < num_phases; ++phase) { - mode_rate += rates[phase] * resv_coeff_[phase]; + mode_rate += rates[phase] * this->resv_coeff_[phase]; } return mode_rate; } @@ -101,49 +94,16 @@ RateType TargetCalculator::calcModeRateFromRates(const Rate template Scalar TargetCalculator:: -groupTarget(const std::optional& ctrl, - DeferredLogger& deferred_logger) const +groupTarget(DeferredLogger& deferred_logger) const { - if (!ctrl && !use_gpmaint_) { - OPM_DEFLOG_THROW(std::logic_error, - "Production group " + this->group_name_ - + "must either have a valid control or use GPMAINT", - deferred_logger); - } - switch (cmode_) { - case Group::ProductionCMode::ORAT: - return ctrl->oil_target; - case Group::ProductionCMode::WRAT: - return ctrl->water_target; - case Group::ProductionCMode::GRAT: - { - // gas target may have been adjusted by GCONSALE - if (group_grat_target_from_sales_ > 0) - return group_grat_target_from_sales_; - - return ctrl->gas_target; - } - case Group::ProductionCMode::LRAT: - return ctrl->liquid_target; - case Group::ProductionCMode::RESV: - { - if (use_gpmaint_ && this->group_state_.has_gpmaint_target(this->group_name_)) - return this->group_state_.gpmaint_target(this->group_name_); - - return ctrl->resv_target; - } - default: - // Should never be here. - assert(false); - return 0.0; - } + return this->groupStateHelper_.getProductionGroupTarget(this->group_, deferred_logger); } template GuideRateModel::Target TargetCalculator::guideTargetMode() const { - switch (cmode_) { + switch (this->cmode_) { case Group::ProductionCMode::ORAT: return GuideRateModel::Target::OIL; case Group::ProductionCMode::WRAT: @@ -163,41 +123,31 @@ TargetCalculator::guideTargetMode() const template InjectionTargetCalculator:: -InjectionTargetCalculator(const Group::InjectionCMode& cmode, - const PhaseUsageInfo& pu, +InjectionTargetCalculator(const GroupStateHelperType& groupStateHelper, const std::vector& resv_coeff, - const std::string& group_name, - const Scalar sales_target, - const GroupState& group_state, + const Group& group, const Phase& injection_phase, - const bool use_gpmaint, DeferredLogger& deferred_logger) - : cmode_(cmode) - , pu_(pu) - , resv_coeff_(resv_coeff) - , group_name_(group_name) - , sales_target_(sales_target) - , group_state_(group_state) - , use_gpmaint_(use_gpmaint) - + : groupStateHelper_{groupStateHelper} + , resv_coeff_{resv_coeff} + , group_{group} + , injection_phase_{injection_phase} + , cmode_{groupStateHelper.groupState().injection_control(group.name(), injection_phase)} { + pos_ = this->groupStateHelper_.phaseToActivePhaseIdx(injection_phase); // initialize to avoid warning - pos_ = pu_.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); target_ = GuideRateModel::Target::WAT; switch (injection_phase) { case Phase::WATER: { - pos_ = pu_.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); target_ = GuideRateModel::Target::WAT; break; } case Phase::OIL: { - pos_ = pu_.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); target_ = GuideRateModel::Target::OIL; break; } case Phase::GAS: { - pos_ = pu_.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx); target_ = GuideRateModel::Target::GAS; break; } @@ -211,70 +161,18 @@ InjectionTargetCalculator(const Group::InjectionCMode& cmode, template Scalar InjectionTargetCalculator:: -groupTarget(const std::optional& ctrl, - DeferredLogger& deferred_logger) const +groupTarget(DeferredLogger& deferred_logger) const { - if (!ctrl && !use_gpmaint_) { - OPM_DEFLOG_THROW(std::logic_error, - "Injection group " + this->group_name_ - + "must either have a valid control or use GPMAINT", - deferred_logger); - } - switch (cmode_) { - case Group::InjectionCMode::RATE: - if (use_gpmaint_ && this->group_state_.has_gpmaint_target(this->group_name_)) - return this->group_state_.gpmaint_target(this->group_name_); - - return ctrl->surface_max_rate; - case Group::InjectionCMode::RESV: - if (use_gpmaint_ && this->group_state_.has_gpmaint_target(this->group_name_)) - return this->group_state_.gpmaint_target(this->group_name_) / resv_coeff_[pos_]; - - return ctrl->resv_max_rate / resv_coeff_[pos_]; - case Group::InjectionCMode::REIN: { - Scalar production_rate = this->group_state_.injection_rein_rates(ctrl->reinj_group)[pos_]; - return ctrl->target_reinj_fraction * production_rate; - } - case Group::InjectionCMode::VREP: { - // We use the injection_reservoir_rates directly instead of the reduction rates here to account for the - // possibility that the group in question has both a VREP control and another injection control for a different phase. - const std::vector& group_injection_reservoir_rates = this->group_state_.injection_reservoir_rates(this->group_name_); - Scalar voidage_rate = group_state_.injection_vrep_rate(ctrl->voidage_group) * ctrl->target_void_fraction; - if (ctrl->phase != Phase::WATER) { - const int pos = pu_.canonicalToActivePhaseIdx(IndexTraits::waterPhaseIdx); - voidage_rate -= group_injection_reservoir_rates[pos]; - } - if (ctrl->phase != Phase::OIL) { - const int pos = pu_.canonicalToActivePhaseIdx(IndexTraits::oilPhaseIdx); - voidage_rate -= group_injection_reservoir_rates[pos]; - } - if (ctrl->phase != Phase::GAS) { - const int pos = pu_.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx); - voidage_rate -= group_injection_reservoir_rates[pos]; - } - return voidage_rate / resv_coeff_[pos_]; - } - case Group::InjectionCMode::SALE: { - assert(pos_ == pu_.canonicalToActivePhaseIdx(IndexTraits::gasPhaseIdx) ); - // Gas injection rate = Total gas production rate + gas import rate - gas consumption rate - sales rate; - // Gas import and consumption is already included in the REIN rates - Scalar inj_rate = group_state_.injection_rein_rates(this->group_name_)[pos_]; - inj_rate -= sales_target_; - return inj_rate; - } - default: - OPM_DEFLOG_THROW(std::logic_error, - "Invalid Group::InjectionCMode in InjectionTargetCalculator", - deferred_logger); - return 0.0; - } + return this->groupStateHelper_.getInjectionGroupTarget( + this->group_, this->injection_phase_, this->resv_coeff_, deferred_logger + ); } template GuideRateModel::Target InjectionTargetCalculator::guideTargetMode() const { - return target_; + return this->target_; } #define INSTANTIATE_TARGET_CALCULATOR(T,...) \ diff --git a/opm/simulators/wells/TargetCalculator.hpp b/opm/simulators/wells/TargetCalculator.hpp index dba6f7bec40..c3432ab1054 100644 --- a/opm/simulators/wells/TargetCalculator.hpp +++ b/opm/simulators/wells/TargetCalculator.hpp @@ -33,6 +33,7 @@ namespace Opm { class DeferredLogger; template class GroupState; template class PhaseUsageInfo; +template class GroupStateHelper; namespace GroupStateHelpers { @@ -43,13 +44,11 @@ template class TargetCalculator { public: - TargetCalculator(const Group::ProductionCMode cmode, - const PhaseUsageInfo& pu, + using GroupStateHelperType = Opm::GroupStateHelper; + + TargetCalculator(const GroupStateHelperType& groupStateHelper, const std::vector& resv_coeff, - const Scalar group_grat_target_from_sales, - const std::string& group_name, - const GroupState& group_state, - const bool use_gpmaint); + const Group& group); template RateType calcModeRateFromRates(const std::vector& rates) const @@ -60,19 +59,15 @@ class TargetCalculator template RateType calcModeRateFromRates(const RateType* rates) const; - Scalar groupTarget(const std::optional& ctrl, - DeferredLogger& deferred_logger) const; + Scalar groupTarget(DeferredLogger& deferred_logger) const; GuideRateModel::Target guideTargetMode() const; private: Group::ProductionCMode cmode_; - const PhaseUsageInfo& pu_; + const GroupStateHelperType& groupStateHelper_; const std::vector& resv_coeff_; - const Scalar group_grat_target_from_sales_; - const std::string& group_name_; - const GroupState& group_state_; - bool use_gpmaint_; + const Group& group_; }; /// Based on a group control mode, extract or calculate rates, and @@ -81,14 +76,12 @@ template class InjectionTargetCalculator { public: - InjectionTargetCalculator(const Group::InjectionCMode& cmode, - const PhaseUsageInfo& pu, + using GroupStateHelperType = GroupStateHelper; + + InjectionTargetCalculator(const GroupStateHelperType& groupStateHelper, const std::vector& resv_coeff, - const std::string& group_name, - const Scalar sales_target, - const GroupState& group_state, + const Group& group, const Phase& injection_phase, - const bool use_gpmaint, DeferredLogger& deferred_logger); template @@ -97,19 +90,16 @@ class InjectionTargetCalculator return rates[pos_]; } - Scalar groupTarget(const std::optional& ctrl, - DeferredLogger& deferred_logger) const; + Scalar groupTarget(DeferredLogger& deferred_logger) const; GuideRateModel::Target guideTargetMode() const; private: - Group::InjectionCMode cmode_; - const PhaseUsageInfo& pu_; + const GroupStateHelperType& groupStateHelper_; const std::vector& resv_coeff_; - const std::string& group_name_; - Scalar sales_target_; - const GroupState& group_state_; - bool use_gpmaint_; + const Group& group_; + const Phase& injection_phase_; + Group::InjectionCMode cmode_; int pos_; GuideRateModel::Target target_; }; diff --git a/opm/simulators/wells/WellAssemble.cpp b/opm/simulators/wells/WellAssemble.cpp index 680c9f67304..4617ba1195e 100644 --- a/opm/simulators/wells/WellAssemble.cpp +++ b/opm/simulators/wells/WellAssemble.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -53,10 +54,7 @@ template template void WellAssemble:: -assembleControlEqProd(const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, +assembleControlEqProd(const GroupStateHelperType& groupStateHelper, const Well::ProductionControls& controls, const EvalWell& bhp, const std::vector& rates, // Always 3 canonical rates. @@ -64,6 +62,8 @@ assembleControlEqProd(const WellState& well_state, EvalWell& control_eq, DeferredLogger& deferred_logger) const { + const auto& well_state = groupStateHelper.wellState(); + const auto& group_state = groupStateHelper.groupState(); const auto current = well_state.well(well_.indexOfWell()).production_cmode; const Scalar efficiencyFactor = well_.wellEcl().getEfficiencyFactor() * well_state[well_.name()].efficiency_scaling_factor; @@ -142,7 +142,7 @@ assembleControlEqProd(const WellState& well_state, } case Well::ProducerCMode::GRUP: { assert(well_.wellEcl().isAvailableForGroupControl()); - const auto& group = schedule.getGroup(well_.wellEcl().groupName(), well_.currentStep()); + const auto& group = groupStateHelper.schedule().getGroup(well_.wellEcl().groupName(), well_.currentStep()); // Annoying thing: the rates passed to this function are // always of size 3 and in canonical (for PhaseUsage) // order. This is what is needed for VFP calculations if @@ -169,10 +169,7 @@ assembleControlEqProd(const WellState& well_state, }; WellGroupControls(well_).getGroupProductionControl(group, - well_state, - group_state, - schedule, - summaryState, + groupStateHelper, bhp, active_rates, rCoeff, @@ -198,10 +195,7 @@ template template void WellAssemble:: -assembleControlEqInj(const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, +assembleControlEqInj(const GroupStateHelperType& groupStateHelper, const Well::InjectionControls& controls, const EvalWell& bhp, const EvalWell& injection_rate, @@ -209,6 +203,8 @@ assembleControlEqInj(const WellState& well_state, EvalWell& control_eq, DeferredLogger& deferred_logger) const { + const auto& well_state = groupStateHelper.wellState(); + const auto& group_state = groupStateHelper.groupState(); auto current = well_state.well(well_.indexOfWell()).injection_cmode; const InjectorType injectorType = controls.injector_type; const Scalar efficiencyFactor = well_.wellEcl().getEfficiencyFactor() * @@ -260,7 +256,7 @@ assembleControlEqInj(const WellState& well_state, } case Well::InjectorCMode::GRUP: { assert(well_.wellEcl().isAvailableForGroupControl()); - const auto& group = schedule.getGroup(well_.wellEcl().groupName(), well_.currentStep()); + const auto& group = groupStateHelper.schedule().getGroup(well_.wellEcl().groupName(), well_.currentStep()); auto rCoeff = [this, &group_state](const RegionId id, const int region, const std::optional& prod_gname, std::vector& coeff) @@ -273,10 +269,10 @@ assembleControlEqInj(const WellState& well_state, } }; WellGroupControls(well_).getGroupInjectionControl(group, - well_state, - group_state, - schedule, - summaryState, + groupStateHelper.wellState(), + groupStateHelper.groupState(), + groupStateHelper.schedule(), + groupStateHelper.summaryState(), injectorType, bhp, injection_rate, @@ -294,10 +290,7 @@ assembleControlEqInj(const WellState& well_state, #define INSTANTIATE_METHODS(A,...) \ template void WellAssemble:: \ -assembleControlEqProd<__VA_ARGS__>(const WellState&, \ - const GroupState&, \ - const Schedule&, \ - const SummaryState&, \ +assembleControlEqProd<__VA_ARGS__>(const GroupStateHelper&, \ const Well::ProductionControls&, \ const __VA_ARGS__&, \ const std::vector<__VA_ARGS__>&, \ @@ -305,10 +298,7 @@ assembleControlEqProd<__VA_ARGS__>(const WellState:: \ -assembleControlEqInj<__VA_ARGS__>(const WellState&, \ - const GroupState&, \ - const Schedule&, \ - const SummaryState&, \ +assembleControlEqInj<__VA_ARGS__>(const GroupStateHelper&, \ const Well::InjectionControls&, \ const __VA_ARGS__&, \ const __VA_ARGS__&, \ diff --git a/opm/simulators/wells/WellAssemble.hpp b/opm/simulators/wells/WellAssemble.hpp index 74dabb3b5e9..1fd7a061b98 100644 --- a/opm/simulators/wells/WellAssemble.hpp +++ b/opm/simulators/wells/WellAssemble.hpp @@ -39,6 +39,7 @@ class Schedule; class SummaryState; template class WellInterfaceFluidSystem; template class WellState; +template class GroupStateHelper; struct WellInjectionControls; struct WellProductionControls; @@ -49,15 +50,13 @@ class WellAssemble { static constexpr int Gas = FluidSystem::gasPhaseIdx; using Scalar = typename FluidSystem::Scalar; using IndexTraits = typename FluidSystem::IndexTraitsType; + using GroupStateHelperType = GroupStateHelper; public: explicit WellAssemble(const WellInterfaceFluidSystem& well); template - void assembleControlEqProd(const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + void assembleControlEqProd(const GroupStateHelperType& groupStateHelper, const WellProductionControls& controls, const EvalWell& bhp, const std::vector& rates, // Always 3 canonical rates. @@ -66,10 +65,7 @@ class WellAssemble { DeferredLogger& deferred_logger) const; template - void assembleControlEqInj(const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + void assembleControlEqInj(const GroupStateHelperType& groupStateHelper, const WellInjectionControls& controls, const EvalWell& bhp, const EvalWell& injection_rate, diff --git a/opm/simulators/wells/WellGroupControls.cpp b/opm/simulators/wells/WellGroupControls.cpp index 9ead1b8590d..de28eb32422 100644 --- a/opm/simulators/wells/WellGroupControls.cpp +++ b/opm/simulators/wells/WellGroupControls.cpp @@ -138,10 +138,7 @@ template std::optional WellGroupControls:: getGroupInjectionTargetRate(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, const InjectorType& injectorType, const RateConvFunc& rateConverter, Scalar efficiencyFactor, @@ -170,7 +167,7 @@ getGroupInjectionTargetRate(const Group& group, // Should not be here. assert(false); } - auto currentGroupControl = group_state.injection_control(group.name(), injectionPhase); + auto currentGroupControl = groupStateHelper.groupState().injection_control(group.name(), injectionPhase); if (currentGroupControl == Group::InjectionCMode::FLD || currentGroupControl == Group::InjectionCMode::NONE) { if (!group.injectionGroupControlAvailable(injectionPhase)) { @@ -185,10 +182,9 @@ getGroupInjectionTargetRate(const Group& group, return std::nullopt; } else { // Inject share of parents control - const auto& parent = schedule.getGroup( group.parent(), well_.currentStep()); + const auto& parent = groupStateHelper.schedule().getGroup( group.parent(), well_.currentStep()); efficiencyFactor *= group.getGroupEfficiencyFactor(); - return getGroupInjectionTargetRate(parent, well_state, group_state, - schedule, summaryState, injectorType, + return getGroupInjectionTargetRate(parent, groupStateHelper, injectorType, rateConverter, efficiencyFactor, deferred_logger); } } @@ -197,17 +193,14 @@ getGroupInjectionTargetRate(const Group& group, return std::nullopt; } - return well_state.well(well_.indexOfWell()).group_target; + return groupStateHelper.wellState().well(well_.indexOfWell()).group_target; } template template void WellGroupControls:: getGroupProductionControl(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, const EvalWell& bhp, const std::vector& rates, const RateConvFunc& rateConverter, @@ -215,6 +208,10 @@ getGroupProductionControl(const Group& group, EvalWell& control_eq, DeferredLogger& deferred_logger) const { + const auto& group_state = groupStateHelper.groupState(); + const auto& summaryState = groupStateHelper.summaryState(); + const auto& schedule = groupStateHelper.schedule(); + const auto& well_state = groupStateHelper.wellState(); const Group::ProductionCMode& currentGroupControl = group_state.production_control(group.name()); if (currentGroupControl == Group::ProductionCMode::FLD || currentGroupControl == Group::ProductionCMode::NONE) { @@ -234,8 +231,7 @@ getGroupProductionControl(const Group& group, // Produce share of parents control const auto& parent = schedule.getGroup(group.parent(), well_.currentStep()); efficiencyFactor *= group.getGroupEfficiencyFactor(); - getGroupProductionControl(parent, well_state, group_state, - schedule, summaryState, bhp, + getGroupProductionControl(parent, groupStateHelper, bhp, rates, rateConverter, efficiencyFactor, control_eq, deferred_logger); return; @@ -260,17 +256,8 @@ getGroupProductionControl(const Group& group, // gconsale may adjust the grat target. // the adjusted rates is send to the targetCalculator - Scalar gratTargetFromSales = 0.0; - if (group_state.has_grat_sales_target(group.name())) - gratTargetFromSales = group_state.grat_sales_target(group.name()); - GroupStateHelpers::TargetCalculator tcalc(currentGroupControl, - well_state.phaseUsageInfo(), - resv_coeff, - gratTargetFromSales, - group.name(), - group_state, - group.has_gpmaint_control(currentGroupControl)); + GroupStateHelpers::TargetCalculator tcalc{groupStateHelper, resv_coeff, group}; const auto target_rate = well_state.well(well_.indexOfWell()).group_target; if (target_rate) { @@ -287,14 +274,14 @@ template Scalar WellGroupControls:: getGroupProductionTargetRate(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, const RateConvFunc& rateConverter, Scalar efficiencyFactor, DeferredLogger& deferred_logger) const { + const auto& well_state = groupStateHelper.wellState(); + const auto& group_state = groupStateHelper.groupState(); + const auto& schedule = groupStateHelper.schedule(); const Group::ProductionCMode& currentGroupControl = group_state.production_control(group.name()); if (currentGroupControl == Group::ProductionCMode::FLD || currentGroupControl == Group::ProductionCMode::NONE) { @@ -304,8 +291,7 @@ getGroupProductionTargetRate(const Group& group, // Produce share of parents control const auto& parent = schedule.getGroup(group.parent(), well_.currentStep()); efficiencyFactor *= group.getGroupEfficiencyFactor(); - return getGroupProductionTargetRate(parent, well_state, group_state, - schedule, summaryState, + return getGroupProductionTargetRate(parent, groupStateHelper, rateConverter, efficiencyFactor, deferred_logger); } @@ -322,21 +308,9 @@ getGroupProductionTargetRate(const Group& group, std::vector resv_coeff(well_.phaseUsage().numActivePhases(), 1.0); rateConverter(0, well_.pvtRegionIdx(), group.name(), resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS. - // gconsale may adjust the grat target. - // the adjusted rates is send to the targetCalculator - Scalar gratTargetFromSales = 0.0; - if (group_state.has_grat_sales_target(group.name())) - gratTargetFromSales = group_state.grat_sales_target(group.name()); - - GroupStateHelpers -::TargetCalculator tcalc(currentGroupControl, - well_state.phaseUsageInfo(), - resv_coeff, - gratTargetFromSales, - group.name(), - group_state, - group.has_gpmaint_control(currentGroupControl)); - + GroupStateHelpers::TargetCalculator tcalc{groupStateHelper, + resv_coeff, + group}; const auto target_rate = well_state.well(well_.indexOfWell()).group_target; if (!target_rate) { @@ -357,7 +331,7 @@ ::TargetCalculator tcalc(currentGroupControl, template std::pair WellGroupControls:: -getAutoChokeGroupProductionTargetRate(const std::string& name, +getAutoChokeGroupProductionTargetRate(const Group& bottom_group, const Group& group, const GroupStateHelperType& groupStateHelper, const Schedule& schedule, @@ -379,7 +353,7 @@ getAutoChokeGroupProductionTargetRate(const std::string& name, // Produce share of parents control const auto& parent = schedule.getGroup(group.parent(), reportStepIdx); efficiencyFactor *= group.getGroupEfficiencyFactor(); - return getAutoChokeGroupProductionTargetRate(name, parent, groupStateHelper, + return getAutoChokeGroupProductionTargetRate(bottom_group, parent, groupStateHelper, schedule, summaryState, resv_coeff, efficiencyFactor, reportStepIdx, guideRate, deferred_logger); @@ -397,19 +371,9 @@ getAutoChokeGroupProductionTargetRate(const std::string& name, // std::vector resv_coeff(well_.phaseUsage().num_phases, 1.0); // rateConverter(0, well_.pvtRegionIdx(), group.name(), resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS. - // gconsale may adjust the grat target. - // the adjusted rates is send to the targetCalculator - Scalar gratTargetFromSales = 0.0; - if (groupStateHelper.groupState().has_grat_sales_target(group.name())) - gratTargetFromSales = group_state.grat_sales_target(group.name()); - - GroupStateHelpers::TargetCalculator tcalc(currentGroupControl, - well_state.phaseUsageInfo(), + GroupStateHelpers::TargetCalculator tcalc{groupStateHelper, resv_coeff, - gratTargetFromSales, - group.name(), - group_state, - group.has_gpmaint_control(currentGroupControl)); + group}; GroupStateHelpers::FractionCalculator fcalc(schedule, groupStateHelper, @@ -429,12 +393,8 @@ getAutoChokeGroupProductionTargetRate(const std::string& name, return tcalc.calcModeRateFromRates(groupTargetReductions); }; - std::optional ctrl; - if (!group.has_gpmaint_control(currentGroupControl)) - ctrl = group.productionControls(summaryState); - - const Scalar orig_target = tcalc.groupTarget(ctrl, deferred_logger); - const auto chain = groupStateHelper.groupChainTopBot(name, group.name()); + const Scalar orig_target = tcalc.groupTarget(deferred_logger); + const auto chain = groupStateHelper.groupChainTopBot(bottom_group.name(), group.name()); // Because 'name' is the last of the elements, and not an ancestor, we subtract one below. const std::size_t num_ancestors = chain.size() - 1; Scalar target = orig_target; @@ -469,10 +429,7 @@ getAutoChokeGroupProductionTargetRate(const std::string& name, DeferredLogger& deferred_logger) const; \ template void WellGroupControls:: \ getGroupProductionControl(const Group&, \ - const WellState&, \ - const GroupState&, \ - const Schedule&, \ - const SummaryState&, \ + const GroupStateHelper&, \ const __VA_ARGS__& bhp, \ const std::vector<__VA_ARGS__>&, \ const RateConvFunc& rateConverter, \ diff --git a/opm/simulators/wells/WellGroupControls.hpp b/opm/simulators/wells/WellGroupControls.hpp index 7d71f2eaf4d..7551245facc 100644 --- a/opm/simulators/wells/WellGroupControls.hpp +++ b/opm/simulators/wells/WellGroupControls.hpp @@ -71,10 +71,7 @@ class WellGroupControls { std::optional getGroupInjectionTargetRate(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, const InjectorType& injectorType, const RateConvFunc& rateConverter, Scalar efficiencyFactor, @@ -82,10 +79,7 @@ class WellGroupControls { template void getGroupProductionControl(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, const EvalWell& bhp, const std::vector& rates, const RateConvFunc& rateConverter, @@ -94,15 +88,12 @@ class WellGroupControls { DeferredLogger& deferred_logger) const; Scalar getGroupProductionTargetRate(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, const RateConvFunc& rateConverter, Scalar efficiencyFactor, DeferredLogger& deferred_logger) const; - static std::pair getAutoChokeGroupProductionTargetRate(const std::string& name, + static std::pair getAutoChokeGroupProductionTargetRate(const Group& bottom_group, const Group& group, const GroupStateHelperType& groupStateHelper, const Schedule& schedule, diff --git a/opm/simulators/wells/WellInterface.hpp b/opm/simulators/wells/WellInterface.hpp index 7371075c5b9..fc0af592941 100644 --- a/opm/simulators/wells/WellInterface.hpp +++ b/opm/simulators/wells/WellInterface.hpp @@ -157,13 +157,13 @@ class WellInterface : public WellInterfaceIndices& B_avg, const bool changed_to_open_this_step); - virtual ConvergenceReport getWellConvergence(const Simulator& simulator, - const WellStateType& well_state, + virtual ConvergenceReport getWellConvergence(const GroupStateHelperType& groupStateHelper, const std::vector& B_avg, DeferredLogger& deferred_logger, const bool relax_tolerance) const = 0; virtual void solveEqAndUpdateWellState(const Simulator& simulator, + const GroupStateHelperType& groupStateHelper, WellStateType& well_state, DeferredLogger& deferred_logger) = 0; @@ -204,6 +204,7 @@ class WellInterface : public WellInterfaceIndices& well_flux, DeferredLogger& deferred_logger) const = 0; - bool wellUnderZeroRateTarget(const Simulator& simulator, - const WellStateType& well_state, + bool wellUnderZeroRateTarget(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) const; - bool wellUnderZeroGroupRateTarget(const Simulator& simulator, - const WellStateType& well_state, - DeferredLogger& deferred_logger, - std::optional group_control = std::nullopt) const; - - bool stoppedOrZeroRateTarget(const Simulator& simulator, - const WellStateType& well_state, + bool stoppedOrZeroRateTarget(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) const; bool updateWellStateWithTHPTargetProd(const Simulator& simulator, @@ -251,6 +245,10 @@ class WellInterface : public WellInterfaceIndices group_control = std::nullopt) const; + enum class IndividualOrGroup { Individual, Group, Both }; bool updateWellControl(const Simulator& simulator, const IndividualOrGroup iog, @@ -269,12 +267,11 @@ class WellInterface : public WellInterfaceIndices std::optional WellInterfaceFluidSystem:: getGroupInjectionTargetRate(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, const InjectorType& injectorType, Scalar efficiencyFactor, DeferredLogger& deferred_logger) const { + const auto& group_state = groupStateHelper.groupState(); auto rCoeff = [this, &group_state](const RegionId id, const int region, const std::optional& prod_gname, std::vector& coeff) @@ -252,10 +250,7 @@ getGroupInjectionTargetRate(const Group& group, }; return WellGroupControls(*this).getGroupInjectionTargetRate(group, - well_state, - group_state, - schedule, - summaryState, + groupStateHelper, injectorType, rCoeff, efficiencyFactor, @@ -266,13 +261,11 @@ template typename FluidSystem::Scalar WellInterfaceFluidSystem:: getGroupProductionTargetRate(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, Scalar efficiencyFactor, DeferredLogger& deferred_logger) const { + const auto& group_state = groupStateHelper.groupState(); auto rCoeff = [this, &group_state](const RegionId id, const int region, const std::optional& prod_gname, std::vector& coeff) @@ -285,10 +278,7 @@ getGroupProductionTargetRate(const Group& group, }; return WellGroupControls(*this).getGroupProductionTargetRate(group, - well_state, - group_state, - schedule, - summaryState, + groupStateHelper, rCoeff, efficiencyFactor, deferred_logger); @@ -297,23 +287,21 @@ getGroupProductionTargetRate(const Group& group, template bool WellInterfaceFluidSystem:: -zeroGroupRateTarget(const SummaryState& summary_state, - const Schedule& schedule, - const WellState& well_state, - const GroupState& group_state, +zeroGroupRateTarget(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) const { + const auto& well_state = groupStateHelper.wellState(); const auto& well = this->well_ecl_; - const auto& group = schedule.getGroup(well.groupName(), this->currentStep()); + const auto& group = groupStateHelper.schedule().getGroup(well.groupName(), this->currentStep()); const Scalar efficiencyFactor = well.getEfficiencyFactor() * well_state[well.name()].efficiency_scaling_factor; if (this->isInjector()) { // Check injector under group control - const auto& controls = well.injectionControls(summary_state); + const auto& controls = well.injectionControls(groupStateHelper.summaryState()); const std::optional target = - this->getGroupInjectionTargetRate(group, well_state, - group_state, schedule, - summary_state, controls.injector_type, + this->getGroupInjectionTargetRate(group, + groupStateHelper, + controls.injector_type, efficiencyFactor, deferred_logger); if (target.has_value()) { return target.value() == 0.0; @@ -323,9 +311,8 @@ zeroGroupRateTarget(const SummaryState& summary_state, } else { // Check producer under group control const Scalar scale = - this->getGroupProductionTargetRate(group, well_state, - group_state, schedule, - summary_state, efficiencyFactor, + this->getGroupProductionTargetRate(group, groupStateHelper, + efficiencyFactor, deferred_logger); return scale == 0.0; } diff --git a/opm/simulators/wells/WellInterfaceFluidSystem.hpp b/opm/simulators/wells/WellInterfaceFluidSystem.hpp index 5c530689bfa..3859684233f 100644 --- a/opm/simulators/wells/WellInterfaceFluidSystem.hpp +++ b/opm/simulators/wells/WellInterfaceFluidSystem.hpp @@ -106,28 +106,19 @@ class WellInterfaceFluidSystem : public WellInterfaceGeneric getGroupInjectionTargetRate(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, const InjectorType& injectorType, Scalar efficiencyFactor, DeferredLogger& deferred_logger) const; Scalar getGroupProductionTargetRate(const Group& group, - const WellState& well_state, - const GroupState& group_state, - const Schedule& schedule, - const SummaryState& summaryState, + const GroupStateHelperType& groupStateHelper, Scalar efficiencyFactor, DeferredLogger& deferred_logger) const; - bool zeroGroupRateTarget(const SummaryState& summary_state, - const Schedule& schedule, - const WellState& well_state, - const GroupState& group_state, - DeferredLogger& deferredLogger) const; + bool zeroGroupRateTarget(const GroupStateHelperType& groupStateHelper, + DeferredLogger& deferred_logger) const; // For the conversion between the surface volume rate and reservoir voidage rate const RateConverterType& rateConverter_; diff --git a/opm/simulators/wells/WellInterface_impl.hpp b/opm/simulators/wells/WellInterface_impl.hpp index ac23c6fd24b..da43616232a 100644 --- a/opm/simulators/wells/WellInterface_impl.hpp +++ b/opm/simulators/wells/WellInterface_impl.hpp @@ -193,7 +193,7 @@ namespace Opm DeferredLogger& deferred_logger) /* const */ { OPM_TIMEFUNCTION(); - if (stoppedOrZeroRateTarget(simulator, well_state, deferred_logger)) { + if (stoppedOrZeroRateTarget(groupStateHelper, deferred_logger)) { return false; } @@ -265,7 +265,7 @@ namespace Opm this->well_control_log_.push_back(from); } updateWellStateWithTarget(simulator, groupStateHelper, well_state, deferred_logger); - updatePrimaryVariables(simulator, well_state, deferred_logger); + updatePrimaryVariables(groupStateHelper, deferred_logger); } return changed; @@ -297,7 +297,7 @@ namespace Opm } const bool oscillating = std::count(this->well_control_log_.begin(), this->well_control_log_.end(), from) >= this->param_.max_number_of_well_switches_; - if (oscillating || this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger) || !(well_state.well(this->index_of_well_).status == WellStatus::OPEN)) { + if (oscillating || this->wellUnderZeroRateTarget(groupStateHelper, deferred_logger) || !(well_state.well(this->index_of_well_).status == WellStatus::OPEN)) { return false; } @@ -341,7 +341,7 @@ namespace Opm // don't call for thp since this might trigger additional local solve updateWellStateWithTarget(simulator, groupStateHelper, well_state, deferred_logger); } - updatePrimaryVariables(simulator, well_state, deferred_logger); + updatePrimaryVariables(groupStateHelper, deferred_logger); } } return changed; @@ -424,8 +424,8 @@ namespace Opm ws.open(); scaleSegmentRatesAndPressure(well_state_copy); - calculateExplicitQuantities(simulator, well_state_copy, deferred_logger); - updatePrimaryVariables(simulator, well_state_copy, deferred_logger); + calculateExplicitQuantities(simulator, groupStateHelper_copy, deferred_logger); + updatePrimaryVariables(groupStateHelper_copy, deferred_logger); if (this->isProducer()) { const auto& schedule = simulator.vanguard().schedule(); @@ -476,7 +476,7 @@ namespace Opm for (int p = 0; p < np; ++p) { ws.well_potentials[p] = std::max(Scalar{0.0}, potentials[p]); } - const bool under_zero_target = this->wellUnderZeroGroupRateTarget(simulator, well_state_copy, deferred_logger); + const bool under_zero_target = this->wellUnderZeroGroupRateTarget(groupStateHelper_copy, deferred_logger); this->updateWellTestState(well_state_copy.well(this->indexOfWell()), simulation_time, /*writeMessageToOPMLog=*/ false, @@ -633,7 +633,7 @@ namespace Opm const bool isThp = ws.production_cmode == Well::ProducerCMode::THP; // check stability of solution under thp-control - if (converged && !stoppedOrZeroRateTarget(simulator, well_state, deferred_logger) && isThp) { + if (converged && !stoppedOrZeroRateTarget(groupStateHelper, deferred_logger) && isThp) { auto rates = well_state.well(this->index_of_well_).surface_rates; this->adaptRatesForVFP(rates); this->updateIPRImplicit(simulator, groupStateHelper, well_state, deferred_logger); @@ -1030,7 +1030,7 @@ namespace Opm ); if (converged) { - const bool zero_target = this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger); + const bool zero_target = this->wellUnderZeroRateTarget(groupStateHelper, deferred_logger); if (this->wellIsStopped() && !zero_target && nonzero_rate_original) { // Well had non-zero rate, but was stopped during local well-solve. We re-open the well // for the next global iteration, but if the zero rate persists, it will be stopped. @@ -1306,7 +1306,6 @@ namespace Opm DeferredLogger& deferred_logger) const { OPM_TIMEFUNCTION(); - const auto& group_state = groupStateHelper.groupState(); // only bhp and wellRates are used to initilize the primaryvariables for standard wells const auto& well = this->well_ecl_; const int well_index = this->index_of_well_; @@ -1426,10 +1425,7 @@ namespace Opm well_state[well.name()].efficiency_scaling_factor; std::optional target = this->getGroupInjectionTargetRate(group, - well_state, - group_state, - schedule, - summaryState, + groupStateHelper, injectorType, efficiencyFactor, deferred_logger); @@ -1658,10 +1654,7 @@ namespace Opm const Scalar efficiencyFactor = well.getEfficiencyFactor() * well_state[well.name()].efficiency_scaling_factor; Scalar scale = this->getGroupProductionTargetRate(group, - well_state, - group_state, - schedule, - summaryState, + groupStateHelper, efficiencyFactor, deferred_logger); @@ -1695,36 +1688,32 @@ namespace Opm template bool WellInterface:: - wellUnderZeroRateTarget(const Simulator& simulator, - const WellStateType& well_state, - DeferredLogger& deferred_logger) const + wellUnderZeroRateTarget(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) const { OPM_TIMEFUNCTION(); + const auto& well_state = groupStateHelper.wellState(); // Check if well is under zero rate control, either directly or from group const bool isGroupControlled = this->wellUnderGroupControl(well_state.well(this->index_of_well_)); if (!isGroupControlled) { // well is not under group control, check "individual" version - const auto& summaryState = simulator.vanguard().summaryState(); + const auto& summaryState = groupStateHelper.summaryState(); return this->wellUnderZeroRateTargetIndividual(summaryState, well_state); } else { - return this->wellUnderZeroGroupRateTarget(simulator, well_state, deferred_logger, isGroupControlled); + return this->wellUnderZeroGroupRateTarget(groupStateHelper, deferred_logger, isGroupControlled); } } template bool - WellInterface::wellUnderZeroGroupRateTarget(const Simulator& simulator, - const WellStateType& well_state, + WellInterface::wellUnderZeroGroupRateTarget(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger, const std::optional group_control) const { + const auto& well_state = groupStateHelper.wellState(); // Check if well is under zero rate target from group const bool isGroupControlled = group_control.value_or(this->wellUnderGroupControl(well_state.well(this->index_of_well_))); if (isGroupControlled) { - const auto& summaryState = simulator.vanguard().summaryState(); - const auto& group_state = simulator.problem().wellModel().groupState(); - const auto& schedule = simulator.vanguard().schedule(); - return this->zeroGroupRateTarget(summaryState, schedule, well_state, group_state, deferred_logger); + return this->zeroGroupRateTarget(groupStateHelper, deferred_logger); } return false; } @@ -1732,14 +1721,13 @@ namespace Opm template bool WellInterface:: - stoppedOrZeroRateTarget(const Simulator& simulator, - const WellStateType& well_state, + stoppedOrZeroRateTarget(const GroupStateHelperType& groupStateHelper, DeferredLogger& deferred_logger) const { // Check if well is stopped or under zero rate control, either // directly or from group. return this->wellIsStopped() - || this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger); + || this->wellUnderZeroRateTarget(groupStateHelper, deferred_logger); } template