mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #1671 from atgeirr/fix-infinite-loop
Fix potential infinite loop
This commit is contained in:
@@ -243,7 +243,8 @@ namespace Opm {
|
||||
bool hasTHPConstraints() const;
|
||||
|
||||
/// Shut down any single well, but only if it is in prediction mode.
|
||||
void forceShutWellByNameIfPredictionMode(const std::string& wellname, const double simulation_time);
|
||||
/// Returns true if the well was actually found and shut.
|
||||
bool forceShutWellByNameIfPredictionMode(const std::string& wellname, const double simulation_time);
|
||||
|
||||
protected:
|
||||
|
||||
|
||||
@@ -133,30 +133,37 @@ namespace Opm {
|
||||
|
||||
|
||||
|
||||
/// Return true if any well has a THP constraint.
|
||||
/// Return true if the well was found and shut.
|
||||
template<typename TypeTag>
|
||||
void
|
||||
bool
|
||||
BlackoilWellModel<TypeTag>::
|
||||
forceShutWellByNameIfPredictionMode(const std::string& wellname,
|
||||
const double simulation_time)
|
||||
{
|
||||
// Only add the well to the closed list on the
|
||||
// process that owns it.
|
||||
int well_was_shut = 0;
|
||||
for (const auto& well : well_container_) {
|
||||
if (well->name() == wellname) {
|
||||
if (well->underPredictionMode()) {
|
||||
wellTestState_.addClosedWell(wellname, WellTestConfig::Reason::PHYSICAL, simulation_time);
|
||||
well_was_shut = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Communicate across processes if a well was shut.
|
||||
well_was_shut = ebosSimulator_.vanguard().grid().comm().max(well_was_shut);
|
||||
|
||||
// Only log a message on the output rank.
|
||||
if (terminal_output_) {
|
||||
if (terminal_output_ && well_was_shut) {
|
||||
const std::string msg = "Well " + wellname
|
||||
+ " will be shut because it cannot get converged.";
|
||||
OpmLog::info(msg);
|
||||
}
|
||||
|
||||
return (well_was_shut == 1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -334,12 +334,13 @@ namespace Opm {
|
||||
substepTimer.setLastStepFailed(false);
|
||||
|
||||
}
|
||||
else { // in case of no convergence (linearIterations < 0)
|
||||
else { // in case of no convergence
|
||||
substepTimer.setLastStepFailed(true);
|
||||
|
||||
failureReport_ += substepReport;
|
||||
|
||||
// increase restart counter
|
||||
// If we have restarted (i.e. cut the timestep) too
|
||||
// many times, we have failed and throw an exception.
|
||||
if (restarts >= solverRestartMax_) {
|
||||
const auto msg = std::string("Solver failed to converge after cutting timestep ")
|
||||
+ std::to_string(restarts) + " times.";
|
||||
@@ -349,10 +350,11 @@ namespace Opm {
|
||||
OPM_THROW_NOLOG(Opm::NumericalIssue, msg);
|
||||
}
|
||||
|
||||
// The new, chopped timestep.
|
||||
const double newTimeStep = restartFactor_ * dt;
|
||||
const double minimumChoppedTimestep = 0.25 * unit::day;
|
||||
if (newTimeStep > minimumChoppedTimestep) {
|
||||
// Chop the timestep.
|
||||
|
||||
// Define utility function for chopping timestep.
|
||||
auto chopTimestep = [&]() {
|
||||
substepTimer.provideTimeStepEstimate(newTimeStep);
|
||||
if (solverVerbose_) {
|
||||
std::string msg;
|
||||
@@ -361,44 +363,50 @@ namespace Opm {
|
||||
OpmLog::problem(msg);
|
||||
}
|
||||
++restarts;
|
||||
};
|
||||
|
||||
const double minimumChoppedTimestep = 0.25 * unit::day;
|
||||
if (newTimeStep > minimumChoppedTimestep) {
|
||||
chopTimestep();
|
||||
} else {
|
||||
// We are below the threshold, and will check if there are any
|
||||
// wells we should close rather than chopping again.
|
||||
std::set<std::string> failing_wells = consistentlyFailingWells(solver.model().stepReports());
|
||||
if (failing_wells.empty()) {
|
||||
// Found no wells to close, chop the timestep as above.
|
||||
substepTimer.provideTimeStepEstimate(newTimeStep);
|
||||
if (solverVerbose_) {
|
||||
std::string msg;
|
||||
msg = causeOfFailure + "\nTimestep chopped to "
|
||||
+ std::to_string(unit::convert::to(substepTimer.currentStepLength(), unit::day)) + " days\n";
|
||||
OpmLog::problem(msg);
|
||||
}
|
||||
++restarts;
|
||||
chopTimestep();
|
||||
} else {
|
||||
// Close all consistently failing wells.
|
||||
int num_shut_wells = 0;
|
||||
for (const auto& well : failing_wells) {
|
||||
solver.model().wellModel().forceShutWellByNameIfPredictionMode(well, substepTimer.simulationTimeElapsed());
|
||||
}
|
||||
substepTimer.provideTimeStepEstimate(dt);
|
||||
if (solverVerbose_) {
|
||||
std::string msg;
|
||||
msg = "\nProblematic well(s) were shut: ";
|
||||
for (const auto& well : failing_wells) {
|
||||
msg += well;
|
||||
msg += " ";
|
||||
bool was_shut = solver.model().wellModel().forceShutWellByNameIfPredictionMode(well, substepTimer.simulationTimeElapsed());
|
||||
if (was_shut) {
|
||||
++num_shut_wells;
|
||||
}
|
||||
}
|
||||
if (num_shut_wells == 0) {
|
||||
// None of the problematic wells were prediction wells,
|
||||
// so none were shut. We must fall back to chopping again.
|
||||
chopTimestep();
|
||||
} else {
|
||||
substepTimer.provideTimeStepEstimate(dt);
|
||||
if (solverVerbose_) {
|
||||
std::string msg;
|
||||
msg = "\nProblematic well(s) were shut: ";
|
||||
for (const auto& well : failing_wells) {
|
||||
msg += well;
|
||||
msg += " ";
|
||||
}
|
||||
msg += "(retrying timestep)\n";
|
||||
OpmLog::problem(msg);
|
||||
}
|
||||
msg += "(retrying timestep)\n";
|
||||
OpmLog::problem(msg);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
ebosProblem.setNextTimeStepSize(substepTimer.currentStepLength());
|
||||
}
|
||||
|
||||
|
||||
// store estimated time step for next reportStep
|
||||
suggestedNextTimestep_ = substepTimer.currentStepLength();
|
||||
if (timestepVerbose_) {
|
||||
|
||||
Reference in New Issue
Block a user