Refactor run() in SimulatorFullyImplicit....hpp

Similar to the previous commit b25f489, run() is here 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, stepReport, solverTimer,
totalTimer, and adaptiveTimeStepping, which are made private class
variables.
This commit is contained in:
Håkon Hægland 2020-02-28 20:41:48 +01:00
parent b25f48971c
commit bb208047a8

View File

@ -129,171 +129,188 @@ public:
/// \param[in,out] state state of reservoir: pressure, fluxes /// \param[in,out] state state of reservoir: pressure, fluxes
/// \return simulation report, with timing data /// \return simulation report, with timing data
SimulatorReport run(SimulatorTimer& timer) SimulatorReport run(SimulatorTimer& timer)
{
runInit(timer);
// Main simulation loop.
while (!timer.done()) {
runStep(timer);
}
return runLastStep();
}
void runInit(SimulatorTimer &timer)
{ {
failureReport_ = SimulatorReport(); failureReport_ = SimulatorReport();
ebosSimulator_.setEpisodeIndex(-1); ebosSimulator_.setEpisodeIndex(-1);
// Create timers and file for writing timing info. // Create timers and file for writing timing info.
Opm::time::StopWatch solverTimer; solverTimer_ = std::make_unique<Opm::time::StopWatch>();
Opm::time::StopWatch totalTimer; totalTimer_ = std::make_unique<Opm::time::StopWatch>();
totalTimer.start(); totalTimer_->start();
// adaptive time stepping // adaptive time stepping
const auto& events = schedule().getEvents();
std::unique_ptr<TimeStepper > adaptiveTimeStepping;
bool enableAdaptive = EWOMS_GET_PARAM(TypeTag, bool, EnableAdaptiveTimeStepping); bool enableAdaptive = EWOMS_GET_PARAM(TypeTag, bool, EnableAdaptiveTimeStepping);
bool enableTUNING = EWOMS_GET_PARAM(TypeTag, bool, EnableTuning); bool enableTUNING = EWOMS_GET_PARAM(TypeTag, bool, EnableTuning);
if (enableAdaptive) { if (enableAdaptive) {
if (enableTUNING) { if (enableTUNING) {
adaptiveTimeStepping.reset(new TimeStepper(schedule().getTuning(timer.currentStepNum()), terminalOutput_)); adaptiveTimeStepping_ = std::make_unique<TimeStepper>(
schedule().getTuning(timer.currentStepNum()), terminalOutput_);
} }
else { else {
adaptiveTimeStepping.reset(new TimeStepper(terminalOutput_)); adaptiveTimeStepping_ = std::make_unique<TimeStepper>(terminalOutput_);
} }
if (isRestart()) { if (isRestart()) {
// For restarts the ebosSimulator may have gotten some information // For restarts the ebosSimulator may have gotten some information
// about the next timestep size from the OPMEXTRA field // about the next timestep size from the OPMEXTRA field
adaptiveTimeStepping->setSuggestedNextStep(ebosSimulator_.timeStepSize()); adaptiveTimeStepping_->setSuggestedNextStep(ebosSimulator_.timeStepSize());
} }
} }
}
SimulatorReport report; bool runStep(SimulatorTimer& timer)
SimulatorReport stepReport; {
if (timer.done()) {
return false;
}
// Report timestep.
if (terminalOutput_) {
std::ostringstream ss;
timer.report(ss);
OpmLog::debug(ss.str());
}
// Main simulation loop. if (terminalOutput_) {
while (!timer.done()) { std::ostringstream stepMsg;
// Report timestep. boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%d-%b-%Y");
if (terminalOutput_) { stepMsg.imbue(std::locale(std::locale::classic(), facet));
std::ostringstream ss; stepMsg << "\nReport step " << std::setw(2) <<timer.currentStepNum()
timer.report(ss); << "/" << timer.numSteps()
OpmLog::debug(ss.str()); << " at day " << (double)unit::convert::to(timer.simulationTimeElapsed(), unit::day)
} << "/" << (double)unit::convert::to(timer.totalTime(), unit::day)
<< ", date = " << timer.currentDateTime();
OpmLog::info(stepMsg.str());
}
if (terminalOutput_) { // write the inital state at the report stage
std::ostringstream stepMsg; if (timer.initialStep()) {
boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%d-%b-%Y");
stepMsg.imbue(std::locale(std::locale::classic(), facet));
stepMsg << "\nReport step " << std::setw(2) <<timer.currentStepNum()
<< "/" << timer.numSteps()
<< " at day " << (double)unit::convert::to(timer.simulationTimeElapsed(), unit::day)
<< "/" << (double)unit::convert::to(timer.totalTime(), unit::day)
<< ", date = " << timer.currentDateTime();
OpmLog::info(stepMsg.str());
}
// write the inital state at the report stage
if (timer.initialStep()) {
Dune::Timer perfTimer;
perfTimer.start();
ebosSimulator_.setEpisodeIndex(-1);
ebosSimulator_.setEpisodeLength(0.0);
ebosSimulator_.setTimeStepSize(0.0);
wellModel_().beginReportStep(timer.currentStepNum());
ebosSimulator_.problem().writeOutput();
report.output_write_time += perfTimer.stop();
}
// Run a multiple steps of the solver depending on the time step control.
solverTimer.start();
auto solver = createSolver(wellModel_());
ebosSimulator_.startNextEpisode(ebosSimulator_.startTime() + schedule().getTimeMap().getTimePassedUntil(timer.currentStepNum()),
timer.currentStepLength());
ebosSimulator_.setEpisodeIndex(timer.currentStepNum());
solver->model().beginReportStep();
// 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 (enableTUNING) {
if (events.hasEvent(ScheduleEvents::TUNING_CHANGE,timer.currentStepNum())) {
adaptiveTimeStepping->updateTUNING(schedule().getTuning(timer.currentStepNum()));
}
}
bool event = events.hasEvent(ScheduleEvents::NEW_WELL, timer.currentStepNum()) ||
events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE, timer.currentStepNum()) ||
events.hasEvent(ScheduleEvents::INJECTION_UPDATE, timer.currentStepNum()) ||
events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE, timer.currentStepNum());
stepReport = adaptiveTimeStepping->step(timer, *solver, event, nullptr);
report += stepReport;
failureReport_ += adaptiveTimeStepping->failureReport();
}
else {
// solve for complete report step
stepReport = solver->step(timer);
report += stepReport;
failureReport_ += solver->failureReport();
if (terminalOutput_) {
std::ostringstream ss;
stepReport.reportStep(ss);
OpmLog::info(ss.str());
}
}
// write simulation state at the report stage
Dune::Timer perfTimer; Dune::Timer perfTimer;
perfTimer.start(); perfTimer.start();
const double nextstep = adaptiveTimeStepping ? adaptiveTimeStepping->suggestedNextStep() : -1.0;
ebosSimulator_.problem().setNextTimeStepSize(nextstep); ebosSimulator_.setEpisodeIndex(-1);
ebosSimulator_.setEpisodeLength(0.0);
ebosSimulator_.setTimeStepSize(0.0);
wellModel_().beginReportStep(timer.currentStepNum());
ebosSimulator_.problem().writeOutput(); ebosSimulator_.problem().writeOutput();
report.output_write_time += perfTimer.stop();
solver->model().endReportStep(); report_.output_write_time += perfTimer.stop();
}
// take time that was used to solve system for this reportStep // Run a multiple steps of the solver depending on the time step control.
solverTimer.stop(); solverTimer_->start();
// update timing. auto solver = createSolver(wellModel_());
report.solver_time += solverTimer.secsSinceStart();
// Increment timer, remember well state. ebosSimulator_.startNextEpisode(
++timer; ebosSimulator_.startTime()
+ schedule().getTimeMap().getTimePassedUntil(timer.currentStepNum()),
timer.currentStepLength());
ebosSimulator_.setEpisodeIndex(timer.currentStepNum());
solver->model().beginReportStep();
bool enableTUNING = EWOMS_GET_PARAM(TypeTag, bool, EnableTuning);
const auto& events = schedule().getEvents();
// If sub stepping is enabled allow the solver to sub cycle
if (terminalOutput_) { // in case the report steps are too large for the solver to converge
if (!timer.initialStep()) { //
const std::string version = moduleVersionName(); // \Note: The report steps are met in any case
outputTimestampFIP(timer, version); // \Note: The sub stepping will require a copy of the state variables
if (adaptiveTimeStepping_) {
if (enableTUNING) {
if (events.hasEvent(ScheduleEvents::TUNING_CHANGE,timer.currentStepNum())) {
adaptiveTimeStepping_->updateTUNING(schedule().getTuning(timer.currentStepNum()));
} }
} }
if (terminalOutput_) { bool event = events.hasEvent(ScheduleEvents::NEW_WELL, timer.currentStepNum()) ||
std::string msg = events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE, timer.currentStepNum()) ||
"Time step took " + std::to_string(solverTimer.secsSinceStart()) + " seconds; " events.hasEvent(ScheduleEvents::INJECTION_UPDATE, timer.currentStepNum()) ||
"total solver time " + std::to_string(report.solver_time) + " seconds."; events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE, timer.currentStepNum());
OpmLog::debug(msg); stepReport_ = adaptiveTimeStepping_->step(timer, *solver, event, nullptr);
} report_ += stepReport_;
failureReport_ += adaptiveTimeStepping_->failureReport();
}
else {
// solve for complete report step
stepReport_ = solver->step(timer);
report_ += stepReport_;
failureReport_ += solver->failureReport();
if (terminalOutput_) {
std::ostringstream ss;
stepReport_.reportStep(ss);
OpmLog::info(ss.str());
}
} }
// write simulation state at the report stage
Dune::Timer perfTimer;
perfTimer.start();
const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
ebosSimulator_.problem().setNextTimeStepSize(nextstep);
ebosSimulator_.problem().writeOutput();
report_.output_write_time += perfTimer.stop();
solver->model().endReportStep();
// take time that was used to solve system for this reportStep
solverTimer_->stop();
// update timing.
report_.solver_time += solverTimer_->secsSinceStart();
// Increment timer, remember well state.
++timer;
if (terminalOutput_) {
if (!timer.initialStep()) {
const std::string version = moduleVersionName();
outputTimestampFIP(timer, version);
}
}
if (terminalOutput_) {
std::string msg =
"Time step took " + std::to_string(solverTimer_->secsSinceStart()) + " seconds; "
"total solver time " + std::to_string(report_.solver_time) + " seconds.";
OpmLog::debug(msg);
}
return true;
}
SimulatorReport runLastStep()
{
// make sure all output is written to disk before run is finished // make sure all output is written to disk before run is finished
{ {
Dune::Timer finalOutputTimer; Dune::Timer finalOutputTimer;
finalOutputTimer.start(); finalOutputTimer.start();
ebosSimulator_.problem().finalizeOutput(); ebosSimulator_.problem().finalizeOutput();
report.output_write_time += finalOutputTimer.stop(); report_.output_write_time += finalOutputTimer.stop();
} }
// Stop timer and create timing report // Stop timer and create timing report
totalTimer.stop(); totalTimer_->stop();
report.total_time = totalTimer.secsSinceStart(); report_.total_time = totalTimer_->secsSinceStart();
report.converged = true; report_.converged = true;
return report; return report_;
} }
/** \brief Returns the simulator report for the failed substeps of the simulation. /** \brief Returns the simulator report for the failed substeps of the simulation.
*/ */
const SimulatorReport& failureReport() const const SimulatorReport& failureReport() const
@ -351,6 +368,8 @@ protected:
Simulator& ebosSimulator_; Simulator& ebosSimulator_;
std::unique_ptr<WellConnectionAuxiliaryModule<TypeTag>> wellAuxMod_; std::unique_ptr<WellConnectionAuxiliaryModule<TypeTag>> wellAuxMod_;
SimulatorReport failureReport_; SimulatorReport failureReport_;
SimulatorReport report_;
SimulatorReport stepReport_;
ModelParameters modelParam_; ModelParameters modelParam_;
SolverParameters solverParam_; SolverParameters solverParam_;
@ -359,6 +378,11 @@ protected:
PhaseUsage phaseUsage_; PhaseUsage phaseUsage_;
// Misc. data // Misc. data
bool terminalOutput_; bool terminalOutput_;
// Timers
std::unique_ptr<Opm::time::StopWatch> solverTimer_;
std::unique_ptr<Opm::time::StopWatch> totalTimer_;
std::unique_ptr<TimeStepper> adaptiveTimeStepping_;
}; };
} // namespace Opm } // namespace Opm