22#ifndef OPM_SIMULATOR_FULLY_IMPLICIT_BLACKOIL_IMPL_HEADER_INCLUDED
23#define OPM_SIMULATOR_FULLY_IMPLICIT_BLACKOIL_IMPL_HEADER_INCLUDED
26#ifndef OPM_SIMULATOR_FULLY_IMPLICIT_BLACKOIL_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);
334 this->solver_->model().beginReportStep();
336 const bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
343 if (adaptiveTimeStepping_) {
344 auto tuningUpdater = [enableTUNING,
this,
346 double substep_length,
347 const int sub_step_number)
349 auto& schedule = this->simulator_.vanguard().schedule();
350 auto& events = this->schedule()[reportStep].events();
353 if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
355 schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
356 const auto& sched_state = schedule[reportStep];
357 const auto& max_next_tstep = sched_state.max_next_tstep(enableTUNING);
358 const auto& tuning = sched_state.tuning();
361 adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning);
364 solver_->model().updateTUNING(tuning);
365 this->updateTUNING(tuning);
366 substep_length = this->adaptiveTimeStepping_->suggestedNextStep();
368 substep_length = max_next_tstep;
369 this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
371 result = max_next_tstep > 0;
374 if (events.hasEvent(ScheduleEvents::TUNINGDP_CHANGE)) {
376 schedule.clear_event(ScheduleEvents::TUNINGDP_CHANGE, reportStep);
381 const auto& sched_state = schedule[reportStep];
382 const auto& tuning_dp = sched_state.tuning_dp();
383 solver_->model().updateTUNINGDP(tuning_dp);
384 this->updateTUNINGDP(tuning_dp);
387 const auto& wcycle = schedule[reportStep].wcycle.get();
388 if (wcycle.empty()) {
392 const auto& wmatcher = schedule.wellMatcher(reportStep);
393 double wcycle_time_step =
394 wcycle.nextTimeStep(curr_time,
397 this->wellModel_().wellOpenTimes(),
398 this->wellModel_().wellCloseTimes(),
400 &wg_events = this->wellModel_().reportStepStartEvents()]
401 (
const std::string& name)
403 if (sub_step_number != 0) {
406 return wg_events.hasEvent(name, ScheduleEvents::REQUEST_OPEN_WELL);
409 wcycle_time_step = this->grid().comm().min(wcycle_time_step);
410 if (substep_length != wcycle_time_step) {
411 this->adaptiveTimeStepping_->updateNEXTSTEP(wcycle_time_step);
419 this->adaptiveTimeStepping_->suggestedNextStep(), 0);
421#ifdef RESERVOIR_COUPLING_ENABLED
422 if (this->reservoirCouplingMaster_) {
423 this->reservoirCouplingMaster_->maybeSpawnSlaveProcesses(timer.
currentStepNum());
424 this->reservoirCouplingMaster_->maybeActivate(timer.
currentStepNum());
426 else if (this->reservoirCouplingSlave_) {
427 this->reservoirCouplingSlave_->maybeActivate(timer.
currentStepNum());
431 bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
432 events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
433 events.hasEvent(ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER) ||
434 events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE) ||
435 events.hasEvent(ScheduleEvents::INJECTION_UPDATE) ||
436 events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
437 auto stepReport = adaptiveTimeStepping_->step(timer, *solver_, event, tuningUpdater);
438 report_ += stepReport;
441 auto stepReport = solver_->step(timer,
nullptr);
442 report_ += stepReport;
444 simulator_.problem().setSubStepReport(stepReport);
445 simulator_.problem().setSimulationReport(report_);
446 simulator_.problem().endTimeStep();
447 if (terminalOutput_) {
448 std::ostringstream ss;
449 stepReport.reportStep(ss);
450 OpmLog::info(ss.str());
455 Dune::Timer perfTimer;
457 const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
458 simulator_.problem().setNextTimeStepSize(nextstep);
459 simulator_.problem().writeOutput(
true);
460 report_.success.output_write_time += perfTimer.stop();
462 solver_->model().endReportStep();
465 solverTimer_->stop();
468 report_.success.solver_time += solverTimer_->secsSinceStart();
470 if (this->grid().comm().rank() == 0) {
473 const auto& reps = this->solver_->model().stepReports();
474 convergence_output_.write(reps);
480 if (terminalOutput_) {
482 "Time step took " +
std::to_string(solverTimer_->secsSinceStart()) +
" seconds; "
483 "total solver time " +
std::to_string(report_.success.solver_time) +
" seconds.";
487 serializer_.save(timer);
492template<
class TypeTag>
499 Dune::Timer finalOutputTimer;
500 finalOutputTimer.start();
502 simulator_.problem().finalizeOutput();
508 report_.success.total_time = totalTimer_->secsSinceStart();
509 report_.success.converged =
true;
514template<
class TypeTag>
515template<
class Serializer>
520 serializer(simulator_);
522 serializer(adaptiveTimeStepping_);
525template<
class TypeTag>
529 [[maybe_unused]]
const std::string& groupName)
532 serializer.read(*
this, groupName,
"simulator_data");
536template<
class TypeTag>
540 [[maybe_unused]]
const std::string& groupName)
const
543 serializer.write(*
this, groupName,
"simulator_data");
547template<
class TypeTag>
548std::array<std::string,5>
552 std::ostringstream str;
557 simulator_.vanguard().caseName(),
561template<
class TypeTag>
562std::unique_ptr<typename SimulatorFullyImplicitBlackoil<TypeTag>::Solver>
566 auto model = std::make_unique<Model>(simulator_,
571 if (this->modelParam_.write_partitions_) {
572 const auto& iocfg = this->eclState().cfg().io();
574 const auto odir = iocfg.getOutputDir()
575 / std::filesystem::path {
"partition" }
576 / iocfg.getBaseName();
578 if (this->grid().comm().rank() == 0) {
579 create_directories(odir);
582 this->grid().comm().barrier();
584 model->writePartitions(odir);
586 this->modelParam_.write_partitions_ =
false;
589 return std::make_unique<Solver>(solverParam_, std::move(model));
Class for handling the blackoil well model.
Definition: BlackoilWellModel.hpp:98
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 black-oil simulation.
Definition: SimulatorFullyImplicitBlackoil.hpp:114
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: SimulatorFullyImplicitBlackoil.hpp:118
void loadState(HDF5Serializer &serializer, const std::string &groupName) override
Load this simulator's data block from an OPMRST file via HDF5.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:528
void updateTUNINGDP(const TuningDp &tuning_dp)
Apply a TUNINGDP keyword to the cached model parameters.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:256
void init(const SimulatorTimer &timer)
One-shot setup performed before the first runStep.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:204
void updateTUNING(const Tuning &tuning)
Apply a TUNING keyword to the cached model parameters.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:240
SimulatorReport run(SimulatorTimer &timer)
Run the entire simulation to completion.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:109
~SimulatorFullyImplicitBlackoil() override
Ends the convergence-output thread cleanly on all ranks.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:78
void serializeOp(Serializer &serializer)
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:518
std::unique_ptr< Solver > createSolver(WellModel &wellModel)
Build the Solver used during the current report step.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:564
void saveState(HDF5Serializer &serializer, const std::string &groupName) const override
Save this simulator's data block to an OPMRST file via HDF5.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:539
const Grid & grid() const
Definition: SimulatorFullyImplicitBlackoil.hpp:282
SimulatorFullyImplicitBlackoil(Simulator &simulator)
Construct from the surrounding eWoms Simulator.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:46
static void registerParameters()
Register all parameters consumed by this class and its major collaborators.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:87
SimulatorConvergenceOutput convergence_output_
Background thread for INFOSTEP / INFOITER files.
Definition: SimulatorFullyImplicitBlackoil.hpp:356
bool terminalOutput_
Emit high-level progress to std::cout (rank 0 only).
Definition: SimulatorFullyImplicitBlackoil.hpp:341
bool runStep(SimulatorTimer &timer)
Advance the simulation by one report step.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:279
SimulatorReport finalize()
Stop the timers and emit the final OPMRST output.
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:495
std::array< std::string, 5 > getHeader() const override
Definition: SimulatorFullyImplicitBlackoil_impl.hpp:550
Simulator & simulator_
Surrounding eWoms simulator; observed, not owned.
Definition: SimulatorFullyImplicitBlackoil.hpp:329
Definition: SimulatorTimer.hpp:39
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:187
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()