Refactor SimulatorFullyImplicitBlackoilEbos.hpp

A resubmission of commit bb20804 in PR #2403 and PR #2442 to work with the
current master.

Continues the work in #2619 and #2631 to refactor main simulation loop in
flow to work with the Python bindings.

The run() method in SimulatorFullyImplicitBlackoilEbos.hpp is refactored
in preparation for the implementation of a Python step() function in a
later commit. Currently run() is called from runSimulatorInitOrRun() in
FlowMainEbos.hpp using the runSimulatorRunCallback_(). Later, there
will be other callbacks like runSimulatorStepInitCallback_(), and
runSimulatorStepCallback_(), that will need to call different parts of
the code in run(). The run() function is thus refactored into run(),
runInit(), runStep(), and runLastStep(). Also, some of the local
variables in run() have to be made persistent between calls to
runStep(), this applies to variables report, solverTimer, totalTimer,
and adaptiveTimeStepping, which are made private class variables.
This commit is contained in:
Håkon Hægland 2020-05-29 15:42:13 +02:00
parent 3766f19de3
commit e8a4065192

View File

@ -128,44 +128,52 @@ public:
/// \param[in,out] state state of reservoir: pressure, fluxes
/// \return simulation report, with timing data
SimulatorReport run(SimulatorTimer& timer)
{
runInit(timer);
// Main simulation loop.
while (!timer.done()) {
runStep(timer);
}
return runLastStep();
}
void runInit(SimulatorTimer &timer)
{
ebosSimulator_.setEpisodeIndex(-1);
// Create timers and file for writing timing info.
Opm::time::StopWatch solverTimer;
Opm::time::StopWatch totalTimer;
totalTimer.start();
solverTimer_ = std::make_unique<Opm::time::StopWatch>();
totalTimer_ = std::make_unique<Opm::time::StopWatch>();
totalTimer_->start();
// adaptive time stepping
const auto& events = schedule().getEvents();
std::unique_ptr<TimeStepper > adaptiveTimeStepping;
bool enableAdaptive = EWOMS_GET_PARAM(TypeTag, bool, EnableAdaptiveTimeStepping);
bool enableTUNING = EWOMS_GET_PARAM(TypeTag, bool, EnableTuning);
if (enableAdaptive) {
if (enableTUNING) {
adaptiveTimeStepping.reset(new TimeStepper(schedule().getTuning(timer.currentStepNum()), terminalOutput_));
adaptiveTimeStepping_ = std::make_unique<TimeStepper>(
schedule().getTuning(timer.currentStepNum()), terminalOutput_);
}
else {
adaptiveTimeStepping.reset(new TimeStepper(terminalOutput_));
adaptiveTimeStepping_ = std::make_unique<TimeStepper>(terminalOutput_);
}
if (isRestart()) {
// For restarts the ebosSimulator may have gotten some information
// about the next timestep size from the OPMEXTRA field
adaptiveTimeStepping->setSuggestedNextStep(ebosSimulator_.timeStepSize());
adaptiveTimeStepping_->setSuggestedNextStep(ebosSimulator_.timeStepSize());
}
}
}
SimulatorReport report;
// Main simulation loop.
while (!timer.done()) {
bool runStep(SimulatorTimer& timer)
{
if (schedule().exitStatus().has_value()) {
if (terminalOutput_) {
OpmLog::info("Stopping simulation since EXIT was triggered by an action keyword.");
}
report.success.exit_status = schedule().exitStatus().value();
break;
report_.success.exit_status = schedule().exitStatus().value();
return false;
}
// Report timestep.
@ -199,28 +207,32 @@ public:
wellModel_().beginReportStep(timer.currentStepNum());
ebosSimulator_.problem().writeOutput();
report.success.output_write_time += perfTimer.stop();
report_.success.output_write_time += perfTimer.stop();
}
// Run a multiple steps of the solver depending on the time step control.
solverTimer.start();
solverTimer_->start();
auto solver = createSolver(wellModel_());
ebosSimulator_.startNextEpisode(ebosSimulator_.startTime() + schedule().getTimeMap().getTimePassedUntil(timer.currentStepNum()),
ebosSimulator_.startNextEpisode(
ebosSimulator_.startTime()
+ schedule().getTimeMap().getTimePassedUntil(timer.currentStepNum()),
timer.currentStepLength());
ebosSimulator_.setEpisodeIndex(timer.currentStepNum());
solver->model().beginReportStep();
const auto& events = schedule().getEvents();
bool enableTUNING = EWOMS_GET_PARAM(TypeTag, bool, EnableTuning);
// If sub stepping is enabled allow the solver to sub cycle
// in case the report steps are too large for the solver to converge
//
// \Note: The report steps are met in any case
// \Note: The sub stepping will require a copy of the state variables
if (adaptiveTimeStepping) {
if (adaptiveTimeStepping_) {
if (enableTUNING) {
if (events.hasEvent(ScheduleEvents::TUNING_CHANGE,timer.currentStepNum())) {
adaptiveTimeStepping->updateTUNING(schedule().getTuning(timer.currentStepNum()));
adaptiveTimeStepping_->updateTUNING(schedule().getTuning(timer.currentStepNum()));
}
}
@ -228,12 +240,12 @@ public:
events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE, timer.currentStepNum()) ||
events.hasEvent(ScheduleEvents::INJECTION_UPDATE, timer.currentStepNum()) ||
events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE, timer.currentStepNum());
auto stepReport = adaptiveTimeStepping->step(timer, *solver, event, nullptr);
report += stepReport;
auto stepReport = adaptiveTimeStepping_->step(timer, *solver, event, nullptr);
report_ += stepReport;
} else {
// solve for complete report step
auto stepReport = solver->step(timer);
report += stepReport;
report_ += stepReport;
if (terminalOutput_) {
std::ostringstream ss;
stepReport.reportStep(ss);
@ -244,23 +256,22 @@ public:
// write simulation state at the report stage
Dune::Timer perfTimer;
perfTimer.start();
const double nextstep = adaptiveTimeStepping ? adaptiveTimeStepping->suggestedNextStep() : -1.0;
const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
ebosSimulator_.problem().setNextTimeStepSize(nextstep);
ebosSimulator_.problem().writeOutput();
report.success.output_write_time += perfTimer.stop();
report_.success.output_write_time += perfTimer.stop();
solver->model().endReportStep();
// take time that was used to solve system for this reportStep
solverTimer.stop();
solverTimer_->stop();
// update timing.
report.success.solver_time += solverTimer.secsSinceStart();
report_.success.solver_time += solverTimer_->secsSinceStart();
// Increment timer, remember well state.
++timer;
if (terminalOutput_) {
if (!timer.initialStep()) {
const std::string version = moduleVersionName();
@ -270,28 +281,30 @@ public:
if (terminalOutput_) {
std::string msg =
"Time step took " + std::to_string(solverTimer.secsSinceStart()) + " seconds; "
"total solver time " + std::to_string(report.success.solver_time) + " seconds.";
"Time step took " + std::to_string(solverTimer_->secsSinceStart()) + " seconds; "
"total solver time " + std::to_string(report_.success.solver_time) + " seconds.";
OpmLog::debug(msg);
}
return true;
}
SimulatorReport runLastStep()
{
// make sure all output is written to disk before run is finished
{
Dune::Timer finalOutputTimer;
finalOutputTimer.start();
ebosSimulator_.problem().finalizeOutput();
report.success.output_write_time += finalOutputTimer.stop();
report_.success.output_write_time += finalOutputTimer.stop();
}
// Stop timer and create timing report
totalTimer.stop();
report.success.total_time = totalTimer.secsSinceStart();
report.success.converged = true;
totalTimer_->stop();
report_.success.total_time = totalTimer_->secsSinceStart();
report_.success.converged = true;
return report;
return report_;
}
const Grid& grid() const
@ -353,6 +366,11 @@ protected:
PhaseUsage phaseUsage_;
// Misc. data
bool terminalOutput_;
SimulatorReport report_;
std::unique_ptr<Opm::time::StopWatch> solverTimer_;
std::unique_ptr<Opm::time::StopWatch> totalTimer_;
std::unique_ptr<TimeStepper> adaptiveTimeStepping_;
};
} // namespace Opm