Simplify GroupTargetCalculator by delegating to GroupStateHelper

Eliminate complicated variant handling in initForInjector_() and
initForProducer_(). The code previously required knowledge of std::variant
internals to understand.

Changes:
- Add getInjectionGuideTargetMode() and getProductionGuideTargetMode()
  to GroupStateHelper, delegating the Phase/CMode to GuideRateModel::Target
  conversion
- Refactor initForInjector_() and initForProducer_() to construct
  calculators directly instead of going through variant intermediaries
- Merge getTargetFromCalculator() and getTargetNoGuideRate() into
  getGroupTargetNoGuideRate(), eliminating redundant method and
  unused variant parameter
- Call GroupStateHelper directly for groupTarget() instead of extracting
  from variant

The variant type is still used for calcModeRateFromRates() which requires
the polymorphic behavior.
This commit is contained in:
Håkon Hægland committed 2026-01-26 12:02:19 +01:00
1 parent fda1b04f7c
commit a49aab171e
4 files changed
+84 -38

No files matched your search

+42
View File
@@ -527,6 +527,48 @@ getProductionGroupTarget(const Group& group) const
}
}
template<typename Scalar, typename IndexTraits>
GuideRateModel::Target
GroupStateHelper<Scalar, IndexTraits>::
getProductionGuideTargetMode(const Group& group) const
{
const auto cmode = this->groupState().production_control(group.name());
switch (cmode) {
case Group::ProductionCMode::ORAT:
return GuideRateModel::Target::OIL;
case Group::ProductionCMode::WRAT:
return GuideRateModel::Target::WAT;
case Group::ProductionCMode::GRAT:
return GuideRateModel::Target::GAS;
case Group::ProductionCMode::LRAT:
return GuideRateModel::Target::LIQ;
case Group::ProductionCMode::RESV:
return GuideRateModel::Target::RES;
default:
return GuideRateModel::Target::NONE;
}
}
template<typename Scalar, typename IndexTraits>
GuideRateModel::Target
GroupStateHelper<Scalar, IndexTraits>::
getInjectionGuideTargetMode(Phase injection_phase) const
{
switch (injection_phase) {
case Phase::WATER:
return GuideRateModel::Target::WAT;
case Phase::OIL:
return GuideRateModel::Target::OIL;
case Phase::GAS:
return GuideRateModel::Target::GAS;
default:
OPM_DEFLOG_THROW(std::logic_error,
"Invalid injection phase in getInjectionGuideTargetMode",
this->deferredLogger());
return GuideRateModel::Target::NONE;
}
}
template <typename Scalar, typename IndexTraits>
std::vector<Scalar>
GroupStateHelper<Scalar, IndexTraits>::
+10
View File
@@ -239,8 +239,18 @@ public:
const Phase& injection_phase,
const std::vector<Scalar>& resv_coeff) const;
/// @brief Get the guide rate target mode for an injection phase
/// @param injection_phase The injection phase (WATER, OIL, or GAS)
/// @return The corresponding GuideRateModel::Target for the injection phase
GuideRateModel::Target getInjectionGuideTargetMode(Phase injection_phase) const;
Scalar getProductionGroupTarget(const Group& group) const;
/// @brief Get the guide rate target mode for a production group
/// @param group The production group
/// @return The GuideRateModel::Target based on the group's production control mode
GuideRateModel::Target getProductionGuideTargetMode(const Group& group) const;
GuideRate::RateVector getProductionGroupRateVector(const std::string& group_name) const;
std::optional<Scalar> getWellGroupTargetInjector(const std::string& name,
+29 -33
View File
@@ -134,7 +134,7 @@ calculateGroupTarget()
}
}
if (group.is_field() || !this->parentGroupControlAvailable_(group)) {
return this->getTargetNoGuideRate(group);
return this->getGroupTargetNoGuideRate(group);
}
assert(this->parentGroupControlAvailable_(group));
if (!this->hasGuideRate(group)) {
@@ -151,7 +151,7 @@ calculateGroupTarget()
// - parent control available,
// - but no guide rate
// this could be considered an error, but we can also fall back to use its own target.
return this->getTargetNoGuideRate(group);
return this->getGroupTargetNoGuideRate(group);
}
const auto efficiency_factor = group.getGroupEfficiencyFactor();
auto target = this->calculateGroupTargetRecursive_(this->parentGroup(group), efficiency_factor);
@@ -163,7 +163,7 @@ calculateGroupTarget()
return target;
}
// If a higher level target was not found or not violated, use the group's own target.
return this->getTargetNoGuideRate(group);
return this->getGroupTargetNoGuideRate(group);
}
template<class Scalar, class IndexTraits>
@@ -211,18 +211,27 @@ template<class Scalar, class IndexTraits>
typename GroupTargetCalculator<Scalar, IndexTraits>::TargetInfo
GroupTargetCalculator<Scalar, IndexTraits>::
GeneralCalculator::
getTargetFromCalculator(const TargetCalculatorType& target_calculator, const Group& group)
getGroupTargetNoGuideRate(const Group& group)
{
// Efficiency factor is not applied here, since it only applies to child rates, not to the group's
// own target.
// NOTE: If a master group is under individual control and has a RESV rate target, it should be
// transferred into a RESV target for the slave group. But it is not obvious how to transform it
// since the master and slave groups in general have different PVT properties.
// TODO: For now we assume the RESV rate target is in slave reservoir units, and just send it as is
// to the slave group. Alternatively, we could also throw an error here for that case
if (this->targetType() == TargetType::Injection) {
const auto& control_mode = this->groupState().injection_control(group.name(), this->injectionPhase_());
return TargetInfo{
std::get<InjectionTargetCalculator>(target_calculator).groupTarget(), control_mode
this->groupStateHelper().getInjectionGroupTarget(group, this->injectionPhase_(), this->resvCoeffsInj()),
control_mode
};
}
else {
const auto& control_mode = this->groupState().production_control(group.name());
return TargetInfo{
std::get<TargetCalculator>(target_calculator).groupTarget(), control_mode
this->groupStateHelper().getProductionGroupTarget(group),
control_mode
};
}
}
@@ -301,23 +310,6 @@ calculateGroupTargetRecursive_(const Group& group, const Scalar efficiency_facto
return top_bottom_calc.calculateGroupTarget();
}
template<class Scalar, class IndexTraits>
typename GroupTargetCalculator<Scalar, IndexTraits>::TargetInfo
GroupTargetCalculator<Scalar, IndexTraits>::
GeneralCalculator::
getTargetNoGuideRate(const Group& group)
{
// Efficiency factor is not applied here, since it only applies to child rates, not to the group's
// own target.
// NOTE: If a master group is under individual control and has a RESV rate target, it should be
// transferred into a RESV target for the slave group. But it is not obvious how to transform it
// since the master and slave groups in general have different PVT properties.
// TODO: For now we assume the RESV rate target is in slave reservoir units, and just send it as is
// to the slave group. Alternatively, we could also throw an error here for that case
const auto target_calculator = this->getTargetCalculator(group);
return this->getTargetFromCalculator(target_calculator, group);
}
template<class Scalar, class IndexTraits>
bool
GroupTargetCalculator<Scalar, IndexTraits>::
@@ -450,7 +442,7 @@ calculateGroupTarget()
}
}
// Return the bottom group's target rate as is.
return this->getTargetNoGuideRate_(this->bottom_group_);
return this->getGroupTargetNoGuideRate_(this->bottom_group_);
}
// -------------------------------------------------------
@@ -612,11 +604,13 @@ GroupTargetCalculator<Scalar, IndexTraits>::
TopToBottomCalculator::
initForInjector_()
{
auto calc = this->getInjectionTargetCalculator_(this->top_group_);
this->target_calculator_.template emplace<InjectionTargetCalculator>(
std::get<InjectionTargetCalculator>(calc));
auto guide_target_mode =
std::get<InjectionTargetCalculator>(this->target_calculator_).guideTargetMode();
this->groupStateHelper(),
this->resvCoeffsInj(),
this->top_group_,
this->injectionPhase_()
);
const auto guide_target_mode = this->groupStateHelper().getInjectionGuideTargetMode(this->injectionPhase_());
this->fraction_calculator_.emplace(
this->schedule(),
this->groupStateHelper(),
@@ -635,11 +629,13 @@ GroupTargetCalculator<Scalar, IndexTraits>::
TopToBottomCalculator::
initForProducer_()
{
auto calc = this->getProductionTargetCalculator_(this->top_group_);
this->target_calculator_.template emplace<TargetCalculator>(std::get<TargetCalculator>(calc));
auto guide_target_mode =
std::get<TargetCalculator>(this->target_calculator_).guideTargetMode();
auto dummy_phase = Phase::OIL; // Dummy phase, not used for producers.
this->target_calculator_.template emplace<TargetCalculator>(
this->groupStateHelper(),
this->resvCoeffsProd(),
this->top_group_
);
const auto guide_target_mode = this->groupStateHelper().getProductionGuideTargetMode(this->top_group_);
const auto dummy_phase = Phase::OIL; // Dummy phase, not used for producers.
this->fraction_calculator_.emplace(
this->schedule(),
this->groupStateHelper(),
@@ -120,9 +120,7 @@ public:
TargetCalculatorType getInjectionTargetCalculator(const Group& group);
TargetCalculatorType getProductionTargetCalculator(const Group& group) const;
TargetCalculatorType getTargetCalculator(const Group& group);
TargetInfo getTargetFromCalculator(
const TargetCalculatorType& target_calculator, const Group& group);
TargetInfo getTargetNoGuideRate(const Group& group);
TargetInfo getGroupTargetNoGuideRate(const Group& group);
const GuideRate& guideRate() const { return this->parent_calculator_.guideRate(); }
bool hasGuideRate(const Group& group) const { return this->hasGuideRate(group.name()); }
bool hasGuideRate(const std::string& name) const {
@@ -221,8 +219,8 @@ public:
/// @param group The master group to get the corresponding slave group reservoir rate for
/// @return Total reservoir rate, or throws an error if not a RC master group
Scalar getSlaveGroupReservoirRate_(const Group& master_group);
TargetInfo getTargetNoGuideRate_(const Group& group) const {
return this->parent_calculator_.getTargetNoGuideRate(group);
TargetInfo getGroupTargetNoGuideRate_(const Group& group) const {
return this->parent_calculator_.getGroupTargetNoGuideRate(group);
}
ControlMode getToplevelControlMode_() const;
Scalar getTopLevelTarget_();