Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 77 additions & 1 deletion opm/simulators/wells/BlackoilWellModelGeneric.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1336,7 +1336,8 @@ updateAndCommunicateGroupData(const int reportStepIdx,
const Scalar efficiencyFactor = well->wellEcl().getEfficiencyFactor() *
ws.efficiency_scaling_factor;
// Translate injector type from control to Phase.
std::optional<Scalar> group_target;
using GroupTarget = typename SingleWellState<Scalar, IndexTraits>::GroupTarget;
std::optional<GroupTarget> group_target;
if (well->isProducer()) {
group_target = group_state_helper.getWellGroupTargetProducer(
well->name(),
Expand Down Expand Up @@ -1947,6 +1948,81 @@ operator==(const BlackoilWellModelGeneric& rhs) const
&& this->gen_gaslift_ == rhs.gen_gaslift_;
}

template <typename Scalar, typename IndexTraits>
void
BlackoilWellModelGeneric<Scalar, IndexTraits>::
updateNONEProductionGroups(const GasLiftOpt& glo, DeferredLogger& deferred_logger)
{
auto& group_state = this->groupState();
const auto& prod_group_controls = group_state.get_production_controls();
if (prod_group_controls.empty()) {
return;
}

const auto& well_state = this->wellState();
// numbers of the group production controls, including NONE mode
const std::size_t num_gpc = prod_group_controls.size();
// collect groups that currently provide production targets to any well on this rank
std::unordered_set<std::string> targeted_production_groups;
targeted_production_groups.reserve(num_gpc);

for (std::size_t w = 0; w < well_state.size(); ++w) {
const auto& ws = well_state.well(w);
if (ws.producer && ws.production_cmode == WellProducerCMode::GRUP) {
const auto& group_target = ws.group_target;
if (group_target.has_value()) {
targeted_production_groups.insert(group_target->group_name);
} else {
const std::string msg = fmt::format("Well {} is on GRUP control but has no group target assigned.", ws.name);
deferred_logger.debug(msg);
}
}
}

// parallel communication to synchronize production groups used on all processes
// all the group names in prod_group_controls
std::vector<std::string> gnames;
gnames.reserve(num_gpc);
// the group control is enforcing constraints for at least one well on this rank
// then it will be globally communicated across all the processes
std::vector<int> production_control_used;
production_control_used.reserve(num_gpc);

for (const auto& kv : prod_group_controls) {
const auto& name = kv.first;
gnames.emplace_back(name);
const bool is_used = targeted_production_groups.find(name) != targeted_production_groups.end();
production_control_used.emplace_back(is_used ? 1 : 0);
}

// parallel communication to synchronize production groups used on all processes
if (comm_.size() > 1 && num_gpc > 0) {
comm_.sum(production_control_used.data(), static_cast<int>(num_gpc));
}

for (std::size_t i = 0; i < num_gpc; ++i) {
if (production_control_used[i] > 0) {
continue;
}
const auto& gname = gnames[i];
if (group_state.production_control(gname) != Group::ProductionCMode::NONE) {
// If the production group is specified for gas lift optimization,
// the current gas lift optimization implementation relies on the control
// mode is not NONE or FLD. As a result, we can not set it to NONE here.
// More systematic development might be needed in the future in this area.
if (glo.active() && glo.has_group(gname)) {
continue;
}
if (comm_.rank() == 0) {
const std::string msg = fmt::format("Production group {} has no constraints active, setting control mode to NONE", gname);
deferred_logger.info(msg);
}
group_state.production_control(gname, Group::ProductionCMode::NONE);
}
}
}


template class BlackoilWellModelGeneric<double, BlackOilDefaultFluidSystemIndices>;

#if FLOW_INSTANTIATE_FLOAT
Expand Down
2 changes: 2 additions & 0 deletions opm/simulators/wells/BlackoilWellModelGeneric.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,8 @@ class BlackoilWellModelGeneric
void assignMassGasRate(data::Wells& wsrpt,
const Scalar gasDensity) const;

void updateNONEProductionGroups(const GasLiftOpt& glo, DeferredLogger& deferred_logger);

Schedule& schedule_;

const SummaryState& summaryState_;
Expand Down
3 changes: 3 additions & 0 deletions opm/simulators/wells/BlackoilWellModel_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -742,6 +742,9 @@ namespace Opm {

this->calculateProductivityIndexValues(local_deferredLogger);

const auto& glo = this->schedule().glo(reportStepIdx);
this->updateNONEProductionGroups(glo, local_deferredLogger);

this->commitWGState();

const Opm::Parallel::Communication& comm = grid().comm();
Expand Down
7 changes: 7 additions & 0 deletions opm/simulators/wells/GroupState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,13 @@ GroupState<Scalar>::production_control(const std::string& gname) const
return group_iter->second;
}

template<class Scalar>
const std::map<std::string, Group::ProductionCMode>&
GroupState<Scalar>::get_production_controls() const
{
return this->production_controls;
};

//-------------------------------------------------------------------------

template<class Scalar>
Expand Down
1 change: 1 addition & 0 deletions opm/simulators/wells/GroupState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ class GroupState {
bool has_production_control(const std::string& gname) const;
void production_control(const std::string& gname, Group::ProductionCMode cmode);
Group::ProductionCMode production_control(const std::string& gname) const;
const std::map<std::string, Group::ProductionCMode>& get_production_controls() const;

bool has_injection_control(const std::string& gname, Phase phase) const;
void injection_control(const std::string& gname, Phase phase, Group::InjectionCMode cmode);
Expand Down
18 changes: 10 additions & 8 deletions opm/simulators/wells/GroupStateHelper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,7 +198,8 @@ GroupStateHelper<Scalar, IndexTraits>::checkGroupConstraintsInj(const std::strin
if (this->schedule_.hasWell(name)
&& this->wellState().well(name).group_target) { // for wells we already have computed the target
Scalar scale = 1.0;
const Scalar group_target_rate_available = *this->wellState().well(name).group_target;
const auto& group_target = this->wellState().well(name).group_target;
const Scalar group_target_rate_available = group_target->target_value;
const Scalar current_well_rate_available
= tcalc.calcModeRateFromRates(rates); // Switch sign since 'rates' are negative for producers.
if (current_well_rate_available > 1e-12) {
Expand Down Expand Up @@ -371,7 +372,8 @@ GroupStateHelper<Scalar, IndexTraits>::checkGroupConstraintsProd(const std::stri

// Switch sign since 'rates' are negative for producers.
const Scalar current_well_rate_available = -tcalc.calcModeRateFromRates(rates);
const Scalar group_target_rate_available = *this->wellState().well(name).group_target;
const auto& group_target = this->wellState().well(name).group_target;
const Scalar group_target_rate_available = group_target->target_value;
Scalar scale = 1.0;
if (current_well_rate_available > 1e-12) {
scale = group_target_rate_available / current_well_rate_available;
Expand Down Expand Up @@ -483,7 +485,7 @@ GroupStateHelper<Scalar, IndexTraits>::getProductionGroupRateVector(const std::s
}

template <typename Scalar, typename IndexTraits>
std::optional<Scalar>
std::optional<typename SingleWellState<Scalar, IndexTraits>::GroupTarget>
GroupStateHelper<Scalar, IndexTraits>::getWellGroupTargetInjector(const std::string& name,
const std::string& parent,
const Group& group,
Expand Down Expand Up @@ -612,12 +614,12 @@ GroupStateHelper<Scalar, IndexTraits>::getWellGroupTargetInjector(const std::str
target *= local_fraction_lambda(chain[ii + 1], chain[ii + 1]);
}
}
// Avoid negative target rates comming from too large local reductions.
return std::max(Scalar(0.0), target / efficiency_factor);
// Avoid negative target rates coming from too large local reductions.
return GroupTarget{group.name(), std::max(Scalar(0.0), target / efficiency_factor)};
}

template <typename Scalar, typename IndexTraits>
std::optional<Scalar>
std::optional<typename SingleWellState<Scalar, IndexTraits>::GroupTarget>
GroupStateHelper<Scalar, IndexTraits>::getWellGroupTargetProducer(const std::string& name,
const std::string& parent,
const Group& group,
Expand All @@ -630,7 +632,7 @@ GroupStateHelper<Scalar, IndexTraits>::getWellGroupTargetProducer(const std::str
// 'parent' will be the name of 'group'. But if we recurse, 'name' and
// 'parent' will stay fixed while 'group' will be higher up
// in the group tree.
// Eficiencyfactor is the well efficiency factor for the first group the well is
// Efficiency factor is the well efficiency factor for the first group the well is
// part of. Later it is the accumulated factor including the group efficiency factor
// of the child of group.
OPM_TIMEFUNCTION();
Expand Down Expand Up @@ -741,7 +743,7 @@ GroupStateHelper<Scalar, IndexTraits>::getWellGroupTargetProducer(const std::str
}
}
// Avoid negative target rates coming from too large local reductions.
return std::max(Scalar(0.0), target / efficiency_factor);
return GroupTarget{group.name(), std::max(Scalar(0.0), target / efficiency_factor)};
}

template <typename Scalar, typename IndexTraits>
Expand Down
34 changes: 18 additions & 16 deletions opm/simulators/wells/GroupStateHelper.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -142,22 +142,24 @@ class GroupStateHelper

GuideRate::RateVector getProductionGroupRateVector(const std::string& group_name) const;

std::optional<Scalar> getWellGroupTargetInjector(const std::string& name,
const std::string& parent,
const Group& group,
const Scalar* rates,
const Phase injection_phase,
const Scalar efficiency_factor,
const std::vector<Scalar>& resv_coeff,
DeferredLogger& deferred_logger) const;

std::optional<Scalar> getWellGroupTargetProducer(const std::string& name,
const std::string& parent,
const Group& group,
const Scalar* rates,
const Scalar efficiency_factor,
const std::vector<Scalar>& resv_coeff,
DeferredLogger& deferred_logger) const;
using GroupTarget = typename SingleWellState<Scalar, IndexTraits>::GroupTarget;

std::optional<GroupTarget> getWellGroupTargetInjector(const std::string& name,
const std::string& parent,
const Group& group,
const Scalar* rates,
const Phase injection_phase,
const Scalar efficiency_factor,
const std::vector<Scalar>& resv_coeff,
DeferredLogger& deferred_logger) const;

std::optional<GroupTarget> getWellGroupTargetProducer(const std::string& name,
const std::string& parent,
const Group& group,
const Scalar* rates,
const Scalar efficiency_factor,
const std::vector<Scalar>& resv_coeff,
DeferredLogger& deferred_logger) const;

GuideRate::RateVector getWellRateVector(const std::string& name) const;

Expand Down
17 changes: 16 additions & 1 deletion opm/simulators/wells/SingleWellState.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,21 @@ class SingleWellState {
vaporized_water = 3
};

struct GroupTarget {
std::string group_name;
Scalar target_value;

bool operator==(const GroupTarget& other) const {
return group_name == other.group_name && target_value == other.target_value;
}

template<class Serializer>
void serializeOp(Serializer& serializer) {
serializer(group_name);
serializer(target_value);
}
};

std::vector<Scalar> well_potentials;
std::vector<Scalar> productivity_index;
std::vector<Scalar> implicit_ipr_a;
Expand All @@ -127,7 +142,7 @@ class SingleWellState {
std::vector<Scalar> prev_surface_rates;
PerfData<Scalar> perf_data;
bool trivial_group_target;
std::optional<Scalar> group_target;
std::optional<GroupTarget> group_target;
SegmentState<Scalar> segments;
Events events;
WellInjectorCMode injection_cmode{WellInjectorCMode::CMODE_UNDEFINED};
Expand Down
10 changes: 5 additions & 5 deletions opm/simulators/wells/WellGroupControls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ getGroupInjectionControl(const Group& group,

const auto target_rate = well_state.well(well_.indexOfWell()).group_target;
if (target_rate) {
control_eq = injection_rate - *target_rate;
control_eq = injection_rate - target_rate->target_value;
} else {
const auto& controls = well.injectionControls(summaryState);
control_eq = bhp - controls.bhp_limit;
Expand Down Expand Up @@ -197,7 +197,7 @@ getGroupInjectionTargetRate(const Group& group,
return std::nullopt;
}

return well_state.well(well_.indexOfWell()).group_target;
return well_state.well(well_.indexOfWell()).group_target->target_value;
}

template<typename Scalar, typename IndexTraits>
Expand Down Expand Up @@ -275,7 +275,7 @@ getGroupProductionControl(const Group& group,
const auto target_rate = well_state.well(well_.indexOfWell()).group_target;
if (target_rate) {
const auto current_rate = -tcalc.calcModeRateFromRates(rates); // Switch sign since 'rates' are negative for producers.
control_eq = current_rate - *target_rate;
control_eq = current_rate - target_rate->target_value;
} else {
const auto& controls = well.productionControls(summaryState);
control_eq = bhp - controls.bhp_limit;
Expand Down Expand Up @@ -342,15 +342,15 @@ ::TargetCalculator<Scalar, IndexTraits> tcalc(currentGroupControl,
if (!target_rate) {
return 1.0;
}
if (*target_rate == 0.0) {
if (target_rate->target_value == 0.0) {
return 0.0;
}
const auto& ws = well_state.well(well_.indexOfWell());
const auto& rates = ws.surface_rates;
const auto current_rate = -tcalc.calcModeRateFromRates(rates); // Switch sign since 'rates' are negative for producers.
Scalar scale = 1.0;
if (current_rate > 1e-14)
scale = *target_rate / current_rate;
scale = target_rate->target_value / current_rate;

return scale;
}
Expand Down