Include checking for zero targets from groups where required

This commit is contained in:
Stein Krogstad 2024-03-19 12:50:34 +01:00 committed by Arne Morten Kvarving
parent 2db90a92e7
commit 427351cc12
15 changed files with 195 additions and 189 deletions

View File

@ -490,7 +490,7 @@ namespace Opm {
// This is done only for producers, as injectors will only have a single // This is done only for producers, as injectors will only have a single
// nonzero phase anyway. // nonzero phase anyway.
for (auto& well : well_container_) { for (auto& well : well_container_) {
const bool zero_target = well->stopppedOrZeroRateTarget(summaryState, this->wellState()); const bool zero_target = well->stoppedOrZeroRateTarget(simulator_, this->wellState(), local_deferredLogger);
if (well->isProducer() && !zero_target) { if (well->isProducer() && !zero_target) {
well->updateWellStateRates(simulator_, this->wellState(), local_deferredLogger); well->updateWellStateRates(simulator_, this->wellState(), local_deferredLogger);
} }
@ -1076,8 +1076,7 @@ namespace Opm {
} }
++iter; ++iter;
for (auto& well : this->well_container_) { for (auto& well : this->well_container_) {
const auto& summary_state = this->simulator_.vanguard().summaryState(); well->solveEqAndUpdateWellState(simulator_, well_state, deferred_logger);
well->solveEqAndUpdateWellState(summary_state, well_state, deferred_logger);
} }
this->initPrimaryVariablesEvaluation(); this->initPrimaryVariablesEvaluation();
} while (iter < max_iter); } while (iter < max_iter);
@ -1711,9 +1710,8 @@ namespace Opm {
DeferredLogger local_deferredLogger; DeferredLogger local_deferredLogger;
OPM_BEGIN_PARALLEL_TRY_CATCH(); OPM_BEGIN_PARALLEL_TRY_CATCH();
{ {
const auto& summary_state = simulator_.vanguard().summaryState();
for (auto& well : well_container_) { for (auto& well : well_container_) {
well->recoverWellSolutionAndUpdateWellState(summary_state, x, this->wellState(), local_deferredLogger); well->recoverWellSolutionAndUpdateWellState(simulator_, x, this->wellState(), local_deferredLogger);
} }
} }
OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger, OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
@ -1731,10 +1729,9 @@ namespace Opm {
// try/catch here, as this function is not called in // try/catch here, as this function is not called in
// parallel but for each individual domain of each rank. // parallel but for each individual domain of each rank.
DeferredLogger local_deferredLogger; DeferredLogger local_deferredLogger;
const auto& summary_state = this->simulator_.vanguard().summaryState();
for (auto& well : well_container_) { for (auto& well : well_container_) {
if (well_domain_.at(well->name()) == domain.index) { if (well_domain_.at(well->name()) == domain.index) {
well->recoverWellSolutionAndUpdateWellState(summary_state, x, well->recoverWellSolutionAndUpdateWellState(simulator_, x,
this->wellState(), this->wellState(),
local_deferredLogger); local_deferredLogger);
} }
@ -1782,7 +1779,6 @@ namespace Opm {
const std::vector<Scalar>& B_avg, const std::vector<Scalar>& B_avg,
DeferredLogger& local_deferredLogger) const DeferredLogger& local_deferredLogger) const
{ {
const auto& summary_state = simulator_.vanguard().summaryState();
const int iterationIdx = simulator_.model().newtonMethod().numIterations(); const int iterationIdx = simulator_.model().newtonMethod().numIterations();
const bool relax_tolerance = iterationIdx > param_.strict_outer_iter_wells_; const bool relax_tolerance = iterationIdx > param_.strict_outer_iter_wells_;
@ -1790,7 +1786,7 @@ namespace Opm {
for (const auto& well : well_container_) { for (const auto& well : well_container_) {
if ((well_domain_.at(well->name()) == domain.index)) { if ((well_domain_.at(well->name()) == domain.index)) {
if (well->isOperableAndSolvable() || well->wellIsStopped()) { if (well->isOperableAndSolvable() || well->wellIsStopped()) {
report += well->getWellConvergence(summary_state, report += well->getWellConvergence(simulator_,
this->wellState(), this->wellState(),
B_avg, B_avg,
local_deferredLogger, local_deferredLogger,
@ -1833,9 +1829,8 @@ namespace Opm {
const int iterationIdx = simulator_.model().newtonMethod().numIterations(); const int iterationIdx = simulator_.model().newtonMethod().numIterations();
for (const auto& well : well_container_) { for (const auto& well : well_container_) {
if (well->isOperableAndSolvable() || well->wellIsStopped()) { if (well->isOperableAndSolvable() || well->wellIsStopped()) {
const auto& summary_state = simulator_.vanguard().summaryState();
local_report += well->getWellConvergence( local_report += well->getWellConvergence(
summary_state, this->wellState(), B_avg, local_deferredLogger, simulator_, this->wellState(), B_avg, local_deferredLogger,
iterationIdx > param_.strict_outer_iter_wells_); iterationIdx > param_.strict_outer_iter_wells_);
} else { } else {
ConvergenceReport report; ConvergenceReport report;
@ -2356,8 +2351,7 @@ namespace Opm {
auto& events = this->wellState().well(well->indexOfWell()).events; auto& events = this->wellState().well(well->indexOfWell()).events;
if (events.hasEvent(WellState<Scalar>::event_mask)) { if (events.hasEvent(WellState<Scalar>::event_mask)) {
well->updateWellStateWithTarget(simulator_, this->groupState(), this->wellState(), deferred_logger); well->updateWellStateWithTarget(simulator_, this->groupState(), this->wellState(), deferred_logger);
const auto& summary_state = simulator_.vanguard().summaryState(); well->updatePrimaryVariables(simulator_, this->wellState(), deferred_logger);
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.
@ -2441,8 +2435,7 @@ namespace Opm {
updatePrimaryVariables(DeferredLogger& deferred_logger) updatePrimaryVariables(DeferredLogger& deferred_logger)
{ {
for (const auto& well : well_container_) { for (const auto& well : well_container_) {
const auto& summary_state = simulator_.vanguard().summaryState(); well->updatePrimaryVariables(simulator_, this->wellState(), deferred_logger);
well->updatePrimaryVariables(summary_state, this->wellState(), deferred_logger);
} }
} }

View File

@ -94,7 +94,7 @@ namespace Opm {
DeferredLogger& deferred_logger) const override; DeferredLogger& deferred_logger) const override;
/// check whether the well equations get converged for this well /// check whether the well equations get converged for this well
ConvergenceReport getWellConvergence(const SummaryState& summary_state, ConvergenceReport getWellConvergence(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
const std::vector<Scalar>& B_avg, const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
@ -107,7 +107,7 @@ 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 SummaryState& summary_state, void recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x, const BVector& x,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override; DeferredLogger& deferred_logger) override;
@ -118,11 +118,11 @@ namespace Opm {
std::vector<Scalar>& well_potentials, std::vector<Scalar>& well_potentials,
DeferredLogger& deferred_logger) override; DeferredLogger& deferred_logger) override;
void updatePrimaryVariables(const SummaryState& summary_state, void updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override; DeferredLogger& deferred_logger) override;
void solveEqAndUpdateWellState(const SummaryState& summary_state, void solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override; // const? DeferredLogger& deferred_logger) override; // const?
@ -174,7 +174,7 @@ 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 SummaryState& summary_state, void updateWellState(const Simulator& simulator,
const BVectorWell& dwells, const BVectorWell& dwells,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,

View File

@ -92,6 +92,7 @@ assembleControlEq(const WellState<Scalar>& well_state,
const Scalar rho, const Scalar rho,
const PrimaryVariables& primary_variables, const PrimaryVariables& primary_variables,
Equations& eqns1, Equations& eqns1,
const bool stopped_or_zero_target,
DeferredLogger& deferred_logger) const DeferredLogger& deferred_logger) const
{ {
static constexpr int Gas = BlackoilPhases::Vapour; static constexpr int Gas = BlackoilPhases::Vapour;
@ -116,7 +117,7 @@ assembleControlEq(const WellState<Scalar>& well_state,
return rates; return rates;
}; };
if (well_.stopppedOrZeroRateTarget(summaryState, well_state)) { if (stopped_or_zero_target) {
control_eq = primary_variables.getWQTotal(); control_eq = primary_variables.getWQTotal();
} else if (well_.isInjector() ) { } else if (well_.isInjector() ) {
// Find scaling factor to get injection rate, // Find scaling factor to get injection rate,

View File

@ -79,6 +79,7 @@ public:
const Scalar rho, const Scalar rho,
const PrimaryVariables& primary_variables, const PrimaryVariables& primary_variables,
Equations& eqns, Equations& eqns,
const bool stopped_or_zero_target,
DeferredLogger& deferred_logger) const; DeferredLogger& deferred_logger) const;
//! \brief Assemble piece of the acceleration term //! \brief Assemble piece of the acceleration term

View File

@ -162,11 +162,11 @@ namespace Opm
template <typename TypeTag> template <typename TypeTag>
void void
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
updatePrimaryVariables(const SummaryState& summary_state, updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& /* deferred_logger */) DeferredLogger& deferred_logger)
{ {
const bool stop_or_zero_rate_target = this->stopppedOrZeroRateTarget(summary_state, well_state); const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger);
this->primary_variables_.update(well_state, stop_or_zero_rate_target); this->primary_variables_.update(well_state, stop_or_zero_rate_target);
} }
@ -199,7 +199,7 @@ namespace Opm
template <typename TypeTag> template <typename TypeTag>
ConvergenceReport ConvergenceReport
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
getWellConvergence(const SummaryState& /* summary_state */, getWellConvergence(const Simulator& /* simulator */,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
const std::vector<Scalar>& B_avg, const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
@ -260,7 +260,7 @@ namespace Opm
template <typename TypeTag> template <typename TypeTag>
void void
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state, recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x, const BVector& x,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
@ -271,7 +271,7 @@ namespace Opm
BVectorWell xw(1); BVectorWell xw(1);
this->linSys_.recoverSolutionWell(x, xw); this->linSys_.recoverSolutionWell(x, xw);
updateWellState(summary_state, xw, well_state, deferred_logger); updateWellState(simulator, xw, well_state, deferred_logger);
} }
@ -578,7 +578,7 @@ namespace Opm
template <typename TypeTag> template <typename TypeTag>
void void
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
solveEqAndUpdateWellState(const SummaryState& summary_state, solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
@ -589,7 +589,7 @@ namespace Opm
try{ try{
const BVectorWell dx_well = this->linSys_.solve(); const BVectorWell dx_well = this->linSys_.solve();
updateWellState(summary_state, dx_well, well_state, deferred_logger); updateWellState(simulator, dx_well, well_state, deferred_logger);
} }
catch(const NumericalProblem& exp) { catch(const NumericalProblem& exp) {
// Add information about the well and log to deferred logger // Add information about the well and log to deferred logger
@ -681,7 +681,7 @@ namespace Opm
template <typename TypeTag> template <typename TypeTag>
void void
MultisegmentWell<TypeTag>:: MultisegmentWell<TypeTag>::
updateWellState(const SummaryState& summary_state, updateWellState(const Simulator& simulator,
const BVectorWell& dwells, const BVectorWell& dwells,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
@ -691,15 +691,20 @@ namespace Opm
const Scalar dFLimit = this->param_.dwell_fraction_max_; const Scalar dFLimit = this->param_.dwell_fraction_max_;
const Scalar max_pressure_change = this->param_.max_pressure_change_ms_wells_; const Scalar max_pressure_change = this->param_.max_pressure_change_ms_wells_;
const bool stop_or_zero_rate_target = this->stopppedOrZeroRateTarget(summary_state, well_state); const bool stop_or_zero_rate_target =
this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger);
this->primary_variables_.updateNewton(dwells, this->primary_variables_.updateNewton(dwells,
relaxation_factor, relaxation_factor,
dFLimit, dFLimit,
stop_or_zero_rate_target, stop_or_zero_rate_target,
max_pressure_change); max_pressure_change);
this->primary_variables_.copyToWellState(*this, getRefDensity(), stop_or_zero_rate_target, const auto& summary_state = simulator.vanguard().summaryState();
well_state, summary_state, deferred_logger); this->primary_variables_.copyToWellState(*this, getRefDensity(),
stop_or_zero_rate_target,
well_state,
summary_state,
deferred_logger);
{ {
auto& ws = well_state.well(this->index_of_well_); auto& ws = well_state.well(this->index_of_well_);
@ -720,8 +725,7 @@ namespace Opm
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
const auto& summary_state = simulator.vanguard().summaryState(); updatePrimaryVariables(simulator, well_state, deferred_logger);
updatePrimaryVariables(summary_state, well_state, deferred_logger);
initPrimaryVariablesEvaluation(); initPrimaryVariablesEvaluation();
computePerfCellPressDiffs(simulator); computePerfCellPressDiffs(simulator);
computeInitialSegmentFluids(simulator); computeInitialSegmentFluids(simulator);
@ -1489,8 +1493,7 @@ namespace Opm
this->regularize_ = true; this->regularize_ = true;
} }
const auto& summary_state = simulator.vanguard().summaryState(); const auto report = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, relax_convergence);
const auto report = getWellConvergence(summary_state, well_state, Base::B_avg_, deferred_logger, relax_convergence);
if (report.converged()) { if (report.converged()) {
converged = true; converged = true;
break; break;
@ -1526,7 +1529,7 @@ namespace Opm
++stagnate_count; ++stagnate_count;
if (stagnate_count == 6) { if (stagnate_count == 6) {
sstr << " well " << this->name() << " observes severe stagnation and/or oscillation. We relax the tolerance and check for convergence. \n"; sstr << " well " << this->name() << " observes severe stagnation and/or oscillation. We relax the tolerance and check for convergence. \n";
const auto reportStag = getWellConvergence(summary_state, well_state, Base::B_avg_, deferred_logger, true); const auto reportStag = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, true);
if (reportStag.converged()) { if (reportStag.converged()) {
converged = true; converged = true;
sstr << " well " << this->name() << " manages to get converged with relaxed tolerances in " << it << " inner iterations"; sstr << " well " << this->name() << " manages to get converged with relaxed tolerances in " << it << " inner iterations";
@ -1553,7 +1556,7 @@ namespace Opm
this->regularize_ = true; this->regularize_ = true;
deferred_logger.debug(sstr.str()); deferred_logger.debug(sstr.str());
} }
updateWellState(summary_state, dx_well, well_state, deferred_logger, relaxation_factor); updateWellState(simulator, dx_well, well_state, deferred_logger, relaxation_factor);
initPrimaryVariablesEvaluation(); initPrimaryVariablesEvaluation();
} }
@ -1635,7 +1638,7 @@ namespace Opm
const bool allow_open = this->well_ecl_.getStatus() == WellStatus::OPEN && const bool allow_open = this->well_ecl_.getStatus() == WellStatus::OPEN &&
well_state.well(this->index_of_well_).status == WellStatus::OPEN; well_state.well(this->index_of_well_).status == WellStatus::OPEN;
// don't allow switcing for wells under zero rate target or requested fixed status and control // don't allow switcing for wells under zero rate target or requested fixed status and control
const bool allow_switching = !this->wellUnderZeroRateTarget(summary_state, well_state) && const bool allow_switching = !this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger) &&
(!fixed_control || !fixed_status) && allow_open; (!fixed_control || !fixed_status) && allow_open;
bool changed = false; bool changed = false;
bool final_check = false; bool final_check = false;
@ -1673,7 +1676,7 @@ namespace Opm
this->regularize_ = true; this->regularize_ = true;
} }
const auto report = getWellConvergence(summary_state, well_state, Base::B_avg_, deferred_logger, relax_convergence); const auto report = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, relax_convergence);
converged = report.converged(); converged = report.converged();
if (converged) { if (converged) {
// if equations are sufficiently linear they might converge in less than min_its_after_switch // if equations are sufficiently linear they might converge in less than min_its_after_switch
@ -1717,7 +1720,7 @@ namespace Opm
if (false) { // this disables the usage of the relaxed tolerance if (false) { // this disables the usage of the relaxed tolerance
fmt::format_to(std::back_inserter(message), " Well {} observes severe stagnation and/or oscillation." fmt::format_to(std::back_inserter(message), " Well {} observes severe stagnation and/or oscillation."
" We relax the tolerance and check for convergence. \n", this->name()); " We relax the tolerance and check for convergence. \n", this->name());
const auto reportStag = getWellConvergence(summary_state, well_state, Base::B_avg_, const auto reportStag = getWellConvergence(simulator, well_state, Base::B_avg_,
deferred_logger, true); deferred_logger, true);
if (reportStag.converged()) { if (reportStag.converged()) {
converged = true; converged = true;
@ -1745,7 +1748,7 @@ namespace Opm
deferred_logger.debug(message); deferred_logger.debug(message);
} }
} }
updateWellState(summary_state, dx_well, well_state, deferred_logger, relaxation_factor); updateWellState(simulator, dx_well, well_state, deferred_logger, relaxation_factor);
initPrimaryVariablesEvaluation(); initPrimaryVariablesEvaluation();
} }
@ -1906,10 +1909,11 @@ namespace Opm
} }
} }
// the fourth dequation, the pressure drop equation // the fourth equation, the pressure drop equation
if (seg == 0) { // top segment, pressure equation is the control equation if (seg == 0) { // top segment, pressure equation is the control equation
const auto& summaryState = simulator.vanguard().summaryState(); const auto& summaryState = simulator.vanguard().summaryState();
const Schedule& schedule = simulator.vanguard().schedule(); const Schedule& schedule = simulator.vanguard().schedule();
const bool stopped_or_zero_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger);
MultisegmentWellAssemble(*this). MultisegmentWellAssemble(*this).
assembleControlEq(well_state, assembleControlEq(well_state,
group_state, group_state,
@ -1920,6 +1924,7 @@ namespace Opm
getRefDensity(), getRefDensity(),
this->primary_variables_, this->primary_variables_,
this->linSys_, this->linSys_,
stopped_or_zero_target,
deferred_logger); deferred_logger);
} else { } else {
const UnitSystem& unit_system = simulator.vanguard().eclState().getDeckUnitSystem(); const UnitSystem& unit_system = simulator.vanguard().eclState().getDeckUnitSystem();

View File

@ -140,7 +140,7 @@ namespace Opm
void initPrimaryVariablesEvaluation() override; void initPrimaryVariablesEvaluation() override;
/// check whether the well equations get converged for this well /// check whether the well equations get converged for this well
virtual ConvergenceReport getWellConvergence(const SummaryState& summary_state, virtual ConvergenceReport getWellConvergence(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
const std::vector<Scalar>& B_avg, const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
@ -153,7 +153,7 @@ 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 SummaryState& summary_state, void recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x, const BVector& x,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override; DeferredLogger& deferred_logger) override;
@ -164,11 +164,11 @@ namespace Opm
std::vector<Scalar>& well_potentials, std::vector<Scalar>& well_potentials,
DeferredLogger& deferred_logger) /* const */ override; DeferredLogger& deferred_logger) /* const */ override;
void updatePrimaryVariables(const SummaryState& summary_state, void updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override; DeferredLogger& deferred_logger) override;
void solveEqAndUpdateWellState(const SummaryState& summary_state, void solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override; DeferredLogger& deferred_logger) override;
@ -262,7 +262,7 @@ 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 SummaryState& summary_state, void updateWellState(const Simulator& simulator,
const BVectorWell& dwells, const BVectorWell& dwells,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger); DeferredLogger& deferred_logger);

View File

@ -93,6 +93,7 @@ assembleControlEq(const WellState<Scalar>& well_state,
const PrimaryVariables& primary_variables, const PrimaryVariables& primary_variables,
const Scalar rho, const Scalar rho,
StandardWellEquations<Scalar,Indices::numEq>& eqns1, StandardWellEquations<Scalar,Indices::numEq>& eqns1,
const bool stopped_or_zero_target,
DeferredLogger& deferred_logger) const DeferredLogger& deferred_logger) const
{ {
static constexpr int Water = BlackoilPhases::Aqua; static constexpr int Water = BlackoilPhases::Aqua;
@ -119,7 +120,7 @@ assembleControlEq(const WellState<Scalar>& well_state,
return rates; return rates;
}; };
if (well_.stopppedOrZeroRateTarget(summaryState, well_state)) { if (stopped_or_zero_target) {
control_eq = primary_variables.eval(PrimaryVariables::WQTotal); control_eq = primary_variables.eval(PrimaryVariables::WQTotal);
} else if (well_.isInjector()) { } else if (well_.isInjector()) {
// Find injection rate. // Find injection rate.

View File

@ -61,6 +61,7 @@ public:
const PrimaryVariables& primary_variables, const PrimaryVariables& primary_variables,
const Scalar rho, const Scalar rho,
StandardWellEquations<Scalar,Indices::numEq>& eqns, StandardWellEquations<Scalar,Indices::numEq>& eqns,
const bool stopped_or_zero_target,
DeferredLogger& deferred_logger) const; DeferredLogger& deferred_logger) const;
//! \brief Assemble injectivity equation. //! \brief Assemble injectivity equation.

View File

@ -462,6 +462,7 @@ namespace Opm
const auto& summaryState = simulator.vanguard().summaryState(); const auto& summaryState = simulator.vanguard().summaryState();
const Schedule& schedule = simulator.vanguard().schedule(); const Schedule& schedule = simulator.vanguard().schedule();
const bool stopped_or_zero_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger);
StandardWellAssemble<FluidSystem,Indices>(*this). StandardWellAssemble<FluidSystem,Indices>(*this).
assembleControlEq(well_state, group_state, assembleControlEq(well_state, group_state,
schedule, summaryState, schedule, summaryState,
@ -469,6 +470,7 @@ namespace Opm
this->primary_variables_, this->primary_variables_,
this->connections_.rho(), this->connections_.rho(),
this->linSys_, this->linSys_,
stopped_or_zero_target,
deferred_logger); deferred_logger);
@ -692,16 +694,17 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
updateWellState(const SummaryState& summary_state, updateWellState(const Simulator& simulator,
const BVectorWell& dwells, const BVectorWell& dwells,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return;
const bool stop_or_zero_rate_target = this->stopppedOrZeroRateTarget(summary_state, well_state); const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger);
updatePrimaryVariablesNewton(dwells, stop_or_zero_rate_target, deferred_logger); updatePrimaryVariablesNewton(dwells, stop_or_zero_rate_target, deferred_logger);
const auto& summary_state = simulator.vanguard().summaryState();
updateWellStateFromPrimaryVariables(stop_or_zero_rate_target, well_state, summary_state, deferred_logger); updateWellStateFromPrimaryVariables(stop_or_zero_rate_target, well_state, summary_state, deferred_logger);
Base::calculateReservoirRates(well_state.well(this->index_of_well_)); Base::calculateReservoirRates(well_state.well(this->index_of_well_));
} }
@ -805,7 +808,10 @@ namespace Opm
// the well index associated with the connection // the well index associated with the connection
Scalar trans_mult = simulator.problem().template wellTransMultiplier<Scalar>(int_quantities, cell_idx); Scalar trans_mult = simulator.problem().template wellTransMultiplier<Scalar>(int_quantities, cell_idx);
const auto& wellstate_nupcol = simulator.problem().wellModel().nupcolWellState().well(this->index_of_well_); const auto& wellstate_nupcol = simulator.problem().wellModel().nupcolWellState().well(this->index_of_well_);
const std::vector<Scalar> tw_perf = this->wellIndex(perf, int_quantities, trans_mult, wellstate_nupcol); const std::vector<Scalar> tw_perf = this->wellIndex(perf,
int_quantities,
trans_mult,
wellstate_nupcol);
std::vector<Scalar> ipr_a_perf(this->ipr_a_.size()); std::vector<Scalar> ipr_a_perf(this->ipr_a_.size());
std::vector<Scalar> ipr_b_perf(this->ipr_b_.size()); std::vector<Scalar> ipr_b_perf(this->ipr_b_.size());
for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx) { for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx) {
@ -849,11 +855,11 @@ namespace Opm
updateIPRImplicit(const Simulator& simulator, updateIPRImplicit(const Simulator& simulator,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
// Compute IPR based on *converged* well-equation: // Compute IPR based on *converged* well-equation:
// For a component rate r the derivative dr/dbhp is obtained by // For a component rate r the derivative dr/dbhp is obtained by
// dr/dbhp = - (partial r/partial x) * inv(partial Eq/partial x) * (partial Eq/partial bhp_target) // dr/dbhp = - (partial r/partial x) * inv(partial Eq/partial x) * (partial Eq/partial bhp_target)
// where Eq(x)=0 is the well equation setup with bhp control and primary variables x // where Eq(x)=0 is the well equation setup with bhp control and primary variables x
// We shouldn't have zero rates at this stage, but check // We shouldn't have zero rates at this stage, but check
bool zero_rates; bool zero_rates;
@ -867,7 +873,7 @@ namespace Opm
const auto msg = fmt::format("updateIPRImplicit: Well {} has zero rate, IPRs might be problematic", this->name()); const auto msg = fmt::format("updateIPRImplicit: Well {} has zero rate, IPRs might be problematic", this->name());
deferred_logger.debug(msg); deferred_logger.debug(msg);
/* /*
// could revert to standard approach here: // could revert to standard approach here:
updateIPR(simulator, deferred_logger); updateIPR(simulator, deferred_logger);
for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx){ for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx){
const int idx = this->modelCompIdxToFlowCompIdx(comp_idx); const int idx = this->modelCompIdxToFlowCompIdx(comp_idx);
@ -876,12 +882,12 @@ namespace Opm
} }
return; return;
*/ */
} }
const auto& group_state = simulator.problem().wellModel().groupState(); const auto& group_state = simulator.problem().wellModel().groupState();
std::fill(ws.implicit_ipr_a.begin(), ws.implicit_ipr_a.end(), 0.); std::fill(ws.implicit_ipr_a.begin(), ws.implicit_ipr_a.end(), 0.);
std::fill(ws.implicit_ipr_b.begin(), ws.implicit_ipr_b.end(), 0.); std::fill(ws.implicit_ipr_b.begin(), ws.implicit_ipr_b.end(), 0.);
auto inj_controls = Well::InjectionControls(0); auto inj_controls = Well::InjectionControls(0);
auto prod_controls = Well::ProductionControls(0); auto prod_controls = Well::ProductionControls(0);
prod_controls.addControl(Well::ProducerCMode::BHP); prod_controls.addControl(Well::ProducerCMode::BHP);
@ -898,7 +904,7 @@ namespace Opm
rhs[0].resize(nEq); rhs[0].resize(nEq);
// rhs = 0 except -1 for control eq // rhs = 0 except -1 for control eq
for (size_t i=0; i < nEq; ++i){ for (size_t i=0; i < nEq; ++i){
rhs[0][i] = 0.0; rhs[0][i] = 0.0;
} }
rhs[0][Bhp] = -1.0; rhs[0][Bhp] = -1.0;
@ -910,7 +916,7 @@ namespace Opm
EvalWell comp_rate = this->primary_variables_.getQs(comp_idx); EvalWell comp_rate = this->primary_variables_.getQs(comp_idx);
const int idx = this->modelCompIdxToFlowCompIdx(comp_idx); const int idx = this->modelCompIdxToFlowCompIdx(comp_idx);
for (size_t pvIdx = 0; pvIdx < nEq; ++pvIdx) { for (size_t pvIdx = 0; pvIdx < nEq; ++pvIdx) {
// well primary variable derivatives in EvalWell start at position Indices::numEq // well primary variable derivatives in EvalWell start at position Indices::numEq
ws.implicit_ipr_b[idx] -= x_well[0][pvIdx]*comp_rate.derivative(pvIdx+Indices::numEq); ws.implicit_ipr_b[idx] -= x_well[0][pvIdx]*comp_rate.derivative(pvIdx+Indices::numEq);
} }
ws.implicit_ipr_a[idx] = ws.implicit_ipr_b[idx]*ws.bhp - comp_rate.value(); ws.implicit_ipr_a[idx] = ws.implicit_ipr_b[idx]*ws.bhp - comp_rate.value();
@ -1175,7 +1181,7 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
ConvergenceReport ConvergenceReport
StandardWell<TypeTag>:: StandardWell<TypeTag>::
getWellConvergence(const SummaryState& summary_state, getWellConvergence(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
const std::vector<Scalar>& B_avg, const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
@ -1190,7 +1196,7 @@ namespace Opm
constexpr Scalar stopped_factor = 1.e-4; constexpr Scalar stopped_factor = 1.e-4;
// use stricter tolerance for dynamic thp to ameliorate network convergence // use stricter tolerance for dynamic thp to ameliorate network convergence
constexpr Scalar dynamic_thp_factor = 1.e-1; constexpr Scalar dynamic_thp_factor = 1.e-1;
if (this->stopppedOrZeroRateTarget(summary_state, well_state)) { if (this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger)) {
tol_wells = tol_wells*stopped_factor; tol_wells = tol_wells*stopped_factor;
} else if (this->getDynamicThpLimit()) { } else if (this->getDynamicThpLimit()) {
tol_wells = tol_wells*dynamic_thp_factor; tol_wells = tol_wells*dynamic_thp_factor;
@ -1357,7 +1363,7 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
solveEqAndUpdateWellState(const SummaryState& summary_state, solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
@ -1369,7 +1375,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(summary_state, dx_well, well_state, deferred_logger); updateWellState(simulator, dx_well, well_state, deferred_logger);
} }
@ -1383,8 +1389,7 @@ namespace Opm
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
const auto& summary_state = simulator.vanguard().summaryState(); updatePrimaryVariables(simulator, well_state, deferred_logger);
updatePrimaryVariables(summary_state, well_state, deferred_logger);
initPrimaryVariablesEvaluation(); initPrimaryVariablesEvaluation();
computeWellConnectionPressures(simulator, well_state, deferred_logger); computeWellConnectionPressures(simulator, well_state, deferred_logger);
this->computeAccumWell(); this->computeAccumWell();
@ -1427,7 +1432,7 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state, recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x, const BVector& x,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
@ -1438,7 +1443,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(summary_state, xw, well_state, deferred_logger); updateWellState(simulator, xw, well_state, deferred_logger);
} }
@ -1535,7 +1540,7 @@ namespace Opm
well_state_copy.wellRates(this->index_of_well_)[phase] well_state_copy.wellRates(this->index_of_well_)[phase]
= sign * ws.well_potentials[phase]; = sign * ws.well_potentials[phase];
} }
well_copy.updatePrimaryVariables(summary_state, well_state_copy, deferred_logger); well_copy.updatePrimaryVariables(simulator, well_state_copy, deferred_logger);
well_copy.initPrimaryVariablesEvaluation(); well_copy.initPrimaryVariablesEvaluation();
well_copy.computeAccumWell(); well_copy.computeAccumWell();
@ -1546,7 +1551,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(summary_state, well_state_copy, deferred_logger); well_copy.updatePrimaryVariables(simulator, well_state_copy, deferred_logger);
well_copy.computeWellConnectionPressures(simulator, well_state_copy, deferred_logger); well_copy.computeWellConnectionPressures(simulator, well_state_copy, deferred_logger);
well_copy.initPrimaryVariablesEvaluation(); well_copy.initPrimaryVariablesEvaluation();
well_copy.computeWellRatesWithBhp(simulator, bhp, well_flux, deferred_logger); well_copy.computeWellRatesWithBhp(simulator, bhp, well_flux, deferred_logger);
@ -1598,7 +1603,7 @@ namespace Opm
DeferredLogger& deferred_logger) const DeferredLogger& deferred_logger) const
{ {
// Create a copy of the well. // Create a copy of the well.
// TODO: check if we can avoid taking multiple copies. Call from updateWellPotentials // TODO: check if we can avoid taking multiple copies. Call from updateWellPotentials
// is allready a copy, but not from other calls. // is allready a copy, but not from other calls.
StandardWell<TypeTag> well_copy(*this); StandardWell<TypeTag> well_copy(*this);
@ -1618,7 +1623,7 @@ namespace Opm
// prepare/modify well state and control // prepare/modify well state and control
well_copy.prepareForPotentialCalculations(summary_state, well_state_copy, inj_controls, prod_controls); well_copy.prepareForPotentialCalculations(summary_state, well_state_copy, inj_controls, prod_controls);
// initialize rates from previous potentials // initialize rates from previous potentials
const int np = this->number_of_phases_; const int np = this->number_of_phases_;
bool trivial = true; bool trivial = true;
@ -1718,7 +1723,7 @@ namespace Opm
if (this->param_.local_well_solver_control_switching_) { if (this->param_.local_well_solver_control_switching_) {
converged_implicit = computeWellPotentialsImplicit(simulator, well_potentials, deferred_logger); converged_implicit = computeWellPotentialsImplicit(simulator, well_potentials, deferred_logger);
} }
if (!converged_implicit) { if (!converged_implicit) {
// does the well have a THP related constraint? // does the well have a THP related constraint?
const auto& summaryState = simulator.vanguard().summaryState(); const auto& summaryState = simulator.vanguard().summaryState();
if (!Base::wellHasTHPConstraints(summaryState) || bhp_controlled_well) { if (!Base::wellHasTHPConstraints(summaryState) || bhp_controlled_well) {
@ -1774,13 +1779,13 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
void void
StandardWell<TypeTag>:: StandardWell<TypeTag>::
updatePrimaryVariables(const SummaryState& summary_state, updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return; if (!this->isOperableAndSolvable() && !this->wellIsStopped()) return;
const bool stop_or_zero_rate_target = this->stopppedOrZeroRateTarget(summary_state, well_state); const bool stop_or_zero_rate_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger);
this->primary_variables_.update(well_state, stop_or_zero_rate_target, deferred_logger); this->primary_variables_.update(well_state, stop_or_zero_rate_target, deferred_logger);
// other primary variables related to polymer injection // other primary variables related to polymer injection
@ -1841,7 +1846,7 @@ namespace Opm
PerforationRates<Scalar> perf_rates; PerforationRates<Scalar> perf_rates;
Scalar trans_mult = simulator.problem().template wellTransMultiplier<Scalar>(int_quant, cell_idx); Scalar trans_mult = simulator.problem().template wellTransMultiplier<Scalar>(int_quant, cell_idx);
const auto& wellstate_nupcol = simulator.problem().wellModel().nupcolWellState().well(this->index_of_well_); const auto& wellstate_nupcol = simulator.problem().wellModel().nupcolWellState().well(this->index_of_well_);
const std::vector<Scalar> Tw = this->wellIndex(perf, int_quant, trans_mult, wellstate_nupcol); const std::vector<Scalar> Tw = this->wellIndex(perf, int_quant, trans_mult, wellstate_nupcol);
computePerfRate(int_quant, mob, bhp, Tw, perf, allow_cf, cq_s, computePerfRate(int_quant, mob, bhp, Tw, perf, allow_cf, cq_s,
perf_rates, deferred_logger); perf_rates, deferred_logger);
// TODO: make area a member // TODO: make area a member
@ -2300,7 +2305,6 @@ namespace Opm
bool converged; bool converged;
bool relax_convergence = false; bool relax_convergence = false;
this->regularize_ = false; this->regularize_ = false;
const auto& summary_state = simulator.vanguard().summaryState();
do { do {
assembleWellEqWithoutIteration(simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger); assembleWellEqWithoutIteration(simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger);
@ -2309,7 +2313,7 @@ namespace Opm
this->regularize_ = true; this->regularize_ = true;
} }
auto report = getWellConvergence(summary_state, well_state, Base::B_avg_, deferred_logger, relax_convergence); auto report = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, relax_convergence);
converged = report.converged(); converged = report.converged();
if (converged) { if (converged) {
@ -2317,7 +2321,7 @@ namespace Opm
} }
++it; ++it;
solveEqAndUpdateWellState(summary_state, well_state, deferred_logger); solveEqAndUpdateWellState(simulator, 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
@ -2340,8 +2344,8 @@ namespace Opm
const Well::ProductionControls& prod_controls, const Well::ProductionControls& prod_controls,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
const GroupState<Scalar>& group_state, const GroupState<Scalar>& group_state,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
const bool fixed_control /*false*/, const bool fixed_control /*false*/,
const bool fixed_status /*false*/) const bool fixed_status /*false*/)
{ {
const int max_iter = this->param_.max_inner_iter_wells_; const int max_iter = this->param_.max_inner_iter_wells_;
@ -2352,8 +2356,8 @@ namespace Opm
const auto& summary_state = simulator.vanguard().summaryState(); const auto& summary_state = simulator.vanguard().summaryState();
// Always take a few (more than one) iterations after a switch before allowing a new switch // Always take a few (more than one) iterations after a switch before allowing a new switch
// The optimal number here is subject to further investigation, but it has been observerved // The optimal number here is subject to further investigation, but it has been observerved
// that unless this number is >1, we may get stuck in a cycle // that unless this number is >1, we may get stuck in a cycle
constexpr int min_its_after_switch = 4; constexpr int min_its_after_switch = 4;
int its_since_last_switch = min_its_after_switch; int its_since_last_switch = min_its_after_switch;
int switch_count= 0; int switch_count= 0;
@ -2366,11 +2370,10 @@ namespace Opm
const bool allow_open = this->well_ecl_.getStatus() == WellStatus::OPEN && const bool allow_open = this->well_ecl_.getStatus() == WellStatus::OPEN &&
well_state.well(this->index_of_well_).status == WellStatus::OPEN; well_state.well(this->index_of_well_).status == WellStatus::OPEN;
// don't allow switcing for wells under zero rate target or requested fixed status and control // don't allow switcing for wells under zero rate target or requested fixed status and control
//const bool allow_switching = !this->wellUnderZeroRateTarget(summary_state, well_state) && const bool allow_switching =
// (!fixed_control || !fixed_status) && allow_open; !this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger) &&
const bool allow_switching = !this->wellUnderZeroRateTargetVersion(simulator, well_state, deferred_logger) && (!fixed_control || !fixed_status) && allow_open;
(!fixed_control || !fixed_status) && allow_open;
bool changed = false; bool changed = false;
bool final_check = false; bool final_check = false;
// well needs to be set operable or else solving/updating of re-opened wells is skipped // well needs to be set operable or else solving/updating of re-opened wells is skipped
@ -2405,7 +2408,7 @@ namespace Opm
this->regularize_ = true; this->regularize_ = true;
} }
auto report = getWellConvergence(summary_state, well_state, Base::B_avg_, deferred_logger, relax_convergence); auto report = getWellConvergence(simulator, well_state, Base::B_avg_, deferred_logger, relax_convergence);
converged = report.converged(); converged = report.converged();
if (converged) { if (converged) {
@ -2420,11 +2423,11 @@ namespace Opm
} }
++it; ++it;
solveEqAndUpdateWellState(summary_state, well_state, deferred_logger); solveEqAndUpdateWellState(simulator, well_state, deferred_logger);
initPrimaryVariablesEvaluation(); initPrimaryVariablesEvaluation();
} while (it < max_iter); } while (it < max_iter);
if (converged) { if (converged) {
if (allow_switching){ if (allow_switching){
// update operability if status change // update operability if status change

View File

@ -155,13 +155,13 @@ public:
virtual void initPrimaryVariablesEvaluation() = 0; virtual void initPrimaryVariablesEvaluation() = 0;
virtual ConvergenceReport getWellConvergence(const SummaryState& summary_state, virtual ConvergenceReport getWellConvergence(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
const std::vector<Scalar>& B_avg, const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger, DeferredLogger& deferred_logger,
const bool relax_tolerance) const = 0; const bool relax_tolerance) const = 0;
virtual void solveEqAndUpdateWellState(const SummaryState& summary_state, virtual void solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) = 0; DeferredLogger& deferred_logger) = 0;
@ -198,7 +198,7 @@ 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 SummaryState& summary_state, virtual void recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x, const BVector& x,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) = 0; DeferredLogger& deferred_logger) = 0;
@ -225,13 +225,13 @@ public:
std::vector<Scalar>& well_flux, std::vector<Scalar>& well_flux,
DeferredLogger& deferred_logger) const = 0; DeferredLogger& deferred_logger) const = 0;
bool wellUnderZeroRateTargetVersion(const Simulator& simulator, bool wellUnderZeroRateTarget(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const; DeferredLogger& deferred_logger) const;
bool stoppedOrZeroRateTargetVersion(const Simulator& simulator, bool stoppedOrZeroRateTarget(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const; DeferredLogger& deferred_logger) const;
bool updateWellStateWithTHPTargetProd(const Simulator& simulator, bool updateWellStateWithTHPTargetProd(const Simulator& simulator,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
@ -254,7 +254,7 @@ public:
const bool fixed_control = false, const bool fixed_control = false,
const bool fixed_status = false); const bool fixed_status = false);
virtual void updatePrimaryVariables(const SummaryState& summary_state, virtual void updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) = 0; DeferredLogger& deferred_logger) = 0;

View File

@ -305,6 +305,42 @@ getGroupProductionTargetRate(const Group& group,
deferred_logger); deferred_logger);
} }
template<typename FluidSystem>
bool
WellInterfaceFluidSystem<FluidSystem>::
wellUnderZeroRateTargetGroup(const SummaryState& summary_state,
const Schedule& schedule,
const WellState<Scalar>& well_state,
const GroupState<Scalar>& group_state,
DeferredLogger& deferred_logger) const
{
const auto& well = this->well_ecl_;
const auto& group = schedule.getGroup(well.groupName(), this->currentStep());
const Scalar efficiencyFactor = well.getEfficiencyFactor();
if (this->isInjector()) {
// Check injector under group control
const auto& controls = well.injectionControls(summary_state);
const std::optional<Scalar> target =
this->getGroupInjectionTargetRate(group, well_state,
group_state, schedule,
summary_state, controls.injector_type,
efficiencyFactor, deferred_logger);
if (target.has_value()) {
return target.value() == 0.0;
} else {
return false;
}
} else {
// Check producer under group control
const Scalar scale =
this->getGroupProductionTargetRate(group, well_state,
group_state, schedule,
summary_state, efficiencyFactor,
deferred_logger);
return scale == 0.0;
}
}
template class WellInterfaceFluidSystem<BlackOilFluidSystem<double,BlackOilDefaultIndexTraits>>; template class WellInterfaceFluidSystem<BlackOilFluidSystem<double,BlackOilDefaultIndexTraits>>;
} // namespace Opm } // namespace Opm

View File

@ -117,6 +117,12 @@ protected:
Scalar efficiencyFactor, Scalar efficiencyFactor,
DeferredLogger& deferred_logger) const; DeferredLogger& deferred_logger) const;
bool wellUnderZeroRateTargetGroup(const SummaryState& summary_state,
const Schedule& schedule,
const WellState<Scalar>& well_state,
const GroupState<Scalar>& group_state,
DeferredLogger& deferredLogger) const;
// For the conversion between the surface volume rate and reservoir voidage rate // For the conversion between the surface volume rate and reservoir voidage rate
const RateConverterType& rateConverter_; const RateConverterType& rateConverter_;
}; };

View File

@ -24,6 +24,7 @@
#include <opm/common/ErrorMacros.hpp> #include <opm/common/ErrorMacros.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/input/eclipse/Schedule/Well/FilterCake.hpp> #include <opm/input/eclipse/Schedule/Well/FilterCake.hpp>
#include <opm/input/eclipse/Schedule/Well/WellBrineProperties.hpp> #include <opm/input/eclipse/Schedule/Well/WellBrineProperties.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp> #include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
@ -605,8 +606,8 @@ isPressureControlled(const WellState<Scalar>& well_state) const
template<class Scalar> template<class Scalar>
bool WellInterfaceGeneric<Scalar>:: bool WellInterfaceGeneric<Scalar>::
wellUnderZeroRateTarget(const SummaryState& summary_state, wellUnderZeroRateTargetIndividual(const SummaryState& summary_state,
const WellState<Scalar>& well_state) const const WellState<Scalar>& well_state) const
{ {
if (this->isProducer()) { // producers if (this->isProducer()) { // producers
const auto prod_controls = this->well_ecl_.productionControls(summary_state); const auto prod_controls = this->well_ecl_.productionControls(summary_state);
@ -619,15 +620,6 @@ wellUnderZeroRateTarget(const SummaryState& summary_state,
} }
} }
template<class Scalar>
bool WellInterfaceGeneric<Scalar>::
stopppedOrZeroRateTarget(const SummaryState& summary_state,
const WellState<Scalar>& well_state) const
{
return (this->wellIsStopped() || this->wellUnderZeroRateTarget(summary_state, well_state));
}
template<class Scalar> template<class Scalar>
void WellInterfaceGeneric<Scalar>::resetWellOperability() void WellInterfaceGeneric<Scalar>::resetWellOperability()
{ {

View File

@ -173,9 +173,6 @@ public:
bool isPressureControlled(const WellState<Scalar>& well_state) const; bool isPressureControlled(const WellState<Scalar>& well_state) const;
bool stopppedOrZeroRateTarget(const SummaryState& summary_state,
const WellState<Scalar>& well_state) const;
Scalar wellEfficiencyFactor() const { return well_efficiency_factor_; } Scalar wellEfficiencyFactor() const { return well_efficiency_factor_; }
//! \brief Update filter cake multipliers. //! \brief Update filter cake multipliers.
@ -200,8 +197,8 @@ protected:
int polymerInjTable_() const; int polymerInjTable_() const;
int polymerWaterTable_() const; int polymerWaterTable_() const;
bool wellUnderZeroRateTarget(const SummaryState& summary_state, bool wellUnderZeroRateTargetIndividual(const SummaryState& summary_state,
const WellState<Scalar>& well_state) const; const WellState<Scalar>& well_state) const;
std::pair<bool,bool> std::pair<bool,bool>
computeWellPotentials(std::vector<Scalar>& well_potentials, computeWellPotentials(std::vector<Scalar>& well_potentials,

View File

@ -198,8 +198,7 @@ namespace Opm
const GroupState<Scalar>& group_state, const GroupState<Scalar>& group_state,
DeferredLogger& deferred_logger) /* const */ DeferredLogger& deferred_logger) /* const */
{ {
const auto& summary_state = simulator.vanguard().summaryState(); if (stoppedOrZeroRateTarget(simulator, well_state, deferred_logger)) {
if (this->stopppedOrZeroRateTarget(summary_state, well_state)) {
return false; return false;
} }
@ -260,7 +259,7 @@ namespace Opm
this->well_control_log_.push_back(from); this->well_control_log_.push_back(from);
updateWellStateWithTarget(simulator, group_state, well_state, deferred_logger); updateWellStateWithTarget(simulator, group_state, well_state, deferred_logger);
updatePrimaryVariables(summaryState, well_state, deferred_logger); updatePrimaryVariables(simulator, well_state, deferred_logger);
} }
return changed; return changed;
@ -282,7 +281,7 @@ namespace Opm
const auto& summary_state = simulator.vanguard().summaryState(); const auto& summary_state = simulator.vanguard().summaryState();
const auto& schedule = simulator.vanguard().schedule(); const auto& schedule = simulator.vanguard().schedule();
if (this->wellUnderZeroRateTarget(summary_state, well_state) || !(this->well_ecl_.getStatus() == WellStatus::OPEN)) { if (this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger) || !(this->well_ecl_.getStatus() == WellStatus::OPEN)) {
return false; return false;
} }
@ -311,8 +310,8 @@ namespace Opm
updateWellStateWithTarget(simulator, group_state, well_state, deferred_logger); updateWellStateWithTarget(simulator, group_state, well_state, deferred_logger);
} else { } else {
ws.thp = this->getTHPConstraint(summary_state); ws.thp = this->getTHPConstraint(summary_state);
} }
updatePrimaryVariables(summary_state, well_state, deferred_logger); updatePrimaryVariables(simulator, well_state, deferred_logger);
} }
} }
return changed; return changed;
@ -377,8 +376,7 @@ 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);
const auto& summary_state = simulator.vanguard().summaryState(); updatePrimaryVariables(simulator, well_state_copy, deferred_logger);
updatePrimaryVariables(summary_state, well_state_copy, deferred_logger);
initPrimaryVariablesEvaluation(); initPrimaryVariablesEvaluation();
if (this->isProducer()) { if (this->isProducer()) {
@ -539,13 +537,13 @@ namespace Opm
const bool isThp = ws.production_cmode == Well::ProducerCMode::THP; const bool isThp = ws.production_cmode == Well::ProducerCMode::THP;
// check stability of solution under thp-control // check stability of solution under thp-control
if (converged && !this->stopppedOrZeroRateTarget(summary_state, well_state) && isThp) { if (converged && !stoppedOrZeroRateTarget(simulator, well_state, deferred_logger) && isThp) {
auto rates = well_state.well(this->index_of_well_).surface_rates; auto rates = well_state.well(this->index_of_well_).surface_rates;
this->adaptRatesForVFP(rates); this->adaptRatesForVFP(rates);
this->updateIPRImplicit(simulator, well_state, deferred_logger); this->updateIPRImplicit(simulator, well_state, deferred_logger);
bool is_stable = WellBhpThpCalculator(*this).isStableSolution(well_state, this->well_ecl_, rates, summary_state); bool is_stable = WellBhpThpCalculator(*this).isStableSolution(well_state, this->well_ecl_, rates, summary_state);
if (!is_stable) { if (!is_stable) {
// solution converged to an unstable point! // solution converged to an unstable point!
this->operability_status_.use_vfpexplicit = true; this->operability_status_.use_vfpexplicit = true;
auto bhp_stable = WellBhpThpCalculator(*this).estimateStableBhp(well_state, this->well_ecl_, rates, this->getRefDensity(), summary_state); auto bhp_stable = WellBhpThpCalculator(*this).estimateStableBhp(well_state, this->well_ecl_, rates, this->getRefDensity(), summary_state);
// if we find an intersection with a sufficiently lower bhp, re-solve equations // if we find an intersection with a sufficiently lower bhp, re-solve equations
@ -570,10 +568,10 @@ namespace Opm
if (!bhp_target.has_value()) { if (!bhp_target.has_value()) {
// well can't operate using explicit fractions // well can't operate using explicit fractions
is_operable = false; is_operable = false;
// solve with zero rate // solve with zero rate
converged = solveWellWithZeroRate(simulator, dt, well_state, deferred_logger); converged = solveWellWithZeroRate(simulator, dt, well_state, deferred_logger);
this->stopWell(); this->stopWell();
} else { } else {
// solve well with the estimated target bhp (or limit) // solve well with the estimated target bhp (or limit)
const Scalar bhp = std::max(bhp_target.value(), const Scalar bhp = std::max(bhp_target.value(),
static_cast<Scalar>(prod_controls.bhp_limit)); static_cast<Scalar>(prod_controls.bhp_limit));
@ -602,8 +600,8 @@ namespace Opm
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
const SummaryState& summary_state, const SummaryState& summary_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
// Given an unconverged well or closed well, estimate an operable bhp (if any) // Given an unconverged well or closed well, estimate an operable bhp (if any)
// Get minimal bhp from vfp-curve // Get minimal bhp from vfp-curve
Scalar bhp_min = WellBhpThpCalculator(*this).calculateMinimumBhpFromThp(well_state, this->well_ecl_, summary_state, this->getRefDensity()); Scalar bhp_min = WellBhpThpCalculator(*this).calculateMinimumBhpFromThp(well_state, this->well_ecl_, summary_state, this->getRefDensity());
// Solve // Solve
@ -615,7 +613,7 @@ namespace Opm
auto rates = well_state.well(this->index_of_well_).surface_rates; auto rates = well_state.well(this->index_of_well_).surface_rates;
this->adaptRatesForVFP(rates); this->adaptRatesForVFP(rates);
return WellBhpThpCalculator(*this).estimateStableBhp(well_state, this->well_ecl_, rates, this->getRefDensity(), summary_state); return WellBhpThpCalculator(*this).estimateStableBhp(well_state, this->well_ecl_, rates, this->getRefDensity(), summary_state);
} }
template<typename TypeTag> template<typename TypeTag>
bool bool
@ -625,11 +623,11 @@ namespace Opm
const Scalar bhp, const Scalar bhp,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
// Solve a well using single bhp-constraint (but close if not operable under this) // Solve a well using single bhp-constraint (but close if not operable under this)
auto group_state = GroupState<Scalar>(); // empty group auto group_state = GroupState<Scalar>(); // empty group
auto inj_controls = Well::InjectionControls(0); auto inj_controls = Well::InjectionControls(0);
auto prod_controls = Well::ProductionControls(0); auto prod_controls = Well::ProductionControls(0);
auto& ws = well_state.well(this->index_of_well_); auto& ws = well_state.well(this->index_of_well_);
auto cmode_inj = ws.injection_cmode; auto cmode_inj = ws.injection_cmode;
auto cmode_prod = ws.production_cmode; auto cmode_prod = ws.production_cmode;
@ -637,21 +635,21 @@ namespace Opm
inj_controls.addControl(Well::InjectorCMode::BHP); inj_controls.addControl(Well::InjectorCMode::BHP);
inj_controls.bhp_limit = bhp; inj_controls.bhp_limit = bhp;
inj_controls.cmode = Well::InjectorCMode::BHP; inj_controls.cmode = Well::InjectorCMode::BHP;
ws.injection_cmode = Well::InjectorCMode::BHP; ws.injection_cmode = Well::InjectorCMode::BHP;
} else { } else {
prod_controls.addControl(Well::ProducerCMode::BHP); prod_controls.addControl(Well::ProducerCMode::BHP);
prod_controls.bhp_limit = bhp; prod_controls.bhp_limit = bhp;
prod_controls.cmode = Well::ProducerCMode::BHP; prod_controls.cmode = Well::ProducerCMode::BHP;
ws.production_cmode = Well::ProducerCMode::BHP; ws.production_cmode = Well::ProducerCMode::BHP;
} }
// update well-state // update well-state
ws.bhp = bhp; ws.bhp = bhp;
// solve // solve
const bool converged = this->iterateWellEqWithSwitching(simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger, /*fixed_control*/true); const bool converged = this->iterateWellEqWithSwitching(simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger, /*fixed_control*/true);
ws.injection_cmode = cmode_inj; ws.injection_cmode = cmode_inj;
ws.production_cmode = cmode_prod; ws.production_cmode = cmode_prod;
return converged; return converged;
} }
template<typename TypeTag> template<typename TypeTag>
bool bool
@ -660,18 +658,18 @@ namespace Opm
const double dt, const double dt,
WellState<Scalar>& well_state, WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) DeferredLogger& deferred_logger)
{ {
// Solve a well as stopped // Solve a well as stopped
const auto well_status_orig = this->wellStatus_; const auto well_status_orig = this->wellStatus_;
this->stopWell(); this->stopWell();
auto group_state = GroupState<Scalar>(); // empty group auto group_state = GroupState<Scalar>(); // empty group
auto inj_controls = Well::InjectionControls(0); auto inj_controls = Well::InjectionControls(0);
auto prod_controls = Well::ProductionControls(0); auto prod_controls = Well::ProductionControls(0);
const bool converged = this->iterateWellEqWithSwitching(simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger, /*fixed_control*/true, /*fixed_status*/ true); const bool converged = this->iterateWellEqWithSwitching(simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger, /*fixed_control*/true, /*fixed_status*/ true);
this->wellStatus_ = well_status_orig; this->wellStatus_ = well_status_orig;
return converged; return converged;
} }
template<typename TypeTag> template<typename TypeTag>
bool bool
@ -1430,67 +1428,39 @@ namespace Opm
template<typename TypeTag> template<typename TypeTag>
bool bool
WellInterface<TypeTag>:: WellInterface<TypeTag>::
wellUnderZeroRateTargetVersion(const Simulator& simulator, wellUnderZeroRateTarget(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const DeferredLogger& deferred_logger) const
{ {
// Extended version of WellInterfaceGeneric::wellUnderZeroRateTarget that also checks group controls // Check if well is under zero rate control, either directly or from group
const auto& ws = well_state.well(this->index_of_well_); const auto& ws = well_state.well(this->index_of_well_);
const auto& summaryState = simulator.vanguard().summaryState();
const bool isGroupControlled = (this->isInjector() && ws.injection_cmode == Well::InjectorCMode::GRUP) || const bool isGroupControlled = (this->isInjector() && ws.injection_cmode == Well::InjectorCMode::GRUP) ||
(this->isProducer() && ws.production_cmode == Well::ProducerCMode::GRUP); (this->isProducer() && ws.production_cmode == Well::ProducerCMode::GRUP);
if (!isGroupControlled) { if (!isGroupControlled) {
// well is not under group control, check "light-weight" version // well is not under group control, check "individual" version
return this->wellUnderZeroRateTarget(summaryState, well_state); const auto& summaryState = simulator.vanguard().summaryState();
return this->wellUnderZeroRateTargetIndividual(summaryState, well_state);
} else { } else {
const auto& well = this->well_ecl_; const auto& summaryState = simulator.vanguard().summaryState();
const auto& schedule = simulator.vanguard().schedule();
const auto& group_state = simulator.problem().wellModel().groupState(); const auto& group_state = simulator.problem().wellModel().groupState();
const auto& group = schedule.getGroup(well.groupName(), this->currentStep()); const auto& schedule = simulator.vanguard().schedule();
const Scalar efficiencyFactor = well.getEfficiencyFactor(); return this->wellUnderZeroRateTargetGroup(summaryState, schedule, well_state, group_state, deferred_logger);
if (this->isInjector()) {
// Check injector under group control
const auto& controls = well.injectionControls(summaryState);
std::optional<Scalar> target = this->getGroupInjectionTargetRate(group,
well_state,
group_state,
schedule,
summaryState,
controls.injector_type,
efficiencyFactor,
deferred_logger);
if (target.has_value()) {
return target.value() == 0.0;
} else {
return false;
}
} else {
// Check producer under group control
Scalar scale = this->getGroupProductionTargetRate(group,
well_state,
group_state,
schedule,
summaryState,
efficiencyFactor,
deferred_logger);
return scale == 0.0;
}
} }
} }
template<typename TypeTag> template<typename TypeTag>
bool bool
WellInterface<TypeTag>:: WellInterface<TypeTag>::
stoppedOrZeroRateTargetVersion(const Simulator& simulator, stoppedOrZeroRateTarget(const Simulator& simulator,
const WellState<Scalar>& well_state, const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const DeferredLogger& deferred_logger) const
{ {
// Extended version of WellInterfaceGeneric::stopppedOrZeroRateTarget that also checks group controls // Check if well is stopped or under zero rate control, either directly or from group
return (this->wellIsStopped() || wellUnderZeroRateTargetVersion(simulator, return (this->wellIsStopped() || wellUnderZeroRateTarget(simulator,
well_state, well_state,
deferred_logger)); deferred_logger));
} }
template<typename TypeTag> template<typename TypeTag>
std::vector<typename WellInterface<TypeTag>::Scalar> std::vector<typename WellInterface<TypeTag>::Scalar>
WellInterface<TypeTag>:: WellInterface<TypeTag>::