make sure zero production rates are obtained for the following wells

1. stopped production wells
2. production wells under zero rate control

We guarantee the objective through enforce zero values for the WQTotal
primary variable during the initialization and update process during the
Newton solution.
This commit is contained in:
Kai Bao 2023-03-22 15:10:00 +01:00
parent 8858d725a8
commit 2c5a4398c9
17 changed files with 166 additions and 77 deletions

View File

@ -1324,7 +1324,8 @@ namespace Opm {
OPM_BEGIN_PARALLEL_TRY_CATCH(); OPM_BEGIN_PARALLEL_TRY_CATCH();
{ {
for (auto& well : well_container_) { 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; auto& events = this->wellState().well(well->indexOfWell()).events;
if (events.hasEvent(WellState::event_mask)) { if (events.hasEvent(WellState::event_mask)) {
well->updateWellStateWithTarget(ebosSimulator_, this->groupState(), this->wellState(), deferred_logger); 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(); well->initPrimaryVariablesEvaluation();
// There is no new well control change input within a report step, // 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. // so next time step, the well does not consider to have effective events anymore.
@ -1733,7 +1735,8 @@ namespace Opm {
updatePrimaryVariables(DeferredLogger& deferred_logger) updatePrimaryVariables(DeferredLogger& deferred_logger)
{ {
for (const auto& well : well_container_) { 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);
} }
} }

View File

@ -108,7 +108,8 @@ namespace Opm
/// using the solution x to recover the solution xw for wells and applying /// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State /// xw to update Well State
void recoverWellSolutionAndUpdateWellState(const BVector& x, void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
const BVector& x,
WellState& well_state, WellState& well_state,
DeferredLogger& deferred_logger) override; DeferredLogger& deferred_logger) override;
@ -118,9 +119,13 @@ namespace Opm
std::vector<double>& well_potentials, std::vector<double>& well_potentials,
DeferredLogger& deferred_logger) override; 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, virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state, const WellState& well_state,
@ -171,7 +176,8 @@ namespace Opm
mutable int debug_cost_counter_ = 0; mutable int debug_cost_counter_ = 0;
// updating the well_state based on well solution dwells // 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, WellState& well_state,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
const double relaxation_factor = 1.0); const double relaxation_factor = 1.0);

View File

@ -34,6 +34,7 @@
#include <opm/simulators/wells/MultisegmentWellPrimaryVariables.hpp> #include <opm/simulators/wells/MultisegmentWellPrimaryVariables.hpp>
#include <opm/simulators/wells/WellAssemble.hpp> #include <opm/simulators/wells/WellAssemble.hpp>
#include <opm/simulators/wells/WellBhpThpCalculator.hpp> #include <opm/simulators/wells/WellBhpThpCalculator.hpp>
#include <opm/simulators/wells/WellHelpers.hpp>
#include <opm/simulators/wells/WellInterfaceIndices.hpp> #include <opm/simulators/wells/WellInterfaceIndices.hpp>
#include <opm/simulators/wells/WellState.hpp> #include <opm/simulators/wells/WellState.hpp>
@ -163,7 +164,7 @@ assembleControlEq(const WellState& well_state,
bhp_from_thp, bhp_from_thp,
control_eq, control_eq,
deferred_logger); 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. // Production mode, zero target. Treat as STOP.
control_eq = primary_variables.getWQTotal(); control_eq = primary_variables.getWQTotal();
} else { } else {

View File

@ -64,7 +64,7 @@ init()
template<class FluidSystem, class Indices, class Scalar> template<class FluidSystem, class Indices, class Scalar>
void MultisegmentWellPrimaryVariables<FluidSystem,Indices,Scalar>:: void MultisegmentWellPrimaryVariables<FluidSystem,Indices,Scalar>::
update(const WellState& well_state) update(const WellState& well_state, const bool zero_rate_target)
{ {
static constexpr int Water = BlackoilPhases::Aqua; static constexpr int Water = BlackoilPhases::Aqua;
static constexpr int Gas = BlackoilPhases::Vapour; static constexpr int Gas = BlackoilPhases::Vapour;
@ -104,6 +104,9 @@ update(const WellState& well_state)
} }
} }
value_[seg][WQTotal] = total_seg_rate; value_[seg][WQTotal] = total_seg_rate;
if (zero_rate_target && seg == 0) {
value_[seg][WQTotal] = 0;
}
if (std::abs(total_seg_rate) > 0.) { if (std::abs(total_seg_rate) > 0.) {
if (has_wfrac_variable) { if (has_wfrac_variable) {
const int water_pos = pu.phase_pos[Water]; const int water_pos = pu.phase_pos[Water];
@ -152,6 +155,7 @@ void MultisegmentWellPrimaryVariables<FluidSystem,Indices,Scalar>::
updateNewton(const BVectorWell& dwells, updateNewton(const BVectorWell& dwells,
const double relaxation_factor, const double relaxation_factor,
const double dFLimit, const double dFLimit,
const bool zero_rate_target,
const double max_pressure_change) const double max_pressure_change)
{ {
const std::vector<std::array<double, numWellEq>> old_primary_variables = value_; const std::vector<std::array<double, numWellEq>> old_primary_variables = value_;
@ -193,6 +197,10 @@ updateNewton(const BVectorWell& dwells,
} }
} }
} }
if (zero_rate_target) {
value_[0][WQTotal] = 0.;
}
} }
template<class FluidSystem, class Indices, class Scalar> template<class FluidSystem, class Indices, class Scalar>

View File

@ -88,12 +88,13 @@ public:
void init(); void init();
//! \brief Copy values from well state. //! \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. //! \brief Update values from newton update vector.
void updateNewton(const BVectorWell& dwells, void updateNewton(const BVectorWell& dwells,
const double relaxation_factor, const double relaxation_factor,
const double DFLimit, const double DFLimit,
const bool zero_rate_target,
const double max_pressure_change); const double max_pressure_change);
//! \brief Copy values to well state. //! \brief Copy values to well state.

View File

@ -148,9 +148,12 @@ namespace Opm
template <typename TypeTag> template <typename TypeTag>
void void
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
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 <typename TypeTag> template <typename TypeTag>
void void
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
recoverWellSolutionAndUpdateWellState(const BVector& x, recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
const BVector& x,
WellState& well_state, WellState& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
@ -250,7 +254,7 @@ namespace Opm
BVectorWell xw(1); BVectorWell xw(1);
this->linSys_.recoverSolutionWell(x, xw); 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 <typename TypeTag> template <typename TypeTag>
void void
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
solveEqAndUpdateWellState(WellState& well_state, DeferredLogger& deferred_logger) solveEqAndUpdateWellState(const Simulator& ebos_simulator,
WellState& well_state,
DeferredLogger& deferred_logger)
{ {
if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return;
@ -536,7 +542,8 @@ namespace Opm
// which is why we do not put the assembleWellEq here. // which is why we do not put the assembleWellEq here.
const BVectorWell dx_well = this->linSys_.solve(); 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 <typename TypeTag> template <typename TypeTag>
void void
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
updateWellState(const BVectorWell& dwells, updateWellState(const SummaryState& summary_state,
const BVectorWell& dwells,
WellState& well_state, WellState& well_state,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
const double relaxation_factor) const double relaxation_factor)
@ -628,9 +636,11 @@ namespace Opm
const double dFLimit = this->param_.dwell_fraction_max_; const double dFLimit = this->param_.dwell_fraction_max_;
const double max_pressure_change = this->param_.max_pressure_change_ms_wells_; 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, this->primary_variables_.updateNewton(dwells,
relaxation_factor, relaxation_factor,
dFLimit, dFLimit,
zero_rate_target,
max_pressure_change); max_pressure_change);
this->primary_variables_.copyToWellState(*this, getRefDensity(), this->primary_variables_.copyToWellState(*this, getRefDensity(),
@ -649,7 +659,8 @@ namespace Opm
const WellState& well_state, const WellState& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
updatePrimaryVariables(well_state, deferred_logger); const auto& summary_state = ebosSimulator.vanguard().summaryState();
updatePrimaryVariables(summary_state, well_state, deferred_logger);
initPrimaryVariablesEvaluation(); initPrimaryVariablesEvaluation();
computePerfCellPressDiffs(ebosSimulator); computePerfCellPressDiffs(ebosSimulator);
computeInitialSegmentFluids(ebosSimulator); computeInitialSegmentFluids(ebosSimulator);
@ -1492,7 +1503,8 @@ namespace Opm
this->regularize_ = true; this->regularize_ = true;
deferred_logger.debug(sstr.str()); 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(); initPrimaryVariablesEvaluation();
} }

View File

@ -156,7 +156,8 @@ namespace Opm
/// using the solution x to recover the solution xw for wells and applying /// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State /// xw to update Well State
void recoverWellSolutionAndUpdateWellState(const BVector& x, void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
const BVector& x,
WellState& well_state, WellState& well_state,
DeferredLogger& deferred_logger) override; DeferredLogger& deferred_logger) override;
@ -166,9 +167,13 @@ namespace Opm
std::vector<double>& well_potentials, std::vector<double>& well_potentials,
DeferredLogger& deferred_logger) /* const */ override; 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, virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state, const WellState& well_state,
@ -252,7 +257,8 @@ namespace Opm
bool regularize_; bool regularize_;
// updating the well_state based on well solution dwells // 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, WellState& well_state,
DeferredLogger& deferred_logger); DeferredLogger& deferred_logger);
@ -359,7 +365,7 @@ namespace Opm
DeferredLogger& deferred_logger) const; DeferredLogger& deferred_logger) const;
void updatePrimaryVariablesNewton(const BVectorWell& dwells, void updatePrimaryVariablesNewton(const BVectorWell& dwells,
const WellState& well_state, const bool zero_rate_target,
DeferredLogger& deferred_logger); DeferredLogger& deferred_logger);
void updateWellStateFromPrimaryVariables(WellState& well_state, DeferredLogger& deferred_logger) const; void updateWellStateFromPrimaryVariables(WellState& well_state, DeferredLogger& deferred_logger) const;

View File

@ -143,7 +143,7 @@ assembleControlEq(const WellState& well_state,
bhp_from_thp, bhp_from_thp,
control_eq, control_eq,
deferred_logger); 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. // Production mode, zero target. Treat as STOP.
control_eq = primary_variables.eval(PrimaryVariables::WQTotal); control_eq = primary_variables.eval(PrimaryVariables::WQTotal);
} else { } else {

View File

@ -81,7 +81,7 @@ Scalar relaxationFactorRate(const Scalar old_value,
const Scalar original_total_rate = old_value; const Scalar original_total_rate = old_value;
const Scalar possible_update_total_rate = old_value - newton_update; 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 // 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. // always be 1.0, more thoughts might be needed.
if (original_total_rate * possible_update_total_rate < 0.) { // sign changed if (original_total_rate * possible_update_total_rate < 0.) { // sign changed
@ -121,7 +121,9 @@ resize(const int numWellEq)
template<class FluidSystem, class Indices, class Scalar> template<class FluidSystem, class Indices, class Scalar>
void StandardWellPrimaryVariables<FluidSystem,Indices,Scalar>:: void StandardWellPrimaryVariables<FluidSystem,Indices,Scalar>::
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 Water = BlackoilPhases::Aqua;
static constexpr int Oil = BlackoilPhases::Liquid; static constexpr int Oil = BlackoilPhases::Liquid;
@ -158,6 +160,9 @@ update(const WellState& well_state, DeferredLogger& deferred_logger)
} }
} else { } else {
value_[WQTotal] = total_well_rate; value_[WQTotal] = total_well_rate;
if (zero_rate_target) {
value_[WQTotal] = 0.;
}
} }
if (std::abs(total_well_rate) > 0.) { if (std::abs(total_well_rate) > 0.) {
@ -240,6 +245,7 @@ updatePolyMW(const WellState& well_state)
template<class FluidSystem, class Indices, class Scalar> template<class FluidSystem, class Indices, class Scalar>
void StandardWellPrimaryVariables<FluidSystem,Indices,Scalar>:: void StandardWellPrimaryVariables<FluidSystem,Indices,Scalar>::
updateNewton(const BVectorWell& dwells, updateNewton(const BVectorWell& dwells,
const bool zero_rate_target,
[[maybe_unused]] const double dFLimit, [[maybe_unused]] const double dFLimit,
const double dBHPLimit) const double dBHPLimit)
{ {
@ -275,6 +281,10 @@ updateNewton(const BVectorWell& dwells,
// updating the total rates Q_t // updating the total rates Q_t
value_[WQTotal] = value_[WQTotal] - dwells[0][WQTotal] * relaxation_factor_rate; 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 // updating the bottom hole pressure
const int sign1 = dwells[0][Bhp] > 0 ? 1: -1; const int sign1 = dwells[0][Bhp] > 0 ? 1: -1;

View File

@ -101,13 +101,16 @@ public:
int numWellEq() const { return numWellEq_; } int numWellEq() const { return numWellEq_; }
//! \brief Copy values from well state. //! \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. //! \brief Copy polymer molecular weigt values from well state.
void updatePolyMW(const WellState& well_state); void updatePolyMW(const WellState& well_state);
//! \brief Update values from newton update vector. //! \brief Update values from newton update vector.
void updateNewton(const BVectorWell& dwells, void updateNewton(const BVectorWell& dwells,
const bool zero_rate_target,
const double dFLimit, const double dFLimit,
const double dBHPLimit); const double dBHPLimit);

View File

@ -993,13 +993,15 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
updateWellState(const BVectorWell& dwells, updateWellState(const SummaryState& summary_state,
const BVectorWell& dwells,
WellState& well_state, WellState& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; 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); updateWellStateFromPrimaryVariables(well_state, deferred_logger);
Base::calculateReservoirRates(well_state.well(this->index_of_well_)); Base::calculateReservoirRates(well_state.well(this->index_of_well_));
@ -1013,12 +1015,12 @@ namespace Opm
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
updatePrimaryVariablesNewton(const BVectorWell& dwells, updatePrimaryVariablesNewton(const BVectorWell& dwells,
const WellState& /* well_state */, const bool zero_rate_target,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
const double dFLimit = this->param_.dwell_fraction_max_; const double dFLimit = this->param_.dwell_fraction_max_;
const double dBHPLimit = this->param_.dbhp_max_rel_; 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 // for the water velocity and skin pressure
if constexpr (Base::has_polymermw) { if constexpr (Base::has_polymermw) {
@ -1581,7 +1583,9 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
solveEqAndUpdateWellState(WellState& well_state, DeferredLogger& deferred_logger) solveEqAndUpdateWellState(const SummaryState& summary_state,
WellState& well_state,
DeferredLogger& deferred_logger)
{ {
if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return;
@ -1591,7 +1595,7 @@ namespace Opm
dx_well[0].resize(this->primary_variables_.numWellEq()); dx_well[0].resize(this->primary_variables_.numWellEq());
this->linSys_.solve( dx_well); 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, const WellState& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
updatePrimaryVariables(well_state, deferred_logger); const auto& summary_state = ebosSimulator.vanguard().summaryState();
updatePrimaryVariables(summary_state, well_state, deferred_logger);
initPrimaryVariablesEvaluation(); initPrimaryVariablesEvaluation();
computeWellConnectionPressures(ebosSimulator, well_state, deferred_logger); computeWellConnectionPressures(ebosSimulator, well_state, deferred_logger);
this->computeAccumWell(); this->computeAccumWell();
@ -1648,7 +1653,8 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
recoverWellSolutionAndUpdateWellState(const BVector& x, recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
const BVector& x,
WellState& well_state, WellState& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
@ -1658,7 +1664,7 @@ namespace Opm
xw[0].resize(this->primary_variables_.numWellEq()); xw[0].resize(this->primary_variables_.numWellEq());
this->linSys_.recoverSolutionWell(x, xw); 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"; " potentials are computed based on unconverged solution";
deferred_logger.debug(msg); 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.computeWellConnectionPressures(ebosSimulator, well_state_copy, deferred_logger);
well_copy.initPrimaryVariablesEvaluation(); well_copy.initPrimaryVariablesEvaluation();
well_copy.computeWellRatesWithBhp(ebosSimulator, bhp, well_flux, deferred_logger); well_copy.computeWellRatesWithBhp(ebosSimulator, bhp, well_flux, deferred_logger);
@ -1970,11 +1976,14 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
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; 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 // other primary variables related to polymer injection
if constexpr (Base::has_polymermw) { if constexpr (Base::has_polymermw) {
@ -2511,7 +2520,8 @@ namespace Opm
} }
++it; ++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 // 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 // under the most restrictive control. Based on this converged results, we can check whether to re-open the well. Either we refactor

View File

@ -43,32 +43,6 @@
namespace Opm 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<class FluidSystem> template<class FluidSystem>
WellAssemble<FluidSystem>:: WellAssemble<FluidSystem>::
WellAssemble(const WellInterfaceFluidSystem<FluidSystem>& well) WellAssemble(const WellInterfaceFluidSystem<FluidSystem>& well)

View File

@ -44,10 +44,6 @@ class WellState;
class WellInjectionControls; class WellInjectionControls;
class WellProductionControls; class WellProductionControls;
/// Helper to avoid singular control equations.
bool rateControlWithZeroTarget(const WellProducerCMode mode,
const WellProductionControls& controls);
template<class FluidSystem> template<class FluidSystem>
class WellAssemble { class WellAssemble {
static constexpr int Water = BlackoilPhases::Aqua; static constexpr int Water = BlackoilPhases::Aqua;

View File

@ -25,6 +25,9 @@
#include <opm/common/OpmLog/OpmLog.hpp> #include <opm/common/OpmLog/OpmLog.hpp>
#include <opm/input/eclipse/Schedule/Well/WellProductionControls.hpp>
#include <opm/input/eclipse/Schedule/Well/WellEnums.hpp>
#include <opm/simulators/wells/ParallelWellInfo.hpp> #include <opm/simulators/wells/ParallelWellInfo.hpp>
#include <fmt/format.h> #include <fmt/format.h>
@ -168,6 +171,33 @@ DenseMatrix transposeDenseDynMatrix(const DenseMatrix& M)
return tmp; 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<double>; template class ParallelStandardWellB<double>;
template<int Dim> using Vec = Dune::BlockVector<Dune::FieldVector<double,Dim>>; template<int Dim> using Vec = Dune::BlockVector<Dune::FieldVector<double,Dim>>;

View File

@ -31,6 +31,8 @@
namespace Opm { namespace Opm {
class ParallelWellInfo; class ParallelWellInfo;
enum class WellProducerCMode;
class WellProductionControls;
namespace wellhelpers { namespace wellhelpers {
@ -83,6 +85,10 @@ void sumDistributedWellEntries(Dune::DynamicMatrix<Scalar>& mat,
template <class DenseMatrix> template <class DenseMatrix>
DenseMatrix transposeDenseDynMatrix(const DenseMatrix& M); 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 wellhelpers
} // namespace Opm } // namespace Opm

View File

@ -156,7 +156,9 @@ public:
virtual ConvergenceReport getWellConvergence(const WellState& well_state, const std::vector<double>& B_avg, DeferredLogger& deferred_logger, const bool relax_tolerance) const = 0; virtual ConvergenceReport getWellConvergence(const WellState& well_state, const std::vector<double>& 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, void assembleWellEq(const Simulator& ebosSimulator,
const double dt, const double dt,
@ -180,7 +182,8 @@ public:
/// using the solution x to recover the solution xw for wells and applying /// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State /// xw to update Well State
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x, virtual void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
const BVector& x,
WellState& well_state, WellState& well_state,
DeferredLogger& deferred_logger) = 0; DeferredLogger& deferred_logger) = 0;
@ -212,7 +215,9 @@ public:
const GroupState& group_state, const GroupState& group_state,
DeferredLogger& deferred_logger) /* const */; 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, virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state, const WellState& well_state,
@ -359,7 +364,8 @@ protected:
Eval getPerfCellPressure(const FluidState& fs) const; Eval getPerfCellPressure(const FluidState& fs) const;
bool wellUnderZeroProductionRateControl(const SummaryState& summary_state,
const WellState& well_state) const;
}; };
} }

View File

@ -26,6 +26,7 @@
#include <opm/simulators/wells/GroupState.hpp> #include <opm/simulators/wells/GroupState.hpp>
#include <opm/simulators/wells/TargetCalculator.hpp> #include <opm/simulators/wells/TargetCalculator.hpp>
#include <opm/simulators/wells/WellBhpThpCalculator.hpp> #include <opm/simulators/wells/WellBhpThpCalculator.hpp>
#include <opm/simulators/wells/WellHelpers.hpp>
#include <dune/common/version.hh> #include <dune/common/version.hh>
@ -244,7 +245,7 @@ namespace Opm
this->well_control_log_.push_back(from); this->well_control_log_.push_back(from);
updateWellStateWithTarget(ebos_simulator, group_state, well_state, deferred_logger); updateWellStateWithTarget(ebos_simulator, group_state, well_state, deferred_logger);
updatePrimaryVariables(well_state, deferred_logger); updatePrimaryVariables(summaryState, well_state, deferred_logger);
} }
return changed; return changed;
@ -269,7 +270,8 @@ namespace Opm
updateWellStateWithTarget(simulator, group_state, well_state_copy, deferred_logger); updateWellStateWithTarget(simulator, group_state, well_state_copy, deferred_logger);
calculateExplicitQuantities(simulator, 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(); initPrimaryVariablesEvaluation();
if (this->isProducer()) { if (this->isProducer()) {
@ -1128,4 +1130,19 @@ namespace Opm
return fs.pressure(FluidSystem::gasPhaseIdx); return fs.pressure(FluidSystem::gasPhaseIdx);
} }
} }
template<typename TypeTag>
bool WellInterface<TypeTag>::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 } // namespace Opm