diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index c194df689..043c2c2f1 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -1324,7 +1324,8 @@ namespace Opm { OPM_BEGIN_PARALLEL_TRY_CATCH(); { for (auto& well : well_container_) { - well->recoverWellSolutionAndUpdateWellState(x, this->wellState(), local_deferredLogger); + const auto& summary_state = ebosSimulator_.vanguard().summaryState(); + well->recoverWellSolutionAndUpdateWellState(summary_state, x, this->wellState(), local_deferredLogger); } } @@ -1659,7 +1660,8 @@ namespace Opm { auto& events = this->wellState().well(well->indexOfWell()).events; if (events.hasEvent(WellState::event_mask)) { well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger); - well->updatePrimaryVariables(this->wellState(), deferred_logger); + const auto& summary_state = ebosSimulator_.vanguard().summaryState(); + well->updatePrimaryVariables(summary_state, this->wellState(), deferred_logger); well->initPrimaryVariablesEvaluation(); // There is no new well control change input within a report step, // so next time step, the well does not consider to have effective events anymore. @@ -1733,7 +1735,8 @@ namespace Opm { updatePrimaryVariables(DeferredLogger& deferred_logger) { for (const auto& well : well_container_) { - well->updatePrimaryVariables(this->wellState(), deferred_logger); + const auto& summary_state = ebosSimulator_.vanguard().summaryState(); + well->updatePrimaryVariables(summary_state, this->wellState(), deferred_logger); } } diff --git a/opm/simulators/wells/MultisegmentWell.hpp b/opm/simulators/wells/MultisegmentWell.hpp index 4b0989f55..332daa2e8 100644 --- a/opm/simulators/wells/MultisegmentWell.hpp +++ b/opm/simulators/wells/MultisegmentWell.hpp @@ -108,7 +108,8 @@ namespace Opm /// using the solution x to recover the solution xw for wells and applying /// xw to update Well State - void recoverWellSolutionAndUpdateWellState(const BVector& x, + void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state, + const BVector& x, WellState& well_state, DeferredLogger& deferred_logger) override; @@ -118,9 +119,13 @@ namespace Opm std::vector& well_potentials, DeferredLogger& deferred_logger) override; - void updatePrimaryVariables(const WellState& well_state, DeferredLogger& deferred_logger) override; + void updatePrimaryVariables(const SummaryState& summary_state, + const WellState& well_state, + DeferredLogger& deferred_logger) override; - virtual void solveEqAndUpdateWellState(WellState& well_state, DeferredLogger& deferred_logger) override; // const? + virtual void solveEqAndUpdateWellState(const Simulator& ebos_simulator, + WellState& well_state, + DeferredLogger& deferred_logger) override; // const? virtual void calculateExplicitQuantities(const Simulator& ebosSimulator, const WellState& well_state, @@ -171,7 +176,8 @@ namespace Opm mutable int debug_cost_counter_ = 0; // updating the well_state based on well solution dwells - void updateWellState(const BVectorWell& dwells, + void updateWellState(const SummaryState& summary_state, + const BVectorWell& dwells, WellState& well_state, DeferredLogger& deferred_logger, const double relaxation_factor = 1.0); diff --git a/opm/simulators/wells/MultisegmentWellAssemble.cpp b/opm/simulators/wells/MultisegmentWellAssemble.cpp index f279fba02..ec9cee24c 100644 --- a/opm/simulators/wells/MultisegmentWellAssemble.cpp +++ b/opm/simulators/wells/MultisegmentWellAssemble.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -163,7 +164,7 @@ assembleControlEq(const WellState& well_state, bhp_from_thp, control_eq, deferred_logger); - } else if (rateControlWithZeroTarget(well_state.well(well_.indexOfWell()).production_cmode, prod_controls)) { + } else if (wellhelpers::rateControlWithZeroTarget(well_state.well(well_.indexOfWell()).production_cmode, prod_controls)) { // Production mode, zero target. Treat as STOP. control_eq = primary_variables.getWQTotal(); } else { diff --git a/opm/simulators/wells/MultisegmentWellPrimaryVariables.cpp b/opm/simulators/wells/MultisegmentWellPrimaryVariables.cpp index 72b18a72b..e1fd2c003 100644 --- a/opm/simulators/wells/MultisegmentWellPrimaryVariables.cpp +++ b/opm/simulators/wells/MultisegmentWellPrimaryVariables.cpp @@ -64,7 +64,7 @@ init() template void MultisegmentWellPrimaryVariables:: -update(const WellState& well_state) +update(const WellState& well_state, const bool zero_rate_target) { static constexpr int Water = BlackoilPhases::Aqua; static constexpr int Gas = BlackoilPhases::Vapour; @@ -104,6 +104,9 @@ update(const WellState& well_state) } } value_[seg][WQTotal] = total_seg_rate; + if (zero_rate_target && seg == 0) { + value_[seg][WQTotal] = 0; + } if (std::abs(total_seg_rate) > 0.) { if (has_wfrac_variable) { const int water_pos = pu.phase_pos[Water]; @@ -152,6 +155,7 @@ void MultisegmentWellPrimaryVariables:: updateNewton(const BVectorWell& dwells, const double relaxation_factor, const double dFLimit, + const bool zero_rate_target, const double max_pressure_change) { const std::vector> old_primary_variables = value_; @@ -193,6 +197,10 @@ updateNewton(const BVectorWell& dwells, } } } + + if (zero_rate_target) { + value_[0][WQTotal] = 0.; + } } template diff --git a/opm/simulators/wells/MultisegmentWellPrimaryVariables.hpp b/opm/simulators/wells/MultisegmentWellPrimaryVariables.hpp index 6d2b84076..5dce2d536 100644 --- a/opm/simulators/wells/MultisegmentWellPrimaryVariables.hpp +++ b/opm/simulators/wells/MultisegmentWellPrimaryVariables.hpp @@ -88,12 +88,13 @@ public: void init(); //! \brief Copy values from well state. - void update(const WellState& well_state); + void update(const WellState& well_state, const bool zero_rate_target); //! \brief Update values from newton update vector. void updateNewton(const BVectorWell& dwells, const double relaxation_factor, const double DFLimit, + const bool zero_rate_target, const double max_pressure_change); //! \brief Copy values to well state. diff --git a/opm/simulators/wells/MultisegmentWell_impl.hpp b/opm/simulators/wells/MultisegmentWell_impl.hpp index 129fd4d24..566fa67e2 100644 --- a/opm/simulators/wells/MultisegmentWell_impl.hpp +++ b/opm/simulators/wells/MultisegmentWell_impl.hpp @@ -148,9 +148,12 @@ namespace Opm template void MultisegmentWell:: - updatePrimaryVariables(const WellState& well_state, DeferredLogger& /* deferred_logger */) + updatePrimaryVariables(const SummaryState& summary_state, + const WellState& well_state, + DeferredLogger& /* deferred_logger */) { - this->primary_variables_.update(well_state); + const bool zero_rate_target = this->wellUnderZeroProductionRateControl(summary_state, well_state); + this->primary_variables_.update(well_state, zero_rate_target); } @@ -240,7 +243,8 @@ namespace Opm template void MultisegmentWell:: - recoverWellSolutionAndUpdateWellState(const BVector& x, + recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state, + const BVector& x, WellState& well_state, DeferredLogger& deferred_logger) { @@ -250,7 +254,7 @@ namespace Opm BVectorWell xw(1); this->linSys_.recoverSolutionWell(x, xw); - updateWellState(xw, well_state, deferred_logger); + updateWellState(summary_state, xw, well_state, deferred_logger); } @@ -528,7 +532,9 @@ namespace Opm template void MultisegmentWell:: - solveEqAndUpdateWellState(WellState& well_state, DeferredLogger& deferred_logger) + solveEqAndUpdateWellState(const Simulator& ebos_simulator, + WellState& well_state, + DeferredLogger& deferred_logger) { if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; @@ -536,7 +542,8 @@ namespace Opm // which is why we do not put the assembleWellEq here. const BVectorWell dx_well = this->linSys_.solve(); - updateWellState(dx_well, well_state, deferred_logger); + const auto& summary_state = ebos_simulator.vanguard().summaryState(); + updateWellState(summary_state, dx_well, well_state, deferred_logger); } @@ -619,7 +626,8 @@ namespace Opm template void MultisegmentWell:: - updateWellState(const BVectorWell& dwells, + updateWellState(const SummaryState& summary_state, + const BVectorWell& dwells, WellState& well_state, DeferredLogger& deferred_logger, const double relaxation_factor) @@ -628,9 +636,11 @@ namespace Opm const double dFLimit = this->param_.dwell_fraction_max_; const double max_pressure_change = this->param_.max_pressure_change_ms_wells_; + const bool zero_rate_target = this->wellUnderZeroProductionRateControl(summary_state, well_state); this->primary_variables_.updateNewton(dwells, relaxation_factor, dFLimit, + zero_rate_target, max_pressure_change); this->primary_variables_.copyToWellState(*this, getRefDensity(), @@ -649,7 +659,8 @@ namespace Opm const WellState& well_state, DeferredLogger& deferred_logger) { - updatePrimaryVariables(well_state, deferred_logger); + const auto& summary_state = ebosSimulator.vanguard().summaryState(); + updatePrimaryVariables(summary_state, well_state, deferred_logger); initPrimaryVariablesEvaluation(); computePerfCellPressDiffs(ebosSimulator); computeInitialSegmentFluids(ebosSimulator); @@ -1492,7 +1503,8 @@ namespace Opm this->regularize_ = true; deferred_logger.debug(sstr.str()); } - updateWellState(dx_well, well_state, deferred_logger, relaxation_factor); + const auto& summary_state = ebosSimulator.vanguard().summaryState(); + updateWellState(summary_state, dx_well, well_state, deferred_logger, relaxation_factor); initPrimaryVariablesEvaluation(); } diff --git a/opm/simulators/wells/StandardWell.hpp b/opm/simulators/wells/StandardWell.hpp index c9253c2c7..ca0629a30 100644 --- a/opm/simulators/wells/StandardWell.hpp +++ b/opm/simulators/wells/StandardWell.hpp @@ -156,7 +156,8 @@ namespace Opm /// using the solution x to recover the solution xw for wells and applying /// xw to update Well State - void recoverWellSolutionAndUpdateWellState(const BVector& x, + void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state, + const BVector& x, WellState& well_state, DeferredLogger& deferred_logger) override; @@ -166,9 +167,13 @@ namespace Opm std::vector& well_potentials, DeferredLogger& deferred_logger) /* const */ override; - void updatePrimaryVariables(const WellState& well_state, DeferredLogger& deferred_logger) override; + void updatePrimaryVariables(const SummaryState& summary_state, + const WellState& well_state, + DeferredLogger& deferred_logger) override; - virtual void solveEqAndUpdateWellState(WellState& well_state, DeferredLogger& deferred_logger) override; + void solveEqAndUpdateWellState(const SummaryState& summary_state, + WellState& well_state, + DeferredLogger& deferred_logger); virtual void calculateExplicitQuantities(const Simulator& ebosSimulator, const WellState& well_state, @@ -252,7 +257,8 @@ namespace Opm bool regularize_; // updating the well_state based on well solution dwells - void updateWellState(const BVectorWell& dwells, + void updateWellState(const SummaryState& summary_state, + const BVectorWell& dwells, WellState& well_state, DeferredLogger& deferred_logger); @@ -359,7 +365,7 @@ namespace Opm DeferredLogger& deferred_logger) const; void updatePrimaryVariablesNewton(const BVectorWell& dwells, - const WellState& well_state, + const bool zero_rate_target, DeferredLogger& deferred_logger); void updateWellStateFromPrimaryVariables(WellState& well_state, DeferredLogger& deferred_logger) const; diff --git a/opm/simulators/wells/StandardWellAssemble.cpp b/opm/simulators/wells/StandardWellAssemble.cpp index 49d191a27..76803b84a 100644 --- a/opm/simulators/wells/StandardWellAssemble.cpp +++ b/opm/simulators/wells/StandardWellAssemble.cpp @@ -143,7 +143,7 @@ assembleControlEq(const WellState& well_state, bhp_from_thp, control_eq, deferred_logger); - } else if (rateControlWithZeroTarget(well_state.well(well_.indexOfWell()).production_cmode, prod_controls)) { + } else if (wellhelpers::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 { diff --git a/opm/simulators/wells/StandardWellPrimaryVariables.cpp b/opm/simulators/wells/StandardWellPrimaryVariables.cpp index 9124b898e..82858d956 100644 --- a/opm/simulators/wells/StandardWellPrimaryVariables.cpp +++ b/opm/simulators/wells/StandardWellPrimaryVariables.cpp @@ -81,7 +81,7 @@ Scalar relaxationFactorRate(const Scalar old_value, const Scalar original_total_rate = old_value; const Scalar possible_update_total_rate = old_value - newton_update; - // 0.8 here is a experimental value, which remains to be optimized + // 0.8 here is an experimental value, which remains to be optimized // if the original rate is zero or possible_update_total_rate is zero, relaxation_factor will // always be 1.0, more thoughts might be needed. if (original_total_rate * possible_update_total_rate < 0.) { // sign changed @@ -121,7 +121,9 @@ resize(const int numWellEq) template void StandardWellPrimaryVariables:: -update(const WellState& well_state, DeferredLogger& deferred_logger) +update(const WellState& well_state, + const bool zero_rate_target, + DeferredLogger& deferred_logger) { static constexpr int Water = BlackoilPhases::Aqua; static constexpr int Oil = BlackoilPhases::Liquid; @@ -158,6 +160,9 @@ update(const WellState& well_state, DeferredLogger& deferred_logger) } } else { value_[WQTotal] = total_well_rate; + if (zero_rate_target) { + value_[WQTotal] = 0.; + } } if (std::abs(total_well_rate) > 0.) { @@ -240,6 +245,7 @@ updatePolyMW(const WellState& well_state) template void StandardWellPrimaryVariables:: updateNewton(const BVectorWell& dwells, + const bool zero_rate_target, [[maybe_unused]] const double dFLimit, const double dBHPLimit) { @@ -275,6 +281,10 @@ updateNewton(const BVectorWell& dwells, // updating the total rates Q_t value_[WQTotal] = value_[WQTotal] - dwells[0][WQTotal] * relaxation_factor_rate; + if (zero_rate_target) { + value_[WQTotal] = 0.; + } + // TODO: here, we make sure it is zero for zero rated wells // updating the bottom hole pressure const int sign1 = dwells[0][Bhp] > 0 ? 1: -1; diff --git a/opm/simulators/wells/StandardWellPrimaryVariables.hpp b/opm/simulators/wells/StandardWellPrimaryVariables.hpp index 4c301e4e1..aecf29a4b 100644 --- a/opm/simulators/wells/StandardWellPrimaryVariables.hpp +++ b/opm/simulators/wells/StandardWellPrimaryVariables.hpp @@ -101,13 +101,16 @@ public: int numWellEq() const { return numWellEq_; } //! \brief Copy values from well state. - void update(const WellState& well_state, DeferredLogger& deferred_logger); + void update(const WellState& well_state, + const bool zero_rate_target, + DeferredLogger& deferred_logger); //! \brief Copy polymer molecular weigt values from well state. void updatePolyMW(const WellState& well_state); //! \brief Update values from newton update vector. void updateNewton(const BVectorWell& dwells, + const bool zero_rate_target, const double dFLimit, const double dBHPLimit); diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 3f87cbbf4..fc6b824ab 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -993,13 +993,15 @@ namespace Opm template void StandardWell:: - updateWellState(const BVectorWell& dwells, + updateWellState(const SummaryState& summary_state, + const BVectorWell& dwells, WellState& well_state, DeferredLogger& deferred_logger) { if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; - updatePrimaryVariablesNewton(dwells, well_state, deferred_logger); + const bool zero_rate_target = this->wellUnderZeroProductionRateControl(summary_state, well_state); + updatePrimaryVariablesNewton(dwells, zero_rate_target, deferred_logger); updateWellStateFromPrimaryVariables(well_state, deferred_logger); Base::calculateReservoirRates(well_state.well(this->index_of_well_)); @@ -1013,12 +1015,12 @@ namespace Opm void StandardWell:: updatePrimaryVariablesNewton(const BVectorWell& dwells, - const WellState& /* well_state */, + const bool zero_rate_target, DeferredLogger& deferred_logger) { const double dFLimit = this->param_.dwell_fraction_max_; const double dBHPLimit = this->param_.dbhp_max_rel_; - this->primary_variables_.updateNewton(dwells, dFLimit, dBHPLimit); + this->primary_variables_.updateNewton(dwells, zero_rate_target, dFLimit, dBHPLimit); // for the water velocity and skin pressure if constexpr (Base::has_polymermw) { @@ -1581,7 +1583,9 @@ namespace Opm template void StandardWell:: - solveEqAndUpdateWellState(WellState& well_state, DeferredLogger& deferred_logger) + solveEqAndUpdateWellState(const SummaryState& summary_state, + WellState& well_state, + DeferredLogger& deferred_logger) { if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; @@ -1591,7 +1595,7 @@ namespace Opm dx_well[0].resize(this->primary_variables_.numWellEq()); this->linSys_.solve( dx_well); - updateWellState(dx_well, well_state, deferred_logger); + updateWellState(summary_state, dx_well, well_state, deferred_logger); } @@ -1605,7 +1609,8 @@ namespace Opm const WellState& well_state, DeferredLogger& deferred_logger) { - updatePrimaryVariables(well_state, deferred_logger); + const auto& summary_state = ebosSimulator.vanguard().summaryState(); + updatePrimaryVariables(summary_state, well_state, deferred_logger); initPrimaryVariablesEvaluation(); computeWellConnectionPressures(ebosSimulator, well_state, deferred_logger); this->computeAccumWell(); @@ -1648,7 +1653,8 @@ namespace Opm template void StandardWell:: - recoverWellSolutionAndUpdateWellState(const BVector& x, + recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state, + const BVector& x, WellState& well_state, DeferredLogger& deferred_logger) { @@ -1658,7 +1664,7 @@ namespace Opm xw[0].resize(this->primary_variables_.numWellEq()); this->linSys_.recoverSolutionWell(x, xw); - updateWellState(xw, well_state, deferred_logger); + updateWellState(summary_state, xw, well_state, deferred_logger); } @@ -1754,7 +1760,7 @@ namespace Opm " potentials are computed based on unconverged solution"; deferred_logger.debug(msg); } - well_copy.updatePrimaryVariables(well_state_copy, deferred_logger); + well_copy.updatePrimaryVariables(summary_state, well_state_copy, deferred_logger); well_copy.computeWellConnectionPressures(ebosSimulator, well_state_copy, deferred_logger); well_copy.initPrimaryVariablesEvaluation(); well_copy.computeWellRatesWithBhp(ebosSimulator, bhp, well_flux, deferred_logger); @@ -1970,11 +1976,14 @@ namespace Opm template void StandardWell:: - updatePrimaryVariables(const WellState& well_state, DeferredLogger& deferred_logger) + updatePrimaryVariables(const SummaryState& summary_state, + const WellState& well_state, + DeferredLogger& deferred_logger) { if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; - this->primary_variables_.update(well_state, deferred_logger); + const bool zero_rate_target = this->wellUnderZeroProductionRateControl(summary_state, well_state); + this->primary_variables_.update(well_state, zero_rate_target, deferred_logger); // other primary variables related to polymer injection if constexpr (Base::has_polymermw) { @@ -2511,7 +2520,8 @@ namespace Opm } ++it; - solveEqAndUpdateWellState(well_state, deferred_logger); + const auto& summary_state = ebosSimulator.vanguard().summaryState(); + solveEqAndUpdateWellState(summary_state, well_state, deferred_logger); // TODO: when this function is used for well testing purposes, will need to check the controls, so that we will obtain convergence // under the most restrictive control. Based on this converged results, we can check whether to re-open the well. Either we refactor diff --git a/opm/simulators/wells/WellAssemble.cpp b/opm/simulators/wells/WellAssemble.cpp index fa1bb4af5..40d92c96d 100644 --- a/opm/simulators/wells/WellAssemble.cpp +++ b/opm/simulators/wells/WellAssemble.cpp @@ -43,32 +43,6 @@ 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 9672195b1..3e4c4bc15 100644 --- a/opm/simulators/wells/WellAssemble.hpp +++ b/opm/simulators/wells/WellAssemble.hpp @@ -44,10 +44,6 @@ 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; diff --git a/opm/simulators/wells/WellHelpers.cpp b/opm/simulators/wells/WellHelpers.cpp index 69dd95acd..874fca857 100644 --- a/opm/simulators/wells/WellHelpers.cpp +++ b/opm/simulators/wells/WellHelpers.cpp @@ -25,6 +25,9 @@ #include +#include +#include + #include #include @@ -168,6 +171,33 @@ DenseMatrix transposeDenseDynMatrix(const DenseMatrix& M) return tmp; } +bool rateControlWithZeroTarget(const WellProducerCMode& mode, + const WellProductionControls& controls) +{ + switch (mode) { + case WellProducerCMode::ORAT: + return controls.oil_rate == 0.0; + case WellProducerCMode::WRAT: + return controls.water_rate == 0.0; + case WellProducerCMode::GRAT: + return controls.gas_rate == 0.0; + case WellProducerCMode::LRAT: + return controls.liquid_rate == 0.0; + case WellProducerCMode::CRAT: + // Unsupported, will cause exception elsewhere, treat as nonzero target here. + return false; + case WellProducerCMode::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 class ParallelStandardWellB; template using Vec = Dune::BlockVector>; diff --git a/opm/simulators/wells/WellHelpers.hpp b/opm/simulators/wells/WellHelpers.hpp index 3a4e62238..f68d66c16 100644 --- a/opm/simulators/wells/WellHelpers.hpp +++ b/opm/simulators/wells/WellHelpers.hpp @@ -31,6 +31,8 @@ namespace Opm { class ParallelWellInfo; +enum class WellProducerCMode; +class WellProductionControls; namespace wellhelpers { @@ -83,6 +85,10 @@ void sumDistributedWellEntries(Dune::DynamicMatrix& mat, template DenseMatrix transposeDenseDynMatrix(const DenseMatrix& M); +/// Helper to check whether the well is under zero production rate control +bool rateControlWithZeroTarget(const WellProducerCMode& mode, + const WellProductionControls& controls); + } // namespace wellhelpers } // namespace Opm diff --git a/opm/simulators/wells/WellInterface.hpp b/opm/simulators/wells/WellInterface.hpp index b6c57984d..5508580f3 100644 --- a/opm/simulators/wells/WellInterface.hpp +++ b/opm/simulators/wells/WellInterface.hpp @@ -156,7 +156,9 @@ public: virtual ConvergenceReport getWellConvergence(const WellState& well_state, const std::vector& B_avg, DeferredLogger& deferred_logger, const bool relax_tolerance) const = 0; - virtual void solveEqAndUpdateWellState(WellState& well_state, DeferredLogger& deferred_logger) = 0; + virtual void solveEqAndUpdateWellState(const Simulator& ebos_simulator, + WellState& well_state, + DeferredLogger& deferred_logger) = 0; void assembleWellEq(const Simulator& ebosSimulator, const double dt, @@ -180,7 +182,8 @@ public: /// using the solution x to recover the solution xw for wells and applying /// xw to update Well State - virtual void recoverWellSolutionAndUpdateWellState(const BVector& x, + virtual void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state, + const BVector& x, WellState& well_state, DeferredLogger& deferred_logger) = 0; @@ -212,7 +215,9 @@ public: const GroupState& group_state, DeferredLogger& deferred_logger) /* const */; - virtual void updatePrimaryVariables(const WellState& well_state, DeferredLogger& deferred_logger) = 0; + virtual void updatePrimaryVariables(const SummaryState& summary_state, + const WellState& well_state, + DeferredLogger& deferred_logger) = 0; virtual void calculateExplicitQuantities(const Simulator& ebosSimulator, const WellState& well_state, @@ -359,7 +364,8 @@ protected: Eval getPerfCellPressure(const FluidState& fs) const; - + bool wellUnderZeroProductionRateControl(const SummaryState& summary_state, + const WellState& well_state) const; }; } diff --git a/opm/simulators/wells/WellInterface_impl.hpp b/opm/simulators/wells/WellInterface_impl.hpp index 0918e5b81..31af6b0a8 100644 --- a/opm/simulators/wells/WellInterface_impl.hpp +++ b/opm/simulators/wells/WellInterface_impl.hpp @@ -26,6 +26,7 @@ #include #include #include +#include #include @@ -244,7 +245,7 @@ namespace Opm this->well_control_log_.push_back(from); updateWellStateWithTarget(ebos_simulator, group_state, well_state, deferred_logger); - updatePrimaryVariables(well_state, deferred_logger); + updatePrimaryVariables(summaryState, well_state, deferred_logger); } return changed; @@ -269,7 +270,8 @@ namespace Opm updateWellStateWithTarget(simulator, group_state, well_state_copy, deferred_logger); calculateExplicitQuantities(simulator, well_state_copy, deferred_logger); - updatePrimaryVariables(well_state_copy, deferred_logger); + const auto& summary_state = simulator.vanguard().summaryState(); + updatePrimaryVariables(summary_state, well_state_copy, deferred_logger); initPrimaryVariablesEvaluation(); if (this->isProducer()) { @@ -1128,4 +1130,19 @@ namespace Opm return fs.pressure(FluidSystem::gasPhaseIdx); } } + + + template + bool WellInterface::wellUnderZeroProductionRateControl(const SummaryState& summary_state, + const WellState& well_state) const + { + if (this->wellIsStopped()) return true; + + bool zero_rate_target = false; + if (this->well_ecl_.isProducer()) { + const auto prod_controls = this->well_ecl_.productionControls(summary_state); + zero_rate_target = wellhelpers::rateControlWithZeroTarget(well_state.well(this->index_of_well_).production_cmode, prod_controls); + } + return zero_rate_target; + } } // namespace Opm