22#ifndef OPM_SIMULATOR_FULLY_IMPLICIT_IMPL_HEADER_INCLUDED
23#define OPM_SIMULATOR_FULLY_IMPLICIT_IMPL_HEADER_INCLUDED
26#ifndef OPM_SIMULATOR_FULLY_IMPLICIT_HEADER_INCLUDED
31#include <opm/input/eclipse/Units/UnitSystem.hpp>
37#include <fmt/format.h>
44template<
class TypeTag>
47 : simulator_(simulator)
50 simulator_.vanguard().eclState().getIOConfig(),
51 Parameters::
Get<Parameters::SaveStep>(),
52 Parameters::
Get<Parameters::LoadStep>(),
53 Parameters::
Get<Parameters::SaveFile>(),
54 Parameters::
Get<Parameters::LoadFile>())
58 if (this->
grid().comm().rank() == 0) {
59 this->
terminalOutput_ = Parameters::Get<Parameters::EnableTerminalOutput>();
62 [compNames =
typename Model::ComponentName{}](
const int compIdx)
63 {
return std::string_view { compNames.name(compIdx) }; }
66 if (!
simulator_.vanguard().eclState().getIOConfig().initOnly()) {
68 startThread(this->
simulator_.vanguard().eclState(),
69 Parameters::Get<Parameters::OutputExtraConvergenceInfo>(),
70 R
"(OutputExtraConvergenceInfo (--output-extra-convergence-info))",
76template<
class TypeTag>
81 convergence_output_.endThread();
84template<
class TypeTag>
89 ModelParameters::registerParameters();
90 SolverParameters::registerParameters();
91 TimeStepper::registerParameters();
98#ifdef RESERVOIR_COUPLING_ENABLED
99template<
class TypeTag>
104 init(timer, argc, argv);
106template<
class TypeTag>
116 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
118 while (!timer.
done()) {
119 simulator_.problem().writeReports(timer);
120 bool continue_looping = runStep(timer);
121 if (!continue_looping)
break;
123 simulator_.problem().writeReports(timer);
125#ifdef RESERVOIR_COUPLING_ENABLED
128 if (this->reservoirCouplingMaster_) {
129 this->reservoirCouplingMaster_->sendTerminateAndDisconnect();
131 else if (this->reservoirCouplingSlave_ && !this->reservoirCouplingSlave_->terminated()) {
135 this->reservoirCouplingSlave_->receiveTerminateAndDisconnect();
142#ifdef RESERVOIR_COUPLING_ENABLED
143template<
class TypeTag>
148 for (std::size_t report_step = 0; report_step < this->schedule().size(); ++report_step) {
149 auto rescoup = this->schedule()[report_step].rescoup();
150 auto slave_count = rescoup.slaveCount();
151 auto master_group_count = rescoup.masterGroupCount();
155 if (slave_count > 0) {
158 else if (master_group_count > 0) {
160 throw ReservoirCouplingError(
161 "Inconsistent reservoir coupling master schedule: "
162 "Master group count is greater than 0 but slave count is 0"
170#ifdef RESERVOIR_COUPLING_ENABLED
171template<
class TypeTag>
174init(
const SimulatorTimer& timer,
int argc,
char** argv)
176 auto slave_mode = Parameters::Get<Parameters::Slave>();
178 this->reservoirCouplingSlave_ =
179 std::make_unique<ReservoirCouplingSlave<Scalar>>(
181 this->schedule(), timer
183 this->reservoirCouplingSlave_->sendAndReceiveInitialData();
184 this->simulator_.setReservoirCouplingSlave(this->reservoirCouplingSlave_.get());
185 wellModel_().setReservoirCouplingSlave(this->reservoirCouplingSlave_.get());
188 auto master_mode = checkRunningAsReservoirCouplingMaster();
190 this->reservoirCouplingMaster_ =
191 std::make_unique<ReservoirCouplingMaster<Scalar>>(
196 this->simulator_.setReservoirCouplingMaster(this->reservoirCouplingMaster_.get());
197 wellModel_().setReservoirCouplingMaster(this->reservoirCouplingMaster_.get());
201template<
class TypeTag>
207 simulator_.setEpisodeIndex(-1);
210 solverTimer_ = std::make_unique<time::StopWatch>();
211 totalTimer_ = std::make_unique<time::StopWatch>();
212 totalTimer_->start();
215 bool enableAdaptive = Parameters::Get<Parameters::EnableAdaptiveTimeStepping>();
216 bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
217 if (enableAdaptive) {
218 const UnitSystem& unitSystem = this->simulator_.vanguard().eclState().getUnits();
220 auto max_next_tstep = sched_state.max_next_tstep(enableTUNING);
222 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(max_next_tstep,
223 sched_state.tuning(),
224 unitSystem, report_, terminalOutput_);
227 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(unitSystem, report_, max_next_tstep, terminalOutput_);
232 adaptiveTimeStepping_->setSuggestedNextStep(simulator_.timeStepSize());
237template<
class TypeTag>
242 modelParam_.tolerance_cnv_ = tuning.TRGCNV;
243 modelParam_.tolerance_cnv_relaxed_ = tuning.XXXCNV;
244 modelParam_.tolerance_mb_ = tuning.TRGMBE;
245 modelParam_.tolerance_mb_relaxed_ = tuning.XXXMBE;
246 modelParam_.newton_max_iter_ = tuning.NEWTMX;
247 modelParam_.newton_min_iter_ = tuning.NEWTMN;
248 if (terminalOutput_) {
253template<
class TypeTag>
259 modelParam_.tolerance_max_dp_ = tuning_dp.TRGDDP;
260 modelParam_.tolerance_max_ds_ = tuning_dp.TRGDDS;
261 modelParam_.tolerance_max_drs_ = tuning_dp.TRGDDRS;
262 modelParam_.tolerance_max_drv_ = tuning_dp.TRGDDRV;
265 if (terminalOutput_) {
267 if (tuning_dp.TRGLCV_has_value) {
268 OpmLog::warning(
"TUNINGDP item 1 (TRGLCV) is not supported.");
270 if (tuning_dp.XXXLCV_has_value) {
271 OpmLog::warning(
"TUNINGDP item 2 (XXXLCV) is not supported.");
276template<
class TypeTag>
281 if (schedule().exitStatus().has_value()) {
282 if (terminalOutput_) {
283 OpmLog::info(
"Stopping simulation since EXIT was triggered by an action keyword.");
285 report_.success.exit_status = schedule().exitStatus().value();
289 if (serializer_.shouldLoad()) {
290 serializer_.loadTimerInfo(timer);
294 if (terminalOutput_) {
295 std::ostringstream ss;
297 OpmLog::debug(ss.str());
303 Dune::Timer perfTimer;
306 simulator_.setEpisodeIndex(-1);
307 simulator_.setEpisodeLength(0.0);
308 simulator_.setTimeStepSize(0.0);
310 simulator_.problem().writeOutput(
true);
312 report_.success.output_write_time += perfTimer.stop();
316 solverTimer_->start();
319 solver_ = createSolver(wellModel_());
322 simulator_.startNextEpisode(
323 simulator_.startTime()
328 if (serializer_.shouldLoad()) {
329 wellModel_().prepareDeserialize(serializer_.loadStep() - 1);
330 serializer_.loadState();
331 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
338 if (restoreStateHook_) {
342 this->solver_->model().beginReportStep();
344 const bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
351 if (adaptiveTimeStepping_) {
352 auto tuningUpdater = [enableTUNING,
this,
354 double substep_length,
355 const int sub_step_number)
357 auto& schedule = this->simulator_.vanguard().schedule();
358 auto& events = this->schedule()[reportStep].events();
361 if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
363 schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
364 const auto& sched_state = schedule[reportStep];
365 const auto& max_next_tstep = sched_state.max_next_tstep(enableTUNING);
366 const auto& tuning = sched_state.tuning();
369 adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning);
372 solver_->model().updateTUNING(tuning);
373 this->updateTUNING(tuning);
374 substep_length = this->adaptiveTimeStepping_->suggestedNextStep();
376 substep_length = max_next_tstep;
377 this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
379 result = max_next_tstep > 0;
382 if (events.hasEvent(ScheduleEvents::TUNINGDP_CHANGE)) {
384 schedule.clear_event(ScheduleEvents::TUNINGDP_CHANGE, reportStep);
389 const auto& sched_state = schedule[reportStep];
390 const auto& tuning_dp = sched_state.tuning_dp();
391 solver_->model().updateTUNINGDP(tuning_dp);
392 this->updateTUNINGDP(tuning_dp);
395 const auto& wcycle = schedule[reportStep].wcycle.get();
396 if (wcycle.empty()) {
400 const auto& wmatcher = schedule.wellMatcher(reportStep);
401 double wcycle_time_step =
402 wcycle.nextTimeStep(curr_time,
405 this->wellModel_().wellOpenTimes(),
406 this->wellModel_().wellCloseTimes(),
408 &wg_events = this->wellModel_().reportStepStartEvents()]
409 (
const std::string& name)
411 if (sub_step_number != 0) {
414 return wg_events.hasEvent(name, ScheduleEvents::REQUEST_OPEN_WELL);
417 wcycle_time_step = this->grid().comm().min(wcycle_time_step);
418 if (substep_length != wcycle_time_step) {
419 this->adaptiveTimeStepping_->updateNEXTSTEP(wcycle_time_step);
427 this->adaptiveTimeStepping_->suggestedNextStep(), 0);
429#ifdef RESERVOIR_COUPLING_ENABLED
430 if (this->reservoirCouplingMaster_) {
431 this->reservoirCouplingMaster_->maybeSpawnSlaveProcesses(timer.
currentStepNum());
432 this->reservoirCouplingMaster_->maybeActivate(timer.
currentStepNum());
434 else if (this->reservoirCouplingSlave_) {
435 this->reservoirCouplingSlave_->maybeActivate(timer.
currentStepNum());
439 bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
440 events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
441 events.hasEvent(ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER) ||
442 events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE) ||
443 events.hasEvent(ScheduleEvents::INJECTION_UPDATE) ||
444 events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
445 auto stepReport = adaptiveTimeStepping_->step(timer, *solver_, event, tuningUpdater);
446 report_ += stepReport;
447#ifdef RESERVOIR_COUPLING_ENABLED
454 if (this->reservoirCouplingSlave_ && this->reservoirCouplingSlave_->terminated()) {
455 this->handleSlaveTerminated_();
461 auto stepReport = solver_->step(timer,
nullptr);
462 report_ += stepReport;
464 simulator_.problem().setSubStepReport(stepReport);
465 simulator_.problem().setSimulationReport(report_);
466 simulator_.problem().endTimeStep();
467 if (terminalOutput_) {
468 std::ostringstream ss;
469 stepReport.reportStep(ss);
470 OpmLog::info(ss.str());
475 Dune::Timer perfTimer;
477 const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
478 simulator_.problem().setNextTimeStepSize(nextstep);
479 simulator_.problem().writeOutput(
true);
480 report_.success.output_write_time += perfTimer.stop();
482 solver_->model().endReportStep();
485 solverTimer_->stop();
488 report_.success.solver_time += solverTimer_->secsSinceStart();
490 if (this->grid().comm().rank() == 0) {
493 const auto& reps = this->solver_->model().stepReports();
494 convergence_output_.write(reps);
500 if (terminalOutput_) {
502 "Time step took " +
std::to_string(solverTimer_->secsSinceStart()) +
" seconds; "
503 "total solver time " +
std::to_string(report_.success.solver_time) +
" seconds.";
507 serializer_.save(timer);
512#ifdef RESERVOIR_COUPLING_ENABLED
513template<
class TypeTag>
518 if (terminalOutput_) {
519 OpmLog::info(
"Reservoir coupling: master simulation has ended; "
520 "stopping slave simulation gracefully.");
528 this->solver_->model().endReportStep();
531 this->solverTimer_->stop();
532 this->report_.success.solver_time += this->solverTimer_->secsSinceStart();
536template<
class TypeTag>
543 Dune::Timer finalOutputTimer;
544 finalOutputTimer.start();
546 simulator_.problem().finalizeOutput();
552 report_.success.total_time = totalTimer_->secsSinceStart();
553 report_.success.converged =
true;
558template<
class TypeTag>
559template<
class Serializer>
564 serializer(simulator_);
566 serializer(adaptiveTimeStepping_);
569template<
class TypeTag>
573 [[maybe_unused]]
const std::string& groupName)
576 serializer.read(*
this, groupName,
"simulator_data");
580template<
class TypeTag>
584 [[maybe_unused]]
const std::string& groupName)
const
587 serializer.write(*
this, groupName,
"simulator_data");
591template<
class TypeTag>
592std::array<std::string,5>
596 std::ostringstream str;
601 simulator_.vanguard().caseName(),
605template<
class TypeTag>
606std::unique_ptr<typename SimulatorFullyImplicit<TypeTag>::Solver>
610 auto model = std::make_unique<Model>(simulator_,
615 if (this->modelParam_.write_partitions_) {
616 const auto& iocfg = this->eclState().cfg().io();
618 const auto odir = iocfg.getOutputDir()
619 / std::filesystem::path {
"partition" }
620 / iocfg.getBaseName();
622 if (this->grid().comm().rank() == 0) {
623 create_directories(odir);
626 this->grid().comm().barrier();
628 model->writePartitions(odir);
630 this->modelParam_.write_partitions_ =
false;
633 return std::make_unique<Solver>(solverParam_, std::move(model));
std::function< std::string_view(int)> ComponentToPhaseName
Definition: ExtraConvergenceOutputThread.hpp:109
Definition: FlowGenericVanguard.hpp:108
static Parallel::Communication & comm()
Obtain global communicator.
Definition: FlowGenericVanguard.hpp:336
Class for (de-)serializing using HDF5.
Definition: HDF5Serializer.hpp:37
Top-level driver for a fully implicit flow simulation.
Definition: SimulatorFullyImplicit.hpp:115
SimulatorReport finalize()
Stop the timers and emit the final OPMRST output.
Definition: SimulatorFullyImplicit_impl.hpp:539
void init(const SimulatorTimer &timer)
One-shot setup performed before the first runStep.
Definition: SimulatorFullyImplicit_impl.hpp:204
void serializeOp(Serializer &serializer)
Definition: SimulatorFullyImplicit_impl.hpp:562
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: SimulatorFullyImplicit.hpp:119
void saveState(HDF5Serializer &serializer, const std::string &groupName) const override
Save this simulator's data block to an OPMRST file via HDF5.
Definition: SimulatorFullyImplicit_impl.hpp:583
SimulatorReport run(SimulatorTimer &timer)
Run the entire simulation to completion.
Definition: SimulatorFullyImplicit_impl.hpp:109
SimulatorFullyImplicit(Simulator &simulator)
Construct from the surrounding eWoms Simulator.
Definition: SimulatorFullyImplicit_impl.hpp:46
std::unique_ptr< Solver > createSolver(WellModel &wellModel)
Build the Solver used during the current report step.
Definition: SimulatorFullyImplicit_impl.hpp:608
bool terminalOutput_
Emit high-level progress to std::cout (rank 0 only).
Definition: SimulatorFullyImplicit.hpp:376
void updateTUNINGDP(const TuningDp &tuning_dp)
Apply a TUNINGDP keyword to the cached model parameters.
Definition: SimulatorFullyImplicit_impl.hpp:256
void loadState(HDF5Serializer &serializer, const std::string &groupName) override
Load this simulator's data block from an OPMRST file via HDF5.
Definition: SimulatorFullyImplicit_impl.hpp:572
std::array< std::string, 5 > getHeader() const override
Definition: SimulatorFullyImplicit_impl.hpp:594
static void registerParameters()
Register all parameters consumed by this class and its major collaborators.
Definition: SimulatorFullyImplicit_impl.hpp:87
SimulatorConvergenceOutput convergence_output_
Background thread for INFOSTEP / INFOITER files.
Definition: SimulatorFullyImplicit.hpp:391
Simulator & simulator_
Surrounding eWoms simulator; observed, not owned.
Definition: SimulatorFullyImplicit.hpp:364
~SimulatorFullyImplicit() override
Ends the convergence-output thread cleanly on all ranks.
Definition: SimulatorFullyImplicit_impl.hpp:78
const Grid & grid() const
Definition: SimulatorFullyImplicit.hpp:302
void updateTUNING(const Tuning &tuning)
Apply a TUNING keyword to the cached model parameters.
Definition: SimulatorFullyImplicit_impl.hpp:240
GetPropType< TypeTag, Properties::WellModel > WellModel
Definition: SimulatorFullyImplicit.hpp:141
bool runStep(SimulatorTimer &timer)
Advance the simulation by one report step.
Definition: SimulatorFullyImplicit_impl.hpp:279
Definition: SimulatorTimer.hpp:38
double currentStepLength() const override
bool initialStep() const override
Whether the current step is the first step.
void report(std::ostream &os) const
double simulationTimeElapsed() const override
int currentStepNum() const override
bool done() const override
Return true if op++() has been called numSteps() times.
void printValues(std::ostream &os)
Print values of the run-time parameters.
auto Get(bool errorIfNotRegistered=true)
Retrieve a runtime parameter.
Definition: parametersystem.hpp:191
void logTuning(const Tuning &tuning)
Log tuning parameters.
void registerSimulatorParameters()
void outputReportStep(const SimulatorTimer &timer)
Definition: blackoilbioeffectsmodules.hh:45
std::string compileTimestamp()
std::string moduleVersion()
std::string to_string(const ConvergenceReport::ReservoirFailure::Type t)
Definition: SimulatorReport.hpp:122
SimulatorReportSingle success
Definition: SimulatorReport.hpp:123
double output_write_time
Definition: SimulatorReport.hpp:46
static void registerParameters()
static void registerParameters()