mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
add group target calculation
added temporary output mainly rebasing rebasing some further attempts fixed target calculations remove some case specific choices clean up some clean up generalised code for calculating target rate in groupControlledWells small rebase fix <double> replaced by <Scalar> <double> replaced by <Scalar> (2)
This commit is contained in:
parent
6b2c372f11
commit
9d735b8d6e
@ -479,7 +479,8 @@ template<class Scalar> class WellContributions;
|
||||
bool updateWellControlsAndNetwork(const bool mandatory_network_balance,
|
||||
const double dt,
|
||||
DeferredLogger& local_deferredLogger);
|
||||
|
||||
|
||||
double computeWellGroupTarget(DeferredLogger& local_deferredLogger);
|
||||
void computeWellGroupThp(const double dt, DeferredLogger& local_deferredLogger);
|
||||
|
||||
/// Update rank's notion of intersecting wells and their
|
||||
|
@ -1313,6 +1313,7 @@ updateAndCommunicateGroupData(const int reportStepIdx,
|
||||
phase_usage_,
|
||||
guideRate_,
|
||||
well_state,
|
||||
summaryState_,
|
||||
this->groupState(),
|
||||
groupTargetReduction);
|
||||
std::vector<Scalar> groupTargetReductionInj(numPhases(), 0.0);
|
||||
@ -1323,6 +1324,7 @@ updateAndCommunicateGroupData(const int reportStepIdx,
|
||||
phase_usage_,
|
||||
guideRate_,
|
||||
well_state,
|
||||
summaryState_,
|
||||
this->groupState(),
|
||||
groupTargetReductionInj);
|
||||
|
||||
|
@ -42,12 +42,11 @@
|
||||
#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>
|
||||
|
||||
#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
|
||||
#include <opm/simulators/wells/WellGroupHelpers.hpp>
|
||||
#include <opm/simulators/wells/TargetCalculator.hpp>
|
||||
#include <opm/simulators/utils/MPIPacker.hpp>
|
||||
#include <opm/simulators/utils/phaseUsageFromDeck.hpp>
|
||||
|
||||
@ -55,7 +54,6 @@
|
||||
#include <opm/simulators/linalg/gpubridge/WellContributions.hpp>
|
||||
#endif
|
||||
|
||||
|
||||
#if HAVE_MPI
|
||||
#include <opm/simulators/utils/MPISerializer.hpp>
|
||||
#endif
|
||||
@ -1329,7 +1327,6 @@ namespace Opm {
|
||||
const auto& balance = this->schedule()[reportStepIdx].network_balance();
|
||||
const Scalar thp_tolerance = balance.thp_tolerance();
|
||||
|
||||
|
||||
if (!network.active()) {
|
||||
return;
|
||||
}
|
||||
@ -1342,20 +1339,51 @@ namespace Opm {
|
||||
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_;
|
||||
|
||||
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);
|
||||
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;
|
||||
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 from 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_tmp = tcalc.groupTarget(ctrl, local_deferredLogger);
|
||||
}
|
||||
|
||||
const Scalar orig_target = target_tmp;
|
||||
std::cout<< "Group: " << group.name() << " orig_target: " << orig_target*86400 << std::endl;
|
||||
|
||||
auto mismatch = [&] (auto group_thp) {
|
||||
Scalar group_rate(0.0);
|
||||
@ -1376,31 +1404,6 @@ namespace Opm {
|
||||
return (group_rate - orig_target)/orig_target;
|
||||
};
|
||||
|
||||
double min_thp, max_thp;
|
||||
std::array<double, 2> range_initial;
|
||||
//Find an initial bracket
|
||||
if (!this->well_group_thp_calc_.has_value()){
|
||||
// Retrieve the terminal pressure of the associated root of the manifold group
|
||||
std::string node_name = nodeName;
|
||||
while (!network.node(node_name).terminal_pressure().has_value()) {
|
||||
auto branch = network.uptree_branch(node_name).value();
|
||||
node_name = branch.uptree_node();
|
||||
}
|
||||
|
||||
min_thp = network.node(node_name).terminal_pressure().value();
|
||||
std::optional<double> approximate_solution0;
|
||||
WellBhpThpCalculator::bruteForceBracketCommonTHP(mismatch, min_thp, max_thp, local_deferredLogger);
|
||||
|
||||
// Narrow down the bracket
|
||||
double low1, high1;
|
||||
std::array<double, 2> range = {0.9*min_thp, 1.1*max_thp};
|
||||
std::optional<double> appr_sol;
|
||||
WellBhpThpCalculator::bruteForceBracketCommonTHP(mismatch, range, low1, high1, appr_sol, 0.0, local_deferredLogger);
|
||||
min_thp = low1;
|
||||
max_thp = high1;
|
||||
range_initial = {min_thp, max_thp};
|
||||
}
|
||||
|
||||
const auto upbranch = network.uptree_branch(nodeName);
|
||||
const auto it = this->node_pressures_.find((*upbranch).uptree_node());
|
||||
const Scalar nodal_pressure = it->second;
|
||||
@ -1471,7 +1474,6 @@ namespace Opm {
|
||||
for (auto& well : this->well_container_) {
|
||||
std::string well_name = well->name();
|
||||
if (group.hasWell(well_name)) {
|
||||
|
||||
well->setDynamicThpLimit(well_group_thp);
|
||||
}
|
||||
}
|
||||
|
@ -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_) {
|
||||
@ -147,7 +150,7 @@ guideRate(const std::string& name,
|
||||
return WellGroupHelpers<Scalar>::getGuideRate(name, schedule_, well_state_, group_state_,
|
||||
report_step_, guide_rate_, target_, pu_);
|
||||
} else {
|
||||
if (groupControlledWells(name, always_included_child) > 0) {
|
||||
if ((groupControlledWells(name, always_included_child) > 0)) {
|
||||
if (is_producer_ && guide_rate_->has(name)) {
|
||||
return guide_rate_->get(name, target_, getGroupRateVector(name));
|
||||
} else if (!is_producer_ && guide_rate_->has(name, injection_phase_)) {
|
||||
@ -174,6 +177,7 @@ groupControlledWells(const std::string& group_name,
|
||||
return WellGroupHelpers<Scalar>::groupControlledWells(schedule_,
|
||||
well_state_,
|
||||
this->group_state_,
|
||||
this->summary_state_,
|
||||
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_;
|
||||
|
@ -113,26 +113,6 @@ GroupState::update_well_group_thp(const std::string& gname, const double& thp)
|
||||
this->group_thp[gname] = thp;
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
double GroupState<Scalar>::
|
||||
GroupState::well_group_thp(const std::string& gname) const
|
||||
{
|
||||
auto group_iter = this->group_thp.find(gname);
|
||||
if (group_iter == this->group_thp.end())
|
||||
throw std::logic_error("No such group");
|
||||
|
||||
return group_iter->second;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
template<class Scalar>
|
||||
void GroupState<Scalar>::
|
||||
GroupState::update_well_group_thp(const std::string& gname, const double& thp)
|
||||
{
|
||||
this->group_thp[gname] = thp;
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
Scalar GroupState<Scalar>::
|
||||
GroupState::well_group_thp(const std::string& gname) const
|
||||
@ -144,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>
|
||||
|
@ -55,8 +55,8 @@ public:
|
||||
const std::vector<Scalar>& production_rates(const std::string& gname) const;
|
||||
|
||||
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,
|
||||
@ -214,11 +214,7 @@ private:
|
||||
std::map<std::string, Scalar> inj_vrep_rate;
|
||||
std::map<std::string, Scalar> m_grat_sales_target;
|
||||
std::map<std::string, Scalar> m_gpmaint_target;
|
||||
<<<<<<< HEAD
|
||||
std::map<std::string, Scalar> group_thp;
|
||||
=======
|
||||
std::map<std::string, double> group_thp;
|
||||
>>>>>>> 8e410ac73 (Automatic choke)
|
||||
|
||||
std::map<std::pair<Phase, std::string>, Group::InjectionCMode> injection_controls;
|
||||
WellContainer<GPMaint::State> gpmaint_state;
|
||||
|
@ -1051,13 +1051,14 @@ 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;
|
||||
for (int i = 0; i < sample_number + 1; ++i) {
|
||||
max_thp = min_thp + interval * i;
|
||||
eq_high = eq(max_thp);
|
||||
// std::cout << "max_thp: " << max_thp/1E5 << " eq_high: " << eq_high << " eq_low: " << eq_low << std::endl;
|
||||
if (eq_high * eq_low <= 0.) {
|
||||
bracket_found = true;
|
||||
min_thp = max_thp - interval;
|
||||
|
@ -130,24 +130,6 @@ public:
|
||||
static bool bruteForceBracketCommonTHP(const std::function<Scalar(const Scalar)>& eq,
|
||||
Scalar& min_thp, Scalar& max_thp);
|
||||
|
||||
//! \brief Find limits using brute-force solver.
|
||||
static bool bruteForceBracket(const std::function<double(const double)>& eq,
|
||||
const std::array<double, 2>& range,
|
||||
double& low, double& high,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
//! \brief Find limits using brute-force solver.
|
||||
static bool bruteForceBracketCommonTHP(const std::function<double(const double)>& eq,
|
||||
const std::array<double, 2>& range,
|
||||
double& low, double& high,
|
||||
std::optional<double>& approximate_solution,
|
||||
const double& limit,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
//! \brief Find limits using brute-force solver.
|
||||
static bool bruteForceBracketCommonTHP(const std::function<double(const double)>& eq,
|
||||
double& min_thp, double& max_thp);
|
||||
|
||||
private:
|
||||
//! \brief Compute BHP from THP limit for an injector - implementation.
|
||||
template<class ErrorPolicy>
|
||||
|
@ -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(),
|
||||
@ -525,14 +529,17 @@ getGroupProductionTargetRate(const Group& group,
|
||||
// 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;
|
||||
std::cout << "target: " << target*86400 << " time: " << well_.currentStep() << " orig" << std::endl;
|
||||
for (std::size_t ii = 0; ii < num_ancestors; ++ii) {
|
||||
if ((ii == 0) || well_.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]);
|
||||
std::cout << "ii: " << ii << " group: " << chain[ii] << " LocRed:" << localReduction(chain[ii])*86400 << " target: " << target*86400 << std::endl;
|
||||
}
|
||||
target *= localFraction(chain[ii+1]);
|
||||
std::cout << "ii: " << ii << " group: " << chain[ii+1] << " LocFrac: " << localFraction(chain[ii+1]) << " target: " << target*86400 << std::endl;
|
||||
}
|
||||
// Avoid negative target rates coming from too large local reductions.
|
||||
const Scalar target_rate = std::max(Scalar(0.0), target / efficiencyFactor);
|
||||
@ -549,6 +556,116 @@ 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);
|
||||
|
||||
// Scalar fr_true = fcalc.fraction("B1", "M5S", true);
|
||||
// fr_true = fcalc.fraction("B1", "M5S", true);
|
||||
// Scalar fr_false = fcalc.fraction("B1", "M5S", false);
|
||||
// fr_false = fcalc.fraction("B1", "M5S", false);
|
||||
// std::cout << "fr_true: " << fr_true << " fr_false: " << fr_false << std::endl;
|
||||
|
||||
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;
|
||||
std::cout << "target: " << target*86400 << " time: " << reportStepIdx << " modified" << std::endl;
|
||||
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]);
|
||||
std::cout << "ii: " << ii << " group: " << chain[ii] << " LocRed:" << localReduction(chain[ii])*86400 << " target: " << target*86400 << std::endl;
|
||||
}
|
||||
target *= localFraction(chain[ii+1]);
|
||||
std::cout << "ii: " << ii << " group: " << chain[ii+1] << " LocFrac: " << localFraction(chain[ii+1]) << " target: " << target*86400 << std::endl;
|
||||
}
|
||||
// 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>
|
||||
@ -345,6 +347,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)
|
||||
{
|
||||
@ -359,6 +362,7 @@ updateGroupTargetReduction(const Group& group,
|
||||
pu,
|
||||
guide_rate,
|
||||
wellState,
|
||||
summaryState,
|
||||
group_state,
|
||||
subGroupTargetReduction);
|
||||
|
||||
@ -400,7 +404,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, reportStepIdx, subGroupName, "", !isInjector, phase);
|
||||
if (individual_control || num_group_controlled_wells == 0) {
|
||||
groupTargetReduction[phase_pos]
|
||||
+= subGroupEfficiency * sumWellSurfaceRates(subGroup, schedule, wellState, reportStepIdx, phase_pos, isInjector);
|
||||
@ -416,7 +420,8 @@ 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, reportStepIdx, subGroupName, "", !isInjector, /*injectionPhaseNotUsed*/Phase::OIL);
|
||||
std::cout<< "Group: " << subGroupName << " NumGroupControlledWells: " << num_group_controlled_wells << std::endl;
|
||||
if (individual_control || num_group_controlled_wells == 0) {
|
||||
for (int phase = 0; phase < np; phase++) {
|
||||
groupTargetReduction[phase]
|
||||
@ -431,6 +436,7 @@ updateGroupTargetReduction(const Group& group,
|
||||
}
|
||||
}
|
||||
}
|
||||
std::cout << "A: Group: " << group.name() << ", currentGroupControl: " << Group::ProductionCMode2String(currentGroupControl) << ", GroupTargetReduction[1]: " << groupTargetReduction[1]*86400 << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@ -464,10 +470,16 @@ 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;
|
||||
}
|
||||
}
|
||||
std::cout<< "B: " << " Group: " << group.name() << ", Well: "
|
||||
<< wellName << ", cmode: " << ws.production_cmode << ", GroupTargetReduction[1]: "
|
||||
<< groupTargetReduction[1]*86400 << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isInjector)
|
||||
@ -1086,6 +1098,7 @@ int WellGroupHelpers<Scalar>::
|
||||
groupControlledWells(const Schedule& schedule,
|
||||
const WellState<Scalar>& well_state,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const SummaryState& summary_state,
|
||||
const int report_step,
|
||||
const std::string& group_name,
|
||||
const std::string& always_included_child,
|
||||
@ -1107,16 +1120,65 @@ 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, 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_guide_rate = ctrl.guide_rate;
|
||||
const auto& control_group_cmode = ctrl.cmode;
|
||||
|
||||
const auto& group_guide_rate = group.productionControls(summary_state).guide_rate;
|
||||
|
||||
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);
|
||||
// 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 < 0.99 * target_rate)
|
||||
included = false;
|
||||
}
|
||||
|
||||
if (included) {
|
||||
++num_wells;
|
||||
}
|
||||
@ -1155,6 +1217,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>::
|
||||
@ -1234,6 +1317,7 @@ checkGroupConstraintsProd(const std::string& name,
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
wellState,
|
||||
group_state,
|
||||
summaryState,
|
||||
reportStepIdx,
|
||||
guideRate,
|
||||
tcalc.guideTargetMode(),
|
||||
@ -1276,6 +1360,7 @@ checkGroupConstraintsProd(const std::string& name,
|
||||
const int num_gr_ctrl = groupControlledWells(schedule,
|
||||
wellState,
|
||||
group_state,
|
||||
summaryState,
|
||||
reportStepIdx,
|
||||
chain[ii],
|
||||
"",
|
||||
@ -1296,6 +1381,7 @@ checkGroupConstraintsProd(const std::string& name,
|
||||
// we add a factor here to avoid switching due to numerical instability
|
||||
const Scalar factor = 1.01;
|
||||
if (currentRateFraction > (guiderateFraction * factor)) {
|
||||
std::cout << guided_group << " localCurrentRate(guided_group): " << localCurrentRate(guided_group) << chain[ii-1] << " localCurrentRate(chain[ii-1]) " << localCurrentRate(chain[ii-1]) << std::endl;
|
||||
return std::make_pair(true, guiderateFraction / currentRateFraction);
|
||||
}
|
||||
}
|
||||
@ -1409,6 +1495,7 @@ checkGroupConstraintsInj(const std::string& name,
|
||||
WGHelpers::FractionCalculator fcalc(schedule,
|
||||
wellState,
|
||||
group_state,
|
||||
summaryState,
|
||||
reportStepIdx,
|
||||
guideRate,
|
||||
tcalc.guideTargetMode(),
|
||||
@ -1451,12 +1538,13 @@ 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,
|
||||
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,7 @@ public:
|
||||
static int groupControlledWells(const Schedule& schedule,
|
||||
const WellState<Scalar>& well_state,
|
||||
const GroupState<Scalar>& group_state,
|
||||
const SummaryState& summary_state,
|
||||
const int report_step,
|
||||
const std::string& group_name,
|
||||
const std::string& always_included_child,
|
||||
@ -276,6 +278,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,
|
||||
|
@ -519,7 +519,7 @@ WellInterfaceGeneric<Scalar>::getDynamicThpLimit() const
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
void WellInterfaceGeneric::
|
||||
void WellInterfaceGeneric<Scalar>::
|
||||
setDynamicThpLimit(const std::optional<Scalar> thp_limit)
|
||||
{
|
||||
dynamic_thp_limit_ = thp_limit;
|
||||
|
Loading…
Reference in New Issue
Block a user