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>())
133 this->terminalOutput_ =
false;
134 if (this->grid().comm().rank() == 0) {
135 this->terminalOutput_ = Parameters::Get<Parameters::EnableTerminalOutput>();
137 this->startConvergenceOutputThread(Parameters::Get<Parameters::OutputExtraConvergenceInfo>(),
138 R
"(OutputExtraConvergenceInfo (--output-extra-convergence-info))");
145 this->endConvergenceOutputThread();
148 static void registerParameters()
150 ModelParameters::registerParameters();
151 SolverParameters::registerParameters();
152 TimeStepper::registerParameters();
154 Parameters::Register<Parameters::EnableTerminalOutput>
155 (
"Print high-level information about the simulation's progress to the terminal");
156 Parameters::Register<Parameters::EnableAdaptiveTimeStepping>
157 (
"Use adaptive time stepping between report steps");
158 Parameters::Register<Parameters::OutputExtraConvergenceInfo>
159 (
"Provide additional convergence output "
160 "files for diagnostic purposes. "
161 "\"none\" gives no extra output and "
162 "overrides all other options, "
163 "\"steps\" generates an INFOSTEP file, "
164 "\"iterations\" generates an INFOITER file. "
165 "Combine options with commas, e.g., "
166 "\"steps,iterations\" for multiple outputs.");
167 Parameters::Register<Parameters::SaveStep>
168 (
"Save serialized state to .OPMRST file. "
169 "Either a specific report step, \"all\" to save "
170 "all report steps or \":x\" to save every x'th step."
171 "Use negative values of \"x\" to keep only the last "
172 "written step, or \"last\" to save every step, keeping "
174 Parameters::Register<Parameters::LoadStep>
175 (
"Load serialized state from .OPMRST file. "
176 "Either a specific report step, or 0 to load last "
177 "stored report step.");
178 Parameters::Register<Parameters::SaveFile>
179 (
"FileName for .OPMRST file used for saving serialized state. "
180 "If empty, CASENAME.OPMRST is used.");
181 Parameters::Hide<Parameters::SaveFile>();
182 Parameters::Register<Parameters::LoadFile>
183 (
"FileName for .OPMRST file used to load serialized state. "
184 "If empty, CASENAME.OPMRST is used.");
185 Parameters::Hide<Parameters::LoadFile>();
200 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
202 while (!timer.
done()) {
203 simulator_.problem().writeReports(timer);
204 bool continue_looping = runStep(timer);
205 if (!continue_looping)
break;
207 simulator_.problem().writeReports(timer);
213 simulator_.setEpisodeIndex(-1);
216 solverTimer_ = std::make_unique<time::StopWatch>();
217 totalTimer_ = std::make_unique<time::StopWatch>();
218 totalTimer_->start();
221 bool enableAdaptive = Parameters::Get<Parameters::EnableAdaptiveTimeStepping>();
222 bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
223 if (enableAdaptive) {
224 const UnitSystem& unitSystem = this->simulator_.vanguard().eclState().getUnits();
226 auto max_next_tstep = sched_state.max_next_tstep(enableTUNING);
228 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(max_next_tstep,
229 sched_state.tuning(),
230 unitSystem, terminalOutput_);
233 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(unitSystem, max_next_tstep, terminalOutput_);
239 adaptiveTimeStepping_->setSuggestedNextStep(simulator_.timeStepSize());
244 void updateTUNING(
const Tuning& tuning)
246 modelParam_.tolerance_mb_ = tuning.XXXMBE;
247 if (terminalOutput_) {
248 OpmLog::debug(fmt::format(
"Setting SimulatorFullyImplicitBlackoil mass balance limit (XXXMBE) to {:.2e}", tuning.XXXMBE));
252 bool runStep(SimulatorTimer& timer)
254 if (schedule().exitStatus().has_value()) {
255 if (terminalOutput_) {
256 OpmLog::info(
"Stopping simulation since EXIT was triggered by an action keyword.");
258 report_.success.exit_status = schedule().exitStatus().value();
267 if (terminalOutput_) {
268 std::ostringstream ss;
270 OpmLog::debug(ss.str());
273 if (terminalOutput_) {
274 details::outputReportStep(timer);
278 if (timer.initialStep()) {
279 Dune::Timer perfTimer;
282 simulator_.setEpisodeIndex(-1);
283 simulator_.setEpisodeLength(0.0);
284 simulator_.setTimeStepSize(0.0);
285 wellModel_().beginReportStep(timer.currentStepNum());
286 simulator_.problem().writeOutput();
288 report_.success.output_write_time += perfTimer.stop();
292 solverTimer_->start();
295 solver_ = createSolver(wellModel_());
298 simulator_.startNextEpisode(
299 simulator_.startTime()
300 + schedule().seconds(timer.currentStepNum()),
301 timer.currentStepLength());
302 simulator_.setEpisodeIndex(timer.currentStepNum());
305 wellModel_().prepareDeserialize(serializer_.
loadStep() - 1);
307 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
310 this->solver_->model().beginReportStep();
312 const bool enableTUNING = Parameters::Get<Parameters::EnableTuning>();
319 if (adaptiveTimeStepping_) {
320 auto tuningUpdater = [enableTUNING,
this, reportStep = timer.currentStepNum()]()
322 auto& schedule = this->simulator_.vanguard().schedule();
323 auto& events = this->schedule()[reportStep].events();
325 if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
327 schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
328 const auto& sched_state = schedule[reportStep];
329 const auto& max_next_tstep = sched_state.max_next_tstep(enableTUNING);
330 const auto& tuning = sched_state.tuning();
333 adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning);
336 solver_->model().updateTUNING(tuning);
337 this->updateTUNING(tuning);
339 this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
341 return max_next_tstep >0;
346 const auto& events = schedule()[timer.currentStepNum()].events();
347 bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
348 events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
349 events.hasEvent(ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER) ||
350 events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE) ||
351 events.hasEvent(ScheduleEvents::INJECTION_UPDATE) ||
352 events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
353 auto stepReport = adaptiveTimeStepping_->step(timer, *solver_, event,
nullptr, tuningUpdater);
354 report_ += stepReport;
356 simulator_.problem().setSimulationReport(report_);
359 auto stepReport = solver_->step(timer);
360 report_ += stepReport;
361 if (terminalOutput_) {
362 std::ostringstream ss;
363 stepReport.reportStep(ss);
364 OpmLog::info(ss.str());
369 Dune::Timer perfTimer;
371 const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
372 simulator_.problem().setNextTimeStepSize(nextstep);
373 simulator_.problem().writeOutput();
374 report_.success.output_write_time += perfTimer.stop();
376 solver_->model().endReportStep();
379 solverTimer_->stop();
382 report_.success.solver_time += solverTimer_->secsSinceStart();
384 if (this->grid().comm().rank() == 0) {
387 const auto& reps = this->solver_->model().stepReports();
389 auto reports = std::vector<StepReport> {
390 reps.begin() + this->already_reported_steps_, reps.end()
393 this->writeConvergenceOutput(std::move(reports));
395 this->already_reported_steps_ = reps.size();
401 if (terminalOutput_) {
403 "Time step took " + std::to_string(solverTimer_->secsSinceStart()) +
" seconds; "
404 "total solver time " + std::to_string(report_.success.solver_time) +
" seconds.";
408 serializer_.
save(timer);
413 SimulatorReport finalize()
417 Dune::Timer finalOutputTimer;
418 finalOutputTimer.start();
420 simulator_.problem().finalizeOutput();
421 report_.success.output_write_time += finalOutputTimer.stop();
426 report_.success.total_time = totalTimer_->secsSinceStart();
427 report_.success.converged =
true;
432 const Grid& grid()
const
433 {
return simulator_.vanguard().grid(); }
435 template<
class Serializer>
436 void serializeOp(Serializer& serializer)
438 serializer(simulator_);
440 serializer(adaptiveTimeStepping_);
443 const Model& model()
const
444 {
return solver_->model(); }
449 [[maybe_unused]]
const std::string& groupName)
override
452 serializer.read(*
this, groupName,
"simulator_data");
458 [[maybe_unused]]
const std::string& groupName)
const override
461 serializer.write(*
this, groupName,
"simulator_data");
468 std::ostringstream str;
469 Parameters::printValues(str);
473 simulator_.vanguard().caseName(),
480 return simulator_.vanguard().globalCell();
484 std::unique_ptr<Solver> createSolver(WellModel& wellModel)
486 auto model = std::make_unique<Model>(simulator_,
491 if (this->modelParam_.write_partitions_) {
492 const auto& iocfg = this->eclState().cfg().io();
494 const auto odir = iocfg.getOutputDir()
495 / std::filesystem::path {
"partition" }
496 / iocfg.getBaseName();
498 if (this->grid().comm().rank() == 0) {
499 create_directories(odir);
502 this->grid().comm().barrier();
504 model->writePartitions(odir);
506 this->modelParam_.write_partitions_ =
false;
509 return std::make_unique<Solver>(solverParam_, std::move(model));
512 const EclipseState& eclState()
const
513 {
return simulator_.vanguard().eclState(); }
516 const Schedule& schedule()
const
517 {
return simulator_.vanguard().schedule(); }
519 bool isRestart()
const
521 const auto& initconfig = eclState().getInitConfig();
522 return initconfig.restartRequested();
525 WellModel& wellModel_()
526 {
return simulator_.problem().wellModel(); }
528 const WellModel& wellModel_()
const
529 {
return simulator_.problem().wellModel(); }
531 void startConvergenceOutputThread(std::string_view convOutputOptions,
532 std::string_view optionName)
534 const auto config = ConvergenceOutputConfiguration {
535 convOutputOptions, optionName
537 if (! config.want(ConvergenceOutputConfiguration::Option::Iterations)) {
542 [compNames =
typename Model::ComponentName{}](
const int compIdx)
543 {
return std::string_view { compNames.name(compIdx) }; }
547 [usys = this->eclState().getUnits()](
const double time)
548 {
return usys.from_si(UnitSystem::measure::time, time); }
551 this->convergenceOutputQueue_.emplace();
552 this->convergenceOutputObject_.emplace
553 (this->eclState().getIOConfig().getOutputDir(),
554 this->eclState().getIOConfig().getBaseName(),
555 std::move(getPhaseName),
556 std::move(convertTime),
557 config, *this->convergenceOutputQueue_);
559 this->convergenceOutputThread_
561 &this->convergenceOutputObject_.value());
564 void writeConvergenceOutput(std::vector<StepReport>&& reports)
566 if (! this->convergenceOutputThread_.has_value()) {
570 auto requests = std::vector<ConvergenceReportQueue::OutputRequest>{};
571 requests.reserve(reports.size());
573 for (
auto&& report : reports) {
574 requests.push_back({ report.report_step, report.current_step, std::move(report.report) });
577 this->convergenceOutputQueue_->enqueue(std::move(requests));
580 void endConvergenceOutputThread()
582 if (! this->convergenceOutputThread_.has_value()) {
586 this->convergenceOutputQueue_->signalLastOutputRequest();
587 this->convergenceOutputThread_->join();
591 Simulator& simulator_;
593 ModelParameters modelParam_;
594 SolverParameters solverParam_;
596 std::unique_ptr<Solver> solver_;
599 PhaseUsage phaseUsage_;
601 bool terminalOutput_;
603 SimulatorReport report_;
604 std::size_t already_reported_steps_ = 0;
605 std::unique_ptr<time::StopWatch> solverTimer_;
606 std::unique_ptr<time::StopWatch> totalTimer_;
607 std::unique_ptr<TimeStepper> adaptiveTimeStepping_;
609 std::optional<ConvergenceReportQueue> convergenceOutputQueue_{};
610 std::optional<ConvergenceOutputThread> convergenceOutputObject_{};
611 std::optional<std::thread> convergenceOutputThread_{};
613 SimulatorSerializer serializer_;