Merge pull request #5232 from steink/check_zero_target_from_group

When checking for zero target rates, also check wells under group control where required
This commit is contained in:
Bård Skaflestad 2024-05-27 22:09:26 +02:00 committed by GitHub
commit 8199342ce9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 215 additions and 134 deletions

View File

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

View File

@ -94,7 +94,7 @@ namespace Opm {
DeferredLogger& deferred_logger) const override;
/// 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 std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger,
@ -107,7 +107,7 @@ namespace Opm {
/// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State
void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
void recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override;
@ -118,11 +118,11 @@ namespace Opm {
std::vector<Scalar>& well_potentials,
DeferredLogger& deferred_logger) override;
void updatePrimaryVariables(const SummaryState& summary_state,
void updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override;
void solveEqAndUpdateWellState(const SummaryState& summary_state,
void solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override; // const?
@ -174,7 +174,7 @@ namespace Opm {
mutable int debug_cost_counter_ = 0;
// updating the well_state based on well solution dwells
void updateWellState(const SummaryState& summary_state,
void updateWellState(const Simulator& simulator,
const BVectorWell& dwells,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger,

View File

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

View File

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

View File

@ -162,11 +162,11 @@ namespace Opm
template <typename TypeTag>
void
MultisegmentWell<TypeTag>::
updatePrimaryVariables(const SummaryState& summary_state,
updatePrimaryVariables(const Simulator& simulator,
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);
}
@ -199,7 +199,7 @@ namespace Opm
template <typename TypeTag>
ConvergenceReport
MultisegmentWell<TypeTag>::
getWellConvergence(const SummaryState& /* summary_state */,
getWellConvergence(const Simulator& /* simulator */,
const WellState<Scalar>& well_state,
const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger,
@ -260,7 +260,7 @@ namespace Opm
template <typename TypeTag>
void
MultisegmentWell<TypeTag>::
recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
@ -271,7 +271,7 @@ namespace Opm
BVectorWell xw(1);
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>
void
MultisegmentWell<TypeTag>::
solveEqAndUpdateWellState(const SummaryState& summary_state,
solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
{
@ -589,7 +589,7 @@ namespace Opm
try{
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) {
// Add information about the well and log to deferred logger
@ -681,7 +681,7 @@ namespace Opm
template <typename TypeTag>
void
MultisegmentWell<TypeTag>::
updateWellState(const SummaryState& summary_state,
updateWellState(const Simulator& simulator,
const BVectorWell& dwells,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger,
@ -691,15 +691,20 @@ namespace Opm
const Scalar dFLimit = this->param_.dwell_fraction_max_;
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,
relaxation_factor,
dFLimit,
stop_or_zero_rate_target,
max_pressure_change);
this->primary_variables_.copyToWellState(*this, getRefDensity(), stop_or_zero_rate_target,
well_state, summary_state, deferred_logger);
const auto& summary_state = simulator.vanguard().summaryState();
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_);
@ -720,8 +725,7 @@ namespace Opm
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
{
const auto& summary_state = simulator.vanguard().summaryState();
updatePrimaryVariables(summary_state, well_state, deferred_logger);
updatePrimaryVariables(simulator, well_state, deferred_logger);
initPrimaryVariablesEvaluation();
computePerfCellPressDiffs(simulator);
computeInitialSegmentFluids(simulator);
@ -1489,8 +1493,7 @@ namespace Opm
this->regularize_ = true;
}
const auto& summary_state = simulator.vanguard().summaryState();
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);
if (report.converged()) {
converged = true;
break;
@ -1526,7 +1529,7 @@ namespace Opm
++stagnate_count;
if (stagnate_count == 6) {
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()) {
converged = true;
sstr << " well " << this->name() << " manages to get converged with relaxed tolerances in " << it << " inner iterations";
@ -1553,7 +1556,7 @@ namespace Opm
this->regularize_ = true;
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();
}
@ -1635,7 +1638,7 @@ namespace Opm
const bool allow_open = this->well_ecl_.getStatus() == 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
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;
bool changed = false;
bool final_check = false;
@ -1673,7 +1676,7 @@ namespace Opm
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();
if (converged) {
// 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
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());
const auto reportStag = getWellConvergence(summary_state, well_state, Base::B_avg_,
const auto reportStag = getWellConvergence(simulator, well_state, Base::B_avg_,
deferred_logger, true);
if (reportStag.converged()) {
converged = true;
@ -1745,7 +1748,7 @@ namespace Opm
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();
}
@ -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
const auto& summaryState = simulator.vanguard().summaryState();
const Schedule& schedule = simulator.vanguard().schedule();
const bool stopped_or_zero_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger);
MultisegmentWellAssemble(*this).
assembleControlEq(well_state,
group_state,
@ -1920,6 +1924,7 @@ namespace Opm
getRefDensity(),
this->primary_variables_,
this->linSys_,
stopped_or_zero_target,
deferred_logger);
} else {
const UnitSystem& unit_system = simulator.vanguard().eclState().getDeckUnitSystem();

View File

@ -140,7 +140,7 @@ namespace Opm
void initPrimaryVariablesEvaluation() override;
/// 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 std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger,
@ -153,7 +153,7 @@ namespace Opm
/// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State
void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
void recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override;
@ -164,11 +164,11 @@ namespace Opm
std::vector<Scalar>& well_potentials,
DeferredLogger& deferred_logger) /* const */ override;
void updatePrimaryVariables(const SummaryState& summary_state,
void updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override;
void solveEqAndUpdateWellState(const SummaryState& summary_state,
void solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) override;
@ -262,7 +262,7 @@ namespace Opm
bool regularize_;
// updating the well_state based on well solution dwells
void updateWellState(const SummaryState& summary_state,
void updateWellState(const Simulator& simulator,
const BVectorWell& dwells,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger);

View File

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

View File

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

View File

@ -462,6 +462,7 @@ namespace Opm
const auto& summaryState = simulator.vanguard().summaryState();
const Schedule& schedule = simulator.vanguard().schedule();
const bool stopped_or_zero_target = this->stoppedOrZeroRateTarget(simulator, well_state, deferred_logger);
StandardWellAssemble<FluidSystem,Indices>(*this).
assembleControlEq(well_state, group_state,
schedule, summaryState,
@ -469,6 +470,7 @@ namespace Opm
this->primary_variables_,
this->connections_.rho(),
this->linSys_,
stopped_or_zero_target,
deferred_logger);
@ -692,16 +694,17 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
updateWellState(const SummaryState& summary_state,
updateWellState(const Simulator& simulator,
const BVectorWell& dwells,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
{
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);
const auto& summary_state = simulator.vanguard().summaryState();
updateWellStateFromPrimaryVariables(stop_or_zero_rate_target, well_state, summary_state, deferred_logger);
Base::calculateReservoirRates(well_state.well(this->index_of_well_));
}
@ -805,7 +808,10 @@ namespace Opm
// the well index associated with the connection
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 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_b_perf(this->ipr_b_.size());
for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx) {
@ -849,11 +855,11 @@ namespace Opm
updateIPRImplicit(const Simulator& simulator,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
{
{
// 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)
// 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
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());
deferred_logger.debug(msg);
/*
// could revert to standard approach here:
// could revert to standard approach here:
updateIPR(simulator, deferred_logger);
for (int comp_idx = 0; comp_idx < this->num_components_; ++comp_idx){
const int idx = this->modelCompIdxToFlowCompIdx(comp_idx);
@ -876,12 +882,12 @@ namespace Opm
}
return;
*/
}
}
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_b.begin(), ws.implicit_ipr_b.end(), 0.);
auto inj_controls = Well::InjectionControls(0);
auto prod_controls = Well::ProductionControls(0);
prod_controls.addControl(Well::ProducerCMode::BHP);
@ -898,7 +904,7 @@ namespace Opm
rhs[0].resize(nEq);
// rhs = 0 except -1 for control eq
for (size_t i=0; i < nEq; ++i){
rhs[0][i] = 0.0;
rhs[0][i] = 0.0;
}
rhs[0][Bhp] = -1.0;
@ -910,7 +916,7 @@ namespace Opm
EvalWell comp_rate = this->primary_variables_.getQs(comp_idx);
const int idx = this->modelCompIdxToFlowCompIdx(comp_idx);
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_a[idx] = ws.implicit_ipr_b[idx]*ws.bhp - comp_rate.value();
@ -1175,7 +1181,7 @@ namespace Opm
template<typename TypeTag>
ConvergenceReport
StandardWell<TypeTag>::
getWellConvergence(const SummaryState& summary_state,
getWellConvergence(const Simulator& simulator,
const WellState<Scalar>& well_state,
const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger,
@ -1190,7 +1196,7 @@ namespace Opm
constexpr Scalar stopped_factor = 1.e-4;
// use stricter tolerance for dynamic thp to ameliorate network convergence
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;
} else if (this->getDynamicThpLimit()) {
tol_wells = tol_wells*dynamic_thp_factor;
@ -1357,7 +1363,7 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
solveEqAndUpdateWellState(const SummaryState& summary_state,
solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
{
@ -1369,7 +1375,7 @@ namespace Opm
dx_well[0].resize(this->primary_variables_.numWellEq());
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,
DeferredLogger& deferred_logger)
{
const auto& summary_state = simulator.vanguard().summaryState();
updatePrimaryVariables(summary_state, well_state, deferred_logger);
updatePrimaryVariables(simulator, well_state, deferred_logger);
initPrimaryVariablesEvaluation();
computeWellConnectionPressures(simulator, well_state, deferred_logger);
this->computeAccumWell();
@ -1427,7 +1432,7 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
@ -1438,7 +1443,7 @@ namespace Opm
xw[0].resize(this->primary_variables_.numWellEq());
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]
= 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.computeAccumWell();
@ -1546,7 +1551,7 @@ namespace Opm
" potentials are computed based on unconverged solution";
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.initPrimaryVariablesEvaluation();
well_copy.computeWellRatesWithBhp(simulator, bhp, well_flux, deferred_logger);
@ -1598,7 +1603,7 @@ namespace Opm
DeferredLogger& deferred_logger) const
{
// 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.
StandardWell<TypeTag> well_copy(*this);
@ -1618,7 +1623,7 @@ namespace Opm
// prepare/modify well state and control
well_copy.prepareForPotentialCalculations(summary_state, well_state_copy, inj_controls, prod_controls);
// initialize rates from previous potentials
const int np = this->number_of_phases_;
bool trivial = true;
@ -1718,7 +1723,7 @@ namespace Opm
if (this->param_.local_well_solver_control_switching_) {
converged_implicit = computeWellPotentialsImplicit(simulator, well_potentials, deferred_logger);
}
if (!converged_implicit) {
if (!converged_implicit) {
// does the well have a THP related constraint?
const auto& summaryState = simulator.vanguard().summaryState();
if (!Base::wellHasTHPConstraints(summaryState) || bhp_controlled_well) {
@ -1774,13 +1779,13 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
updatePrimaryVariables(const SummaryState& summary_state,
updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
{
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);
// other primary variables related to polymer injection
@ -1841,7 +1846,7 @@ namespace Opm
PerforationRates<Scalar> perf_rates;
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 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,
perf_rates, deferred_logger);
// TODO: make area a member
@ -2300,7 +2305,6 @@ namespace Opm
bool converged;
bool relax_convergence = false;
this->regularize_ = false;
const auto& summary_state = simulator.vanguard().summaryState();
do {
assembleWellEqWithoutIteration(simulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger);
@ -2309,7 +2313,7 @@ namespace Opm
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();
if (converged) {
@ -2317,7 +2321,7 @@ namespace Opm
}
++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
// 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,
WellState<Scalar>& well_state,
const GroupState<Scalar>& group_state,
DeferredLogger& deferred_logger,
const bool fixed_control /*false*/,
DeferredLogger& deferred_logger,
const bool fixed_control /*false*/,
const bool fixed_status /*false*/)
{
const int max_iter = this->param_.max_inner_iter_wells_;
@ -2352,8 +2356,8 @@ namespace Opm
const auto& summary_state = simulator.vanguard().summaryState();
// 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
// that unless this number is >1, we may get stuck in a cycle
// 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
constexpr int min_its_after_switch = 4;
int its_since_last_switch = min_its_after_switch;
int switch_count= 0;
@ -2366,8 +2370,10 @@ namespace Opm
const bool allow_open = this->well_ecl_.getStatus() == 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
const bool allow_switching = !this->wellUnderZeroRateTarget(summary_state, well_state) &&
(!fixed_control || !fixed_status) && allow_open;
const bool allow_switching =
!this->wellUnderZeroRateTarget(simulator, well_state, deferred_logger) &&
(!fixed_control || !fixed_status) && allow_open;
bool changed = false;
bool final_check = false;
// well needs to be set operable or else solving/updating of re-opened wells is skipped
@ -2402,7 +2408,7 @@ namespace Opm
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();
if (converged) {
@ -2417,11 +2423,11 @@ namespace Opm
}
++it;
solveEqAndUpdateWellState(summary_state, well_state, deferred_logger);
solveEqAndUpdateWellState(simulator, well_state, deferred_logger);
initPrimaryVariablesEvaluation();
} while (it < max_iter);
if (converged) {
if (allow_switching){
// update operability if status change

View File

@ -155,13 +155,13 @@ public:
virtual void initPrimaryVariablesEvaluation() = 0;
virtual ConvergenceReport getWellConvergence(const SummaryState& summary_state,
virtual ConvergenceReport getWellConvergence(const Simulator& simulator,
const WellState<Scalar>& well_state,
const std::vector<Scalar>& B_avg,
DeferredLogger& deferred_logger,
const bool relax_tolerance) const = 0;
virtual void solveEqAndUpdateWellState(const SummaryState& summary_state,
virtual void solveEqAndUpdateWellState(const Simulator& simulator,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) = 0;
@ -198,7 +198,7 @@ public:
/// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State
virtual void recoverWellSolutionAndUpdateWellState(const SummaryState& summary_state,
virtual void recoverWellSolutionAndUpdateWellState(const Simulator& simulator,
const BVector& x,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) = 0;
@ -225,6 +225,14 @@ public:
std::vector<Scalar>& well_flux,
DeferredLogger& deferred_logger) const = 0;
bool wellUnderZeroRateTarget(const Simulator& simulator,
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const;
bool stoppedOrZeroRateTarget(const Simulator& simulator,
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const;
bool updateWellStateWithTHPTargetProd(const Simulator& simulator,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const;
@ -246,7 +254,7 @@ public:
const bool fixed_control = false,
const bool fixed_status = false);
virtual void updatePrimaryVariables(const SummaryState& summary_state,
virtual void updatePrimaryVariables(const Simulator& simulator,
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) = 0;

View File

@ -305,6 +305,42 @@ getGroupProductionTargetRate(const Group& group,
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>>;
} // namespace Opm

View File

@ -117,6 +117,12 @@ protected:
Scalar efficiencyFactor,
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
const RateConverterType& rateConverter_;
};

View File

@ -24,6 +24,7 @@
#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/WellBrineProperties.hpp>
#include <opm/input/eclipse/Schedule/Well/WellConnections.hpp>
@ -605,8 +606,8 @@ isPressureControlled(const WellState<Scalar>& well_state) const
template<class Scalar>
bool WellInterfaceGeneric<Scalar>::
wellUnderZeroRateTarget(const SummaryState& summary_state,
const WellState<Scalar>& well_state) const
wellUnderZeroRateTargetIndividual(const SummaryState& summary_state,
const WellState<Scalar>& well_state) const
{
if (this->isProducer()) { // producers
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>
void WellInterfaceGeneric<Scalar>::resetWellOperability()
{

View File

@ -173,9 +173,6 @@ public:
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_; }
//! \brief Update filter cake multipliers.
@ -200,8 +197,8 @@ protected:
int polymerInjTable_() const;
int polymerWaterTable_() const;
bool wellUnderZeroRateTarget(const SummaryState& summary_state,
const WellState<Scalar>& well_state) const;
bool wellUnderZeroRateTargetIndividual(const SummaryState& summary_state,
const WellState<Scalar>& well_state) const;
std::pair<bool,bool>
computeWellPotentials(std::vector<Scalar>& well_potentials,

View File

@ -198,8 +198,7 @@ namespace Opm
const GroupState<Scalar>& group_state,
DeferredLogger& deferred_logger) /* const */
{
const auto& summary_state = simulator.vanguard().summaryState();
if (this->stopppedOrZeroRateTarget(summary_state, well_state)) {
if (stoppedOrZeroRateTarget(simulator, well_state, deferred_logger)) {
return false;
}
@ -260,7 +259,7 @@ namespace Opm
this->well_control_log_.push_back(from);
updateWellStateWithTarget(simulator, group_state, well_state, deferred_logger);
updatePrimaryVariables(summaryState, well_state, deferred_logger);
updatePrimaryVariables(simulator, well_state, deferred_logger);
}
return changed;
@ -282,7 +281,7 @@ namespace Opm
const auto& summary_state = simulator.vanguard().summaryState();
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;
}
@ -311,8 +310,8 @@ namespace Opm
updateWellStateWithTarget(simulator, group_state, well_state, deferred_logger);
} else {
ws.thp = this->getTHPConstraint(summary_state);
}
updatePrimaryVariables(summary_state, well_state, deferred_logger);
}
updatePrimaryVariables(simulator, well_state, deferred_logger);
}
}
return changed;
@ -377,8 +376,7 @@ namespace Opm
updateWellStateWithTarget(simulator, group_state, well_state_copy, deferred_logger);
calculateExplicitQuantities(simulator, well_state_copy, deferred_logger);
const auto& summary_state = simulator.vanguard().summaryState();
updatePrimaryVariables(summary_state, well_state_copy, deferred_logger);
updatePrimaryVariables(simulator, well_state_copy, deferred_logger);
initPrimaryVariablesEvaluation();
if (this->isProducer()) {
@ -539,13 +537,13 @@ namespace Opm
const bool isThp = ws.production_cmode == Well::ProducerCMode::THP;
// 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;
this->adaptRatesForVFP(rates);
this->updateIPRImplicit(simulator, well_state, deferred_logger);
bool is_stable = WellBhpThpCalculator(*this).isStableSolution(well_state, this->well_ecl_, rates, summary_state);
if (!is_stable) {
// solution converged to an unstable point!
// solution converged to an unstable point!
this->operability_status_.use_vfpexplicit = true;
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
@ -570,10 +568,10 @@ namespace Opm
if (!bhp_target.has_value()) {
// well can't operate using explicit fractions
is_operable = false;
// solve with zero rate
// solve with zero rate
converged = solveWellWithZeroRate(simulator, dt, well_state, deferred_logger);
this->stopWell();
} else {
} else {
// solve well with the estimated target bhp (or limit)
const Scalar bhp = std::max(bhp_target.value(),
static_cast<Scalar>(prod_controls.bhp_limit));
@ -602,8 +600,8 @@ namespace Opm
WellState<Scalar>& well_state,
const SummaryState& summary_state,
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
Scalar bhp_min = WellBhpThpCalculator(*this).calculateMinimumBhpFromThp(well_state, this->well_ecl_, summary_state, this->getRefDensity());
// Solve
@ -615,7 +613,7 @@ namespace Opm
auto rates = well_state.well(this->index_of_well_).surface_rates;
this->adaptRatesForVFP(rates);
return WellBhpThpCalculator(*this).estimateStableBhp(well_state, this->well_ecl_, rates, this->getRefDensity(), summary_state);
}
}
template<typename TypeTag>
bool
@ -625,11 +623,11 @@ namespace Opm
const Scalar bhp,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
{
{
// Solve a well using single bhp-constraint (but close if not operable under this)
auto group_state = GroupState<Scalar>(); // empty group
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 cmode_inj = ws.injection_cmode;
auto cmode_prod = ws.production_cmode;
@ -637,21 +635,21 @@ namespace Opm
inj_controls.addControl(Well::InjectorCMode::BHP);
inj_controls.bhp_limit = bhp;
inj_controls.cmode = Well::InjectorCMode::BHP;
ws.injection_cmode = Well::InjectorCMode::BHP;
ws.injection_cmode = Well::InjectorCMode::BHP;
} else {
prod_controls.addControl(Well::ProducerCMode::BHP);
prod_controls.bhp_limit = bhp;
prod_controls.cmode = Well::ProducerCMode::BHP;
ws.production_cmode = Well::ProducerCMode::BHP;
ws.production_cmode = Well::ProducerCMode::BHP;
}
// update well-state
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);
ws.injection_cmode = cmode_inj;
ws.production_cmode = cmode_prod;
return converged;
}
}
template<typename TypeTag>
bool
@ -660,18 +658,18 @@ namespace Opm
const double dt,
WellState<Scalar>& well_state,
DeferredLogger& deferred_logger)
{
{
// Solve a well as stopped
const auto well_status_orig = this->wellStatus_;
this->stopWell();
auto group_state = GroupState<Scalar>(); // empty group
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);
this->wellStatus_ = well_status_orig;
return converged;
}
}
template<typename TypeTag>
bool
@ -1427,6 +1425,42 @@ namespace Opm
}
}
template<typename TypeTag>
bool
WellInterface<TypeTag>::
wellUnderZeroRateTarget(const Simulator& simulator,
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const
{
// Check if well is under zero rate control, either directly or from group
const auto& ws = well_state.well(this->index_of_well_);
const bool isGroupControlled = (this->isInjector() && ws.injection_cmode == Well::InjectorCMode::GRUP) ||
(this->isProducer() && ws.production_cmode == Well::ProducerCMode::GRUP);
if (!isGroupControlled) {
// well is not under group control, check "individual" version
const auto& summaryState = simulator.vanguard().summaryState();
return this->wellUnderZeroRateTargetIndividual(summaryState, well_state);
} else {
const auto& summaryState = simulator.vanguard().summaryState();
const auto& group_state = simulator.problem().wellModel().groupState();
const auto& schedule = simulator.vanguard().schedule();
return this->wellUnderZeroRateTargetGroup(summaryState, schedule, well_state, group_state, deferred_logger);
}
}
template<typename TypeTag>
bool
WellInterface<TypeTag>::
stoppedOrZeroRateTarget(const Simulator& simulator,
const WellState<Scalar>& well_state,
DeferredLogger& deferred_logger) const
{
// Check if well is stopped or under zero rate control, either directly or from group
return (this->wellIsStopped() || wellUnderZeroRateTarget(simulator,
well_state,
deferred_logger));
}
template<typename TypeTag>
std::vector<typename WellInterface<TypeTag>::Scalar>
WellInterface<TypeTag>::