mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #5754 from plgbrts/ac-group-guide-rates
Allow group guide rates in case that a group is an auto choke group
This commit is contained in:
@@ -464,8 +464,9 @@ template<class Scalar> class WellContributions;
|
||||
bool updateWellControlsAndNetwork(const bool mandatory_network_balance,
|
||||
const double dt,
|
||||
DeferredLogger& local_deferredLogger);
|
||||
|
||||
void computeWellGroupThp(const double dt, DeferredLogger& local_deferredLogger);
|
||||
|
||||
double computeWellGroupTarget(DeferredLogger& local_deferredLogger);
|
||||
bool computeWellGroupThp(const double dt, DeferredLogger& local_deferredLogger);
|
||||
|
||||
/// Update rank's notion of intersecting wells and their
|
||||
/// associate solution variables.
|
||||
|
||||
@@ -1312,6 +1312,7 @@ updateAndCommunicateGroupData(const int reportStepIdx,
|
||||
phase_usage_,
|
||||
guideRate_,
|
||||
well_state,
|
||||
summaryState_,
|
||||
this->groupState(),
|
||||
groupTargetReduction);
|
||||
std::vector<Scalar> groupTargetReductionInj(numPhases(), 0.0);
|
||||
@@ -1322,6 +1323,7 @@ updateAndCommunicateGroupData(const int reportStepIdx,
|
||||
phase_usage_,
|
||||
guideRate_,
|
||||
well_state,
|
||||
summaryState_,
|
||||
this->groupState(),
|
||||
groupTargetReductionInj);
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
#include <opm/simulators/wells/ParallelWBPCalculation.hpp>
|
||||
#include <opm/simulators/wells/VFPProperties.hpp>
|
||||
#include <opm/simulators/wells/WellBhpThpCalculator.hpp>
|
||||
#include <opm/simulators/wells/WellGroupControls.hpp>
|
||||
#include <opm/simulators/wells/WellGroupHelpers.hpp>
|
||||
#include <opm/simulators/wells/TargetCalculator.hpp>
|
||||
|
||||
@@ -1378,7 +1379,7 @@ namespace Opm {
|
||||
// The wells of such group should have a common THP and total phase rate(s) obeying (if possible)
|
||||
// the well group constraint set by GCONPROD
|
||||
template <typename TypeTag>
|
||||
void
|
||||
bool
|
||||
BlackoilWellModel<TypeTag>::
|
||||
computeWellGroupThp(const double dt, DeferredLogger& local_deferredLogger)
|
||||
{
|
||||
@@ -1388,19 +1389,19 @@ namespace Opm {
|
||||
const Scalar thp_tolerance = balance.thp_tolerance();
|
||||
|
||||
if (!network.active()) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto& well_state = this->wellState();
|
||||
auto& group_state = this->groupState();
|
||||
|
||||
bool well_group_thp_updated = false;
|
||||
for (const std::string& nodeName : network.node_names()) {
|
||||
const bool has_choke = network.node(nodeName).as_choke();
|
||||
if (has_choke) {
|
||||
const auto& summary_state = this->simulator_.vanguard().summaryState();
|
||||
const Group& group = this->schedule().getGroup(nodeName, reportStepIdx);
|
||||
const auto ctrl = group.productionControls(summary_state);
|
||||
const auto cmode = ctrl.cmode;
|
||||
|
||||
const auto pu = this->phase_usage_;
|
||||
//TODO: Auto choke combined with RESV control is not supported
|
||||
std::vector<Scalar> resv_coeff(pu.num_phases, 1.0);
|
||||
@@ -1408,10 +1409,43 @@ namespace Opm {
|
||||
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;
|
||||
Scalar target_tmp{0.0};
|
||||
bool fld_none = false;
|
||||
if (cmode_tmp == Group::ProductionCMode::FLD || cmode_tmp == Group::ProductionCMode::NONE) {
|
||||
fld_none = true;
|
||||
// Target is set for an ancestor group. Target for autochoke group to be
|
||||
// derived via group guide rates
|
||||
const Scalar efficiencyFactor = 1.0;
|
||||
const Group& parentGroup = this->schedule().getGroup(group.parent(), reportStepIdx);
|
||||
auto target = WellGroupControls<Scalar>::getAutoChokeGroupProductionTargetRate(
|
||||
group.name(),
|
||||
parentGroup,
|
||||
well_state,
|
||||
group_state,
|
||||
this->schedule(),
|
||||
summary_state,
|
||||
resv_coeff,
|
||||
efficiencyFactor,
|
||||
reportStepIdx,
|
||||
pu,
|
||||
&this->guideRate_,
|
||||
local_deferredLogger);
|
||||
target_tmp = target.first;
|
||||
cmode_tmp = target.second;
|
||||
}
|
||||
const auto cmode = cmode_tmp;
|
||||
WGHelpers::TargetCalculator tcalc(cmode, pu, resv_coeff,
|
||||
gratTargetFromSales, nodeName, group_state,
|
||||
group.has_gpmaint_control(cmode));
|
||||
const Scalar orig_target = tcalc.groupTarget(ctrl, local_deferredLogger);
|
||||
if (!fld_none)
|
||||
{
|
||||
// Target is set for the autochoke group itself
|
||||
target_tmp = tcalc.groupTarget(ctrl, local_deferredLogger);
|
||||
}
|
||||
|
||||
const Scalar orig_target = target_tmp;
|
||||
|
||||
auto mismatch = [&] (auto group_thp) {
|
||||
Scalar group_rate(0.0);
|
||||
@@ -1507,9 +1541,14 @@ namespace Opm {
|
||||
}
|
||||
|
||||
// Use the group THP in computeNetworkPressures().
|
||||
group_state.update_well_group_thp(nodeName, well_group_thp);
|
||||
const auto& current_well_group_thp = group_state.is_autochoke_group(nodeName) ? group_state.well_group_thp(nodeName) : 1e30;
|
||||
if (std::abs(current_well_group_thp - well_group_thp) > balance.pressure_tolerance()) {
|
||||
well_group_thp_updated = true;
|
||||
group_state.update_well_group_thp(nodeName, well_group_thp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return well_group_thp_updated;
|
||||
}
|
||||
|
||||
template<typename TypeTag>
|
||||
@@ -2267,19 +2306,21 @@ namespace Opm {
|
||||
if (this->shouldBalanceNetwork(episodeIdx, iterationIdx) || mandatory_network_balance) {
|
||||
const double dt = this->simulator_.timeStepSize();
|
||||
// Calculate common THP for subsea manifold well group (item 3 of NODEPROP set to YES)
|
||||
computeWellGroupThp(dt, deferred_logger);
|
||||
bool well_group_thp_updated = computeWellGroupThp(dt, deferred_logger);
|
||||
constexpr int max_number_of_sub_iterations = 20;
|
||||
constexpr Scalar damping_factor = 0.1;
|
||||
bool more_network_sub_update = false;
|
||||
for (int i = 0; i < max_number_of_sub_iterations; i++) {
|
||||
const auto local_network_imbalance = this->updateNetworkPressures(episodeIdx, damping_factor);
|
||||
const Scalar network_imbalance = comm.max(local_network_imbalance);
|
||||
const auto& balance = this->schedule()[episodeIdx].network_balance();
|
||||
constexpr Scalar relaxation_factor = 10.0;
|
||||
const Scalar tolerance = relax_network_tolerance ? relaxation_factor * balance.pressure_tolerance() : balance.pressure_tolerance();
|
||||
more_network_update = this->networkActive() && network_imbalance > tolerance;
|
||||
if (!more_network_update)
|
||||
more_network_sub_update = this->networkActive() && network_imbalance > tolerance;
|
||||
if (!more_network_sub_update)
|
||||
break;
|
||||
}
|
||||
more_network_update = more_network_sub_update || well_group_thp_updated;
|
||||
}
|
||||
|
||||
bool changed_well_group = false;
|
||||
|
||||
@@ -37,6 +37,7 @@ FractionCalculator<Scalar>::
|
||||
FractionCalculator(const Schedule& schedule,
|
||||
const WellState<Scalar>& well_state,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const SummaryState& summary_state,
|
||||
const int report_step,
|
||||
const GuideRate* guide_rate,
|
||||
const GuideRateModel::Target target,
|
||||
@@ -46,6 +47,7 @@ FractionCalculator(const Schedule& schedule,
|
||||
: schedule_(schedule)
|
||||
, well_state_(well_state)
|
||||
, group_state_(group_state)
|
||||
, summary_state_(summary_state)
|
||||
, report_step_(report_step)
|
||||
, guide_rate_(guide_rate)
|
||||
, target_(target)
|
||||
@@ -123,6 +125,7 @@ guideRateSum(const Group& group,
|
||||
total_guide_rate += guideRate(child_group, always_included_child);
|
||||
}
|
||||
}
|
||||
|
||||
for (const std::string& child_well : group.wells()) {
|
||||
bool included = (child_well == always_included_child);
|
||||
if (is_producer_) {
|
||||
@@ -174,6 +177,8 @@ groupControlledWells(const std::string& group_name,
|
||||
return WellGroupHelpers<Scalar>::groupControlledWells(schedule_,
|
||||
well_state_,
|
||||
this->group_state_,
|
||||
this->summary_state_,
|
||||
this->guide_rate_,
|
||||
report_step_,
|
||||
group_name,
|
||||
always_included_child,
|
||||
|
||||
@@ -41,6 +41,7 @@ public:
|
||||
FractionCalculator(const Schedule& schedule,
|
||||
const WellState<Scalar>& well_state,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const SummaryState& summary_state,
|
||||
const int report_step,
|
||||
const GuideRate* guide_rate,
|
||||
const GuideRateModel::Target target,
|
||||
@@ -65,6 +66,7 @@ private:
|
||||
const Schedule& schedule_;
|
||||
const WellState<Scalar>& well_state_;
|
||||
const GroupState<Scalar>& group_state_;
|
||||
const SummaryState& summary_state_;
|
||||
int report_step_;
|
||||
const GuideRate* guide_rate_;
|
||||
GuideRateModel::Target target_;
|
||||
|
||||
@@ -124,6 +124,13 @@ GroupState::well_group_thp(const std::string& gname) const
|
||||
return group_iter->second;
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
bool GroupState<Scalar>::
|
||||
GroupState::is_autochoke_group(const std::string& gname) const
|
||||
{
|
||||
return (this->group_thp.count(gname) > 0);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<class Scalar>
|
||||
|
||||
@@ -56,6 +56,7 @@ public:
|
||||
|
||||
void update_well_group_thp(const std::string& gname, const double& thp);
|
||||
Scalar well_group_thp(const std::string& gname) const;
|
||||
bool is_autochoke_group(const std::string& gname) const;
|
||||
|
||||
bool has_production_reduction_rates(const std::string& gname) const;
|
||||
void update_production_reduction_rates(const std::string& gname,
|
||||
|
||||
@@ -1051,7 +1051,7 @@ bruteForceBracketCommonTHP(const std::function<Scalar(const Scalar)>& eq,
|
||||
Scalar& min_thp, Scalar& max_thp)
|
||||
{
|
||||
bool bracket_found = false;
|
||||
constexpr int sample_number = 1000;
|
||||
constexpr int sample_number = 1000;
|
||||
constexpr Scalar interval = 1E5;
|
||||
Scalar eq_low = eq(min_thp);
|
||||
Scalar eq_high = 0.0;
|
||||
|
||||
@@ -151,6 +151,7 @@ getGroupInjectionControl(const Group& group,
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
well_state,
|
||||
group_state,
|
||||
summaryState,
|
||||
well_.currentStep(),
|
||||
well_.guideRate(),
|
||||
tcalc.guideTargetMode(),
|
||||
@@ -284,6 +285,7 @@ getGroupInjectionTargetRate(const Group& group,
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
well_state,
|
||||
group_state,
|
||||
summaryState,
|
||||
well_.currentStep(),
|
||||
well_.guideRate(),
|
||||
tcalc.guideTargetMode(),
|
||||
@@ -401,6 +403,7 @@ getGroupProductionControl(const Group& group,
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
well_state,
|
||||
group_state,
|
||||
summaryState,
|
||||
well_.currentStep(),
|
||||
well_.guideRate(),
|
||||
tcalc.guideTargetMode(),
|
||||
@@ -499,6 +502,7 @@ getGroupProductionTargetRate(const Group& group,
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
well_state,
|
||||
group_state,
|
||||
summaryState,
|
||||
well_.currentStep(),
|
||||
well_.guideRate(),
|
||||
tcalc.guideTargetMode(),
|
||||
@@ -549,6 +553,107 @@ getGroupProductionTargetRate(const Group& group,
|
||||
return scale;
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
std::pair<Scalar, Group::ProductionCMode> WellGroupControls<Scalar>::
|
||||
getAutoChokeGroupProductionTargetRate(const std::string& name,
|
||||
const Group& group,
|
||||
const WellState<Scalar>& well_state,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const Schedule& schedule,
|
||||
const SummaryState& summaryState,
|
||||
const std::vector<Scalar>& resv_coeff,
|
||||
Scalar efficiencyFactor,
|
||||
const int reportStepIdx,
|
||||
const PhaseUsage& pu,
|
||||
const GuideRate* guideRate,
|
||||
DeferredLogger& deferred_logger)
|
||||
{
|
||||
const Group::ProductionCMode& currentGroupControl = group_state.production_control(group.name());
|
||||
if (currentGroupControl == Group::ProductionCMode::FLD ||
|
||||
currentGroupControl == Group::ProductionCMode::NONE) {
|
||||
if (!group.productionGroupControlAvailable()) {
|
||||
return std::make_pair(1.0, currentGroupControl);
|
||||
} else {
|
||||
// Produce share of parents control
|
||||
const auto& parent = schedule.getGroup(group.parent(), reportStepIdx);
|
||||
efficiencyFactor *= group.getGroupEfficiencyFactor();
|
||||
return getAutoChokeGroupProductionTargetRate(name, parent, well_state, group_state,
|
||||
schedule, summaryState,
|
||||
resv_coeff, efficiencyFactor, reportStepIdx, pu,
|
||||
guideRate, deferred_logger);
|
||||
}
|
||||
}
|
||||
|
||||
if (!group.isProductionGroup()) {
|
||||
return std::make_pair(1.0, currentGroupControl);
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
||||
// Make conversion factors for RESV <-> surface rates.
|
||||
// std::vector<double> 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 (group_state.has_grat_sales_target(group.name()))
|
||||
gratTargetFromSales = group_state.grat_sales_target(group.name());
|
||||
|
||||
WGHelpers::TargetCalculator tcalc(currentGroupControl,
|
||||
pu,
|
||||
resv_coeff,
|
||||
gratTargetFromSales,
|
||||
group.name(),
|
||||
group_state,
|
||||
group.has_gpmaint_control(currentGroupControl));
|
||||
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
well_state,
|
||||
group_state,
|
||||
summaryState,
|
||||
reportStepIdx,
|
||||
guideRate,
|
||||
tcalc.guideTargetMode(),
|
||||
pu,
|
||||
true,
|
||||
Phase::OIL);
|
||||
|
||||
auto localFraction = [&](const std::string& child) {
|
||||
return fcalc.localFraction(child, child); //Note child needs to be passed to always include since the global isGrup map is not updated yet.
|
||||
};
|
||||
|
||||
auto localReduction = [&](const std::string& group_name) {
|
||||
const std::vector<Scalar>& groupTargetReductions = group_state.production_reduction_rates(group_name);
|
||||
return tcalc.calcModeRateFromRates(groupTargetReductions);
|
||||
};
|
||||
|
||||
std::optional<Group::ProductionControls> ctrl;
|
||||
if (!group.has_gpmaint_control(currentGroupControl))
|
||||
ctrl = group.productionControls(summaryState);
|
||||
|
||||
const double orig_target = tcalc.groupTarget(ctrl, deferred_logger);
|
||||
const auto chain = WellGroupHelpers<Scalar>::groupChainTopBot(name, group.name(),
|
||||
schedule, reportStepIdx);
|
||||
// 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;
|
||||
double target = orig_target;
|
||||
for (std::size_t ii = 0; ii < num_ancestors; ++ii) {
|
||||
if ((ii == 0) || guideRate->has(chain[ii])) {
|
||||
// Apply local reductions only at the control level
|
||||
// (top) and for levels where we have a specified
|
||||
// group guide rate.
|
||||
target -= localReduction(chain[ii]);
|
||||
}
|
||||
target *= localFraction(chain[ii+1]);
|
||||
}
|
||||
// Avoid negative target rates coming from too large local reductions.
|
||||
const double target_rate = std::max(0.0, target / efficiencyFactor);
|
||||
|
||||
return std::make_pair(target_rate, currentGroupControl);
|
||||
}
|
||||
|
||||
#define INSTANTIATE(T,...) \
|
||||
template void WellGroupControls<T>:: \
|
||||
getGroupInjectionControl(const Group&, \
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#ifndef OPM_WELL_GROUP_CONTROLS_HEADER_INCLUDED
|
||||
#define OPM_WELL_GROUP_CONTROLS_HEADER_INCLUDED
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Group/GuideRate.hpp>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
@@ -37,6 +38,7 @@ class Group;
|
||||
template<class Scalar> class GroupState;
|
||||
enum class InjectorType;
|
||||
using RegionId = int;
|
||||
struct PhaseUsage;
|
||||
class Schedule;
|
||||
class SummaryState;
|
||||
template<class Scalar> class WellInterfaceGeneric;
|
||||
@@ -99,6 +101,19 @@ public:
|
||||
Scalar efficiencyFactor,
|
||||
DeferredLogger& deferred_logger) const;
|
||||
|
||||
static std::pair<Scalar, Group::ProductionCMode> getAutoChokeGroupProductionTargetRate(const std::string& name,
|
||||
const Group& parent,
|
||||
const WellState<Scalar>& well_state,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const Schedule& schedule,
|
||||
const SummaryState& summaryState,
|
||||
const std::vector<Scalar>& resv_coeff,
|
||||
Scalar efficiencyFactor,
|
||||
const int reportStepIdx,
|
||||
const PhaseUsage& pu,
|
||||
const GuideRate* guideRate,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
private:
|
||||
const WellInterfaceGeneric<Scalar>& well_; //!< Reference to well interface
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <opm/input/eclipse/Schedule/Group/GConSale.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/GPMaint.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/Group.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Group/GuideRateConfig.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||
|
||||
@@ -35,6 +36,7 @@
|
||||
#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
|
||||
#include <opm/simulators/utils/ParallelCommunication.hpp>
|
||||
|
||||
#include <opm/simulators/wells/BlackoilWellModelConstraints.hpp>
|
||||
#include <opm/simulators/wells/FractionCalculator.hpp>
|
||||
#include <opm/simulators/wells/GroupState.hpp>
|
||||
#include <opm/simulators/wells/RegionAverageCalculator.hpp>
|
||||
@@ -347,6 +349,7 @@ updateGroupTargetReduction(const Group& group,
|
||||
const PhaseUsage& pu,
|
||||
const GuideRate& guide_rate,
|
||||
const WellState<Scalar>& wellState,
|
||||
const SummaryState& summaryState,
|
||||
GroupState<Scalar>& group_state,
|
||||
std::vector<Scalar>& groupTargetReduction)
|
||||
{
|
||||
@@ -361,6 +364,7 @@ updateGroupTargetReduction(const Group& group,
|
||||
pu,
|
||||
guide_rate,
|
||||
wellState,
|
||||
summaryState,
|
||||
group_state,
|
||||
subGroupTargetReduction);
|
||||
|
||||
@@ -402,7 +406,7 @@ updateGroupTargetReduction(const Group& group,
|
||||
const bool individual_control = (currentGroupControl != Group::InjectionCMode::FLD
|
||||
&& currentGroupControl != Group::InjectionCMode::NONE);
|
||||
const int num_group_controlled_wells
|
||||
= groupControlledWells(schedule, wellState, group_state, reportStepIdx, subGroupName, "", !isInjector, phase);
|
||||
= groupControlledWells(schedule, wellState, group_state, summaryState, &guide_rate, reportStepIdx, subGroupName, "", !isInjector, phase);
|
||||
if (individual_control || num_group_controlled_wells == 0) {
|
||||
groupTargetReduction[phase_pos]
|
||||
+= subGroupEfficiency * sumWellSurfaceRates(subGroup, schedule, wellState, reportStepIdx, phase_pos, isInjector);
|
||||
@@ -418,7 +422,7 @@ updateGroupTargetReduction(const Group& group,
|
||||
const bool individual_control = (currentGroupControl != Group::ProductionCMode::FLD
|
||||
&& currentGroupControl != Group::ProductionCMode::NONE);
|
||||
const int num_group_controlled_wells
|
||||
= groupControlledWells(schedule, wellState, group_state, reportStepIdx, subGroupName, "", !isInjector, /*injectionPhaseNotUsed*/Phase::OIL);
|
||||
= groupControlledWells(schedule, wellState, group_state, summaryState, &guide_rate, reportStepIdx, subGroupName, "", !isInjector, /*injectionPhaseNotUsed*/Phase::OIL);
|
||||
if (individual_control || num_group_controlled_wells == 0) {
|
||||
for (int phase = 0; phase < np; phase++) {
|
||||
groupTargetReduction[phase]
|
||||
@@ -468,10 +472,13 @@ updateGroupTargetReduction(const Group& group,
|
||||
groupTargetReduction[phase] += ws.surface_rates[phase] * efficiency;
|
||||
}
|
||||
} else {
|
||||
if (ws.production_cmode != Well::ProducerCMode::GRUP)
|
||||
for (int phase = 0; phase < np; phase++) {
|
||||
groupTargetReduction[phase] -= ws.surface_rates[phase] * efficiency;
|
||||
if ((ws.production_cmode != Well::ProducerCMode::GRUP)){
|
||||
if (!group.as_choke()) {
|
||||
for (int phase = 0; phase < np; phase++) {
|
||||
groupTargetReduction[phase] -= ws.surface_rates[phase] * efficiency;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isInjector)
|
||||
@@ -1091,6 +1098,8 @@ int WellGroupHelpers<Scalar>::
|
||||
groupControlledWells(const Schedule& schedule,
|
||||
const WellState<Scalar>& well_state,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const SummaryState& summary_state,
|
||||
const GuideRate* guideRate,
|
||||
const int report_step,
|
||||
const std::string& group_name,
|
||||
const std::string& always_included_child,
|
||||
@@ -1112,16 +1121,81 @@ groupControlledWells(const Schedule& schedule,
|
||||
|
||||
if (included) {
|
||||
num_wells
|
||||
+= groupControlledWells(schedule, well_state, group_state, report_step, child_group, always_included_child, is_production_group, injection_phase);
|
||||
+= groupControlledWells(schedule, well_state, group_state, summary_state, guideRate, report_step, child_group, always_included_child, is_production_group, injection_phase);
|
||||
}
|
||||
}
|
||||
for (const std::string& child_well : group.wells()) {
|
||||
bool included = (child_well == always_included_child);
|
||||
if (is_production_group) {
|
||||
included = included || well_state.isProductionGrup(child_well);
|
||||
included = included || well_state.isProductionGrup(child_well) || group.as_choke();
|
||||
} else {
|
||||
included = included || well_state.isInjectionGrup(child_well);
|
||||
}
|
||||
const auto ctrl1 = group_state.production_control(group.name());
|
||||
if (group.as_choke() && ((ctrl1 == Group::ProductionCMode::FLD) || (ctrl1 == Group::ProductionCMode::NONE))){
|
||||
// The auto choke group has not own group control but inherits control from an ancestor group.
|
||||
// Number of wells should be calculated as zero when wells of auto choke group do not deliver target.
|
||||
// This behaviour is then similar to no-autochoke group with wells not on GRUP control.
|
||||
// The rates of these wells are summed up. The parent group target is reduced with this rate.
|
||||
// This reduced target becomes the target of the other child group of this parent.
|
||||
const PhaseUsage& pu = well_state.phaseUsage();
|
||||
std::vector<Scalar> rates(pu.num_phases, 0.0);
|
||||
for (int phase_pos = 0; phase_pos < pu.num_phases; ++phase_pos) {
|
||||
rates[phase_pos] = WellGroupHelpers<Scalar>::sumWellSurfaceRates(group,
|
||||
schedule,
|
||||
well_state,
|
||||
report_step,
|
||||
phase_pos,
|
||||
false);
|
||||
}
|
||||
|
||||
// Get the ancestor of the auto choke group that has group control (cmode != FLD, NONE)
|
||||
const auto& control_group_name = control_group(group, group_state, report_step, schedule);
|
||||
const auto& control_group = schedule.getGroup(control_group_name, report_step);
|
||||
const auto& ctrl = control_group.productionControls(summary_state);
|
||||
const auto& control_group_cmode = ctrl.cmode;
|
||||
|
||||
const auto& group_guide_rate = group.productionControls(summary_state).guide_rate;
|
||||
|
||||
if (group_guide_rate > 0) {
|
||||
// Guide rate is not default for the auto choke group
|
||||
Scalar gratTargetFromSales = 0.0;
|
||||
if (group_state.has_grat_sales_target(control_group_name))
|
||||
gratTargetFromSales = group_state.grat_sales_target(control_group_name);
|
||||
|
||||
std::vector<Scalar> resv_coeff(pu.num_phases, 1.0);
|
||||
WGHelpers::TargetCalculator tcalc(control_group_cmode,
|
||||
pu,
|
||||
resv_coeff,
|
||||
gratTargetFromSales,
|
||||
group.name(),
|
||||
group_state,
|
||||
group.has_gpmaint_control(control_group_cmode));
|
||||
auto deferred_logger = Opm::DeferredLogger();
|
||||
const auto& control_group_target = tcalc.groupTarget(ctrl, 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 derived from the children groups
|
||||
const auto& control_group_guide_rate = getGuideRate(control_group_name,
|
||||
schedule,
|
||||
well_state,
|
||||
group_state,
|
||||
report_step,
|
||||
guideRate,
|
||||
tcalc.guideTargetMode(),
|
||||
pu);
|
||||
|
||||
if (control_group_guide_rate > 0) {
|
||||
// Target rate for the auto choke group
|
||||
const Scalar target_rate = control_group_target * group_guide_rate / control_group_guide_rate;
|
||||
const Scalar current_rate = tcalc.calcModeRateFromRates(rates);
|
||||
|
||||
if (current_rate < target_rate)
|
||||
included = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (included) {
|
||||
++num_wells;
|
||||
}
|
||||
@@ -1160,6 +1234,27 @@ groupChainTopBot(const std::string& bottom,
|
||||
return chain;
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
std::string
|
||||
WellGroupHelpers<Scalar>::
|
||||
control_group(const Group& group,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const int reportStepIdx,
|
||||
const Schedule& schedule)
|
||||
{
|
||||
const Group::ProductionCMode& currentGroupControl = group_state.production_control(group.name());
|
||||
|
||||
if (currentGroupControl == Group::ProductionCMode::FLD || currentGroupControl == Group::ProductionCMode::NONE) {
|
||||
const auto& parent = schedule.getGroup(group.parent(), reportStepIdx);
|
||||
return control_group(parent,
|
||||
group_state,
|
||||
reportStepIdx,
|
||||
schedule);
|
||||
}
|
||||
|
||||
return group.name();
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
std::pair<bool, Scalar>
|
||||
WellGroupHelpers<Scalar>::
|
||||
@@ -1239,6 +1334,7 @@ checkGroupConstraintsProd(const std::string& name,
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
wellState,
|
||||
group_state,
|
||||
summaryState,
|
||||
reportStepIdx,
|
||||
guideRate,
|
||||
tcalc.guideTargetMode(),
|
||||
@@ -1281,6 +1377,8 @@ checkGroupConstraintsProd(const std::string& name,
|
||||
const int num_gr_ctrl = groupControlledWells(schedule,
|
||||
wellState,
|
||||
group_state,
|
||||
summaryState,
|
||||
guideRate,
|
||||
reportStepIdx,
|
||||
chain[ii],
|
||||
"",
|
||||
@@ -1414,6 +1512,7 @@ checkGroupConstraintsInj(const std::string& name,
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
wellState,
|
||||
group_state,
|
||||
summaryState,
|
||||
reportStepIdx,
|
||||
guideRate,
|
||||
tcalc.guideTargetMode(),
|
||||
@@ -1456,12 +1555,14 @@ checkGroupConstraintsInj(const std::string& name,
|
||||
for (std::size_t ii = 1; ii < num_ancestors; ++ii) {
|
||||
const int num_gr_ctrl = groupControlledWells(schedule,
|
||||
wellState,
|
||||
group_state,
|
||||
reportStepIdx,
|
||||
chain[ii],
|
||||
"",
|
||||
/*is_producer*/ false,
|
||||
injectionPhase);
|
||||
group_state,
|
||||
summaryState,
|
||||
guideRate,
|
||||
reportStepIdx,
|
||||
chain[ii],
|
||||
"",
|
||||
/*is_producer*/ false,
|
||||
injectionPhase);
|
||||
if (guideRate->has(chain[ii], injectionPhase) && num_gr_ctrl > 0) {
|
||||
local_reduction_level = ii;
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ public:
|
||||
const PhaseUsage& pu,
|
||||
const GuideRate& guide_rate,
|
||||
const WellState<Scalar>& wellState,
|
||||
const SummaryState& summaryState,
|
||||
GroupState<Scalar>& group_state,
|
||||
std::vector<Scalar>& groupTargetReduction);
|
||||
|
||||
@@ -247,6 +248,8 @@ public:
|
||||
static int groupControlledWells(const Schedule& schedule,
|
||||
const WellState<Scalar>& well_state,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const SummaryState& summary_state,
|
||||
const GuideRate* guideRate,
|
||||
const int report_step,
|
||||
const std::string& group_name,
|
||||
const std::string& always_included_child,
|
||||
@@ -276,6 +279,12 @@ public:
|
||||
const Schedule& schedule,
|
||||
const int report_step);
|
||||
|
||||
static std::string
|
||||
control_group(const Group& group,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const int reportStepIdx,
|
||||
const Schedule& schedule);
|
||||
|
||||
static std::pair<bool, Scalar>
|
||||
checkGroupConstraintsProd(const std::string& name,
|
||||
const std::string& parent,
|
||||
|
||||
@@ -518,6 +518,13 @@ WellInterfaceGeneric<Scalar>::getDynamicThpLimit() const
|
||||
return dynamic_thp_limit_;
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
void WellInterfaceGeneric<Scalar>::
|
||||
setDynamicThpLimit(const std::optional<Scalar> thp_limit)
|
||||
{
|
||||
dynamic_thp_limit_ = thp_limit;
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
void WellInterfaceGeneric<Scalar>::
|
||||
updatePerforatedCell(std::vector<bool>& is_cell_perforated)
|
||||
|
||||
Reference in New Issue
Block a user