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
36namespace Opm::Properties {
37
38template<class TypeTag, class MyTypeTag>
40 using type = UndefinedProperty;
41};
42template<class TypeTag, class MyTypeTag>
44 using type = UndefinedProperty;
45};
46
47template<class TypeTag>
48struct EnableTerminalOutput<TypeTag, TTag::EclFlowProblem> {
49 static constexpr bool value = true;
50};
51template<class TypeTag>
52struct EnableAdaptiveTimeStepping<TypeTag, TTag::EclFlowProblem> {
53 static constexpr bool value = true;
54};
55template<class TypeTag>
56struct EnableTuning<TypeTag, TTag::EclFlowProblem> {
57 static constexpr bool value = false;
58};
59
60} // namespace Opm::Properties
61
62namespace Opm {
63
64void outputReportStep(const SimulatorTimer& timer);
65void outputTimestampFIP(const SimulatorTimer& timer,
66 const std::string& title,
67 const std::string& version);
68
70template<class TypeTag>
72{
73public:
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
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
333protected:
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