Fix trivial NETV

This commit includes several fixes related to supporting NETV guide rates that are zero
This commit is contained in:
Tor Harald Sandve 2024-12-12 08:46:29 +01:00
parent 09acc593dd
commit 5bab785056
3 changed files with 47 additions and 31 deletions

View File

@ -77,18 +77,25 @@ Scalar FractionCalculator<Scalar>::
localFraction(const std::string& name,
const std::string& always_included_child)
{
const Scalar my_guide_rate = guideRate(name, always_included_child);
const Group& parent_group = schedule_.getGroup(parent(name), report_step_);
const Scalar total_guide_rate = guideRateSum(parent_group, always_included_child);
bool only_use_potentials = false;
const Scalar my_guide_rate = guideRate(name, always_included_child, only_use_potentials);
// the total guide gate is the same as my_guide rate
// the well/group is probably on its own, i.e. return 1
// even is its guide_rate is zero
const Scalar guide_rate_epsilon = 1e-12;
if ( std::abs(my_guide_rate - total_guide_rate) < guide_rate_epsilon )
const Group& parent_group = schedule_.getGroup(parent(name), report_step_);
const auto [total_guide_rate, num_active_groups] = guideRateSum(parent_group, always_included_child, only_use_potentials);
// the group/well "name" is the only active group/well we therefore return 1 as the fraction
// even though my_guide_rate may be zero
if (num_active_groups == 1)
return 1.0;
assert(total_guide_rate > my_guide_rate);
if (total_guide_rate == 0 ) {
// if the total guide rate is zero (for instance due to netv = 0) we use the potentials
// to distribute the group rate
only_use_potentials = true;
const Scalar my_pot = guideRate(name, always_included_child, only_use_potentials);
const Scalar my_total_pot = guideRateSum(parent_group, always_included_child, only_use_potentials).first;
return my_pot / my_total_pot;
}
return my_guide_rate / total_guide_rate;
}
@ -104,11 +111,13 @@ parent(const std::string& name)
}
template<class Scalar>
Scalar FractionCalculator<Scalar>::
std::pair<Scalar, int> FractionCalculator<Scalar>::
guideRateSum(const Group& group,
const std::string& always_included_child)
const std::string& always_included_child,
const bool use_potentials)
{
Scalar total_guide_rate = 0.0;
int number_of_included_well_or_group = 0;
for (const std::string& child_group : group.groups()) {
bool included = (child_group == always_included_child);
if (is_producer_) {
@ -122,7 +131,10 @@ guideRateSum(const Group& group,
(ctrl == Group::InjectionCMode::NONE);
}
if (included) {
total_guide_rate += guideRate(child_group, always_included_child);
if(groupControlledWells(child_group, always_included_child) > 0) {
number_of_included_well_or_group++;
total_guide_rate += guideRate(child_group, always_included_child, use_potentials);
}
}
}
@ -133,34 +145,35 @@ guideRateSum(const Group& group,
} else {
included |= well_state_.isInjectionGrup(child_well);
}
if (included) {
total_guide_rate += guideRate(child_well, always_included_child);
number_of_included_well_or_group++;
total_guide_rate += guideRate(child_well, always_included_child, use_potentials);
}
}
return total_guide_rate;
return {total_guide_rate, number_of_included_well_or_group};
}
template<class Scalar>
Scalar FractionCalculator<Scalar>::
guideRate(const std::string& name,
const std::string& always_included_child)
const std::string& always_included_child,
const bool use_potentials)
{
if (schedule_.hasWell(name, report_step_)) {
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 (is_producer_ && guide_rate_->has(name)) {
if (is_producer_ && guide_rate_->has(name) && !use_potentials) {
return guide_rate_->get(name, target_, getGroupRateVector(name));
} else if (!is_producer_ && guide_rate_->has(name, injection_phase_)) {
} else if (!is_producer_ && guide_rate_->has(name, injection_phase_) && !use_potentials) {
return guide_rate_->get(name, injection_phase_);
} else {
// We are a group, with default guide rate.
// Compute guide rate by accumulating our children's guide rates.
const Group& group = schedule_.getGroup(name, report_step_);
const double eff = group.getGroupEfficiencyFactor();
return eff * guideRateSum(group, always_included_child);
return eff * guideRateSum(group, always_included_child, use_potentials).first;
}
} else {
// No group-controlled subordinate wells.

View File

@ -56,10 +56,12 @@ public:
private:
std::string parent(const std::string& name);
Scalar guideRateSum(const Group& group,
const std::string& always_included_child);
std::pair<Scalar,int> guideRateSum(const Group& group,
const std::string& always_included_child,
const bool use_potentials);
Scalar guideRate(const std::string& name,
const std::string& always_included_child);
const std::string& always_included_child,
const bool use_potentials);
int groupControlledWells(const std::string& group_name,
const std::string& always_included_child);
GuideRate::RateVector getGroupRateVector(const std::string& group_name);

View File

@ -300,14 +300,14 @@ updateGuideRatesForInjectionGroups(const Group& group,
if(!group.hasInjectionControl(phase))
continue;
Scalar guideRateValue = 0.0;
std::optional<Scalar> guideRateValue;
const auto& controls = group.injectionControls(phase, summaryState);
switch (controls.guide_rate_def){
case Group::GuideRateInjTarget::RATE:
break;
case Group::GuideRateInjTarget::VOID:
{
guideRateValue = group_state.injection_vrep_rate(group.name());
guideRateValue = std::max(Scalar(0.0), group_state.injection_vrep_rate(group.name()));
break;
}
case Group::GuideRateInjTarget::NETV:
@ -315,17 +315,16 @@ updateGuideRatesForInjectionGroups(const Group& group,
guideRateValue = group_state.injection_vrep_rate(group.name());
const std::vector<Scalar>& injRES = group_state.injection_reservoir_rates(group.name());
if (phase != Phase::OIL && pu.phase_used[BlackoilPhases::Liquid])
guideRateValue -= injRES[pu.phase_pos[BlackoilPhases::Liquid]];
guideRateValue = *guideRateValue - injRES[pu.phase_pos[BlackoilPhases::Liquid]];
if (phase != Phase::GAS && pu.phase_used[BlackoilPhases::Vapour])
guideRateValue -= injRES[pu.phase_pos[BlackoilPhases::Vapour]];
guideRateValue = *guideRateValue - injRES[pu.phase_pos[BlackoilPhases::Vapour]];
if (phase != Phase::WATER && pu.phase_used[BlackoilPhases::Aqua])
guideRateValue -= injRES[pu.phase_pos[BlackoilPhases::Aqua]];
guideRateValue = *guideRateValue - injRES[pu.phase_pos[BlackoilPhases::Aqua]];
guideRateValue = std::max(Scalar(0.0), *guideRateValue);
break;
}
case Group::GuideRateInjTarget::RESV:
OPM_DEFLOG_THROW(std::runtime_error, "GUIDE PHASE RESV not implemented. Group " + group.name(), deferred_logger);
case Group::GuideRateInjTarget::POTN:
break;
case Group::GuideRateInjTarget::NO_GUIDE_RATE:
break;
default:
@ -335,7 +334,9 @@ updateGuideRatesForInjectionGroups(const Group& group,
}
const UnitSystem& unit_system = schedule.getUnits();
guideRateValue = unit_system.from_si(UnitSystem::measure::rate, guideRateValue);
if (guideRateValue) {
guideRateValue = unit_system.from_si(UnitSystem::measure::rate, *guideRateValue);
}
guideRate->compute(group.name(), phase, reportStepIdx, guideRateValue);
}
}