From 1542f2c087e7647f132d640761f12d78f51a9c90 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 20 Oct 2022 11:03:29 +0200 Subject: [PATCH 1/2] refactor the network update moving the well controls and network update out of assembleImpl to avoid call assmebleImpl in a recursive manner --- opm/simulators/wells/BlackoilWellModel.hpp | 21 +++- .../wells/BlackoilWellModel_impl.hpp | 103 +++++++++++++----- opm/simulators/wells/WellInterface.hpp | 14 +++ opm/simulators/wells/WellInterface_impl.hpp | 41 ++++++- 4 files changed, 141 insertions(+), 38 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModel.hpp b/opm/simulators/wells/BlackoilWellModel.hpp index 946c624f4..317132630 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -292,7 +292,8 @@ namespace Opm { // at the beginning of each time step (Not report step) void prepareTimeStep(DeferredLogger& deferred_logger); void initPrimaryVariablesEvaluation() const; - std::tuple updateWellControls(DeferredLogger& deferred_logger); + + std::pair updateWellControls(DeferredLogger& deferred_logger, const std::size_t network_update_it = 0); void updateAndCommunicate(const int reportStepIdx, const int iterationIdx, @@ -384,10 +385,15 @@ namespace Opm { // and in the well equations. void assemble(const int iterationIdx, const double dt); - bool assembleImpl(const int iterationIdx, - const double dt, - const std::size_t recursion_level, - DeferredLogger& local_deferredLogger); + + // the function handles one itearation of updating well controls and also network related. + // it is possible to decouple the update of well controls and network related further + // the returned two booleans are {continue_due_to_network, well_group_control_changed}, respectively + std::pair updateWellControlsAndNetworkIteration(const double dt, + const std::size_t network_update_iteration, + DeferredLogger& local_deferredLogger); + + bool updateWellControlsAndNetwork(const double dt, DeferredLogger& local_deferredLogger); // called at the end of a time step void timeStepSucceeded(const double& simulationTime, const double dt); @@ -424,6 +430,11 @@ namespace Opm { void assembleWellEq(const double dt, DeferredLogger& deferred_logger); + void prepareWellsBeforeAssembling(const double dt, DeferredLogger& deferred_logger); + + // TODO: finding a better naming + void assembleWellEqWithoutIteration(const double dt, DeferredLogger& deferred_logger); + bool maybeDoGasLiftOptimize(DeferredLogger& deferred_logger); void gasLiftOptimizationStage1(DeferredLogger& deferred_logger, diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index ff222a92c..6d4b976dc 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #if HAVE_MPI #include @@ -870,7 +871,9 @@ namespace Opm { terminal_output_, grid().comm()); } - const bool well_group_control_changed = assembleImpl(iterationIdx, dt, 0, local_deferredLogger); + const bool well_group_control_changed = updateWellControlsAndNetwork(dt, local_deferredLogger); + + assembleWellEqWithoutIteration(dt, local_deferredLogger); // if group or well control changes we don't consider the // case converged @@ -881,17 +884,34 @@ namespace Opm { - template bool BlackoilWellModel:: - assembleImpl(const int iterationIdx, - const double dt, - const std::size_t recursion_level, - DeferredLogger& local_deferredLogger) + updateWellControlsAndNetwork(const double dt, DeferredLogger& local_deferredLogger) { + // not necessarily that we always need to update once of the network solutions + bool do_network_update = true; + bool well_group_control_changed = false; + std::size_t network_update_iteration = 0; + while (do_network_update) { + std::tie(do_network_update, well_group_control_changed) = + updateWellControlsAndNetworkIteration(dt, network_update_iteration, local_deferredLogger); + ++network_update_iteration; + } + return well_group_control_changed; + } - auto [well_group_control_changed, network_changed, network_imbalance] = updateWellControls(local_deferredLogger); + + + + template + std::pair + BlackoilWellModel:: + updateWellControlsAndNetworkIteration(const double dt, + const std::size_t network_update_iteration, + DeferredLogger& local_deferredLogger) + { + auto [well_group_control_changed, more_network_update] = updateWellControls(local_deferredLogger, network_update_iteration); bool alq_updated = false; OPM_BEGIN_PARALLEL_TRY_CATCH(); @@ -900,9 +920,10 @@ namespace Opm { initPrimaryVariablesEvaluation(); alq_updated = maybeDoGasLiftOptimize(local_deferredLogger); - assembleWellEq(dt, local_deferredLogger); + + prepareWellsBeforeAssembling(dt, local_deferredLogger); } - OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger, "assemble() failed: ", + OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger, "updateWellControlsAndNetworkIteration() failed: ", terminal_output_, grid().comm()); //update guide rates @@ -915,23 +936,16 @@ namespace Opm { std::vector pot(numPhases(), 0.0); const Group& fieldGroup = schedule().getGroup("FIELD", reportStepIdx); WellGroupHelpers::updateGuideRates(fieldGroup, schedule(), summaryState, this->phase_usage_, reportStepIdx, simulationTime, - this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger); + this->wellState(), this->groupState(), comm, &this->guideRate_, pot, local_deferredLogger); } - // Maybe do a recursive call to iterate network and well controls. - if (network_changed) { - if (shouldBalanceNetwork(reportStepIdx, iterationIdx) && - shouldIterateNetwork(reportStepIdx, recursion_level, network_imbalance)) { - well_group_control_changed = assembleImpl(iterationIdx, dt, recursion_level + 1, local_deferredLogger); - } - } - return well_group_control_changed; + + return {more_network_update, well_group_control_changed}; } - template bool BlackoilWellModel:: @@ -1143,6 +1157,29 @@ namespace Opm { } } + template + void + BlackoilWellModel:: + prepareWellsBeforeAssembling(const double dt, DeferredLogger& deferred_logger) + { + for (auto& well : well_container_) { + well->prepareWellBeforeAssembling(ebosSimulator_, dt, this->wellState(), this->groupState(), deferred_logger); + } + } + + + template + void + BlackoilWellModel:: + assembleWellEqWithoutIteration(const double dt, DeferredLogger& deferred_logger) + { + for (auto& well: well_container_) { + well->assembleWellEqWithoutIteration(ebosSimulator_, dt, this->wellState(), this->groupState(), + deferred_logger); + } + } + + template void BlackoilWellModel:: @@ -1451,25 +1488,35 @@ namespace Opm { template - std::tuple + std::pair BlackoilWellModel:: - updateWellControls(DeferredLogger& deferred_logger) + updateWellControls(DeferredLogger& deferred_logger, + const std::size_t network_update_it) { // Even if there are no wells active locally, we cannot // return as the DeferredLogger uses global communication. // For no well active globally we simply return. - if( !wellsActive() ) return { false, false, 0.0 }; + if( !wellsActive() ) return { false, false }; const int episodeIdx = ebosSimulator_.episodeIndex(); const int iterationIdx = ebosSimulator_.model().newtonMethod().numIterations(); const auto& comm = ebosSimulator_.vanguard().grid().comm(); updateAndCommunicateGroupData(episodeIdx, iterationIdx); - const auto [local_network_changed, local_network_imbalance] - = shouldBalanceNetwork(episodeIdx, iterationIdx) ? - updateNetworkPressures(episodeIdx) : std::make_pair(false, 0.0); - const bool network_changed = comm.sum(local_network_changed); - const double network_imbalance = comm.max(local_network_imbalance); + // network related + bool more_network_update = false; + if (shouldBalanceNetwork(episodeIdx, iterationIdx)) { + const auto [local_network_changed, local_network_imbalance] = updateNetworkPressures(episodeIdx); + const bool network_changed = comm.sum(local_network_changed); + const double network_imbalance = comm.max(local_network_imbalance); + if (network_changed) { + const auto& balance = schedule()[episodeIdx].network_balance(); + // Iterate if not converged, and number of iterations is not yet max (NETBALAN item 3). + if (network_update_it < balance.pressure_max_iter() && network_imbalance > balance.pressure_tolerance()) { + more_network_update = true; + } + } + } bool changed_well_group = false; // Check group individual constraints. @@ -1515,7 +1562,7 @@ namespace Opm { const Group& fieldGroup = schedule().getGroup("FIELD", episodeIdx); updateWsolvent(fieldGroup, episodeIdx, this->nupcolWellState()); - return { changed_well_group, network_changed, network_imbalance }; + return { changed_well_group, more_network_update }; } diff --git a/opm/simulators/wells/WellInterface.hpp b/opm/simulators/wells/WellInterface.hpp index 10adec4f7..03399534d 100644 --- a/opm/simulators/wells/WellInterface.hpp +++ b/opm/simulators/wells/WellInterface.hpp @@ -166,6 +166,20 @@ public: const GroupState& group_state, DeferredLogger& deferred_logger); + void assembleWellEqWithoutIteration(const Simulator& ebosSimulator, + const double dt, + WellState& well_state, + const GroupState& group_state, + DeferredLogger& deferred_logger); + + // TODO: better name or further refactoring the function to make it more clear + void prepareWellBeforeAssembling(const Simulator& ebosSimulator, + const double dt, + WellState& well_state, + const GroupState& group_state, + DeferredLogger& deferred_logger); + + virtual void computeWellRatesWithBhp( const Simulator& ebosSimulator, const double& bhp, diff --git a/opm/simulators/wells/WellInterface_impl.hpp b/opm/simulators/wells/WellInterface_impl.hpp index e32563bf2..1489abba9 100644 --- a/opm/simulators/wells/WellInterface_impl.hpp +++ b/opm/simulators/wells/WellInterface_impl.hpp @@ -470,6 +470,42 @@ namespace Opm const GroupState& group_state, DeferredLogger& deferred_logger) { + + prepareWellBeforeAssembling(ebosSimulator, dt, well_state, group_state, deferred_logger); + + assembleWellEqWithoutIteration(ebosSimulator, dt, well_state, group_state, deferred_logger); + } + + + + template + void + WellInterface:: + assembleWellEqWithoutIteration(const Simulator& ebosSimulator, + const double dt, + WellState& well_state, + const GroupState& group_state, + DeferredLogger& deferred_logger) + { + const auto& summary_state = ebosSimulator.vanguard().summaryState(); + const auto inj_controls = this->well_ecl_.isInjector() ? this->well_ecl_.injectionControls(summary_state) : Well::InjectionControls(0); + const auto prod_controls = this->well_ecl_.isProducer() ? this->well_ecl_.productionControls(summary_state) : Well::ProductionControls(0); + // TODO: the reason to have inj_controls and prod_controls in the arguments, is that we want to change the control used for the well functions + // TODO: maybe we can use std::optional or pointers to simplify here + assembleWellEqWithoutIteration(ebosSimulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger); + } + + + + template + void + WellInterface:: + prepareWellBeforeAssembling(const Simulator& ebosSimulator, + const double dt, + WellState& well_state, + const GroupState& group_state, + DeferredLogger& deferred_logger) + { const bool old_well_operable = this->operability_status_.isOperableAndSolvable(); if (param_.check_well_operability_iter_) @@ -522,11 +558,6 @@ namespace Opm changed_to_stopped_this_step_ = false; this->changed_to_open_this_step_ = true; } - - const auto& summary_state = ebosSimulator.vanguard().summaryState(); - const auto inj_controls = this->well_ecl_.isInjector() ? this->well_ecl_.injectionControls(summary_state) : Well::InjectionControls(0); - const auto prod_controls = this->well_ecl_.isProducer() ? this->well_ecl_.productionControls(summary_state) : Well::ProductionControls(0); - assembleWellEqWithoutIteration(ebosSimulator, dt, inj_controls, prod_controls, well_state, group_state, deferred_logger); } template From 79eeeae16e3c97a2dfc5e62fc39e6107578563ac Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 20 Apr 2023 15:47:31 +0200 Subject: [PATCH 2/2] addressing the reviewing comments for PR #4596 --- opm/simulators/wells/BlackoilWellModel.hpp | 5 +++-- opm/simulators/wells/BlackoilWellModelGeneric.cpp | 6 +++--- opm/simulators/wells/BlackoilWellModelGeneric.hpp | 4 ++-- opm/simulators/wells/BlackoilWellModel_impl.hpp | 6 +----- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModel.hpp b/opm/simulators/wells/BlackoilWellModel.hpp index 317132630..f316b7b01 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -386,8 +386,9 @@ namespace Opm { void assemble(const int iterationIdx, const double dt); - // the function handles one itearation of updating well controls and also network related. - // it is possible to decouple the update of well controls and network related further + // well controls and network pressures affect each other and are solved in an iterative manner. + // the function handles one iteration of updating well controls and network pressures. + // it is possible to decouple the update of well controls and network pressures further. // the returned two booleans are {continue_due_to_network, well_group_control_changed}, respectively std::pair updateWellControlsAndNetworkIteration(const double dt, const std::size_t network_update_iteration, diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.cpp b/opm/simulators/wells/BlackoilWellModelGeneric.cpp index c1d2b68ab..14d6116cb 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.cpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.cpp @@ -1255,13 +1255,13 @@ shouldBalanceNetwork(const int reportStepIdx, const int iterationIdx) const bool BlackoilWellModelGeneric:: -shouldIterateNetwork(const int reportStepIdx, - const std::size_t recursion_level, +moreNetworkIteration(const int reportStepIdx, + const std::size_t iteration, const double network_imbalance) const { const auto& balance = schedule()[reportStepIdx].network_balance(); // Iterate if not converged, and number of iterations is not yet max (NETBALAN item 3). - return recursion_level < balance.pressure_max_iter() && + return iteration < balance.pressure_max_iter() && network_imbalance > balance.pressure_tolerance(); } diff --git a/opm/simulators/wells/BlackoilWellModelGeneric.hpp b/opm/simulators/wells/BlackoilWellModelGeneric.hpp index cb2e3eaf2..a3a4c9fbe 100644 --- a/opm/simulators/wells/BlackoilWellModelGeneric.hpp +++ b/opm/simulators/wells/BlackoilWellModelGeneric.hpp @@ -177,8 +177,8 @@ public: bool shouldBalanceNetwork(const int reportStepIndex, const int iterationIdx) const; - bool shouldIterateNetwork(const int reportStepIndex, - const std::size_t recursion_level, + bool moreNetworkIteration(const int reportStepIdx, + const std::size_t iteration, const double network_imbalance) const; template diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 6d4b976dc..0b5e6b16f 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -1510,11 +1510,7 @@ namespace Opm { const bool network_changed = comm.sum(local_network_changed); const double network_imbalance = comm.max(local_network_imbalance); if (network_changed) { - const auto& balance = schedule()[episodeIdx].network_balance(); - // Iterate if not converged, and number of iterations is not yet max (NETBALAN item 3). - if (network_update_it < balance.pressure_max_iter() && network_imbalance > balance.pressure_tolerance()) { - more_network_update = true; - } + more_network_update = moreNetworkIteration(episodeIdx, network_update_it, network_imbalance); } }