diff --git a/opm/autodiff/BlackoilWellModel_impl.hpp b/opm/autodiff/BlackoilWellModel_impl.hpp index 9c877c791..1ea2acb7d 100644 --- a/opm/autodiff/BlackoilWellModel_impl.hpp +++ b/opm/autodiff/BlackoilWellModel_impl.hpp @@ -803,7 +803,9 @@ namespace Opm { // Get global (from all processes) convergence report. ConvergenceReport local_report; for (const auto& well : well_container_) { - local_report += well->getWellConvergence(B_avg); + if (well->isOperable() ) { + local_report += well->getWellConvergence(B_avg); + } } ConvergenceReport report = gatherConvergenceReport(local_report); @@ -828,9 +830,10 @@ namespace Opm { BlackoilWellModel:: calculateExplicitQuantities() const { - for (auto& well : well_container_) { - well->calculateExplicitQuantities(ebosSimulator_, well_state_); - } + // TODO: checking isOperable() ? + for (auto& well : well_container_) { + well->calculateExplicitQuantities(ebosSimulator_, well_state_); + } } @@ -934,6 +937,10 @@ namespace Opm { // process group control related prepareGroupControl(); + for (const auto& well : well_container_) { + well->checkWellOperatability(ebosSimulator_); + } + // since the controls are all updated, we should update well_state accordingly for (const auto& well : well_container_) { const int w = well->indexOfWell(); @@ -941,16 +948,22 @@ namespace Opm { const int control = well_controls_get_current(wc); well_state_.currentControls()[w] = control; + if (!well->isOperable() ) continue; + if (well_state_.effectiveEventsOccurred(w) ) { well->updateWellStateWithTarget(ebosSimulator_, well_state_); } // 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 + // TODO: if we can know whether this is the first time step within the report step, + // we do not need to change this + // TODO: we should do this at the end of the time step in case we will need it within + // this time step somewhere if (well_state_.effectiveEventsOccurred(w) ) { well_state_.setEffectiveEventsOccurred(w, false); } - } // end of for (int w = 0; w < nw; ++w) + } // end of for (const auto& well : well_container_) updatePrimaryVariables(); } diff --git a/opm/autodiff/StandardWell_impl.hpp b/opm/autodiff/StandardWell_impl.hpp index 0c7d9d4bb..1031cc7e2 100644 --- a/opm/autodiff/StandardWell_impl.hpp +++ b/opm/autodiff/StandardWell_impl.hpp @@ -440,9 +440,9 @@ namespace Opm WellState& well_state) { - const Opm::SummaryConfig& summaryConfig = ebosSimulator.vanguard().summaryConfig(); + checkWellOperatability(ebosSimulator); - const int np = number_of_phases_; + if (!this->isOperable()) return; // clear all entries duneB_ = 0.0; @@ -461,6 +461,7 @@ namespace Opm well_state.wellVaporizedOilRates()[index_of_well_] = 0.; well_state.wellDissolvedGasRates()[index_of_well_] = 0.; + const int np = number_of_phases_; for (int p = 0; p < np; ++p) { well_state.productivityIndex()[np*index_of_well_ + p] = 0.; } @@ -588,7 +589,8 @@ namespace Opm well_state.perfPress()[first_perf_ + perf] = well_state.bhp()[index_of_well_] + perf_pressure_diffs_[perf]; // Compute Productivity index if asked for - const auto& pu = phaseUsage(); + const auto& pu = phaseUsage(); + const Opm::SummaryConfig& summaryConfig = ebosSimulator.vanguard().summaryConfig(); for (int p = 0; p < np; ++p) { if ( (pu.phase_pos[Water] == p && (summaryConfig.hasSummaryKey("WPIW:" + name()) || summaryConfig.hasSummaryKey("WPIL:" + name()))) || (pu.phase_pos[Oil] == p && (summaryConfig.hasSummaryKey("WPIO:" + name()) || summaryConfig.hasSummaryKey("WPIL:" + name()))) @@ -821,6 +823,8 @@ namespace Opm updateWellState(const BVectorWell& dwells, WellState& well_state) const { + if (!this->isOperable()) return; + updatePrimaryVariablesNewton(dwells, well_state); updateWellStateFromPrimaryVariables(well_state); @@ -1287,7 +1291,7 @@ namespace Opm // wellTestingPhysical can share some code with this function // on solution is that this function will be called updateWellOperatability // and the actual checking part become another function checkWellOperatability - // Let us finish the wellTestingPhysical first. + // Let us wait until finishing the wellTestingPhysical first. // focusing on PRODUCER for now if (well_type_ == INJECTOR) { @@ -1318,6 +1322,12 @@ namespace Opm this->operability_status_.negative_well_rates = allDrawDownWrongDirection(ebos_simulator); const bool well_operable = this->operability_status_.isOperable(); + + if (!well_operable && old_well_operable) { + OpmLog::info(" well " + name() + " gets SHUT during iteration "); + } else if (well_operable && !old_well_operable) { + OpmLog::info(" well " + name() + " gets REVIVED during iteration "); + } } @@ -1943,6 +1953,8 @@ namespace Opm StandardWell:: solveEqAndUpdateWellState(WellState& well_state) { + if (!this->isOperable()) return; + // We assemble the well equations, then we check the convergence, // which is why we do not put the assembleWellEq here. BVectorWell dx_well(1); @@ -1988,6 +2000,8 @@ namespace Opm StandardWell:: apply(const BVector& x, BVector& Ax) const { + if (!this->isOperable()) return; + if ( param_.matrix_add_well_contributions_ ) { // Contributions are already in the matrix itself @@ -2016,6 +2030,8 @@ namespace Opm StandardWell:: apply(BVector& r) const { + if (!this->isOperable()) return; + assert( invDrw_.size() == invDuneD_.N() ); // invDrw_ = invDuneD_ * resWell_ @@ -2033,6 +2049,8 @@ namespace Opm StandardWell:: recoverSolutionWell(const BVector& x, BVectorWell& xw) const { + if (!this->isOperable()) return; + BVectorWell resWell = resWell_; // resWell = resWell - B * x duneB_.mmv(x, resWell); @@ -2050,6 +2068,8 @@ namespace Opm recoverWellSolutionAndUpdateWellState(const BVector& x, WellState& well_state) const { + if (!this->isOperable()) return; + BVectorWell xw(1); recoverSolutionWell(x, xw); updateWellState(xw, well_state); @@ -2254,6 +2274,8 @@ namespace Opm StandardWell:: updatePrimaryVariables(const WellState& well_state) const { + if (!this->isOperable()) return; + const int well_index = index_of_well_; const int np = number_of_phases_; diff --git a/opm/autodiff/WellInterface.hpp b/opm/autodiff/WellInterface.hpp index be8c28fd3..cdf89f94b 100644 --- a/opm/autodiff/WellInterface.hpp +++ b/opm/autodiff/WellInterface.hpp @@ -225,6 +225,9 @@ namespace Opm virtual void checkWellOperatability(const Simulator& ebos_simulator) = 0; + // whether the well is operable + bool isOperable() const; + protected: // to indicate a invalid completion @@ -400,7 +403,7 @@ namespace Opm violate_thp_limit_under_bhp_limit = false; obtain_solution_with_thp_limit = true; violate_bhp_limit_with_thp_limit = false; - // TODO: the following one might need to be different + // TODO: the following one might need to be treated differently negative_well_rates = false; } @@ -425,7 +428,7 @@ namespace Opm // could not get converged, maybe at the end of the time step, after chopping for some steps. // TODO: the best way is that this well can not get converged during local iterations. - bool could_not_get_converged = false; + // bool could_not_get_converged = false; }; } diff --git a/opm/autodiff/WellInterface_impl.hpp b/opm/autodiff/WellInterface_impl.hpp index 1685440df..e6790f6cc 100644 --- a/opm/autodiff/WellInterface_impl.hpp +++ b/opm/autodiff/WellInterface_impl.hpp @@ -1223,4 +1223,15 @@ namespace Opm } + + + + template + bool + WellInterface:: + isOperable() const { + return operability_status_.isOperable(); + } + + }