My Project
SimulatorFullyImplicitBlackoilEbos.hpp
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_SIMULATORFULLYIMPLICITBLACKOILEBOS_HEADER_INCLUDED
23 #define OPM_SIMULATORFULLYIMPLICITBLACKOILEBOS_HEADER_INCLUDED
24 
25 #include <opm/simulators/flow/NonlinearSolverEbos.hpp>
26 #include <opm/simulators/flow/BlackoilModelEbos.hpp>
27 #include <opm/simulators/flow/BlackoilModelParametersEbos.hpp>
28 #include <opm/simulators/wells/WellState.hpp>
29 #include <opm/simulators/aquifers/BlackoilAquiferModel.hpp>
30 #include <opm/simulators/utils/moduleVersion.hpp>
31 #include <opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp>
32 #include <opm/grid/utility/StopWatch.hpp>
33 
34 #include <opm/common/ErrorMacros.hpp>
35 
36 namespace Opm::Properties {
37 
38 template<class TypeTag, class MyTypeTag>
40  using type = UndefinedProperty;
41 };
42 template<class TypeTag, class MyTypeTag>
43 struct EnableTuning {
44  using type = UndefinedProperty;
45 };
46 
47 template<class TypeTag>
48 struct EnableTerminalOutput<TypeTag, TTag::EclFlowProblem> {
49  static constexpr bool value = true;
50 };
51 template<class TypeTag>
52 struct EnableAdaptiveTimeStepping<TypeTag, TTag::EclFlowProblem> {
53  static constexpr bool value = true;
54 };
55 template<class TypeTag>
56 struct EnableTuning<TypeTag, TTag::EclFlowProblem> {
57  static constexpr bool value = false;
58 };
59 
60 } // namespace Opm::Properties
61 
62 namespace Opm {
63 
64 void outputReportStep(const SimulatorTimer& timer);
65 void outputTimestampFIP(const SimulatorTimer& timer,
66  const std::string& title,
67  const std::string& version);
68 
70 template<class TypeTag>
72 {
73 public:
74  using Simulator = GetPropType<TypeTag, Properties::Simulator>;
75  using Grid = GetPropType<TypeTag, Properties::Grid>;
76  using FluidSystem = GetPropType<TypeTag, Properties::FluidSystem>;
77  using ElementContext = GetPropType<TypeTag, Properties::ElementContext>;
78  using BlackoilIndices = GetPropType<TypeTag, Properties::Indices>;
79  using PrimaryVariables = GetPropType<TypeTag, Properties::PrimaryVariables>;
80  using MaterialLaw = GetPropType<TypeTag, Properties::MaterialLaw>;
81  using SolutionVector = GetPropType<TypeTag, Properties::SolutionVector>;
82  using MaterialLawParams = GetPropType<TypeTag, Properties::MaterialLawParams>;
83  using AquiferModel = GetPropType<TypeTag, Properties::EclAquiferModel>;
84 
86  typedef BlackOilPolymerModule<TypeTag> PolymerModule;
87  typedef BlackOilMICPModule<TypeTag> MICPModule;
88 
91  typedef typename Model::ModelParameters ModelParameters;
94 
95 
117  SimulatorFullyImplicitBlackoilEbos(Simulator& ebosSimulator)
118  : ebosSimulator_(ebosSimulator)
119  {
120  phaseUsage_ = phaseUsageFromDeck(eclState());
121 
122  // Only rank 0 does print to std::cout
123  const auto& comm = grid().comm();
124  terminalOutput_ = EWOMS_GET_PARAM(TypeTag, bool, EnableTerminalOutput);
125  terminalOutput_ = terminalOutput_ && (comm.rank() == 0);
126  }
127 
128  static void registerParameters()
129  {
130  ModelParameters::registerParameters();
131  SolverParameters::registerParameters();
132  TimeStepper::registerParameters();
133 
134  EWOMS_REGISTER_PARAM(TypeTag, bool, EnableTerminalOutput,
135  "Print high-level information about the simulation's progress to the terminal");
136  EWOMS_REGISTER_PARAM(TypeTag, bool, EnableAdaptiveTimeStepping,
137  "Use adaptive time stepping between report steps");
138  EWOMS_REGISTER_PARAM(TypeTag, bool, EnableTuning,
139  "Honor some aspects of the TUNING keyword.");
140  }
141 
149  {
150  init(timer);
151  // Make cache up to date. No need for updating it in elementCtx.
152  ebosSimulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
153  // Main simulation loop.
154  while (!timer.done()) {
155  bool continue_looping = runStep(timer);
156  if (!continue_looping) break;
157  }
158  return finalize();
159  }
160 
161  void init(SimulatorTimer &timer)
162  {
163  ebosSimulator_.setEpisodeIndex(-1);
164 
165  // Create timers and file for writing timing info.
166  solverTimer_ = std::make_unique<time::StopWatch>();
167  totalTimer_ = std::make_unique<time::StopWatch>();
168  totalTimer_->start();
169 
170  // adaptive time stepping
171  bool enableAdaptive = EWOMS_GET_PARAM(TypeTag, bool, EnableAdaptiveTimeStepping);
172  bool enableTUNING = EWOMS_GET_PARAM(TypeTag, bool, EnableTuning);
173  if (enableAdaptive) {
174  const UnitSystem& unitSystem = this->ebosSimulator_.vanguard().eclState().getUnits();
175  if (enableTUNING) {
176  const auto& sched_state = schedule()[timer.currentStepNum()];
177  auto max_next_tstep = sched_state.max_next_tstep();
178  adaptiveTimeStepping_ = std::make_unique<TimeStepper>(max_next_tstep,
179  sched_state.tuning(),
180  unitSystem, terminalOutput_);
181  }
182  else {
183  adaptiveTimeStepping_ = std::make_unique<TimeStepper>(unitSystem, terminalOutput_);
184  }
185 
186  if (isRestart()) {
187  // For restarts the ebosSimulator may have gotten some information
188  // about the next timestep size from the OPMEXTRA field
189  adaptiveTimeStepping_->setSuggestedNextStep(ebosSimulator_.timeStepSize());
190  }
191  }
192  }
193 
194  bool runStep(SimulatorTimer& timer)
195  {
196  if (schedule().exitStatus().has_value()) {
197  if (terminalOutput_) {
198  OpmLog::info("Stopping simulation since EXIT was triggered by an action keyword.");
199  }
200  report_.success.exit_status = schedule().exitStatus().value();
201  return false;
202  }
203 
204  // Report timestep.
205  if (terminalOutput_) {
206  std::ostringstream ss;
207  timer.report(ss);
208  OpmLog::debug(ss.str());
209  }
210 
211  if (terminalOutput_) {
212  outputReportStep(timer);
213  }
214 
215  // write the inital state at the report stage
216  if (timer.initialStep()) {
217  Dune::Timer perfTimer;
218  perfTimer.start();
219 
220  ebosSimulator_.setEpisodeIndex(-1);
221  ebosSimulator_.setEpisodeLength(0.0);
222  ebosSimulator_.setTimeStepSize(0.0);
223  wellModel_().beginReportStep(timer.currentStepNum());
224  ebosSimulator_.problem().writeOutput();
225 
226  report_.success.output_write_time += perfTimer.stop();
227  }
228 
229  // Run a multiple steps of the solver depending on the time step control.
230  solverTimer_->start();
231 
232  auto solver = createSolver(wellModel_());
233 
234  ebosSimulator_.startNextEpisode(
235  ebosSimulator_.startTime()
236  + schedule().seconds(timer.currentStepNum()),
237  timer.currentStepLength());
238  ebosSimulator_.setEpisodeIndex(timer.currentStepNum());
239  solver->model().beginReportStep();
240  bool enableTUNING = EWOMS_GET_PARAM(TypeTag, bool, EnableTuning);
241 
242  // If sub stepping is enabled allow the solver to sub cycle
243  // in case the report steps are too large for the solver to converge
244  //
245  // \Note: The report steps are met in any case
246  // \Note: The sub stepping will require a copy of the state variables
247  if (adaptiveTimeStepping_) {
248  const auto& events = schedule()[timer.currentStepNum()].events();
249  if (enableTUNING) {
250  if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
251  const auto& sched_state = schedule()[timer.currentStepNum()];
252  const auto& tuning = sched_state.tuning();
253  const auto& max_next_tstep = sched_state.max_next_tstep();
254  adaptiveTimeStepping_->updateTUNING(max_next_tstep, tuning);
255  }
256  }
257  bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
258  events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
259  events.hasEvent(ScheduleEvents::WELL_SWITCHED_INJECTOR_PRODUCER) ||
260  events.hasEvent(ScheduleEvents::WELL_STATUS_CHANGE);
261  auto stepReport = adaptiveTimeStepping_->step(timer, *solver, event, nullptr);
262  report_ += stepReport;
263  //Pass simulation report to eclwriter for summary output
264  ebosSimulator_.problem().setSimulationReport(report_);
265  } else {
266  // solve for complete report step
267  auto stepReport = solver->step(timer);
268  report_ += stepReport;
269  if (terminalOutput_) {
270  std::ostringstream ss;
271  stepReport.reportStep(ss);
272  OpmLog::info(ss.str());
273  }
274  }
275 
276  // write simulation state at the report stage
277  Dune::Timer perfTimer;
278  perfTimer.start();
279  const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
280  ebosSimulator_.problem().setNextTimeStepSize(nextstep);
281  ebosSimulator_.problem().writeOutput();
282  report_.success.output_write_time += perfTimer.stop();
283 
284  solver->model().endReportStep();
285 
286  // take time that was used to solve system for this reportStep
287  solverTimer_->stop();
288 
289  // update timing.
290  report_.success.solver_time += solverTimer_->secsSinceStart();
291 
292  // Increment timer, remember well state.
293  ++timer;
294 
295  if (terminalOutput_) {
296  if (!timer.initialStep()) {
297  const std::string version = moduleVersionName();
298  outputTimestampFIP(timer, eclState().getTitle(), version);
299  }
300  }
301 
302  if (terminalOutput_) {
303  std::string msg =
304  "Time step took " + std::to_string(solverTimer_->secsSinceStart()) + " seconds; "
305  "total solver time " + std::to_string(report_.success.solver_time) + " seconds.";
306  OpmLog::debug(msg);
307  }
308  return true;
309  }
310 
311  SimulatorReport finalize()
312  {
313  // make sure all output is written to disk before run is finished
314  {
315  Dune::Timer finalOutputTimer;
316  finalOutputTimer.start();
317 
318  ebosSimulator_.problem().finalizeOutput();
319  report_.success.output_write_time += finalOutputTimer.stop();
320  }
321 
322  // Stop timer and create timing report
323  totalTimer_->stop();
324  report_.success.total_time = totalTimer_->secsSinceStart();
325  report_.success.converged = true;
326 
327  return report_;
328  }
329 
330  const Grid& grid() const
331  { return ebosSimulator_.vanguard().grid(); }
332 
333 protected:
334 
335  std::unique_ptr<Solver> createSolver(WellModel& wellModel)
336  {
337  auto model = std::make_unique<Model>(ebosSimulator_,
338  modelParam_,
339  wellModel,
340  terminalOutput_);
341 
342  return std::make_unique<Solver>(solverParam_, std::move(model));
343  }
344 
345  const EclipseState& eclState() const
346  { return ebosSimulator_.vanguard().eclState(); }
347 
348 
349  const Schedule& schedule() const
350  { return ebosSimulator_.vanguard().schedule(); }
351 
352  bool isRestart() const
353  {
354  const auto& initconfig = eclState().getInitConfig();
355  return initconfig.restartRequested();
356  }
357 
358  WellModel& wellModel_()
359  { return ebosSimulator_.problem().wellModel(); }
360 
361  const WellModel& wellModel_() const
362  { return ebosSimulator_.problem().wellModel(); }
363 
364  // Data.
365  Simulator& ebosSimulator_;
366  std::unique_ptr<WellConnectionAuxiliaryModule<TypeTag>> wellAuxMod_;
367 
368  ModelParameters modelParam_;
369  SolverParameters solverParam_;
370 
371  // Observed objects.
372  PhaseUsage phaseUsage_;
373  // Misc. data
374  bool terminalOutput_;
375 
376  SimulatorReport report_;
377  std::unique_ptr<time::StopWatch> solverTimer_;
378  std::unique_ptr<time::StopWatch> totalTimer_;
379  std::unique_ptr<TimeStepper> adaptiveTimeStepping_;
380 };
381 
382 } // namespace Opm
383 
384 #endif // OPM_SIMULATOR_FULLY_IMPLICIT_BLACKOIL_EBOS_HPP
Definition: AdaptiveTimeSteppingEbos.hpp:237
A model implementation for three-phase black oil.
Definition: BlackoilModelEbos.hpp:156
Class for handling the blackoil well model.
Definition: BlackoilWellModel.hpp:94
A nonlinear solver class suitable for general fully-implicit models, as well as pressure,...
Definition: NonlinearSolverEbos.hpp:89
a simulator for the blackoil model
Definition: SimulatorFullyImplicitBlackoilEbos.hpp:72
SimulatorReport run(SimulatorTimer &timer)
Run the simulation.
Definition: SimulatorFullyImplicitBlackoilEbos.hpp:148
SimulatorFullyImplicitBlackoilEbos(Simulator &ebosSimulator)
Initialise from parameters and objects to observe.
Definition: SimulatorFullyImplicitBlackoilEbos.hpp:117
Definition: SimulatorTimer.hpp:37
int currentStepNum() const override
Current step number.
Definition: SimulatorTimer.cpp:80
bool done() const override
Return true if op++() has been called numSteps() times.
Definition: SimulatorTimer.cpp:153
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: BlackoilPhases.hpp:27
std::string moduleVersionName()
Return the version name of the module, for example "2015.10" (for a release branch) or "2016....
Definition: moduleVersion.cpp:34
PhaseUsage phaseUsageFromDeck(const EclipseState &eclipseState)
Looks at presence of WATER, OIL and GAS keywords in state object to determine active phases.
Definition: phaseUsageFromDeck.cpp:145
Solver parameters for the BlackoilModel.
Definition: BlackoilModelParametersEbos.hpp:327
Definition: NonlinearSolverEbos.hpp:101
Definition: SimulatorFullyImplicitBlackoilEbos.hpp:39
Definition: BlackoilWellModel.hpp:82
Definition: SimulatorFullyImplicitBlackoilEbos.hpp:43
Definition: SimulatorReport.hpp:70