121 : simulator_(simulator)
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);
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>();
228 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(
max_next_tstep,
239 adaptiveTimeStepping_->setSuggestedNextStep(simulator_.timeStepSize());
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)
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()) {
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_) {
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);
336 solver_->model().updateTUNING(
tuning);
337 this->updateTUNING(
tuning);
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);
356 simulator_.problem().setSimulationReport(report_);
361 if (terminalOutput_) {
362 std::ostringstream
ss;
364 OpmLog::info(
ss.str());
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()
420 simulator_.problem().finalizeOutput();
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>
443 const Model& model()
const
444 {
return solver_->model(); }
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();
495 / std::filesystem::path {
"partition" }
496 /
iocfg.getBaseName();
498 if (this->grid().comm().rank() == 0) {
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(); }
517 {
return simulator_.vanguard().schedule(); }
519 bool isRestart()
const
521 const auto&
initconfig = eclState().getInitConfig();
525 WellModel& wellModel_()
526 {
return simulator_.problem().wellModel(); }
528 const WellModel& wellModel_()
const
529 {
return simulator_.problem().wellModel(); }
534 const auto config = ConvergenceOutputConfiguration {
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(),
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>{};
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_;