Merge pull request #4881 from vkip/no_network_solve_in_history

Avoid iterating network if no network wells are in prediciton mode
This commit is contained in:
Kai Bao
2023-10-16 14:54:36 +02:00
committed by GitHub
4 changed files with 63 additions and 26 deletions

View File

@@ -405,9 +405,8 @@ namespace Opm {
SimulatorReportSingle last_report_{};
// solve to get a good network solution, group and well states might be updated during the process.
// the reservoir should stay static during this solution procedure.
void balanceNetwork(DeferredLogger& deferred_logger);
// Pre-step network solve at static reservoir conditions (group and well states might be updated)
void doPreStepNetworkRebalance(DeferredLogger& deferred_logger);
// used to better efficiency of calcuation
mutable BVector scaleAddRes_{};

View File

@@ -139,6 +139,13 @@ wellsActive() const
return wells_active_;
}
bool
BlackoilWellModelGeneric::
networkActive() const
{
return network_active_;
}
bool
BlackoilWellModelGeneric::
anyMSWellOpenLocal() const
@@ -978,27 +985,43 @@ hasTHPConstraints() const
return BlackoilWellModelConstraints(*this).hasTHPConstraints();
}
bool
void
BlackoilWellModelGeneric::
needRebalanceNetwork(const int report_step) const
{
updateNetworkActiveState(const int report_step) {
const auto& network = schedule()[report_step].network();
if (!network.active()) {
return false;
this->network_active_ = false;
return;
}
bool network_active = false;
for (const auto& well : well_container_generic_) {
const bool is_partof_network = network.has_node(well->wellEcl().groupName());
const bool prediction_mode = well->wellEcl().predictionMode();
if (is_partof_network && prediction_mode) {
network_active = true;
break;
}
}
this->network_active_ = comm_.max(network_active);
}
bool
BlackoilWellModelGeneric::
needPreStepNetworkRebalance(const int report_step) const
{
const auto& network = schedule()[report_step].network();
bool network_rebalance_necessary = false;
for (const auto& well : well_container_generic_) {
const auto& events = this->wellState().well(well->indexOfWell()).events;
const bool is_partof_network = network.has_node(well->wellEcl().groupName());
// TODO: we might find more relevant events to be included here
// TODO: we might find more relevant events to be included here (including network change events?)
const auto& events = this->wellState().well(well->indexOfWell()).events;
if (is_partof_network && events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE)) {
network_rebalance_necessary = true;
break;
}
}
network_rebalance_necessary = comm_.max(network_rebalance_necessary);
return network_rebalance_necessary;
}
@@ -1059,7 +1082,7 @@ double
BlackoilWellModelGeneric::
updateNetworkPressures(const int reportStepIdx)
{
// Get the network and return if inactive.
// Get the network and return if inactive (no wells in network at this time)
const auto& network = schedule()[reportStepIdx].network();
if (!network.active()) {
return 0.0;
@@ -1076,6 +1099,8 @@ updateNetworkPressures(const int reportStepIdx)
// here, the network imbalance is the difference between the previous nodal pressure and the new nodal pressure
double network_imbalance = 0.;
if (!this->networkActive())
return network_imbalance;
if (!previous_node_pressures.empty()) {
for (const auto& [name, pressure]: previous_node_pressures) {
@@ -1111,7 +1136,7 @@ updateNetworkPressures(const int reportStepIdx)
// Producers only, since we so far only support the
// "extended" network model (properties defined by
// BRANPROP and NODEPROP) which only applies to producers.
if (well->isProducer()) {
if (well->isProducer() && well->wellEcl().predictionMode()) {
const auto it = node_pressures_.find(well->wellEcl().groupName());
if (it != node_pressures_.end()) {
// The well belongs to a group with has a network pressure constraint,

View File

@@ -103,6 +103,9 @@ public:
bool wellsActive() const;
bool hasWell(const std::string& wname) const;
/// return true if network is active (at least one network well in prediction mode)
bool networkActive() const;
// whether there exists any multisegment well open on this process
bool anyMSWellOpenLocal() const;
@@ -169,8 +172,13 @@ public:
/// Return true if any well has a THP constraint.
bool hasTHPConstraints() const;
/// Whether it is necessary to re-balance network
bool needRebalanceNetwork(const int report_step) const;
/// Checks if network is active (at least one network well on prediction).
void updateNetworkActiveState(const int report_step);
/// Checks if there are reasons to perform a pre-step network re-balance.
/// (Currently, the only reasons are network well status changes.)
/// (TODO: Consider if adding network change events would be helpful.)
bool needPreStepNetworkRebalance(const int report_step) const;
/// Shut down any single well
/// Returns true if the well was actually found and shut.
@@ -431,6 +439,7 @@ protected:
PhaseUsage phase_usage_;
bool terminal_output_{false};
bool wells_active_{false};
bool network_active_{false};
bool initial_step_{};
bool report_step_starts_{};

View File

@@ -1006,11 +1006,11 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
balanceNetwork(DeferredLogger& deferred_logger) {
doPreStepNetworkRebalance(DeferredLogger& deferred_logger) {
const double dt = this->ebosSimulator_.timeStepSize();
// TODO: should we also have the group and network backed-up here in case the solution did not get converged?
auto& well_state = this->wellState();
constexpr std::size_t max_iter = 100;
const std::size_t max_iter = param_.network_max_iterations_;
bool converged = false;
std::size_t iter = 0;
bool changed_well_group = false;
@@ -1030,11 +1030,11 @@ namespace Opm {
} while (iter < max_iter);
if (!converged) {
const std::string msg = fmt::format("balanceNetwork did not get converged with {} iterations, and unconverged "
"network balance result will be used", max_iter);
const std::string msg = fmt::format("Initial (pre-step) network balance did not get converged with {} iterations, "
"unconverged network balance result will be used", max_iter);
deferred_logger.warning(msg);
} else {
const std::string msg = fmt::format("balanceNetwork get converged with {} iterations", iter);
const std::string msg = fmt::format("Initial (pre-step) network balance converged with {} iterations", iter);
deferred_logger.debug(msg);
}
}
@@ -1853,7 +1853,7 @@ namespace Opm {
const auto& balance = schedule()[episodeIdx].network_balance();
constexpr double relaxtion_factor = 10.0;
const double tolerance = relax_network_tolerance ? relaxtion_factor * balance.pressure_tolerance() : balance.pressure_tolerance();
more_network_update = network_imbalance > tolerance;
more_network_update = this->networkActive() && network_imbalance > tolerance;
}
bool changed_well_group = false;
@@ -2239,7 +2239,13 @@ namespace Opm {
BlackoilWellModel<TypeTag>::
prepareTimeStep(DeferredLogger& deferred_logger)
{
const bool network_rebalance_necessary = this->needRebalanceNetwork(ebosSimulator_.episodeIndex());
// Check if there is a network with active prediction wells at this time step.
const auto episodeIdx = ebosSimulator_.episodeIndex();
this->updateNetworkActiveState(episodeIdx);
// Rebalance the network initially if any wells in the network have status changes
// (Need to check this before clearing events)
const bool do_prestep_network_rebalance = this->needPreStepNetworkRebalance(episodeIdx);
for (const auto& well : well_container_) {
auto& events = this->wellState().well(well->indexOfWell()).events;
@@ -2257,7 +2263,7 @@ namespace Opm {
try {
well->solveWellEquation(ebosSimulator_, this->wellState(), this->groupState(), deferred_logger);
} catch (const std::exception& e) {
const std::string msg = "Compute initial well solution for " + well->name() + " initially failed. Continue with the privious rates";
const std::string msg = "Compute initial well solution for " + well->name() + " initially failed. Continue with the previous rates";
deferred_logger.warning("WELL_INITIAL_SOLVE_FAILED", msg);
}
}
@@ -2267,10 +2273,8 @@ namespace Opm {
}
updatePrimaryVariables(deferred_logger);
if (network_rebalance_necessary) {
// this is to obtain good network solution
balanceNetwork(deferred_logger);
}
// Actually do the pre-step network rebalance, using the updated well states and initial solutions
if (do_prestep_network_rebalance) doPreStepNetworkRebalance(deferred_logger);
}
template<typename TypeTag>