SimulatorFullyImplicit_impl.hpp
Go to the documentation of this file.
1/*
2 Copyright 2013, 2015, 2020 SINTEF Digital, Mathematics and Cybernetics.
3 Copyright 2015 Andreas Lauser
4 Copyright 2017 IRIS
5
6 This file is part of the Open Porous Media project (OPM).
7
8 OPM is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 OPM is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with OPM. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#ifndef OPM_SIMULATOR_FULLY_IMPLICIT_IMPL_HEADER_INCLUDED
23#define OPM_SIMULATOR_FULLY_IMPLICIT_IMPL_HEADER_INCLUDED
24
25// Improve IDE experience
26#ifndef OPM_SIMULATOR_FULLY_IMPLICIT_HEADER_INCLUDED
27#include <config.h>
29#endif
30
31#include <opm/input/eclipse/Units/UnitSystem.hpp>
32
34
36
37#include <fmt/format.h>
38
39#include <filesystem>
40#include <limits>
41#include <sstream>
42
43namespace Opm {
44
45template<class TypeTag>
48 : simulator_(simulator)
49 , serializer_(*this,
50 FlowGenericVanguard::comm(),
51 simulator_.vanguard().eclState().getIOConfig(),
52 Parameters::Get<Parameters::SaveStep>(),
53 Parameters::Get<Parameters::LoadStep>(),
54 Parameters::Get<Parameters::SaveFile>(),
55 Parameters::Get<Parameters::LoadFile>())
56{
57 // Only rank 0 does print to std::cout, and only if specifically requested.
58 this->terminalOutput_ = false;
59 if (this->grid().comm().rank() == 0) {
60 this->terminalOutput_ = Parameters::Get<Parameters::EnableTerminalOutput>();
61
63 [compNames = typename Model::ComponentName{}](const int compIdx)
64 { return std::string_view { compNames.name(compIdx) }; }
65 };
66
67 if (!simulator_.vanguard().eclState().getIOConfig().initOnly()) {
69 startThread(this->simulator_.vanguard().eclState(),
70 Parameters::Get<Parameters::OutputExtraConvergenceInfo>(),
71 R"(OutputExtraConvergenceInfo (--output-extra-convergence-info))",
72 getPhaseName);
73 }
74 }
75}
76
77template<class TypeTag>
80{
81 // Safe to call on all ranks, not just the I/O rank.
82 convergence_output_.endThread();
83}
84
85template<class TypeTag>
86void
89{
90 ModelParameters::registerParameters();
91 SolverParameters::registerParameters();
92 TimeStepper::registerParameters();
94
97}
98
99#ifdef RESERVOIR_COUPLING_ENABLED
100template<class TypeTag>
103run(SimulatorTimer& timer, int argc, char** argv)
104{
105 init(timer, argc, argv);
106#else
107template<class TypeTag>
110run(SimulatorTimer& timer)
111{
112 init(timer);
113#endif
114 // Make cache up to date. No need for updating it in elementCtx.
115 // NB! Need to be at the correct step in case of restart
116 simulator_.setEpisodeIndex(timer.currentStepNum());
117 simulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
118 // Main simulation loop.
119 while (!timer.done()) {
120 simulator_.problem().writeReports(timer);
121 bool continue_looping = runStep(timer);
122 if (!continue_looping) break;
123 }
124 simulator_.problem().writeReports(timer);
125
126#ifdef RESERVOIR_COUPLING_ENABLED
127 // Clean up MPI intercommunicators before MPI_Finalize()
128 // Master sends terminate=1 signal; slave receives it and both call MPI_Comm_disconnect()
129 if (this->reservoirCouplingMaster_) {
130 this->reservoirCouplingMaster_->sendTerminateAndDisconnect();
131 }
132 else if (this->reservoirCouplingSlave_ && !this->reservoirCouplingSlave_->terminated()) {
133 // We got here by running out of report steps of our own. If the master is still
134 // running, notifyEndOfRunAndDisconnect() tells it so, and the master then continues
135 // with no flow from this slave.
136 //
137 // TODO: Implement GECON item 8, which lets a master deck ask for the opposite: stop
138 // the master run when one of its slaves finishes, rather than continuing without it.
139 //
140 // Only call if not already terminated via maybeReceiveTerminateSignalFromMaster()
141 // (which happens when master finishes before slave reaches end of its loop)
142 this->reservoirCouplingSlave_->notifyEndOfRunAndDisconnect();
143 }
144#endif
145
146 return finalize();
147}
148
149#ifdef RESERVOIR_COUPLING_ENABLED
150template<class TypeTag>
151bool
154{
155 for (std::size_t report_step = 0; report_step < this->schedule().size(); ++report_step) {
156 auto rescoup = this->schedule()[report_step].rescoup();
157 auto slave_count = rescoup.slaveCount();
158 auto master_group_count = rescoup.masterGroupCount();
159 // Master mode is enabled when SLAVES keyword is present.
160 // - Prediction mode: SLAVES + GRUPMAST (master allocates rates)
161 // - History mode: SLAVES only (master synchronizes time-stepping)
162 if (slave_count > 0) {
163 return true;
164 }
165 else if (master_group_count > 0) {
166 // GRUPMAST without SLAVES is invalid
167 throw ReservoirCouplingError(
168 "Inconsistent reservoir coupling master schedule: "
169 "Master group count is greater than 0 but slave count is 0"
170 );
171 }
172 }
173 return false;
174}
175#endif
176
177#ifdef RESERVOIR_COUPLING_ENABLED
178template<class TypeTag>
179void
181init(const SimulatorTimer& timer, int argc, char** argv)
182{
183 auto slave_mode = Parameters::Get<Parameters::Slave>();
184 if (slave_mode) {
185 this->reservoirCouplingSlave_ =
186 std::make_unique<ReservoirCouplingSlave<Scalar>>(
188 this->schedule(), timer
189 );
190 this->reservoirCouplingSlave_->sendAndReceiveInitialData();
191 this->simulator_.setReservoirCouplingSlave(this->reservoirCouplingSlave_.get());
192 wellModel_().setReservoirCouplingSlave(this->reservoirCouplingSlave_.get());
193 }
194 else {
195 auto master_mode = checkRunningAsReservoirCouplingMaster();
196 if (master_mode) {
197 this->reservoirCouplingMaster_ =
198 std::make_unique<ReservoirCouplingMaster<Scalar>>(
200 this->schedule(),
201 argc, argv
202 );
203 this->simulator_.setReservoirCouplingMaster(this->reservoirCouplingMaster_.get());
204 wellModel_().setReservoirCouplingMaster(this->reservoirCouplingMaster_.get());
205 }
206 }
207#else
208template<class TypeTag>
209void
211init(const SimulatorTimer& timer)
212{
213#endif
214 simulator_.setEpisodeIndex(-1);
215
216 // Create timers and file for writing timing info.
217 solverTimer_ = std::make_unique<time::StopWatch>();
218 totalTimer_ = std::make_unique<time::StopWatch>();
219 totalTimer_->start();
220
221 // adaptive time stepping
222 bool enableAdaptive = Parameters::Get<Parameters::EnableAdaptiveTimeStepping>();
223 bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
224 if (enableAdaptive) {
225 const UnitSystem& unitSystem = this->simulator_.vanguard().eclState().getUnits();
226 const auto& sched_state = schedule()[timer.currentStepNum()];
227 auto max_next_tstep = sched_state.max_next_tstep(enableTUNING);
228 if (enableTUNING) {
229 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(max_next_tstep,
230 sched_state.tuning(),
231 unitSystem, report_, terminalOutput_);
232 }
233 else {
234 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(unitSystem, report_, max_next_tstep, terminalOutput_);
235 }
236 if (isRestart()) {
237 // For restarts the simulator may have gotten some information
238 // about the next timestep size from the OPMEXTRA field
239 adaptiveTimeStepping_->setSuggestedNextStep(simulator_.timeStepSize());
240 }
241 }
242}
243
244template<class TypeTag>
245void
247updateTUNING(const Tuning& tuning)
248{
249 modelParam_.tolerance_cnv_ = tuning.TRGCNV;
250 modelParam_.tolerance_cnv_relaxed_ = tuning.XXXCNV;
251 modelParam_.tolerance_mb_ = tuning.TRGMBE;
252 modelParam_.tolerance_mb_relaxed_ = tuning.XXXMBE;
253 modelParam_.newton_max_iter_ = tuning.NEWTMX;
254 modelParam_.newton_min_iter_ = tuning.NEWTMN;
255 if (terminalOutput_) {
256 detail::logTuning(tuning);
257 }
258}
259
260template<class TypeTag>
261void
263updateTUNINGDP(const TuningDp& tuning_dp)
264{
265 // NOTE: If TUNINGDP item is _not_ set it should be 0.0
266 modelParam_.tolerance_max_dp_ = tuning_dp.TRGDDP;
267 modelParam_.tolerance_max_ds_ = tuning_dp.TRGDDS;
268 modelParam_.tolerance_max_drs_ = tuning_dp.TRGDDRS;
269 modelParam_.tolerance_max_drv_ = tuning_dp.TRGDDRV;
270
271 // Terminal warnings
272 if (terminalOutput_) {
273 // Warnings unsupported items
274 if (tuning_dp.TRGLCV_has_value) {
275 OpmLog::warning("TUNINGDP item 1 (TRGLCV) is not supported.");
276 }
277 if (tuning_dp.XXXLCV_has_value) {
278 OpmLog::warning("TUNINGDP item 2 (XXXLCV) is not supported.");
279 }
280 }
281}
282
283template<class TypeTag>
284bool
287{
288 if (schedule().exitStatus().has_value()) {
289 if (terminalOutput_) {
290 OpmLog::info("Stopping simulation since EXIT was triggered by an action keyword.");
291 }
292 report_.success.exit_status = schedule().exitStatus().value();
293 return false;
294 }
295
296 if (serializer_.shouldLoad()) {
297 serializer_.loadTimerInfo(timer);
298 }
299
300 // Report timestep.
301 if (terminalOutput_) {
302 std::ostringstream ss;
303 timer.report(ss);
304 OpmLog::debug(ss.str());
306 }
307
308 // write the inital state at the report stage
309 if (timer.initialStep()) {
310 Dune::Timer perfTimer;
311 perfTimer.start();
312
313 simulator_.setEpisodeIndex(-1);
314 simulator_.setEpisodeLength(0.0);
315 simulator_.setTimeStepSize(0.0);
316 wellModel_().beginReportStep(timer.currentStepNum());
317 simulator_.problem().writeOutput(true);
318
319 report_.success.output_write_time += perfTimer.stop();
320 }
321
322 // Run a multiple steps of the solver depending on the time step control.
323 solverTimer_->start();
324
325 if (!solver_) {
326 solver_ = createSolver(wellModel_());
327 }
328
329 simulator_.startNextEpisode(
330 simulator_.startTime()
331 + schedule().seconds(timer.currentStepNum()),
332 timer.currentStepLength());
333 simulator_.setEpisodeIndex(timer.currentStepNum());
334
335 if (serializer_.shouldLoad()) {
336 wellModel_().prepareDeserialize(serializer_.loadStep() - 1);
337 serializer_.loadState();
338 simulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
339 }
340
341 // Same position as the OPMRST restore above -- after the episode has been
342 // set up and before the solve -- for callers that keep their own state
343 // store. Used by the adjoint's checkpoint/recompute driver, which restores
344 // from its own archive rather than from an .OPMRST file. Off unless set.
345 if (restoreStateHook_) {
346 restoreStateHook_(timer.currentStepNum());
347 }
348
349 this->solver_->model().beginReportStep();
350
351 const bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
352
353 // If sub stepping is enabled allow the solver to sub cycle
354 // in case the report steps are too large for the solver to converge
355 //
356 // \Note: The report steps are met in any case
357 // \Note: The sub stepping will require a copy of the state variables
358 if (adaptiveTimeStepping_) {
359 auto tuningUpdater = [enableTUNING, this,
360 reportStep = timer.currentStepNum()](const double curr_time,
361 double substep_length,
362 const int sub_step_number)
363 {
364 auto& schedule = this->simulator_.vanguard().schedule();
365 auto& events = this->schedule()[reportStep].events();
366
367 // The problem may cap the next time step (e.g. a geomechanical
368 // fracture model limiting steps while the fracture grows).
369 const double problem_max_next_tstep =
370 this->simulator_.problem().maxNextTimeStepSize();
371 const bool problem_caps =
372 problem_max_next_tstep < std::numeric_limits<double>::max();
373
374 bool result = problem_caps;
375 if (problem_caps) {
376 this->adaptiveTimeStepping_->updateNEXTSTEP(problem_max_next_tstep);
377 }
378 if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
379 // Unset the event to not trigger it again on the next sub step
380 schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
381 const auto& sched_state = schedule[reportStep];
382 double max_next_tstep = sched_state.max_next_tstep(enableTUNING);
383 // Both are upper bounds on the next step, so the effective cap is
384 // the smaller one. max_next_tstep() is -1 when the schedule sets
385 // no limit at all, and then the problem's limit stands alone.
386 if (problem_caps) {
387 max_next_tstep = (max_next_tstep > 0.0)
388 ? std::min(max_next_tstep, problem_max_next_tstep)
389 : problem_max_next_tstep;
390 }
391 const auto& tuning = sched_state.tuning();
392
393 if (enableTUNING) {
394 adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning);
395 // \Note: Assumes TUNING is only used with adaptive time-stepping
396 // \Note: Need to update both solver (model) and simulator since solver is re-created each report step.
397 solver_->model().updateTUNING(tuning);
398 this->updateTUNING(tuning);
399 substep_length = this->adaptiveTimeStepping_->suggestedNextStep();
400 } else {
401 substep_length = max_next_tstep;
402 this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
403 }
404 result = max_next_tstep > 0;
405 }
406
407 if (events.hasEvent(ScheduleEvents::TUNINGDP_CHANGE)) {
408 // Unset the event to not trigger it again on the next sub step
409 schedule.clear_event(ScheduleEvents::TUNINGDP_CHANGE, reportStep);
410
411 // Update TUNINGDP parameters
412 // NOTE: Need to update both solver (model) and simulator since solver is re-created each report
413 // step.
414 const auto& sched_state = schedule[reportStep];
415 const auto& tuning_dp = sched_state.tuning_dp();
416 solver_->model().updateTUNINGDP(tuning_dp);
417 this->updateTUNINGDP(tuning_dp);
418 }
419
420 const auto& wcycle = schedule[reportStep].wcycle.get();
421 if (wcycle.empty()) {
422 return result;
423 }
424
425 const auto& wmatcher = schedule.wellMatcher(reportStep);
426 double wcycle_time_step =
427 wcycle.nextTimeStep(curr_time,
428 substep_length,
429 wmatcher,
430 this->wellModel_().wellOpenTimes(),
431 this->wellModel_().wellCloseTimes(),
432 [sub_step_number,
433 &wg_events = this->wellModel_().reportStepStartEvents()]
434 (const std::string& name)
435 {
436 if (sub_step_number != 0) {
437 return false;
438 }
439 return wg_events.hasEvent(name, ScheduleEvents::REQUEST_OPEN_WELL);
440 });
441
442 wcycle_time_step = this->grid().comm().min(wcycle_time_step);
443 if (substep_length != wcycle_time_step) {
444 this->adaptiveTimeStepping_->updateNEXTSTEP(wcycle_time_step);
445 return true;
446 }
447
448 return result;
449 };
450
451 tuningUpdater(timer.simulationTimeElapsed(),
452 this->adaptiveTimeStepping_->suggestedNextStep(), 0);
453
454#ifdef RESERVOIR_COUPLING_ENABLED
455 if (this->reservoirCouplingMaster_) {
456 this->reservoirCouplingMaster_->maybeSpawnSlaveProcesses(timer.currentStepNum());
457 this->reservoirCouplingMaster_->maybeActivate(timer.currentStepNum());
458 }
459 else if (this->reservoirCouplingSlave_) {
460 this->reservoirCouplingSlave_->maybeActivate(timer.currentStepNum());
461 }
462#endif
463 const auto& events = schedule()[timer.currentStepNum()].events();
464 bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
465 events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
466 events.hasEvent(ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER) ||
467 events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE) ||
468 events.hasEvent(ScheduleEvents::INJECTION_UPDATE) ||
469 events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
470 auto stepReport = adaptiveTimeStepping_->step(timer, *solver_, event, tuningUpdater);
471 report_ += stepReport;
472#ifdef RESERVOIR_COUPLING_ENABLED
473 // If the master ended its schedule first (e.g. an END keyword truncates the master
474 // SCHEDULE), the slave received the terminate signal and disconnected its
475 // intercommunicator inside step() above. The coupled run is over for this slave:
476 // finish the current report step cleanly and stop the run loop instead of advancing
477 // to another report step, which would issue an MPI_Recv on the now-disconnected
478 // communicator and abort the job.
479 if (this->reservoirCouplingSlave_ && this->reservoirCouplingSlave_->terminated()) {
480 this->handleSlaveTerminated_();
481 return false; // breaks the while(!timer.done()) loop in run()
482 }
483#endif
484 } else {
485 // solve for complete report step
486 auto stepReport = solver_->step(timer, nullptr);
487 report_ += stepReport;
488 // Pass simulation report to eclwriter for summary output
489 simulator_.problem().setSubStepReport(stepReport);
490 simulator_.problem().setSimulationReport(report_);
491 simulator_.problem().endTimeStep();
492 if (terminalOutput_) {
493 std::ostringstream ss;
494 stepReport.reportStep(ss);
495 OpmLog::info(ss.str());
496 }
497 }
498
499 // write simulation state at the report stage
500 Dune::Timer perfTimer;
501 perfTimer.start();
502 const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
503 simulator_.problem().setNextTimeStepSize(nextstep);
504 simulator_.problem().writeOutput(true);
505 report_.success.output_write_time += perfTimer.stop();
506
507 solver_->model().endReportStep();
508
509 // take time that was used to solve system for this reportStep
510 solverTimer_->stop();
511
512 // update timing.
513 report_.success.solver_time += solverTimer_->secsSinceStart();
514
515 if (this->grid().comm().rank() == 0) {
516 // Grab the step convergence reports that are new since last we
517 // were here.
518 const auto& reps = this->solver_->model().stepReports();
519 convergence_output_.write(reps);
520 }
521
522 // Increment timer, remember well state.
523 ++timer;
524
525 if (terminalOutput_) {
526 std::string msg =
527 "Time step took " + std::to_string(solverTimer_->secsSinceStart()) + " seconds; "
528 "total solver time " + std::to_string(report_.success.solver_time) + " seconds.";
529 OpmLog::debug(msg);
530 }
531
532 serializer_.save(timer);
533
534 return true;
535}
536
537#ifdef RESERVOIR_COUPLING_ENABLED
538template<class TypeTag>
539void
542{
543 if (terminalOutput_) {
544 OpmLog::info("Reservoir coupling: master simulation has ended; "
545 "stopping slave simulation gracefully.");
546 }
547 // The slave stops as soon as it is terminated, so no further substeps run for this report
548 // step. Per-substep SUMMARY output for any substeps already completed in this report step
549 // was written by the adaptive substep loop; the report-step-level restart write is
550 // intentionally skipped because a terminated report step is partial - the last completed
551 // report step is the clean restart point. finalize() flushes the remaining output.
552 // Balance the beginReportStep() issued earlier in runStep().
553 this->solver_->model().endReportStep();
554 // Account for this report step's solver time and leave the timer stopped: runStep()'s own
555 // solverTimer_->stop()/accumulation below is bypassed by the early return on termination.
556 this->solverTimer_->stop();
557 this->report_.success.solver_time += this->solverTimer_->secsSinceStart();
558}
559#endif
560
561template<class TypeTag>
562SimulatorReport
564finalize()
565{
566 // make sure all output is written to disk before run is finished
567 {
568 Dune::Timer finalOutputTimer;
569 finalOutputTimer.start();
570
571 simulator_.problem().finalizeOutput();
572 report_.success.output_write_time += finalOutputTimer.stop();
573 }
574
575 // Stop timer and create timing report
576 totalTimer_->stop();
577 report_.success.total_time = totalTimer_->secsSinceStart();
578 report_.success.converged = true;
579
580 return report_;
581}
582
583template<class TypeTag>
584template<class Serializer>
585void
587serializeOp(Serializer& serializer)
588{
589 serializer(simulator_);
590 serializer(report_);
591 serializer(adaptiveTimeStepping_);
592}
593
594template<class TypeTag>
595void
597loadState([[maybe_unused]] HDF5Serializer& serializer,
598 [[maybe_unused]] const std::string& groupName)
599{
600#if HAVE_HDF5
601 serializer.read(*this, groupName, "simulator_data");
602#endif
603}
604
605template<class TypeTag>
606void
608saveState([[maybe_unused]] HDF5Serializer& serializer,
609 [[maybe_unused]] const std::string& groupName) const
610{
611#if HAVE_HDF5
612 serializer.write(*this, groupName, "simulator_data");
613#endif
614}
615
616template<class TypeTag>
617std::array<std::string,5>
619getHeader() const
620{
621 std::ostringstream str;
623 return {"OPM Flow",
626 simulator_.vanguard().caseName(),
627 str.str()};
628}
629
630template<class TypeTag>
631std::unique_ptr<typename SimulatorFullyImplicit<TypeTag>::Solver>
633createSolver(WellModel& wellModel)
634{
635 auto model = std::make_unique<Model>(simulator_,
636 modelParam_,
637 wellModel,
638 terminalOutput_);
639
640 if (this->modelParam_.write_partitions_) {
641 const auto& iocfg = this->eclState().cfg().io();
642
643 const auto odir = iocfg.getOutputDir()
644 / std::filesystem::path { "partition" }
645 / iocfg.getBaseName();
646
647 if (this->grid().comm().rank() == 0) {
648 create_directories(odir);
649 }
650
651 this->grid().comm().barrier();
652
653 model->writePartitions(odir);
654
655 this->modelParam_.write_partitions_ = false;
656 }
657
658 return std::make_unique<Solver>(solverParam_, std::move(model));
659}
660
661} // namespace Opm
662
663#endif // OPM_SIMULATOR_FULLY_IMPLICIT_IMPL_HEADER_INCLUDED
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:564
void init(const SimulatorTimer &timer)
One-shot setup performed before the first runStep.
Definition: SimulatorFullyImplicit_impl.hpp:211
void serializeOp(Serializer &serializer)
Definition: SimulatorFullyImplicit_impl.hpp:587
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:608
SimulatorReport run(SimulatorTimer &timer)
Run the entire simulation to completion.
Definition: SimulatorFullyImplicit_impl.hpp:110
SimulatorFullyImplicit(Simulator &simulator)
Construct from the surrounding eWoms Simulator.
Definition: SimulatorFullyImplicit_impl.hpp:47
std::unique_ptr< Solver > createSolver(WellModel &wellModel)
Build the Solver used during the current report step.
Definition: SimulatorFullyImplicit_impl.hpp:633
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:263
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:597
std::array< std::string, 5 > getHeader() const override
Definition: SimulatorFullyImplicit_impl.hpp:619
static void registerParameters()
Register all parameters consumed by this class and its major collaborators.
Definition: SimulatorFullyImplicit_impl.hpp:88
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:79
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:247
GetPropType< TypeTag, Properties::WellModel > WellModel
Definition: SimulatorFullyImplicit.hpp:141
bool runStep(SimulatorTimer &timer)
Advance the simulation by one report step.
Definition: SimulatorFullyImplicit_impl.hpp:286
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:125
SimulatorReportSingle success
Definition: SimulatorReport.hpp:126
double output_write_time
Definition: SimulatorReport.hpp:46
static void registerParameters()