Update GCONSUMP.DATA and GCONSUMP_COMPLEX.DATA to be valid input for
full simulation runs while preserving their unit test functionality:
- Fix EQUIL datum depth to match gas-oil contact (7020 → 7000)
- Fix PVTO bubble point relationship (Rs/Pbub must be monotonic)
- Extend PVDG pressure range to cover reservoir pressure (→ 300 bar)
- Adjust SGOF Sg_max to avoid floating-point SOGCR precision issue
The GCONSUMP efficiency factor calculation was incorrectly applying group
efficiency factors to the groups themselves, rather than following the
the pattern used elsewhere in the code base:
- Groups are NOT affected by their own efficiency factors
- Parent groups apply child efficiency factors when accumulating contributions
Changes:
- Fix GroupState::update_gconsump() to implement correct efficiency pattern
- Add test suite with simple and complex hierarchy scenarios
Extract duplicated target calculation algorithm from four methods
into two reusable helper methods:
- getLocalReductionLevel_(): Finds the deepest level in the group chain
where a group has both a guide rate and group-controlled wells (GCW > 0)
- applyReductionsAndFractions_(): Applies local reductions, add-back
(when applicable), and guide rate fractions to calculate the portion
of a top-level group target assigned to a bottom group
The refactored methods are:
- checkGroupConstraintsInj()
- checkGroupConstraintsProd()
- getWellGroupTargetInjector()
- getWellGroupTargetProducer()
This is a pure refactoring with no functional change. The helper methods
use templates for the reduction and fraction lambdas to avoid std::function
overhead in case of performance-critical code.
Move the auto choke exclusion logic out of the well loop in
updateGroupControlledWellsRecursive_() and into a new helper method
isAutoChokeGroupUnderperforming_(). The calculation determines whether
to exclude all wells in an auto choke group from the Group Controlled
Wells (GCW) count based on whether the group is meeting its target rate.
The original code recalculated this group-level decision redundantly
for each well in the loop, even though the result is the same for all
wells. The refactored code computes it once before the loop.
This is a pure refactoring with no functional change.
The master-slave synchronization code in beginTimeStep() was executing
on every internal substep within a "sync" timestep. This is incorrect
because:
1. The SubStepIteration loop typically splits a sync timestep into
multiple smaller internal substeps for numerical stability
2. After the first internal substep, master and slaves are at different
simulation times and cannot exchange data correctly
3. Repeated sync attempts would cause deadlocks or incorrect data
This fix adds an isFirstSubstepOfSyncTimestep flag to track whether we
are at the start of a coordinated "sync" timestep. The flag is:
- Set to true before each SubStepIteration::run() call
- Cleared to false after the first runSubStep_() returns