145 using Simulator = GetPropType<TypeTag, Properties::Simulator>;
146 using Grid = GetPropType<TypeTag, Properties::Grid>;
147 using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
148 using ElementContext = GetPropType<TypeTag, Properties::ElementContext>;
149 using BlackoilIndices = GetPropType<TypeTag, Properties::Indices>;
150 using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
151 using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
152 using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
153 using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
154 using AquiferModel = GetPropType<TypeTag, Properties::AquiferModel>;
157 using PolymerModule = BlackOilPolymerModule<TypeTag>;
158 using MICPModule = BlackOilMICPModule<TypeTag>;
162 using ModelParameters =
typename Model::ModelParameters;
163 using SolverParameters =
typename Solver::SolverParameters;
188 : simulator_(simulator)
191 simulator_.vanguard().eclState().getIOConfig(),
192 Parameters::get<TypeTag, Properties::SaveStep>(),
193 Parameters::get<TypeTag, Properties::LoadStep>(),
194 Parameters::get<TypeTag, Properties::SaveFile>(),
195 Parameters::get<TypeTag, Properties::LoadFile>())
200 this->terminalOutput_ =
false;
201 if (this->grid().comm().rank() == 0) {
202 this->terminalOutput_ = Parameters::get<TypeTag, Properties::EnableTerminalOutput>();
204 this->startConvergenceOutputThread(Parameters::get<TypeTag, Properties::OutputExtraConvergenceInfo>(),
205 R
"(OutputExtraConvergenceInfo (--output-extra-convergence-info))");
212 this->endConvergenceOutputThread();
215 static void registerParameters()
217 ModelParameters::registerParameters();
218 SolverParameters::registerParameters();
219 TimeStepper::registerParameters();
221 Parameters::registerParam<TypeTag, Properties::EnableTerminalOutput>
222 (
"Print high-level information about the simulation's progress to the terminal");
223 Parameters::registerParam<TypeTag, Properties::EnableAdaptiveTimeStepping>
224 (
"Use adaptive time stepping between report steps");
225 Parameters::registerParam<TypeTag, Properties::OutputExtraConvergenceInfo>
226 (
"Provide additional convergence output "
227 "files for diagnostic purposes. "
228 "\"none\" gives no extra output and "
229 "overrides all other options, "
230 "\"steps\" generates an INFOSTEP file, "
231 "\"iterations\" generates an INFOITER file. "
232 "Combine options with commas, e.g., "
233 "\"steps,iterations\" for multiple outputs.");
234 Parameters::registerParam<TypeTag, Properties::SaveStep>
235 (
"Save serialized state to .OPMRST file. "
236 "Either a specific report step, \"all\" to save "
237 "all report steps or \":x\" to save every x'th step."
238 "Use negative values of \"x\" to keep only the last "
239 "written step, or \"last\" to save every step, keeping "
241 Parameters::registerParam<TypeTag, Properties::LoadStep>
242 (
"Load serialized state from .OPMRST file. "
243 "Either a specific report step, or 0 to load last "
244 "stored report step.");
245 Parameters::registerParam<TypeTag, Properties::SaveFile>
246 (
"FileName for .OPMRST file used for saving serialized state. "
247 "If empty, CASENAME.OPMRST is used.");
248 Parameters::hideParam<TypeTag, Properties::SaveFile>();
249 Parameters::registerParam<TypeTag, Properties::LoadFile>
250 (
"FileName for .OPMRST file used to load serialized state. "
251 "If empty, CASENAME.OPMRST is used.");
252 Parameters::hideParam<TypeTag, Properties::LoadFile>();
265 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
267 while (!timer.
done()) {
268 bool continue_looping = runStep(timer);
269 if (!continue_looping)
break;
276 simulator_.setEpisodeIndex(-1);
279 solverTimer_ = std::make_unique<time::StopWatch>();
280 totalTimer_ = std::make_unique<time::StopWatch>();
281 totalTimer_->start();
284 bool enableAdaptive = Parameters::get<TypeTag, Properties::EnableAdaptiveTimeStepping>();
285 bool enableTUNING = Parameters::get<TypeTag, Properties::EnableTuning>();
286 if (enableAdaptive) {
287 const UnitSystem& unitSystem = this->simulator_.vanguard().eclState().getUnits();
289 auto max_next_tstep = sched_state.max_next_tstep(enableTUNING);
291 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(max_next_tstep,
292 sched_state.tuning(),
293 unitSystem, terminalOutput_);
296 adaptiveTimeStepping_ = std::make_unique<TimeStepper>(unitSystem, max_next_tstep, terminalOutput_);
302 adaptiveTimeStepping_->setSuggestedNextStep(simulator_.timeStepSize());
307 void updateTUNING(
const Tuning& tuning)
309 modelParam_.tolerance_mb_ = tuning.XXXMBE;
310 if (terminalOutput_) {
311 OpmLog::debug(fmt::format(
"Setting SimulatorFullyImplicitBlackoil mass balance limit (XXXMBE) to {:.2e}", tuning.XXXMBE));
315 bool runStep(SimulatorTimer& timer)
317 if (schedule().exitStatus().has_value()) {
318 if (terminalOutput_) {
319 OpmLog::info(
"Stopping simulation since EXIT was triggered by an action keyword.");
321 report_.success.exit_status = schedule().exitStatus().value();
330 if (terminalOutput_) {
331 std::ostringstream ss;
333 OpmLog::debug(ss.str());
336 if (terminalOutput_) {
337 details::outputReportStep(timer);
341 if (timer.initialStep()) {
342 Dune::Timer perfTimer;
345 simulator_.setEpisodeIndex(-1);
346 simulator_.setEpisodeLength(0.0);
347 simulator_.setTimeStepSize(0.0);
348 wellModel_().beginReportStep(timer.currentStepNum());
349 simulator_.problem().writeOutput(timer);
351 report_.success.output_write_time += perfTimer.stop();
355 solverTimer_->start();
358 solver_ = createSolver(wellModel_());
361 simulator_.startNextEpisode(
362 simulator_.startTime()
363 + schedule().seconds(timer.currentStepNum()),
364 timer.currentStepLength());
365 simulator_.setEpisodeIndex(timer.currentStepNum());
367 wellModel_().prepareDeserialize(serializer_.
loadStep() - 1);
369 simulator_.model().invalidateAndUpdateIntensiveQuantities(0);
371 solver_->model().beginReportStep();
372 bool enableTUNING = Parameters::get<TypeTag, Properties::EnableTuning>();
379 if (adaptiveTimeStepping_) {
380 auto tuningUpdater = [enableTUNING,
this, reportStep = timer.currentStepNum()]()
382 auto& schedule = this->simulator_.vanguard().schedule();
383 auto& events = this->schedule()[reportStep].events();
385 if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
387 schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
388 const auto& sched_state = schedule[reportStep];
389 const auto& max_next_tstep = sched_state.max_next_tstep(enableTUNING);
390 const auto& tuning = sched_state.tuning();
393 adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning);
396 solver_->model().updateTUNING(tuning);
397 this->updateTUNING(tuning);
399 this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
401 return max_next_tstep >0;
406 const auto& events = schedule()[timer.currentStepNum()].events();
407 bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
408 events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
409 events.hasEvent(ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER) ||
410 events.hasEvent(ScheduleEvents::PRODUCTION_UPDATE) ||
411 events.hasEvent(ScheduleEvents::INJECTION_UPDATE) ||
412 events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
413 auto stepReport = adaptiveTimeStepping_->step(timer, *solver_, event,
nullptr, tuningUpdater);
414 report_ += stepReport;
416 simulator_.problem().setSimulationReport(report_);
419 auto stepReport = solver_->step(timer);
420 report_ += stepReport;
421 if (terminalOutput_) {
422 std::ostringstream ss;
423 stepReport.reportStep(ss);
424 OpmLog::info(ss.str());
429 Dune::Timer perfTimer;
431 const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
432 simulator_.problem().setNextTimeStepSize(nextstep);
433 simulator_.problem().writeOutput(timer);
434 report_.success.output_write_time += perfTimer.stop();
436 solver_->model().endReportStep();
439 solverTimer_->stop();
442 report_.success.solver_time += solverTimer_->secsSinceStart();
444 if (this->grid().comm().rank() == 0) {
446 const auto& reps = solver_->model().stepReports();
447 this->writeConvergenceOutput(std::vector<StepReport>{reps.begin() + already_reported_steps_, reps.end()});
448 already_reported_steps_ = reps.size();
454 if (terminalOutput_) {
456 "Time step took " + std::to_string(solverTimer_->secsSinceStart()) +
" seconds; "
457 "total solver time " + std::to_string(report_.success.solver_time) +
" seconds.";
461 serializer_.
save(timer);
466 SimulatorReport finalize()
470 Dune::Timer finalOutputTimer;
471 finalOutputTimer.start();
473 simulator_.problem().finalizeOutput();
474 report_.success.output_write_time += finalOutputTimer.stop();
479 report_.success.total_time = totalTimer_->secsSinceStart();
480 report_.success.converged =
true;
485 const Grid& grid()
const
486 {
return simulator_.vanguard().grid(); }
488 template<
class Serializer>
489 void serializeOp(Serializer& serializer)
491 serializer(simulator_);
493 serializer(adaptiveTimeStepping_);
496 const Model& model()
const
497 {
return solver_->model(); }
502 [[maybe_unused]]
const std::string& groupName)
override
505 serializer.read(*
this, groupName,
"simulator_data");
511 [[maybe_unused]]
const std::string& groupName)
const override
514 serializer.write(*
this, groupName,
"simulator_data");
521 std::ostringstream str;
522 Parameters::printValues<TypeTag>(str);
526 simulator_.vanguard().caseName(),
533 return simulator_.vanguard().globalCell();
537 std::unique_ptr<Solver> createSolver(WellModel& wellModel)
539 auto model = std::make_unique<Model>(simulator_,
544 if (this->modelParam_.write_partitions_) {
545 const auto& iocfg = this->eclState().cfg().io();
547 const auto odir = iocfg.getOutputDir()
548 / std::filesystem::path {
"partition" }
549 / iocfg.getBaseName();
551 if (this->grid().comm().rank() == 0) {
552 create_directories(odir);
555 this->grid().comm().barrier();
557 model->writePartitions(odir);
559 this->modelParam_.write_partitions_ =
false;
562 return std::make_unique<Solver>(solverParam_, std::move(model));
565 const EclipseState& eclState()
const
566 {
return simulator_.vanguard().eclState(); }
569 const Schedule& schedule()
const
570 {
return simulator_.vanguard().schedule(); }
572 bool isRestart()
const
574 const auto& initconfig = eclState().getInitConfig();
575 return initconfig.restartRequested();
578 WellModel& wellModel_()
579 {
return simulator_.problem().wellModel(); }
581 const WellModel& wellModel_()
const
582 {
return simulator_.problem().wellModel(); }
584 void startConvergenceOutputThread(std::string_view convOutputOptions,
585 std::string_view optionName)
587 const auto config = ConvergenceOutputConfiguration {
588 convOutputOptions, optionName
590 if (! config.want(ConvergenceOutputConfiguration::Option::Iterations)) {
595 [compNames =
typename Model::ComponentName{}](
const int compIdx)
596 {
return std::string_view { compNames.name(compIdx) }; }
600 [usys = this->eclState().getUnits()](
const double time)
601 {
return usys.from_si(UnitSystem::measure::time, time); }
604 this->convergenceOutputQueue_.emplace();
605 this->convergenceOutputObject_.emplace
606 (this->eclState().getIOConfig().getOutputDir(),
607 this->eclState().getIOConfig().getBaseName(),
608 std::move(getPhaseName),
609 std::move(convertTime),
610 config, *this->convergenceOutputQueue_);
612 this->convergenceOutputThread_
614 &this->convergenceOutputObject_.value());
617 void writeConvergenceOutput(std::vector<StepReport>&& reports)
619 if (! this->convergenceOutputThread_.has_value()) {
623 auto requests = std::vector<ConvergenceReportQueue::OutputRequest>{};
624 requests.reserve(reports.size());
626 for (
auto&& report : reports) {
627 requests.push_back({ report.report_step, report.current_step, std::move(report.report) });
630 this->convergenceOutputQueue_->enqueue(std::move(requests));
633 void endConvergenceOutputThread()
635 if (! this->convergenceOutputThread_.has_value()) {
639 this->convergenceOutputQueue_->signalLastOutputRequest();
640 this->convergenceOutputThread_->join();
644 Simulator& simulator_;
646 ModelParameters modelParam_;
647 SolverParameters solverParam_;
649 std::unique_ptr<Solver> solver_;
652 PhaseUsage phaseUsage_;
654 bool terminalOutput_;
656 SimulatorReport report_;
657 std::size_t already_reported_steps_ = 0;
658 std::unique_ptr<time::StopWatch> solverTimer_;
659 std::unique_ptr<time::StopWatch> totalTimer_;
660 std::unique_ptr<TimeStepper> adaptiveTimeStepping_;
662 std::optional<ConvergenceReportQueue> convergenceOutputQueue_{};
663 std::optional<ConvergenceOutputThread> convergenceOutputObject_{};
664 std::optional<std::thread> convergenceOutputThread_{};
666 SimulatorSerializer serializer_;