Skip to content

Conversation

@GitPaean
Copy link
Member

No description provided.

@GitPaean GitPaean added the manual:irrelevant This PR is a minor fix and should not appear in the manual label Oct 22, 2025
@GitPaean
Copy link
Member Author

jenkins build this please

1 similar comment
@GitPaean
Copy link
Member Author

jenkins build this please

@GitPaean
Copy link
Member Author

jenkins build this failure_report please

1 similar comment
@GitPaean
Copy link
Member Author

jenkins build this failure_report please

@GitPaean GitPaean force-pushed the reverting_to_GROUP_NONE branch from 863cb1f to 4d82ebd Compare October 27, 2025 12:04
@GitPaean
Copy link
Member Author

jenkins build this failure_report please

@GitPaean
Copy link
Member Author

GitPaean commented Oct 27, 2025

When investigating https://ci.opm-project.org/job/opm-simulators-PR-builder/8916/testReport/junit/(root)/mpi/compareECLFiles_flow_SPE9_CP_GROUP/ .

It looks like we might get zero RESV group rate at the beginning of the time step. Probably due to uninitialized well rates values are used. (checkGroupProductionConstraints is called before the rates are initialized.)

@GitPaean
Copy link
Member Author

GitPaean commented Oct 28, 2025

posting here for later reference.

In the master branch,

the following code can make the production well rate become zero. due to wellState.well(name).group_target) contain a 0 value. group_target itself is a std::optional, so 0 value is obtained somehow.

    if (schedule.hasWell(name) && wellState.well(name).group_target) { // for wells we already have computed the target
        const Scalar current_well_rate_available = -tcalc.calcModeRateFromRates(rates); // Switch sign since 'rates' are negative for producers.
        const Scalar group_target_rate_available = *wellState.well(name).group_target;
        Scalar scale = 1.0;
        if (current_well_rate_available > 1e-12) {
            scale = group_target_rate_available / current_well_rate_available;
        }

        return std::make_pair(current_well_rate_available > group_target_rate_available, scale);
    }

The calling stack is as follows,

Opm::WellGroupHelpers::checkGroupConstraintsProd WellGroupHelpers.cpp:1578
Opm::WellGroupHelpers::checkGroupConstraintsProd WellGroupHelpers.cpp:1478
Opm::WellGroupConstraints::checkGroupConstraintsProd WellGroupConstraints.cpp:115
Opm::WellGroupConstraints::checkGroupConstraints WellGroupConstraints.cpp:192
Opm::WellInterfaceFluidSystem::checkGroupConstraints WellInterfaceFluidSystem.cpp:204
Opm::WellInterface::updateWellControlAndStatusLocalIteration WellInterface_impl.hpp:320
Opm::StandardWell::iterateWellEqWithSwitching StandardWell_impl.hpp:2439
Opm::WellInterface::solveWellWithOperabilityCheck WellInterface_impl.hpp:602
Opm::WellInterface::iterateWellEquations WellInterface_impl.hpp:523
Opm::WellInterface::solveWellEquation WellInterface_impl.hpp:817
Opm::BlackoilWellModel::prepareTimeStep BlackoilWellModel_impl.hpp:2201
Opm::BlackoilWellModel::assemble BlackoilWellModel_impl.hpp:1173
Opm::BlackoilWellModel::beginIteration BlackoilWellModel.hpp:164
Opm::FlowProblem::beginIteration FlowProblem.hpp:387
Opm::BlackoilModel::assembleReservoir BlackoilModel_impl.hpp:362
Opm::BlackoilModel::initialLinearization BlackoilModel_impl.hpp:170
Opm::BlackoilModel::nonlinearIterationNewton<…> BlackoilModel_impl.hpp:260
Opm::BlackoilModel::nonlinearIteration<…> BlackoilModel_impl.hpp:232
Opm::NonlinearSolver::step NonlinearSolver.hpp:151
Opm::AdaptiveTimeStepping::SubStepIteration::runSubStep_ AdaptiveTimeStepping_impl.hpp:1158
Opm::AdaptiveTimeStepping::SubStepIteration::run AdaptiveTimeStepping_impl.hpp:778
Opm::AdaptiveTimeStepping::SubStepper::runStepOriginal_ AdaptiveTimeStepping_impl.hpp:575
Opm::AdaptiveTimeStepping::SubStepper::run AdaptiveTimeStepping_impl.hpp:491
Opm::AdaptiveTimeStepping::step<…> AdaptiveTimeStepping_impl.hpp:210
Opm::SimulatorFullyImplicitBlackoil::runStep SimulatorFullyImplicitBlackoil.hpp:503
Opm::SimulatorFullyImplicitBlackoil::run SimulatorFullyImplicitBlackoil.hpp:187
Opm::FlowMain::runSimulatorRunCallback_ FlowMain.hpp:377
Opm::FlowMain::runSimulatorInitOrRun_ FlowMain.hpp:461
Opm::FlowMain::runSimulator FlowMain.hpp:364
Opm::FlowMain::execute_ FlowMain.hpp:257
Opm::FlowMain::execute FlowMain.hpp:176
Opm::flowMain<…> Main.hpp:92
Opm::Main::dispatchStatic_<…> Main.hpp:381
Opm::Main::runStatic<…> Main.hpp:158
Opm::flowBlackoilTpfaMainStandalone flow_blackoil.cpp:77
main flow_blackoil_main.cpp:24
__libc_start_call_main 0x00007ffff742a1ca
__libc_start_main_impl 0x00007ffff742a28b
_start 0x00005555556a9065

@GitPaean
Copy link
Member Author

The usage of SingleWellState::group_target is, it is std::optional, but very often (before group control enters), it is initialized as a huge value 1.7976931348623157e+308. So the usage of the std::optional is not that helpful.

Furthermore, the if (schedule.hasWell(name) && wellState.well(name).group_target) { use the condition wellState.well(name).group_target is not valid in this sense.

have not figured out how the 0 value group_target is calculated yet.

@GitPaean
Copy link
Member Author

have not figured out how the 0 value group_target is calculated yet.

There are four wells for that group target. Four wells were under individual control earlier, and the individual rates of any three is bigger than the group target. When we try to calculate the individual group rate, all the four wells get negative group target because the other three wells are already over producing the group target based on their individual rates.

@GitPaean
Copy link
Member Author

The code that uses the group_target looks like the following,

    if (this->schedule_.hasWell(name) && this->wellState().well(name).group_target) {
        // for wells we already have computed the target

        // Switch sign since 'rates' are negative for producers.
        const Scalar current_well_rate_available = -tcalc.calcModeRateFromRates(rates);
        const Scalar group_target_rate_available = *this->wellState().well(name).group_target;
        Scalar scale = 1.0;
        if (current_well_rate_available > 1e-12) {
            scale = group_target_rate_available / current_well_rate_available;
        }

        return std::make_pair(current_well_rate_available > group_target_rate_available, scale);
    }

it is probably not doing much harm if its value is at the level of 1.7976931348623157e+308 , while the design of std::optional is not properly used.

@GitPaean GitPaean force-pushed the reverting_to_GROUP_NONE branch from 4d82ebd to a0ac7ad Compare October 29, 2025 12:59
@GitPaean
Copy link
Member Author

jenkins build this failure_report please

@GitPaean GitPaean force-pushed the reverting_to_GROUP_NONE branch from a0ac7ad to 41f3a96 Compare October 30, 2025 11:35
@GitPaean
Copy link
Member Author

GitPaean commented Nov 7, 2025

This way turns out to be too hard. Closing this one to favor the approach in #6596 .

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.

1 participant