Skip to content

Let reservoir coupling slave UDQs see the production limits in force - #7485

Merged
totto82 merged 1 commit into
OPM:masterfrom
hakonhagland:slave_prod_targets
Oct 2, 2026
Merged

totto82 merged 1 commit into
OPM:masterfrom
hakonhagland:slave_prod_targets

Conversation

@hakonhagland

Copy link
Copy Markdown
Contributor

Replaces #7465, as agreed there: instead of stopping a slave whose UDQs use GOPRT and the other production target vectors for a slave group, report the right number. This is the production counterpart of #7413, which did this for GGIRT/GWIRT.

Depends on OPM/opm-common#5421, which adds data::ReservoirCouplingGroupRates::production_targets and lets the GOPRT, GWPRT, GGPRT and GLPRT evaluators use it.

Report the production limits in force for slave groups (commit 1)

  • The master sends a slave group a production limit for every rate type: the target of its active control mode, and its guide-rate share of the limits further up the master's group tree (GroupConstraintCalculator::groupProductionConstraints()). A slave UDQ that refers to GOPRT, GWPRT, GGPRT or GLPRT for such a group nevertheless read the slave deck's own GCONPROD value, usually zero.
  • New BlackoilWellModelRescoup::storeSlaveGroupProductionTargets(), next to storeSlaveGroupInjectionTargets(). It works out the limit in force per slave group and rate type: the master's, the deck's own, or the smaller of the two, as the group's GRUPSLAV flag says. It then:
    • keeps it on the slave (ReservoirCouplingSlave::effectiveProductionTargets()), so that EclWriter passes it to the summary output through production_targets;
    • primes the summary state with it before the group and field UDQs are evaluated. When nothing is in force, it primes the schedule's own limit.
  • It runs at the same two points as the injection targets: after the handshake at the start of a sync step, and after the mid-step receive. refreshSlaveGroupInjectionTargets() is renamed to refreshSlaveGroupTargets(), since it now refreshes both.
  • The rule is the one GroupStateHelper::getEffectiveProductionLimit_() applies in the control path, with one difference. There the deck's own limit is only consulted for rate types the group has its own GCONPROD limit for. A limit is reported here for every rate type, so under BOTH the deck's own limit only takes part when the group has one, as effectiveSlaveGroupInjectionTarget_() does for injection.
  • RESV is left out: GVPRT does not report a group limit, but adds up the reservoir volume rate targets of the group's wells. GVPRT, GVIRT, the master's GVPR/GVIR and gas lift are to be handled in later PRs, as discussed in Stop a reservoir coupling slave whose UDQs use a target vector it cannot report #7465.

Testing

Two runs of a three-model coupled case: a master and two slaves, METRIC units, master GCONPROD with ORAT targets and a gas limit of 6.9E6 on the master groups.

  • Unchanged case: summary output in the master and both slaves is identical to a run built from an earlier master, at zero tolerance (it reads none of the four vectors).
  • The same case, with the slave's SUMMARY asking for GOPRT, GWPRT, GGPRT and GLPRT for all groups, and a UDQ FUOPTC = GOPRT of one slave group:
    • each producing slave group's GOPRT equals the master's GOPR for its master group at every report step (the field's 9000 split by guide rate). Without this PR it reads the slave deck's own value, which is 0 here, since the slave deck has no GCONPROD;
    • the two producing slave groups' GGPRT add up to the master's 6.9E6 gas limit;
    • GWPRT and GLPRT stay 0: the master sets no water or liquid limit;
    • the UDQ equals that group's GOPRT at all 59 timesteps, including the step where the target changes, so it does not lag a step behind.

@hakonhagland hakonhagland added the manual:irrelevant This PR is a minor fix and should not appear in the manual label Oct 2, 2026
@hakonhagland
hakonhagland marked this pull request as draft October 2, 2026 04:16
@hakonhagland
hakonhagland requested a balanced review from Copilot October 2, 2026 04:16
@hakonhagland

Copy link
Copy Markdown
Contributor Author

Putting this in draft mode until OPM/opm-common#5421 has been merged

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot review overview

🟡 Changes recommended

An empty production handshake can leave stale limits that are subsequently reported as current targets.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds effective slave-group production limits so reservoir-coupling UDQs and summary vectors report master-imposed values.

Changes:

  • Computes effective GOPRT/GWPRT/GGPRT/GLPRT limits.
  • Refreshes target-dependent UDQs during synchronization.
  • Passes production limits to the opm-common summary evaluators.
File Description
BlackoilWellModelRescoup.hpp Declares production-target handling.
BlackoilWellModelRescoup_impl.hpp Computes, stores, and primes effective limits.
BlackoilWellModel_impl.hpp Invokes the expanded target refresh.
ReservoirCouplingSlave.hpp Stores effective production targets.
EclWriter.hpp Exposes targets to summary evaluation.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread opm/simulators/wells/BlackoilWellModelRescoup_impl.hpp
The master run sends a slave group a production limit for every rate
type: the target of its active control mode, and its share of the
limits further up the master's group tree.  A slave UDQ that refers to
GOPRT, GWPRT, GGPRT or GLPRT for such a group nevertheless read the
slave deck's own GCONPROD value, usually zero.

As for the injection targets, work out per slave group and rate type
the limit in force -- the master's, the deck's own, or the smaller of
the two, as the group's GRUPSLAV flag says -- at the same two points:
after the handshake at the start of a sync step, and after the mid-step
receive.  Keep it on the slave for the summary writer, which reports it
through data::ReservoirCouplingGroupRates::production_targets, and prime
the summary state with it before the group and field UDQs are evaluated.

The rule is the one GroupStateHelper::getEffectiveProductionLimit_()
applies in the control path, except that the deck's own limit only takes
part under BOTH when the group has one: that method is only reached for
rate types with an own GCONPROD limit, while a limit is reported here
for every rate type.

refreshSlaveGroupInjectionTargets() becomes refreshSlaveGroupTargets(),
since it now refreshes both.  RESV is left out: GVPRT does not report a
group limit.
@hakonhagland
hakonhagland marked this pull request as ready for review October 2, 2026 08:58
@hakonhagland

Copy link
Copy Markdown
Contributor Author

jenkins build this serial please

@totto82 totto82 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks. The opm-common part is already merged. The code looks correct.

@totto82
totto82 merged commit 1f9de3e into OPM:master Oct 2, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

manual:irrelevant This PR is a minor fix and should not appear in the manual

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants