Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement gsatprod #5894

Merged
merged 5 commits into from
Jan 22, 2025
Merged

Implement gsatprod #5894

merged 5 commits into from
Jan 22, 2025

Conversation

totto82
Copy link
Member

@totto82 totto82 commented Jan 17, 2025

Depends on
OPM/opm-common#4188

Sufficient to run OPM/opm-tests#1207 where GSATPROD only interact with output and new test case OPM/opm-tests#1286

@totto82 totto82 requested a review from bska January 17, 2025 10:03
@totto82
Copy link
Member Author

totto82 commented Jan 17, 2025

Now also with interaction with group controls.

@totto82
Copy link
Member Author

totto82 commented Jan 17, 2025

Simple test case added. OPM/opm-tests#1286

@totto82
Copy link
Member Author

totto82 commented Jan 17, 2025

The only difference between GSATPROD1 and GSATPROD2 is that GSATPROD2 includes GCONPROD with 2500 ORAT. The well PROD's ORAT is correctly limited to meet 2500 ORAT target for group FIELD in GSATPROD2.

image

@totto82 totto82 changed the title Fix parallel gsatprod Implement gsatprod Jan 17, 2025
Copy link
Member

@bska bska left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks okay to me, but I really think we should try to limit the amount of nested logic we add when making new features, and, generally try to simplify the functions if at all possible. The WellGroupHelpers are already quite complicated and the fact that we can't understand any single function in isolation because everything gets accumulated into updateAndCommunicateGroupData().

Comment on lines 101 to 108
const auto& gsatprod = schedule[reportStepIdx].gsatprod.get();
// only sum once
if (wellState.isRank0() && !injector && gsatprod.has(groupName)) {
const auto& gsatprod_rates = gsatprod.get(groupName);
const auto& pu = wellState.phaseUsage();
using Rate = GSatProd::GSatProdGroup::Rate;
if (pu.phase_used[BlackoilPhases::Aqua] && pu.phase_pos[BlackoilPhases::Aqua] == phasePos) {
rate += gsatprod_rates.rate[Rate::Water];
}
if (pu.phase_used[BlackoilPhases::Liquid] && pu.phase_pos[BlackoilPhases::Liquid] == phasePos) {
rate += gsatprod_rates.rate[Rate::Oil];
}
if (pu.phase_used[BlackoilPhases::Vapour] && pu.phase_pos[BlackoilPhases::Vapour] == phasePos) {
rate += gsatprod_rates.rate[Rate::Gas];
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I'd prefer if this logic were separated out to a distinct helper function, or at least a separate loop. Something along the lines of

template <typename Scalar>
Scalar satelliteProduction(const ScheduleState& sched,
                           const std::vector<std::string>& groups,
                           const GSatProd::GSatProdGroup::Rate rateComp)
{
    auto satProdRate = Scalar{};

    const auto& gsatProd = sched.gsatprod();
    for (const auto& group : groups) {
        if (! gsatProd.has(group)) {
            continue;
        }

        gsatProdRate += gsatProd.get(group).rate[rateComp];
    }

    return gsatProdRate;
}

std::optional<GSatProd::GSatProdGroup::Rate>
selectRateComponent(const PhaseUsage& pu, const int phasePos)
{
    using Rate = GSatProd::GSatProdGroup::Rate;

    for (const auto& [phase, rateComp] : std::array {
        std::pair { BlackoilPhases::Aqua, Rate::Water },
        std::pair { BlackoilPhases::Liquid, Rate::Oil },
        std::pair { BlackoilPhases::Vapour, Rate::Gas } })
    {
        if (pu.phase_used[phase] && (pu.phase_pos[phase] == phasePos)) {
            return rateComp;
        }
    }

    return std::nullopt;
}

which you'd call, either as part of sumWellPhaseRates() or separately, as

if (wellState.isRank0() && !injector) {
    const auto rateComp = selecteRateComponent(wellState.phaseUsage(), phasePos);
    if (rateComp.has_value()) {
        rate += satelliteProduction(schedule[reportStepIdx], group.groups(), *rateComp);
    }
}

This would reduce the amount of nested logic.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestions.

Copy link
Member

@bska bska left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the updates. I think this is starting to look good. Just one small issue remaining, I think.

Comment on lines 101 to 108
// only sum satelite production once
if (wellState.isRank0() && !injector) {
const auto rateComp = selectRateComponent(wellState.phaseUsage(), phasePos);
if (rateComp.has_value()) {
rate += satelliteProduction(schedule[reportStepIdx], group.groups(), *rateComp);
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section needs to be outside of the groupName loop lest we include the contributions multiple times in the case that more than one of group.groups() is a satellite.

Copy link
Member

@bska bska left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for the updates. This looks good to me now and I'll merge into master.

@bska bska merged commit e288a61 into OPM:master Jan 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants