95 struct MPI_Comm_Deleter;
114 using ModelParameters =
typename Model::ModelParameters;
115 using SolverParameters =
typename Solver::SolverParameters;
121 : simulator_(simulator)
124 simulator_.vanguard().eclState().getIOConfig(),
125 Parameters::Get<Parameters::SaveStep>(),
126 Parameters::Get<Parameters::LoadStep>(),
127 Parameters::Get<Parameters::SaveFile>(),
128 Parameters::Get<Parameters::LoadFile>())
132 this->terminalOutput_ =
false;
133 if (this->grid().comm().rank() == 0) {
137 [compNames =
typename Model::ComponentName{}](
const int compIdx)
138 {
return std::string_view { compNames.name(compIdx) }; }
141 if (!simulator_.vanguard().eclState().getIOConfig().initOnly()) {
142 this->convergence_output_.
143 startThread(this->simulator_.vanguard().eclState(),
145 R
"(OutputExtraConvergenceInfo (--output-extra-convergence-info))",
157 static void registerParameters()
159 ModelParameters::registerParameters();
160 SolverParameters::registerParameters();
161 TimeStepper::registerParameters();
162 detail::registerSimulatorParameters();
171#ifdef RESERVOIR_COUPLING_ENABLED
172 SimulatorReport
run(SimulatorTimer& timer,
int argc,
char** argv)
174 init(timer, argc, argv);
183 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
185 while (!timer.
done()) {
186 simulator_.problem().writeReports(timer);
187 bool continue_looping = runStep(timer);
188 if (!continue_looping)
break;
190 simulator_.problem().writeReports(timer);
194#ifdef RESERVOIR_COUPLING_ENABLED
199 bool checkRunningAsReservoirCouplingMaster()
201 for (std::size_t report_step = 0; report_step < this->schedule().size(); ++report_step) {
202 auto rescoup = this->schedule()[report_step].rescoup();
203 auto slave_count = rescoup.slaveCount();
204 auto master_group_count = rescoup.masterGroupCount();
207 if (slave_count > 0 && master_group_count > 0) {
210 else if (slave_count > 0 && master_group_count == 0) {
211 throw ReservoirCouplingError(
212 "Inconsistent reservoir coupling master schedule: "
213 "Slave count is greater than 0 but master group count is 0"
216 else if (slave_count == 0 && master_group_count > 0) {
217 throw ReservoirCouplingError(
218 "Inconsistent reservoir coupling master schedule: "
219 "Master group count is greater than 0 but slave count is 0"
227#ifdef RESERVOIR_COUPLING_ENABLED
229 void init(
const SimulatorTimer& timer,
int argc,
char** argv)
231 auto slave_mode = Parameters::Get<Parameters::Slave>();
233 this->reservoirCouplingSlave_ =
234 std::make_unique<ReservoirCouplingSlave>(
236 this->schedule(), timer
238 this->reservoirCouplingSlave_->sendAndReceiveInitialData();
239 this->simulator_.setReservoirCouplingSlave(this->reservoirCouplingSlave_.get());
240 wellModel_().setReservoirCouplingSlave(this->reservoirCouplingSlave_.get());
243 auto master_mode = checkRunningAsReservoirCouplingMaster();
245 this->reservoirCouplingMaster_ =
246 std::make_unique<ReservoirCouplingMaster>(
251 this->simulator_.setReservoirCouplingMaster(this->reservoirCouplingMaster_.get());
252 wellModel_().setReservoirCouplingMaster(this->reservoirCouplingMaster_.get());
256 void init(
const SimulatorTimer& timer)
259 simulator_.setEpisodeIndex(-1);
262 solverTimer_ = std::make_unique<time::StopWatch>();
263 totalTimer_ = std::make_unique<time::StopWatch>();
264 totalTimer_->start();
267 bool enableAdaptive = Parameters::Get<Parameters::EnableAdaptiveTimeStepping>();
268 bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
269 if (enableAdaptive) {
270 const UnitSystem& unitSystem = this->simulator_.vanguard().eclState().getUnits();
271 const auto& sched_state = schedule()[timer.currentStepNum()];
272 auto max_next_tstep = sched_state.max_next_tstep(enableTUNING);
274 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(max_next_tstep,
275 sched_state.tuning(),
276 unitSystem, report_, terminalOutput_);
279 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(unitSystem, report_, max_next_tstep, terminalOutput_);
284 adaptiveTimeStepping_->setSuggestedNextStep(simulator_.timeStepSize());
289 void updateTUNING(
const Tuning& tuning)
291 modelParam_.tolerance_cnv_ = tuning.TRGCNV;
292 modelParam_.tolerance_cnv_relaxed_ = tuning.XXXCNV;
293 modelParam_.tolerance_mb_ = tuning.TRGMBE;
294 modelParam_.tolerance_mb_relaxed_ = tuning.XXXMBE;
295 modelParam_.newton_max_iter_ = tuning.NEWTMX;
296 modelParam_.newton_min_iter_ = tuning.NEWTMN;
297 if (terminalOutput_) {
298 const auto msg = fmt::format(
"Tuning values: "
299 "MB: {:.2e}, CNV: {:.2e}, NEWTMN: {}, NEWTMX: {}",
300 tuning.TRGMBE, tuning.TRGCNV, tuning.NEWTMN, tuning.NEWTMX);
302 if (tuning.TRGTTE_has_value) {
303 OpmLog::warning(
"Tuning item 2-1 (TRGTTE) is not supported.");
305 if (tuning.TRGLCV_has_value) {
306 OpmLog::warning(
"Tuning item 2-4 (TRGLCV) is not supported.");
308 if (tuning.XXXTTE_has_value) {
309 OpmLog::warning(
"Tuning item 2-5 (XXXTTE) is not supported.");
311 if (tuning.XXXLCV_has_value) {
312 OpmLog::warning(
"Tuning item 2-8 (XXXLCV) is not supported.");
314 if (tuning.XXXWFL_has_value) {
315 OpmLog::warning(
"Tuning item 2-9 (XXXWFL) is not supported.");
317 if (tuning.TRGFIP_has_value) {
318 OpmLog::warning(
"Tuning item 2-10 (TRGFIP) is not supported.");
320 if (tuning.TRGSFT_has_value) {
321 OpmLog::warning(
"Tuning item 2-11 (TRGSFT) is not supported.");
323 if (tuning.THIONX_has_value) {
324 OpmLog::warning(
"Tuning item 2-12 (THIONX) is not supported.");
326 if (tuning.TRWGHT_has_value) {
327 OpmLog::warning(
"Tuning item 2-13 (TRWGHT) is not supported.");
329 if (tuning.LITMAX_has_value) {
330 OpmLog::warning(
"Tuning item 3-3 (LITMAX) is not supported.");
332 if (tuning.LITMIN_has_value) {
333 OpmLog::warning(
"Tuning item 3-4 (LITMIN) is not supported.");
335 if (tuning.MXWSIT_has_value) {
336 OpmLog::warning(
"Tuning item 3-5 (MXWSIT) is not supported.");
338 if (tuning.MXWPIT_has_value) {
339 OpmLog::warning(
"Tuning item 3-6 (MXWPIT) is not supported.");
341 if (tuning.DDPLIM_has_value) {
342 OpmLog::warning(
"Tuning item 3-7 (DDPLIM) is not supported.");
344 if (tuning.DDSLIM_has_value) {
345 OpmLog::warning(
"Tuning item 3-8 (DDSLIM) is not supported.");
347 if (tuning.TRGDPR_has_value) {
348 OpmLog::warning(
"Tuning item 3-9 (TRGDPR) is not supported.");
350 if (tuning.XXXDPR_has_value) {
351 OpmLog::warning(
"Tuning item 3-10 (XXXDPR) is not supported.");
353 if (tuning.MNWRFP_has_value) {
354 OpmLog::warning(
"Tuning item 3-11 (MNWRFP) is not supported.");
359 bool runStep(SimulatorTimer& timer)
361 if (schedule().exitStatus().has_value()) {
362 if (terminalOutput_) {
363 OpmLog::info(
"Stopping simulation since EXIT was triggered by an action keyword.");
365 report_.success.exit_status = schedule().exitStatus().value();
369 if (serializer_.shouldLoad()) {
370 serializer_.loadTimerInfo(timer);
374 if (terminalOutput_) {
375 std::ostringstream ss;
377 OpmLog::debug(ss.str());
378 details::outputReportStep(timer);
382 if (timer.initialStep()) {
383 Dune::Timer perfTimer;
386 simulator_.setEpisodeIndex(-1);
387 simulator_.setEpisodeLength(0.0);
388 simulator_.setTimeStepSize(0.0);
389 wellModel_().beginReportStep(timer.currentStepNum());
390 simulator_.problem().writeOutput(
true);
392 report_.success.output_write_time += perfTimer.stop();
396 solverTimer_->start();
399 solver_ = createSolver(wellModel_());
402 simulator_.startNextEpisode(
403 simulator_.startTime()
404 + schedule().seconds(timer.currentStepNum()),
405 timer.currentStepLength());
406 simulator_.setEpisodeIndex(timer.currentStepNum());
408 if (serializer_.shouldLoad()) {
409 wellModel_().prepareDeserialize(serializer_.loadStep() - 1);
410 serializer_.loadState();
411 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
414 this->solver_->model().beginReportStep();
416 const bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
423 if (adaptiveTimeStepping_) {
424 auto tuningUpdater = [enableTUNING,
this,
425 reportStep = timer.currentStepNum()](
const double curr_time,
426 double dt,
const int timeStep)
428 auto& schedule = this->simulator_.vanguard().schedule();
429 auto& events = this->schedule()[reportStep].events();
432 if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
434 schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
435 const auto& sched_state = schedule[reportStep];
436 const auto& max_next_tstep = sched_state.max_next_tstep(enableTUNING);
437 const auto& tuning = sched_state.tuning();
440 adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning);
443 solver_->model().updateTUNING(tuning);
444 this->updateTUNING(tuning);
445 dt = this->adaptiveTimeStepping_->suggestedNextStep();
448 this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
450 result = max_next_tstep > 0;
453 const auto& wcycle = schedule[reportStep].wcycle.get();
454 if (wcycle.empty()) {
458 const auto& wmatcher = schedule.wellMatcher(reportStep);
459 double wcycle_time_step =
460 wcycle.nextTimeStep(curr_time,
463 this->wellModel_().wellOpenTimes(),
464 this->wellModel_().wellCloseTimes(),
466 &wg_events = this->wellModel_().reportStepStartEvents()]
467 (
const std::string& name)
472 return wg_events.hasEvent(name, ScheduleEvents::REQUEST_OPEN_WELL);
475 wcycle_time_step = this->grid().comm().min(wcycle_time_step);
476 if (dt != wcycle_time_step) {
477 this->adaptiveTimeStepping_->updateNEXTSTEP(wcycle_time_step);
484 tuningUpdater(timer.simulationTimeElapsed(),
485 this->adaptiveTimeStepping_->suggestedNextStep(), 0);
487#ifdef RESERVOIR_COUPLING_ENABLED
488 if (this->reservoirCouplingMaster_) {
489 this->reservoirCouplingMaster_->maybeSpawnSlaveProcesses(timer.currentStepNum());
490 this->reservoirCouplingMaster_->maybeActivate(timer.currentStepNum());
492 else if (this->reservoirCouplingSlave_) {
493 this->reservoirCouplingSlave_->maybeActivate(timer.currentStepNum());
496 const auto& events = schedule()[timer.currentStepNum()].events();
497 bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
498 events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
499 events.hasEvent(ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER) ||
500 events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE) ||
501 events.hasEvent(ScheduleEvents::INJECTION_UPDATE) ||
502 events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
503 auto stepReport = adaptiveTimeStepping_->step(timer, *solver_, event, tuningUpdater);
504 report_ += stepReport;
506 simulator_.problem().setSimulationReport(report_);
509 auto stepReport = solver_->step(timer,
nullptr);
510 report_ += stepReport;
511 if (terminalOutput_) {
512 std::ostringstream ss;
513 stepReport.reportStep(ss);
514 OpmLog::info(ss.str());
519 Dune::Timer perfTimer;
521 const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
522 simulator_.problem().setNextTimeStepSize(nextstep);
523 simulator_.problem().writeOutput(
true);
524 report_.success.output_write_time += perfTimer.stop();
526 solver_->model().endReportStep();
529 solverTimer_->stop();
532 report_.success.solver_time += solverTimer_->secsSinceStart();
534 if (this->grid().comm().rank() == 0) {
537 const auto& reps = this->solver_->model().stepReports();
538 convergence_output_.write(reps);
544 if (terminalOutput_) {
546 "Time step took " + std::to_string(solverTimer_->secsSinceStart()) +
" seconds; "
547 "total solver time " + std::to_string(report_.success.solver_time) +
" seconds.";
551 serializer_.save(timer);
556 SimulatorReport finalize()
560 Dune::Timer finalOutputTimer;
561 finalOutputTimer.start();
563 simulator_.problem().finalizeOutput();
564 report_.success.output_write_time += finalOutputTimer.stop();
569 report_.success.total_time = totalTimer_->secsSinceStart();
570 report_.success.converged =
true;
575 const Grid& grid()
const
576 {
return simulator_.vanguard().grid(); }
578 template<
class Serializer>
579 void serializeOp(Serializer& serializer)
581 serializer(simulator_);
583 serializer(adaptiveTimeStepping_);
586 const Model& model()
const
587 {
return solver_->model(); }
592 [[maybe_unused]]
const std::string& groupName)
override
595 serializer.read(*
this, groupName,
"simulator_data");
601 [[maybe_unused]]
const std::string& groupName)
const override
604 serializer.write(*
this, groupName,
"simulator_data");
611 std::ostringstream str;
616 simulator_.vanguard().caseName(),
623 return simulator_.vanguard().globalCell();
626 std::unique_ptr<Solver> createSolver(WellModel& wellModel)
628 auto model = std::make_unique<Model>(simulator_,
633 if (this->modelParam_.write_partitions_) {
634 const auto& iocfg = this->eclState().cfg().io();
636 const auto odir = iocfg.getOutputDir()
637 / std::filesystem::path {
"partition" }
638 / iocfg.getBaseName();
640 if (this->grid().comm().rank() == 0) {
641 create_directories(odir);
644 this->grid().comm().barrier();
646 model->writePartitions(odir);
648 this->modelParam_.write_partitions_ =
false;
651 return std::make_unique<Solver>(solverParam_, std::move(model));
654 const EclipseState& eclState()
const
655 {
return simulator_.vanguard().eclState(); }
658 const Schedule& schedule()
const
659 {
return simulator_.vanguard().schedule(); }
661 bool isRestart()
const
663 const auto& initconfig = eclState().getInitConfig();
664 return initconfig.restartRequested();
667 WellModel& wellModel_()
668 {
return simulator_.problem().wellModel(); }
670 const WellModel& wellModel_()
const
671 {
return simulator_.problem().wellModel(); }
674 Simulator& simulator_;
676 ModelParameters modelParam_;
677 SolverParameters solverParam_;
679 std::unique_ptr<Solver> solver_;
683 bool terminalOutput_;
685 SimulatorReport report_;
686 std::unique_ptr<time::StopWatch> solverTimer_;
687 std::unique_ptr<time::StopWatch> totalTimer_;
688 std::unique_ptr<TimeStepper> adaptiveTimeStepping_;
690 SimulatorConvergenceOutput convergence_output_{};
692#ifdef RESERVOIR_COUPLING_ENABLED
693 bool slaveMode_{
false};
694 std::unique_ptr<ReservoirCouplingMaster> reservoirCouplingMaster_{
nullptr};
695 std::unique_ptr<ReservoirCouplingSlave> reservoirCouplingSlave_{
nullptr};
698 SimulatorSerializer serializer_;