diff --git a/opm/simulators/wells/MultisegmentWellAssemble.cpp b/opm/simulators/wells/MultisegmentWellAssemble.cpp index d2b302534..0a1650201 100644 --- a/opm/simulators/wells/MultisegmentWellAssemble.cpp +++ b/opm/simulators/wells/MultisegmentWellAssemble.cpp @@ -35,6 +35,7 @@ #include #include #include +#include namespace Opm { @@ -162,6 +163,9 @@ assembleControlEq(const WellState& well_state, bhp_from_thp, control_eq, deferred_logger); + } else if (rateControlWithZeroTarget(well_state.well(well_.indexOfWell()).production_cmode, prod_controls)) { + // Production mode, zero target. Treat as STOP. + control_eq = primary_variables.getWQTotal(); } else { // Find rates. const auto rates = getRates(); diff --git a/opm/simulators/wells/StandardWellAssemble.cpp b/opm/simulators/wells/StandardWellAssemble.cpp index ed568497c..49d191a27 100644 --- a/opm/simulators/wells/StandardWellAssemble.cpp +++ b/opm/simulators/wells/StandardWellAssemble.cpp @@ -36,6 +36,7 @@ #include #include #include +#include namespace Opm { @@ -142,6 +143,9 @@ assembleControlEq(const WellState& well_state, bhp_from_thp, control_eq, deferred_logger); + } else if (rateControlWithZeroTarget(well_state.well(well_.indexOfWell()).production_cmode, prod_controls)) { + // Production mode, zero target. Treat as STOP. + control_eq = primary_variables.eval(PrimaryVariables::WQTotal); } else { // Find rates. const auto rates = getRates(); diff --git a/opm/simulators/wells/WellAssemble.cpp b/opm/simulators/wells/WellAssemble.cpp index 40d92c96d..fa1bb4af5 100644 --- a/opm/simulators/wells/WellAssemble.cpp +++ b/opm/simulators/wells/WellAssemble.cpp @@ -43,6 +43,32 @@ namespace Opm { +bool rateControlWithZeroTarget(const Well::ProducerCMode mode, + const Well::ProductionControls& controls) +{ + switch (mode) { + case Well::ProducerCMode::ORAT: + return controls.oil_rate == 0.0; + case Well::ProducerCMode::WRAT: + return controls.water_rate == 0.0; + case Well::ProducerCMode::GRAT: + return controls.gas_rate == 0.0; + case Well::ProducerCMode::LRAT: + return controls.liquid_rate == 0.0; + case Well::ProducerCMode::CRAT: + // Unsupported, will cause exception elsewhere, treat as nonzero target here. + return false; + case Well::ProducerCMode::RESV: + if (controls.prediction_mode) { + return controls.resv_rate == 0.0; + } else { + return controls.water_rate == 0.0 && controls.oil_rate == 0.0 && controls.gas_rate == 0.0; + } + default: + return false; + } +} + template WellAssemble:: WellAssemble(const WellInterfaceFluidSystem& well) diff --git a/opm/simulators/wells/WellAssemble.hpp b/opm/simulators/wells/WellAssemble.hpp index ee584eb63..9672195b1 100644 --- a/opm/simulators/wells/WellAssemble.hpp +++ b/opm/simulators/wells/WellAssemble.hpp @@ -27,6 +27,7 @@ #include #include +#include #include @@ -43,6 +44,10 @@ class WellState; class WellInjectionControls; class WellProductionControls; +/// Helper to avoid singular control equations. +bool rateControlWithZeroTarget(const WellProducerCMode mode, + const WellProductionControls& controls); + template class WellAssemble { static constexpr int Water = BlackoilPhases::Aqua; @@ -80,6 +85,8 @@ private: const WellInterfaceFluidSystem& well_; }; + + } #endif // OPM_WELL_ASSEMBLE_HEADER_INCLUDED