Skip to content

Conversation

@hakonhagland
Copy link
Contributor

The solveWellWithZeroRate() method creates an empty group state and pushes it into the wgHelper object, then passes wgHelper (along with the simulator object) to iterateWellEqWithSwitching(). Further down the call chain in wellUnderZeroGroupRateTarget(), the real group state is recovered by accessing the simulator object, defeating the convention that wgHelper should be the single source of truth for the current group state.

So solveWellWithZeroRate() needs to use both an empty group state when assembling the control equation and the real group state when querying the well's actual operational status in wellUnderZeroGroupRateTarget() (to check whether its parent group has a zero rate target).

We solve this requirement by passing a flag solving_with_zero_rate down from solveWellWithZeroRate() and letting the assembleWellEqWithoutIterationImpl() method check the flag and create the empty group state locally when the flag is set. This eliminates the need for pushing/popping group state in wgHelper while maintaining the distinction between assembly (uses empty group state) and queries (uses real group state).

The issue of having both simulator and wgHelper as sources for the real group state will be addressed in a follow-up PR.


This issue with dual state opened up for the bug and jenkins failure in #6626. That PR tried to eliminate the simulator object in wellUnderZeroGroupRateTarget() and thereby accidentally using the empty group state in the wgHelper object instead, see WellInterface_impl.hpp:1692

When this PR is merged, the plan is to rebase #6626 and fix the bug there.

The solveWellWithZeroRate() method created an empty group state and pushed
it into the wgHelper object, then passed wgHelper (along with the
simulator object) to iterateWellEqWithSwitching(). Further down the
call chain in wellUnderZeroGroupRateTarget(), the real group state
was recovered by accessing the simulator object, defeating the
convention that wgHelper should be the single source of truth for
the current group state.

solveWellWithZeroRate() needs to use both an empty group state when
assembling the control equation and the real group state when querying
the well's actual operational status in wellUnderZeroGroupRateTarget()
(to check whether its parent group has a zero rate target).

We solve this by passing a flag "solving_with_zero_rate" down from
solveWellWithZeroRate() and letting the assembleWellEqWithoutIterationImpl()
method check the flag and create the empty group state locally when the
flag is set. This eliminates the need for pushing/popping group state in
wgHelper while maintaining the distinction between assembly (uses empty
group state) and queries (uses real group state).

The issue of having both simulator and wgHelper as sources for the real
group state will be addressed in a follow-up PR.
@hakonhagland hakonhagland added the manual:irrelevant This PR is a minor fix and should not appear in the manual label Nov 25, 2025
@hakonhagland
Copy link
Contributor Author

jenkins build this please

Copy link
Member

@atgeirr atgeirr left a comment

Choose a reason for hiding this comment

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

Good detective work, should eventually be merged.

Open to discuss the default arguments, if there are very good reasons we need them (for now) I am willing to let that pass.

DeferredLogger& deferred_logger,
const bool fixed_control = false,
const bool fixed_status = false) = 0;
const bool fixed_status = false,
Copy link
Member

Choose a reason for hiding this comment

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

Default arguments are not great, although they can help in the short term to avoid dealing with interface changes. I would like to avoid it when possible though! Is it feasible to remove the default arguments from this (virtual function) overload at least? It seems to me it is primarily called from the non-virtual overload and not from very many places.

If possible, we should also consider updateWellControlAndStatusLocalIteration(), but I assume the function here is easiest to remove defaults from.

if (!fixed_control) {
// When solving_with_zero_rate=true, fixed_control=true, so this block should never
// be entered.
assert(!solving_with_zero_rate);
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 assert() is best used when the logic that is assert()ed is contained within the function itself. Here it is an assumption on the function interface, for a function that does not even have any docs. While I think the check should remain, I prefer that it is an exception since the logic it checks must ensured on the function call site.

We have already changed many such assertations in the code to exceptions.

Default arguments have maintenance issues so avoid using them
if possible.
Convert assert() to throw to be consistent with usage elsewhere in
the code base where external interface violations should cause
thrown exceptions instead of causing assertion failures which will
not even be enforced in release builds.
@hakonhagland
Copy link
Contributor Author

jenkins build this please

@atgeirr
Copy link
Member

atgeirr commented Nov 27, 2025

Thanks for the improvements, merging!

@atgeirr atgeirr merged commit 64a1dc7 into OPM:master Nov 27, 2025
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.

2 participants