FlowProblemBlackoil.hpp
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*
4 Copyright 2023 INRIA
5 Copyright 2024 SINTEF Digital
6
7 This file is part of the Open Porous Media project (OPM).
8
9 OPM is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 2 of the License, or
12 (at your option) any later version.
13
14 OPM is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with OPM. If not, see <http://www.gnu.org/licenses/>.
21
22 Consult the COPYING file in the top-level source directory of this
23 module for the precise wording of the license and the list of
24 copyright holders.
25*/
31#ifndef OPM_FLOW_PROBLEM_BLACK_HPP
32#define OPM_FLOW_PROBLEM_BLACK_HPP
33
34#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
35#include <opm/material/fluidsystems/blackoilpvt/DryGasPvt.hpp>
36#include <opm/material/fluidsystems/blackoilpvt/WetGasPvt.hpp>
37#include <opm/material/fluidsystems/blackoilpvt/LiveOilPvt.hpp>
38#include <opm/material/fluidsystems/blackoilpvt/DeadOilPvt.hpp>
39#include <opm/material/fluidsystems/blackoilpvt/ConstantCompressibilityOilPvt.hpp>
40#include <opm/material/fluidsystems/blackoilpvt/ConstantCompressibilityWaterPvt.hpp>
41
43
44#include <opm/output/eclipse/EclipseIO.hpp>
45
46#include <opm/input/eclipse/Units/Units.hpp>
47
57
59
60#if HAVE_DAMARIS
62#endif
63
64#include <algorithm>
65#include <cstddef>
66#include <functional>
67#include <limits>
68#include <memory>
69#include <stdexcept>
70#include <string>
71#include <string_view>
72#include <vector>
73
74namespace Opm {
75
82template <class TypeTag>
83class FlowProblemBlackoil : public FlowProblem<TypeTag>
84{
85 // TODO: the naming of the Types might be able to be adjusted
86public:
88
89private:
90 using typename FlowProblemType::Scalar;
91 using typename FlowProblemType::Simulator;
92 using typename FlowProblemType::GridView;
93 using typename FlowProblemType::FluidSystem;
94 using typename FlowProblemType::Vanguard;
96 using typename FlowProblemType::EqVector;
102
103 // TODO: potentially some cleaning up depending on the usage later here
119
123
127
129 using typename FlowProblemType::RateVector;
131 using typename FlowProblemType::Indices;
133 using typename FlowProblemType::ElementContext;
134
135 using typename FlowProblemType::MaterialLaw;
136 using typename FlowProblemType::DimMatrix;
137
138 enum { enableDissolvedGas = Indices::compositionSwitchIdx >= 0 };
139 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
140 enum { enableDisgasInWater = getPropValue<TypeTag, Properties::EnableDisgasInWater>() };
141
142 using SolventModule = BlackOilSolventModule<TypeTag>;
143 using PolymerModule = BlackOilPolymerModule<TypeTag>;
144 using FoamModule = BlackOilFoamModule<TypeTag>;
145 using BrineModule = BlackOilBrineModule<TypeTag>;
146 using ExtboModule = BlackOilExtboModule<TypeTag>;
147 using BioeffectsModule = BlackOilBioeffectsModule<TypeTag>;
148 using DispersionModule = BlackOilDispersionModule<TypeTag, enableDispersion>;
149 using DiffusionModule = BlackOilDiffusionModule<TypeTag, enableDiffusion>;
150 using ConvectiveMixingModule = BlackOilConvectiveMixingModule<TypeTag, enableConvectiveMixing>;
151 using ModuleParams = typename BlackOilLocalResidualTPFA<TypeTag>::ModuleParams;
152 using HybridNewton = BlackOilHybridNewton<TypeTag>;
153
154 using InitialFluidState = typename EquilInitializer<TypeTag>::ScalarFluidState;
155 using EclWriterType = EclWriter<TypeTag, OutputBlackOilModule<TypeTag> >;
156 using IndexTraits = typename FluidSystem::IndexTraitsType;
157#if HAVE_DAMARIS
158 using DamarisWriterType = DamarisWriter<TypeTag>;
159#endif
160
161
162public:
165
169 static void registerParameters()
170 {
172
174#if HAVE_DAMARIS
175 DamarisWriterType::registerParameters();
176#endif
178 }
179
183 explicit FlowProblemBlackoil(Simulator& simulator)
184 : FlowProblemType(simulator)
185 , thresholdPressures_(simulator)
186 , mixControls_(simulator.vanguard().schedule())
187 , actionHandler_(simulator.vanguard().eclState(),
188 simulator.vanguard().schedule(),
189 simulator.vanguard().actionState(),
190 simulator.vanguard().summaryState(),
191 this->wellModel_,
192 simulator.vanguard().grid().comm())
193 , hybridNewton_(simulator)
194 {
195 this->model().addOutputModule(std::make_unique<VtkTracerModule<TypeTag>>(simulator));
196
197 // Tell the black-oil extensions to initialize their internal data structures
198 const auto& vanguard = simulator.vanguard();
199
200 BlackOilBrineParams<Scalar> brineParams;
201 brineParams.template initFromState<enableBrine,
202 enableSaltPrecipitation>(vanguard.eclState());
203 BrineModule::setParams(std::move(brineParams));
204
205 DiffusionModule::initFromState(vanguard.eclState());
206 DispersionModule::initFromState(vanguard.eclState());
207
208 BlackOilExtboParams<Scalar> extboParams;
209 extboParams.template initFromState<enableExtbo>(vanguard.eclState());
210 ExtboModule::setParams(std::move(extboParams));
211
213 foamParams.template initFromState<enableFoam>(vanguard.eclState());
214 FoamModule::setParams(std::move(foamParams));
215
216 BlackOilBioeffectsParams<Scalar> bioeffectsParams;
217 bioeffectsParams.template initFromState<enableBioeffects, enableMICP>(vanguard.eclState());
218 BioeffectsModule::setParams(std::move(bioeffectsParams));
219
220 BlackOilPolymerParams<Scalar> polymerParams;
221 polymerParams.template initFromState<enablePolymer, enablePolymerMolarWeight>(vanguard.eclState());
222 PolymerModule::setParams(std::move(polymerParams));
223
224 BlackOilSolventParams<Scalar> solventParams;
225 solventParams.template initFromState<enableSolvent>(vanguard.eclState(), vanguard.schedule());
226 SolventModule::setParams(std::move(solventParams));
227
228 // create the ECL writer
229 eclWriter_ = std::make_unique<EclWriterType>(simulator);
230 enableEclOutput_ = Parameters::Get<Parameters::EnableEclOutput>();
231
232#if HAVE_DAMARIS
233 // create Damaris writer
234 damarisWriter_ = std::make_unique<DamarisWriterType>(simulator);
235 enableDamarisOutput_ = Parameters::Get<Parameters::EnableDamarisOutput>();
236#endif
237 }
238
242 void beginEpisode() override
243 {
245
246 auto& simulator = this->simulator();
247
248 const int episodeIdx = simulator.episodeIndex();
249 const auto& schedule = simulator.vanguard().schedule();
250
251 // Evaluate UDQ assign statements to make sure the settings are
252 // available as UDA controls for the current report step.
253 this->actionHandler_
254 .evalUDQAssignments(episodeIdx, simulator.vanguard().udqState());
255
256 if (episodeIdx >= 0) {
257 const auto& oilVap = schedule[episodeIdx].oilvap();
258 if (oilVap.getType() == OilVaporizationProperties::OilVaporization::VAPPARS) {
259 FluidSystem::setVapPars(oilVap.vap1(), oilVap.vap2());
260 }
261 else {
262 FluidSystem::setVapPars(0.0, 0.0);
263 }
264 }
265
266 ConvectiveMixingModule::beginEpisode(simulator.vanguard().eclState(), schedule, episodeIdx,
267 this->moduleParams_.convectiveMixingModuleParam);
268 }
269
273 void beginTimeStep() override
274 {
277 }
278
283 {
284 // TODO: there should be room to remove duplication for this
285 // function, but there is relatively complicated logic in the
286 // function calls here. Some refactoring is needed.
287 FlowProblemType::finishInit();
288
289 auto& simulator = this->simulator();
290
291 auto finishTransmissibilities = [updated = false, this]() mutable
292 {
293 if (updated) { return; }
294
295 this->transmissibilities_.finishInit([&vg = this->simulator().vanguard()](const unsigned int it) {
296 return vg.gridIdxToEquilGridIdx(it);
297 });
298
299 updated = true;
300 };
301
302 // calculating the TRANX, TRANY, TRANZ and NNC for output purpose
303 // for parallel running, it is based on global trans_
304 // for serial running, it is based on the transmissibilities_
305 // we try to avoid for the parallel running, has both global trans_ and transmissibilities_ allocated at the same time
306 if (enableEclOutput_) {
307 if (simulator.vanguard().grid().comm().size() > 1) {
308 if (simulator.vanguard().grid().comm().rank() == 0)
309 eclWriter_->setTransmissibilities(&simulator.vanguard().globalTransmissibility());
310 } else {
311 finishTransmissibilities();
312 eclWriter_->setTransmissibilities(&simulator.problem().eclTransmissibilities());
313 }
314
315 std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](unsigned int i) {
316 return simulator.vanguard().gridEquilIdxToGridIdx(i);
317 };
318
319 this->eclWriter_->extractOutputTransAndNNC(equilGridToGrid);
320 }
321 simulator.vanguard().releaseGlobalTransmissibilities();
322
323 const auto& eclState = simulator.vanguard().eclState();
324 const auto& schedule = simulator.vanguard().schedule();
325
326 // Set the start time of the simulation
327 simulator.setStartTime(schedule.getStartTime());
328 simulator.setEndTime(schedule.simTime(schedule.size() - 1));
329
330 // We want the episode index to be the same as the report step index to make
331 // things simpler, so we have to set the episode index to -1 because it is
332 // incremented by endEpisode(). The size of the initial time step and
333 // length of the initial episode is set to zero for the same reason.
334 simulator.setEpisodeIndex(-1);
335 simulator.setEpisodeLength(0.0);
336
337 // the "NOGRAV" keyword from Frontsim or setting the EnableGravity to false
338 // disables gravity, else the standard value of the gravity constant at sea level
339 // on earth is used
340 this->gravity_ = 0.0;
341 if (Parameters::Get<Parameters::EnableGravity>() &&
342 eclState.getInitConfig().hasGravity())
343 {
344 // unit::gravity is 9.80665 m^2/s--i.e., standard measure at Tellus equator.
345 this->gravity_[dim - 1] = unit::gravity;
346 }
347
348 if (this->enableTuning_) {
349 // if support for the TUNING keyword is enabled, we get the initial time
350 // steping parameters from it instead of from command line parameters
351 const auto& tuning = schedule[0].tuning();
352 this->initialTimeStepSize_ = tuning.TSINIT.has_value() ? tuning.TSINIT.value() : -1.0;
353 this->maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
354 }
355
356 // conserve inner energy instead of enthalpy if TEMP is used
357 // or THERMAL and parameter ConserveInnerEnergyThermal is true (default false)
358 bool isThermal = eclState.getSimulationConfig().isThermal();
359 bool isTemp = eclState.getSimulationConfig().isTemp();
360 bool conserveInnerEnergy = isTemp || (isThermal && Parameters::Get<Parameters::ConserveInnerEnergyThermal>());
361 FluidSystem::setEnergyEqualEnthalpy(conserveInnerEnergy);
362
363 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
364 FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
365 this->maxOilSaturation_.resize(this->model().numGridDof(), 0.0);
366 }
367
368 this->readRockParameters_(simulator.vanguard().cellCenterDepths(),
369 [&simulator](const unsigned idx)
370 {
371 std::array<int,dim> coords;
372 simulator.vanguard().cartesianCoordinate(idx, coords);
373 std::transform(coords.begin(), coords.end(), coords.begin(),
374 [](const auto c) { return c + 1; });
375 return coords;
376 });
377
380
381 // write the static output files (EGRID, INIT)
382 if (enableEclOutput_) {
383 this->eclWriter_->writeInit();
384 }
385
386 finishTransmissibilities();
387
388 const auto& initconfig = eclState.getInitConfig();
389 this->tracerModel_.init(initconfig.restartRequested());
390 if (initconfig.restartRequested()) {
392 }
393 else {
394 this->readInitialCondition_();
395 }
396 this->temperatureModel_.init();
397 this->tracerModel_.prepareTracerBatches();
398
399 this->updatePffDofData_();
400
401 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>()) {
402 const auto& vanguard = this->simulator().vanguard();
403 const auto& gridView = vanguard.gridView();
404 const int numElements = gridView.size(/*codim=*/0);
405 this->polymer_.maxAdsorption.resize(numElements, 0.0);
406 }
407
409
410 // compute and set eq weights based on initial b values
412
413 if (this->enableDriftCompensation_) {
414 this->drift_.resize(this->model().numGridDof());
415 this->drift_ = 0.0;
416 }
417
418 // after finishing the initialization and writing the initial solution, we move
419 // to the first "real" episode/report step
420 // for restart the episode index and start is already set
421 if (!initconfig.restartRequested() && !eclState.getIOConfig().initOnly()) {
422 simulator.startNextEpisode(schedule.seconds(1));
423 simulator.setEpisodeIndex(0);
424 simulator.setTimeStepIndex(0);
425 }
426
427 if (Parameters::Get<Parameters::CheckSatfuncConsistency>() &&
429 {
430 // User requested that saturation functions be checked for
431 // consistency and essential/critical requirements are not met.
432 // Abort simulation run.
433 //
434 // Note: We need synchronisation here lest ranks other than the
435 // I/O rank throw exceptions too early thereby risking an
436 // incomplete failure report being shown to the user.
437 this->simulator().vanguard().grid().comm().barrier();
438
439 throw std::domain_error {
440 "Saturation function end-points do not "
441 "meet requisite consistency conditions"
442 };
443 }
444
445 // TODO: move to the end for later refactoring of the function finishInit()
446 //
447 // deal with DRSDT
448 this->mixControls_.init(this->model().numGridDof(),
449 this->episodeIndex(),
450 eclState.runspec().tabdims().getNumPVTTables());
451
452 if (this->enableVtkOutput_() && eclState.getIOConfig().initOnly()) {
453 simulator.setTimeStepSize(0.0);
454 simulator.model().applyInitialSolution();
456 }
457
458 if (!eclState.getIOConfig().initOnly()) {
459 if (!this->enableTuning_ && eclState.getSimulationConfig().anyTUNING()) {
460 OpmLog::info("\nThe deck has TUNING in the SCHEDULE section, but "
461 "it is ignored due\nto the flag --enable-tuning=false. "
462 "Set this flag to true to activate it.\n"
463 "Manually tuning the simulator with the TUNING keyword may "
464 "increase run time.\nIt is recommended using the simulator's "
465 "default tuning (--enable-tuning=false).");
466 }
467 }
468 }
469
473 void endTimeStep() override
474 {
475 FlowProblemType::endTimeStep();
476 this->endStepApplyAction();
477 }
478
480 {
481 // After the solution is updated, the values in output module needs
482 // also updated.
483 this->eclWriter().mutableOutputModule().invalidateLocalData();
484
485 // For CpGrid with LGRs, ecl/vtk output is not supported yet.
486 const auto& grid = this->simulator().vanguard().gridView().grid();
487
488 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
489 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
490 if (!isCpGrid || (grid.maxLevel() == 0)) {
491 this->eclWriter_->evalSummaryState(!this->episodeWillBeOver());
492 }
493
494 {
495 OPM_TIMEBLOCK(applyActions);
496
497 const int episodeIdx = this->episodeIndex();
498 auto& simulator = this->simulator();
499
500 // Clear out any existing events as these have already been
501 // processed when we're running an action block
502 this->simulator().vanguard().schedule().clearEvents(episodeIdx);
503
504 // Re-ordering in case of Alugrid
505 this->actionHandler_
506 .applyActions(episodeIdx, simulator.time() + simulator.timeStepSize(),
507 [this](const bool global)
508 {
509 using TransUpdateQuantities = typename
510 Vanguard::TransmissibilityType::TransUpdateQuantities;
511
512 this->transmissibilities_
513 .update(global, TransUpdateQuantities::All,
514 [&vg = this->simulator().vanguard()]
515 (const unsigned int i)
516 {
517 return vg.gridIdxToEquilGridIdx(i);
518 });
519 });
520 }
521 }
522
526 void endEpisode() override
527 {
528 OPM_TIMEBLOCK(endEpisode);
529
530 // Rerun UDQ assignents following action processing on the final
531 // time step of this episode to make sure that any UDQ ASSIGN
532 // operations triggered in action blocks take effect. This is
533 // mainly to work around a shortcoming of the ScheduleState copy
534 // constructor which clears pending UDQ assignments under the
535 // assumption that all such assignments have been processed. If an
536 // action block happens to trigger on the final time step of an
537 // episode and that action block runs a UDQ assignment, then that
538 // assignment would be dropped and the rest of the simulator will
539 // never see its effect without this hack.
540 this->actionHandler_
541 .evalUDQAssignments(this->episodeIndex(), this->simulator().vanguard().udqState());
542
543 FlowProblemType::endEpisode();
544 }
545
546 void writeReports(const SimulatorTimer& timer)
547 {
548 if (this->enableEclOutput_) {
549 this->eclWriter_->writeReports(timer);
550 }
551 }
552
553
558 void writeOutput(const bool verbose) override
559 {
560 FlowProblemType::writeOutput(verbose);
561
562 const auto isSubStep = !this->episodeWillBeOver();
563
564 auto localCellData = data::Solution {};
565
566#if HAVE_DAMARIS
567 // N.B. the Damaris output has to be done before the ECL output as the ECL one
568 // does all kinds of std::move() relocation of data
569 if (this->enableDamarisOutput_ && (this->damarisWriter_ != nullptr)) {
570 this->damarisWriter_->writeOutput(localCellData, isSubStep);
571 }
572#endif
573
574 if (this->enableEclOutput_ && (this->eclWriter_ != nullptr)) {
575 this->eclWriter_->writeOutput(std::move(localCellData), isSubStep);
576 }
577 }
578
580 {
581 OPM_TIMEBLOCK(finalizeOutput);
582 // this will write all pending output to disk
583 // to avoid corruption of output files
584 eclWriter_.reset();
585 }
586
587
592 {
593 FlowProblemType::initialSolutionApplied();
594
595 // let the object for threshold pressures initialize itself. this is done only at
596 // this point, because determining the threshold pressures may require to access
597 // the initial solution.
598 this->thresholdPressures_.finishInit();
599
600 // For CpGrid with LGRs, ecl-output is not supported yet.
601 const auto& grid = this->simulator().vanguard().gridView().grid();
602
603 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
604 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
605 // Skip - for now - calculate the initial fip values for CpGrid with LGRs.
606 if (!isCpGrid || (grid.maxLevel() == 0)) {
607 if (this->simulator().episodeIndex() == 0) {
608 eclWriter_->writeInitialFIPReport();
609 }
610 }
611 }
612
614 unsigned globalDofIdx,
615 unsigned timeIdx) const override
616 {
617 this->aquiferModel_.addToSource(rate, globalDofIdx, timeIdx);
618
619 // Add source term from deck
620 const auto& source = this->simulator().vanguard().schedule()[this->episodeIndex()].source();
621 std::array<int,3> ijk;
622 this->simulator().vanguard().cartesianCoordinate(globalDofIdx, ijk);
623
624 if (source.hasSource(ijk)) {
625 const int pvtRegionIdx = this->pvtRegionIndex(globalDofIdx);
626 static std::array<SourceComponent, 3> sc_map = {SourceComponent::WATER, SourceComponent::OIL, SourceComponent::GAS};
627 static std::array<int, 3> phidx_map = {FluidSystem::waterPhaseIdx, FluidSystem::oilPhaseIdx, FluidSystem::gasPhaseIdx};
628 static std::array<int, 3> cidx_map = {waterCompIdx, oilCompIdx, gasCompIdx};
629
630 for (unsigned i = 0; i < phidx_map.size(); ++i) {
631 const auto phaseIdx = phidx_map[i];
632 const auto sourceComp = sc_map[i];
633 const auto compIdx = cidx_map[i];
634 if (!FluidSystem::phaseIsActive(phaseIdx)) {
635 continue;
636 }
637 Scalar mass_rate = source.rate(ijk, sourceComp) / this->model().dofTotalVolume(globalDofIdx);
638 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
639 mass_rate /= FluidSystem::referenceDensity(phaseIdx, pvtRegionIdx);
640 }
641 rate[FluidSystem::canonicalToActiveCompIdx(compIdx)] += mass_rate;
642 }
643
644 if constexpr (enableSolvent) {
645 Scalar mass_rate = source.rate(ijk, SourceComponent::SOLVENT) / this->model().dofTotalVolume(globalDofIdx);
646 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
647 const auto& solventPvt = SolventModule::solventPvt();
648 mass_rate /= solventPvt.referenceDensity(pvtRegionIdx);
649 }
650 rate[Indices::contiSolventEqIdx] += mass_rate;
651 }
652 if constexpr (enablePolymer) {
653 rate[Indices::polymerConcentrationIdx] += source.rate(ijk, SourceComponent::POLYMER) / this->model().dofTotalVolume(globalDofIdx);
654 }
655 if constexpr (enableMICP) {
656 rate[Indices::microbialConcentrationIdx] += source.rate(ijk, SourceComponent::MICR) / this->model().dofTotalVolume(globalDofIdx);
657 rate[Indices::oxygenConcentrationIdx] += source.rate(ijk, SourceComponent::OXYG) / this->model().dofTotalVolume(globalDofIdx);
658 rate[Indices::ureaConcentrationIdx] += source.rate(ijk, SourceComponent::UREA) / (this->model().dofTotalVolume(globalDofIdx));
659 }
660 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
661 for (unsigned i = 0; i < phidx_map.size(); ++i) {
662 const auto phaseIdx = phidx_map[i];
663 if (!FluidSystem::phaseIsActive(phaseIdx)) {
664 continue;
665 }
666 const auto sourceComp = sc_map[i];
667 const auto source_hrate = source.hrate(ijk, sourceComp);
668 if (source_hrate) {
669 rate[Indices::contiEnergyEqIdx] += source_hrate.value() / this->model().dofTotalVolume(globalDofIdx);
670 } else {
671 const auto& intQuants = this->simulator().model().intensiveQuantities(globalDofIdx, /*timeIdx*/ 0);
672 auto fs = intQuants.fluidState();
673 // if temperature is not set, use cell temperature as default
674 const auto source_temp = source.temperature(ijk, sourceComp);
675 if (source_temp) {
676 Scalar temperature = source_temp.value();
677 fs.setTemperature(temperature);
678 }
679 const auto& h = FluidSystem::enthalpy(fs, phaseIdx, pvtRegionIdx);
680 Scalar mass_rate = source.rate(ijk, sourceComp)/ this->model().dofTotalVolume(globalDofIdx);
681 Scalar energy_rate = getValue(h)*mass_rate;
682 rate[Indices::contiEnergyEqIdx] += energy_rate;
683 }
684 }
685 }
686 }
687
688 // if requested, compensate systematic mass loss for cells which were "well
689 // behaved" in the last time step
690 if (this->enableDriftCompensation_) {
691 const auto& simulator = this->simulator();
692 const auto& model = this->model();
693
694 // we use a lower tolerance for the compensation too
695 // assure the added drift from the last step does not
696 // cause convergence issues on the current step
697 Scalar maxCompensation = model.newtonMethod().tolerance()/10;
698 Scalar poro = this->porosity(globalDofIdx, timeIdx);
699 Scalar dt = simulator.timeStepSize();
700 EqVector dofDriftRate = this->drift_[globalDofIdx];
701 dofDriftRate /= dt*model.dofTotalVolume(globalDofIdx);
702
703 // restrict drift compensation to the CNV tolerance
704 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
705 Scalar cnv = std::abs(dofDriftRate[eqIdx])*dt*model.eqWeight(globalDofIdx, eqIdx)/poro;
706 if (cnv > maxCompensation) {
707 dofDriftRate[eqIdx] *= maxCompensation/cnv;
708 }
709 }
710
711 for (unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
712 rate[eqIdx] -= dofDriftRate[eqIdx];
713 }
714 }
715
719 template <class LhsEval, class Callback>
720 LhsEval permFactTransMultiplier(const IntensiveQuantities& intQuants, unsigned elementIdx, Callback& obtain) const
721 {
722 OPM_TIMEBLOCK_LOCAL(permFactTransMultiplier, Subsystem::PvtProps);
723 if constexpr (enableSaltPrecipitation) {
724 const auto& fs = intQuants.fluidState();
725 unsigned tableIdx = this->simulator().problem().satnumRegionIndex(elementIdx);
726 LhsEval porosityFactor = obtain(1. - fs.saltSaturation());
727 porosityFactor = min(porosityFactor, 1.0);
728 const auto& permfactTable = BrineModule::permfactTable(tableIdx);
729 return permfactTable.eval(porosityFactor, /*extrapolation=*/true);
730 }
731 else if constexpr (enableBioeffects) {
732 return obtain(intQuants.permFactor());
733 }
734 else {
735 return 1.0;
736 }
737 }
738
739 // temporary solution to facilitate output of initial state from flow
740 const InitialFluidState& initialFluidState(unsigned globalDofIdx) const
741 { return initialFluidStates_[globalDofIdx]; }
742
743 std::vector<InitialFluidState>& initialFluidStates()
744 { return initialFluidStates_; }
745
746 const std::vector<InitialFluidState>& initialFluidStates() const
747 { return initialFluidStates_; }
748
749 const EclipseIO& eclIO() const
750 { return eclWriter_->eclIO(); }
751
753 { return eclWriter_->setSubStepReport(report); }
754
756 { return eclWriter_->setSimulationReport(report); }
757
758 InitialFluidState boundaryFluidState(unsigned globalDofIdx, const int directionId) const
759 {
760 OPM_TIMEBLOCK_LOCAL(boundaryFluidState, Subsystem::Assembly);
761 const auto& bcprop = this->simulator().vanguard().schedule()[this->episodeIndex()].bcprop;
762 if (bcprop.size() > 0) {
763 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
764
765 // index == 0: no boundary conditions for this
766 // global cell and direction
767 if (this->bcindex_(dir)[globalDofIdx] == 0)
768 return initialFluidStates_[globalDofIdx];
769
770 const auto& bc = bcprop[this->bcindex_(dir)[globalDofIdx]];
771 if (bc.bctype == BCType::DIRICHLET )
772 {
773 InitialFluidState fluidState;
774 const int pvtRegionIdx = this->pvtRegionIndex(globalDofIdx);
775 fluidState.setPvtRegionIndex(pvtRegionIdx);
776
777 switch (bc.component) {
778 case BCComponent::OIL:
779 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx))
780 throw std::logic_error("oil is not active and you're trying to add oil BC");
781
782 fluidState.setSaturation(FluidSystem::oilPhaseIdx, 1.0);
783 break;
784 case BCComponent::GAS:
785 if (!FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx))
786 throw std::logic_error("gas is not active and you're trying to add gas BC");
787
788 fluidState.setSaturation(FluidSystem::gasPhaseIdx, 1.0);
789 break;
790 case BCComponent::WATER:
791 if (!FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
792 throw std::logic_error("water is not active and you're trying to add water BC");
793
794 fluidState.setSaturation(FluidSystem::waterPhaseIdx, 1.0);
795 break;
796 case BCComponent::SOLVENT:
797 case BCComponent::POLYMER:
798 case BCComponent::MICR:
799 case BCComponent::OXYG:
800 case BCComponent::UREA:
802 throw std::logic_error("you need to specify a valid component (OIL, WATER or GAS) when DIRICHLET type is set in BC");
803 }
804 fluidState.setTotalSaturation(1.0);
805 double pressure = initialFluidStates_[globalDofIdx].pressure(this->refPressurePhaseIdx_());
806 const auto pressure_input = bc.pressure;
807 if (pressure_input) {
808 pressure = *pressure_input;
809 }
810
811 std::array<Scalar, numPhases> pc = {0};
812 const auto& matParams = this->materialLawParams(globalDofIdx);
813 MaterialLaw::capillaryPressures(pc, matParams, fluidState);
814 Valgrind::CheckDefined(pressure);
815 Valgrind::CheckDefined(pc);
816 for (unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
817 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
818 if (Indices::oilEnabled)
819 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
820 else if (Indices::gasEnabled)
821 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
822 else if (Indices::waterEnabled)
823 //single (water) phase
824 fluidState.setPressure(phaseIdx, pressure);
825 }
826 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
827 double temperature = initialFluidStates_[globalDofIdx].temperature(0); // we only have one temperature
828 const auto temperature_input = bc.temperature;
829 if(temperature_input)
830 temperature = *temperature_input;
831 fluidState.setTemperature(temperature);
832 }
833
834 if constexpr (enableDissolvedGas) {
835 if (FluidSystem::enableDissolvedGas()) {
836 fluidState.setRs(0.0);
837 fluidState.setRv(0.0);
838 }
839 }
840 if constexpr (enableDisgasInWater) {
841 if (FluidSystem::enableDissolvedGasInWater()) {
842 fluidState.setRsw(0.0);
843 }
844 }
845 if constexpr (enableVapwat) {
846 if (FluidSystem::enableVaporizedWater()) {
847 fluidState.setRvw(0.0);
848 }
849 }
850
851 for (unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
852 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
853
854 const auto& b = FluidSystem::inverseFormationVolumeFactor(fluidState, phaseIdx, pvtRegionIdx);
855 fluidState.setInvB(phaseIdx, b);
856
857 const auto& rho = FluidSystem::density(fluidState, phaseIdx, pvtRegionIdx);
858 fluidState.setDensity(phaseIdx, rho);
859 if constexpr (energyModuleType == EnergyModules::SequentialImplicitThermal || energyModuleType == EnergyModules::FullyImplicitThermal) {
860 const auto& h = FluidSystem::enthalpy(fluidState, phaseIdx, pvtRegionIdx);
861 fluidState.setEnthalpy(phaseIdx, h);
862 }
863 }
864 fluidState.checkDefined();
865 return fluidState;
866 }
867 }
868 return initialFluidStates_[globalDofIdx];
869 }
870
871
873 { return *eclWriter_; }
874
876 { return *eclWriter_; }
877
882 Scalar maxGasDissolutionFactor(unsigned timeIdx, unsigned globalDofIdx) const
883 {
884 return this->mixControls_.maxGasDissolutionFactor(timeIdx, globalDofIdx,
885 this->episodeIndex(),
886 this->pvtRegionIndex(globalDofIdx));
887 }
888
893 Scalar maxOilVaporizationFactor(unsigned timeIdx, unsigned globalDofIdx) const
894 {
895 return this->mixControls_.maxOilVaporizationFactor(timeIdx, globalDofIdx,
896 this->episodeIndex(),
897 this->pvtRegionIndex(globalDofIdx));
898 }
899
909 {
910 int episodeIdx = this->episodeIndex();
911 return !this->mixControls_.drsdtActive(episodeIdx) &&
912 !this->mixControls_.drvdtActive(episodeIdx) &&
913 this->rockCompPoroMultWc_.empty() &&
914 this->rockCompPoroMult_.empty();
915 }
916
923 template <class Context>
924 void initial(PrimaryVariables& values, const Context& context, unsigned spaceIdx, unsigned timeIdx) const
925 {
926 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
927
928 values.setPvtRegionIndex(pvtRegionIndex(context, spaceIdx, timeIdx));
929 values.assignNaive(initialFluidStates_[globalDofIdx]);
930
931 SolventModule::assignPrimaryVars(values,
932 enableSolvent ? this->solventSaturation_[globalDofIdx] : 0.0,
933 enableSolvent ? this->solventRsw_[globalDofIdx] : 0.0);
934
935 if constexpr (enablePolymer)
936 values[Indices::polymerConcentrationIdx] = this->polymer_.concentration[globalDofIdx];
937
938 if constexpr (enablePolymerMolarWeight)
939 values[Indices::polymerMoleWeightIdx]= this->polymer_.moleWeight[globalDofIdx];
940
941 if constexpr (enableBrine) {
942 if (enableSaltPrecipitation && values.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp) {
943 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltSaturation();
944 }
945 else {
946 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltConcentration();
947 }
948 }
949
950 if constexpr (enableBioeffects) {
951 values[Indices::microbialConcentrationIdx] = this->bioeffects_.microbialConcentration[globalDofIdx];
952 values[Indices::biofilmVolumeFractionIdx]= this->bioeffects_.biofilmVolumeFraction[globalDofIdx];
953 if constexpr (enableMICP) {
954 values[Indices::oxygenConcentrationIdx]= this->bioeffects_.oxygenConcentration[globalDofIdx];
955 values[Indices::ureaConcentrationIdx]= this->bioeffects_.ureaConcentration[globalDofIdx];
956 values[Indices::calciteVolumeFractionIdx]= this->bioeffects_.calciteVolumeFraction[globalDofIdx];
957 }
958 }
959
960 values.checkDefined();
961 }
962
963
964 Scalar drsdtcon(unsigned elemIdx, int episodeIdx) const
965 {
966 return this->mixControls_.drsdtcon(elemIdx, episodeIdx,
967 this->pvtRegionIndex(elemIdx));
968 }
969
970 bool drsdtconIsActive(unsigned elemIdx, int episodeIdx) const
971 {
972 return this->mixControls_.drsdtConvective(episodeIdx, this->pvtRegionIndex(elemIdx));
973 }
974
980 template <class Context>
981 void boundary(BoundaryRateVector& values,
982 const Context& context,
983 unsigned spaceIdx,
984 unsigned timeIdx) const
985 {
986 OPM_TIMEBLOCK_LOCAL(eclProblemBoundary, Subsystem::Assembly);
987 if (!context.intersection(spaceIdx).boundary())
988 return;
989
990 if constexpr (energyModuleType != EnergyModules::FullyImplicitThermal || !enableThermalFluxBoundaries)
991 values.setNoFlow();
992 else {
993 // in the energy case we need to specify a non-trivial boundary condition
994 // because the geothermal gradient needs to be maintained. for this, we
995 // simply assume the initial temperature at the boundary and specify the
996 // thermal flow accordingly. in this context, "thermal flow" means energy
997 // flow due to a temerature gradient while assuming no-flow for mass
998 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
999 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1000 values.setThermalFlow(context, spaceIdx, timeIdx, this->initialFluidStates_[globalDofIdx] );
1001 }
1002
1003 if (this->nonTrivialBoundaryConditions()) {
1004 unsigned indexInInside = context.intersection(spaceIdx).indexInInside();
1005 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1006 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1007 unsigned pvtRegionIdx = pvtRegionIndex(context, spaceIdx, timeIdx);
1008 const auto [type, massrate] = this->boundaryCondition(globalDofIdx, indexInInside);
1009 if (type == BCType::THERMAL)
1010 values.setThermalFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1011 else if (type == BCType::FREE || type == BCType::DIRICHLET)
1012 values.setFreeFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1013 else if (type == BCType::RATE)
1014 values.setMassRate(massrate, pvtRegionIdx);
1015 }
1016 }
1017
1022 void readSolutionFromOutputModule(const int restart_step, bool fip_init)
1023 {
1024 auto& simulator = this->simulator();
1025 const auto& eclState = simulator.vanguard().eclState();
1026
1027 std::size_t numElems = this->model().numGridDof();
1028 this->initialFluidStates_.resize(numElems);
1029 if constexpr (enableSolvent) {
1030 this->solventSaturation_.resize(numElems, 0.0);
1031 this->solventRsw_.resize(numElems, 0.0);
1032 }
1033
1034 if constexpr (enablePolymer)
1035 this->polymer_.concentration.resize(numElems, 0.0);
1036
1037 if constexpr (enablePolymerMolarWeight) {
1038 const std::string msg {"Support of the RESTART for polymer molecular weight "
1039 "is not implemented yet. The polymer weight value will be "
1040 "zero when RESTART begins"};
1041 OpmLog::warning("NO_POLYMW_RESTART", msg);
1042 this->polymer_.moleWeight.resize(numElems, 0.0);
1043 }
1044
1045 if constexpr (enableBioeffects) {
1046 this->bioeffects_.resize(numElems);
1047 }
1048
1049 // Initialize mixing controls before trying to set any lastRx valuesx
1050 this->mixControls_.init(numElems, restart_step, eclState.runspec().tabdims().getNumPVTTables());
1051
1052 if constexpr (enableBioeffects) {
1053 this->bioeffects_ = this->eclWriter_->outputModule().getBioeffects().getSolution();
1054 }
1055
1056 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1057 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1058 elemFluidState.setPvtRegionIndex(pvtRegionIndex(elemIdx));
1059 this->eclWriter_->outputModule().initHysteresisParams(simulator, elemIdx);
1060 this->eclWriter_->outputModule().assignToFluidState(elemFluidState, elemIdx);
1061
1062 // Note: Function processRestartSaturations_() mutates the
1063 // 'ssol' argument--the value from the restart file--if solvent
1064 // is enabled. Then, store the updated solvent saturation into
1065 // 'solventSaturation_'. Otherwise, just pass a dummy value to
1066 // the function and discard the unchanged result. Do not index
1067 // into 'solventSaturation_' unless solvent is enabled.
1068 {
1069 auto ssol = enableSolvent
1070 ? this->eclWriter_->outputModule().getSolventSaturation(elemIdx)
1071 : Scalar(0);
1072
1073 this->processRestartSaturations_(elemFluidState, ssol);
1074
1075 if constexpr (enableSolvent) {
1076 this->solventSaturation_[elemIdx] = ssol;
1077 this->solventRsw_[elemIdx] = this->eclWriter_->outputModule().getSolventRsw(elemIdx);
1078 }
1079 }
1080
1081 // For CO2STORE and H2STORE we need to set the initial temperature for isothermal simulations
1082 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1083 bool needTemperature = (eclState.runspec().co2Storage() || eclState.runspec().h2Storage());
1084 if (needTemperature) {
1085 const auto& fp = simulator.vanguard().eclState().fieldProps();
1086 elemFluidState.setTemperature(fp.get_double("TEMPI")[elemIdx]);
1087 }
1088 }
1089
1090 this->mixControls_.updateLastValues(elemIdx, elemFluidState.Rs(), elemFluidState.Rv());
1091
1092 if constexpr (enablePolymer)
1093 this->polymer_.concentration[elemIdx] = this->eclWriter_->outputModule().getPolymerConcentration(elemIdx);
1094 // if we need to restart for polymer molecular weight simulation, we need to add related here
1095 }
1096
1097 const int episodeIdx = this->episodeIndex();
1098 this->mixControls_.updateMaxValues(episodeIdx, simulator.timeStepSize());
1099
1100 // assign the restart solution to the current solution. note that we still need
1101 // to compute real initial solution after this because the initial fluid states
1102 // need to be correct for stuff like boundary conditions.
1103 auto& sol = this->model().solution(/*timeIdx=*/0);
1104 const auto& gridView = this->gridView();
1105 ElementContext elemCtx(simulator);
1106 for (const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1107 elemCtx.updatePrimaryStencil(elem);
1108 int elemIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0);
1109 this->initial(sol[elemIdx], elemCtx, /*spaceIdx=*/0, /*timeIdx=*/0);
1110 }
1111
1112 // make sure that the ghost and overlap entities exhibit the correct
1113 // solution. alternatively, this could be done in the loop above by also
1114 // considering non-interior elements. Since the initial() method might not work
1115 // 100% correctly for such elements, let's play safe and explicitly synchronize
1116 // using message passing.
1117 this->model().syncOverlap();
1118
1119 if (fip_init) {
1120 this->updateReferencePorosity_();
1121 this->mixControls_.init(this->model().numGridDof(),
1122 this->episodeIndex(),
1123 eclState.runspec().tabdims().getNumPVTTables());
1124 }
1125 }
1126
1130 Scalar thresholdPressure(unsigned elem1Idx, unsigned elem2Idx) const
1131 { return thresholdPressures_.thresholdPressure(elem1Idx, elem2Idx); }
1132
1134 { return thresholdPressures_; }
1135
1137 { return thresholdPressures_; }
1138
1139 const ModuleParams& moduleParams() const
1140 {
1141 return moduleParams_;
1142 }
1143
1144 template<class Serializer>
1145 void serializeOp(Serializer& serializer)
1146 {
1147 serializer(static_cast<FlowProblemType&>(*this));
1148 serializer(mixControls_);
1149 serializer(*eclWriter_);
1150 }
1151
1152protected:
1153 void updateExplicitQuantities_(int episodeIdx, int timeStepSize, const bool first_step_after_restart) override
1154 {
1155 this->updateExplicitQuantities_(first_step_after_restart);
1156
1157 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>())
1158 updateMaxPolymerAdsorption_();
1159
1160 mixControls_.updateExplicitQuantities(episodeIdx, timeStepSize);
1161 }
1162
1164 {
1165 // we need to update the max polymer adsoption data for all elements
1166 this->updateProperty_("FlowProblemBlackoil::updateMaxPolymerAdsorption_() failed:",
1167 [this](unsigned compressedDofIdx, const IntensiveQuantities& iq)
1168 {
1169 this->updateMaxPolymerAdsorption_(compressedDofIdx,iq);
1170 });
1171 }
1172
1173 bool updateMaxPolymerAdsorption_(unsigned compressedDofIdx, const IntensiveQuantities& iq)
1174 {
1175 const Scalar pa = scalarValue(iq.polymerAdsorption());
1176 auto& mpa = this->polymer_.maxAdsorption;
1177 if (mpa[compressedDofIdx] < pa) {
1178 mpa[compressedDofIdx] = pa;
1179 return true;
1180 } else {
1181 return false;
1182 }
1183 }
1184
1186 {
1187 std::vector<Scalar> sumInvB(numPhases, 0.0);
1188 const auto& gridView = this->gridView();
1189 ElementContext elemCtx(this->simulator());
1190 for(const auto& elem: elements(gridView, Dune::Partitions::interior)) {
1191 elemCtx.updatePrimaryStencil(elem);
1192 int elemIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0);
1193 const auto& dofFluidState = this->initialFluidStates_[elemIdx];
1194 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1195 if (!FluidSystem::phaseIsActive(phaseIdx))
1196 continue;
1197
1198 sumInvB[phaseIdx] += dofFluidState.invB(phaseIdx);
1199 }
1200 }
1201
1202 std::size_t numDof = this->model().numGridDof();
1203 const auto& comm = this->simulator().vanguard().grid().comm();
1204 comm.sum(sumInvB.data(),sumInvB.size());
1205 Scalar numTotalDof = comm.sum(numDof);
1206
1207 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1208 if (!FluidSystem::phaseIsActive(phaseIdx))
1209 continue;
1210
1211 Scalar avgB = numTotalDof / sumInvB[phaseIdx];
1212 const unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
1213 const unsigned activeSolventCompIdx = FluidSystem::canonicalToActiveCompIdx(solventCompIdx);
1214 this->model().setEqWeight(activeSolventCompIdx, avgB);
1215 }
1216 }
1217
1218 // update the parameters needed for DRSDT and DRVDT
1220 {
1221 OPM_TIMEBLOCK(updateCompositionChangeLimits);
1222 // update the "last Rs" values for all elements, including the ones in the ghost
1223 // and overlap regions
1224 int episodeIdx = this->episodeIndex();
1225 std::array<bool,3> active{this->mixControls_.drsdtConvective(episodeIdx),
1226 this->mixControls_.drsdtActive(episodeIdx),
1227 this->mixControls_.drvdtActive(episodeIdx)};
1228 if (!active[0] && !active[1] && !active[2]) {
1229 return false;
1230 }
1231
1232 this->updateProperty_("FlowProblemBlackoil::updateCompositionChangeLimits_()) failed:",
1233 [this,episodeIdx,active](unsigned compressedDofIdx,
1234 const IntensiveQuantities& iq)
1235 {
1236 const DimMatrix& perm = this->intrinsicPermeability(compressedDofIdx);
1237 const Scalar distZ = active[0] ? this->simulator().vanguard().cellThickness(compressedDofIdx) : 0.0;
1238 const int pvtRegionIdx = this->pvtRegionIndex(compressedDofIdx);
1239 this->mixControls_.update(compressedDofIdx,
1240 iq,
1241 episodeIdx,
1242 this->gravity_[dim - 1],
1243 perm[dim - 1][dim - 1],
1244 distZ,
1245 pvtRegionIdx);
1246 }
1247 );
1248
1249 return true;
1250 }
1251
1253 {
1254 // Throw an exception if the grid has LGRs. Refined grid are not supported for restart.
1255 if(this->simulator().vanguard().grid().maxLevel() > 0) {
1256 throw std::invalid_argument("Refined grids are not yet supported for restart ");
1257 }
1258
1259 // Set the start time of the simulation
1260 auto& simulator = this->simulator();
1261 const auto& schedule = simulator.vanguard().schedule();
1262 const auto& eclState = simulator.vanguard().eclState();
1263 const auto& initconfig = eclState.getInitConfig();
1264 const int restart_step = initconfig.getRestartStep();
1265 {
1266 simulator.setTime(schedule.seconds(restart_step));
1267
1268 simulator.startNextEpisode(simulator.startTime() + simulator.time(),
1269 schedule.stepLength(restart_step));
1270 simulator.setEpisodeIndex(restart_step);
1271 }
1272 this->eclWriter_->beginRestart();
1273
1274 Scalar dt = std::min(this->eclWriter_->restartTimeStepSize(), simulator.episodeLength());
1275 simulator.setTimeStepSize(dt);
1276
1277 this->readSolutionFromOutputModule(restart_step, false);
1278
1279 this->eclWriter_->endRestart();
1280 }
1281
1283 {
1284 const auto& simulator = this->simulator();
1285
1286 // initial condition corresponds to hydrostatic conditions.
1287 EquilInitializer<TypeTag> equilInitializer(simulator, *(this->materialLawManager_));
1288
1289 std::size_t numElems = this->model().numGridDof();
1290 this->initialFluidStates_.resize(numElems);
1291 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1292 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1293 elemFluidState.assign(equilInitializer.initialFluidState(elemIdx));
1294 }
1295 }
1296
1298 {
1299 const auto& simulator = this->simulator();
1300 const auto& vanguard = simulator.vanguard();
1301 const auto& eclState = vanguard.eclState();
1302 const auto& fp = eclState.fieldProps();
1303 bool has_swat = fp.has_double("SWAT");
1304 bool has_sgas = fp.has_double("SGAS");
1305 bool has_rs = fp.has_double("RS");
1306 bool has_rsw = fp.has_double("RSW");
1307 bool has_rv = fp.has_double("RV");
1308 bool has_rvw = fp.has_double("RVW");
1309 bool has_pressure = fp.has_double("PRESSURE");
1310 bool has_salt = fp.has_double("SALT");
1311 bool has_saltp = fp.has_double("SALTP");
1312
1313 // make sure all required quantities are enables
1314 if (Indices::numPhases > 1) {
1315 if (FluidSystem::phaseIsActive(waterPhaseIdx) && !has_swat)
1316 throw std::runtime_error("The ECL input file requires the presence of the SWAT keyword if "
1317 "the water phase is active");
1318 if (FluidSystem::phaseIsActive(gasPhaseIdx) && !has_sgas && FluidSystem::phaseIsActive(oilPhaseIdx))
1319 throw std::runtime_error("The ECL input file requires the presence of the SGAS keyword if "
1320 "the gas phase is active");
1321 }
1322 if (!has_pressure)
1323 throw std::runtime_error("The ECL input file requires the presence of the PRESSURE "
1324 "keyword if the model is initialized explicitly");
1325 if (FluidSystem::enableDissolvedGas() && !has_rs)
1326 throw std::runtime_error("The ECL input file requires the RS keyword to be present if"
1327 " dissolved gas is enabled and the model is initialized explicitly");
1328 if (FluidSystem::enableDissolvedGasInWater() && !has_rsw)
1329 OpmLog::warning("The model is initialized explicitly and the RSW keyword is not present in the"
1330 " ECL input file. The RSW values are set equal to 0");
1331 if (FluidSystem::enableVaporizedOil() && !has_rv)
1332 throw std::runtime_error("The ECL input file requires the RV keyword to be present if"
1333 " vaporized oil is enabled and the model is initialized explicitly");
1334 if (FluidSystem::enableVaporizedWater() && !has_rvw)
1335 throw std::runtime_error("The ECL input file requires the RVW keyword to be present if"
1336 " vaporized water is enabled and the model is initialized explicitly");
1337 if (enableBrine && !has_salt)
1338 throw std::runtime_error("The ECL input file requires the SALT keyword to be present if"
1339 " brine is enabled and the model is initialized explicitly");
1340 if (enableSaltPrecipitation && !has_saltp)
1341 throw std::runtime_error("The ECL input file requires the SALTP keyword to be present if"
1342 " salt precipitation is enabled and the model is initialized explicitly");
1343
1344 std::size_t numDof = this->model().numGridDof();
1345
1346 initialFluidStates_.resize(numDof);
1347
1348 std::vector<double> waterSaturationData;
1349 std::vector<double> gasSaturationData;
1350 std::vector<double> pressureData;
1351 std::vector<double> rsData;
1352 std::vector<double> rswData;
1353 std::vector<double> rvData;
1354 std::vector<double> rvwData;
1355 std::vector<double> tempiData;
1356 std::vector<double> saltData;
1357 std::vector<double> saltpData;
1358
1359 if (FluidSystem::phaseIsActive(waterPhaseIdx) && Indices::numPhases > 1)
1360 waterSaturationData = fp.get_double("SWAT");
1361 else
1362 waterSaturationData.resize(numDof);
1363
1364 if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(oilPhaseIdx))
1365 gasSaturationData = fp.get_double("SGAS");
1366 else
1367 gasSaturationData.resize(numDof);
1368
1369 pressureData = fp.get_double("PRESSURE");
1370 if (FluidSystem::enableDissolvedGas())
1371 rsData = fp.get_double("RS");
1372
1373 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1374 rswData = fp.get_double("RSW");
1375
1376 if (FluidSystem::enableVaporizedOil())
1377 rvData = fp.get_double("RV");
1378
1379 if (FluidSystem::enableVaporizedWater())
1380 rvwData = fp.get_double("RVW");
1381
1382 // initial reservoir temperature
1383 tempiData = fp.get_double("TEMPI");
1384
1385 // initial salt concentration data
1386 if constexpr (enableBrine)
1387 saltData = fp.get_double("SALT");
1388
1389 // initial precipitated salt saturation data
1390 if constexpr (enableSaltPrecipitation)
1391 saltpData = fp.get_double("SALTP");
1392
1393 // calculate the initial fluid states
1394 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1395 auto& dofFluidState = initialFluidStates_[dofIdx];
1396
1397 dofFluidState.setPvtRegionIndex(pvtRegionIndex(dofIdx));
1398
1400 // set temperature
1402 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1403 Scalar temperatureLoc = tempiData[dofIdx];
1404 if (!std::isfinite(temperatureLoc) || temperatureLoc <= 0)
1405 temperatureLoc = FluidSystem::surfaceTemperature;
1406 dofFluidState.setTemperature(temperatureLoc);
1407 }
1408
1410 // set salt concentration
1412 if constexpr (enableBrine)
1413 dofFluidState.setSaltConcentration(saltData[dofIdx]);
1414
1416 // set precipitated salt saturation
1418 if constexpr (enableSaltPrecipitation)
1419 dofFluidState.setSaltSaturation(saltpData[dofIdx]);
1420
1422 // set saturations
1424 if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
1425 dofFluidState.setSaturation(FluidSystem::waterPhaseIdx,
1426 waterSaturationData[dofIdx]);
1427
1428 if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){
1429 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)){
1430 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1431 1.0
1432 - waterSaturationData[dofIdx]);
1433 }
1434 else
1435 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1436 gasSaturationData[dofIdx]);
1437 }
1438 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1439 const Scalar soil = 1.0 - waterSaturationData[dofIdx] - gasSaturationData[dofIdx];
1440 if (soil < smallSaturationTolerance_) {
1441 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, 0.0);
1442 }
1443 else {
1444 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, soil);
1445 }
1446 }
1447
1449 // set phase pressures
1451 Scalar pressure = pressureData[dofIdx]; // oil pressure (or gas pressure for water-gas system or water pressure for single phase)
1452
1453 // this assumes that capillary pressures only depend on the phase saturations
1454 // and possibly on temperature. (this is always the case for ECL problems.)
1455 std::array<Scalar, numPhases> pc = {0};
1456 const auto& matParams = this->materialLawParams(dofIdx);
1457 MaterialLaw::capillaryPressures(pc, matParams, dofFluidState);
1458 Valgrind::CheckDefined(pressure);
1459 Valgrind::CheckDefined(pc);
1460 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1461 if (!FluidSystem::phaseIsActive(phaseIdx))
1462 continue;
1463
1464 if (Indices::oilEnabled)
1465 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
1466 else if (Indices::gasEnabled)
1467 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
1468 else if (Indices::waterEnabled)
1469 //single (water) phase
1470 dofFluidState.setPressure(phaseIdx, pressure);
1471 }
1472
1473 if constexpr (enableDissolvedGas) {
1474 if (FluidSystem::enableDissolvedGas())
1475 dofFluidState.setRs(rsData[dofIdx]);
1476 else if (Indices::gasEnabled && Indices::oilEnabled)
1477 dofFluidState.setRs(0.0);
1478 if (FluidSystem::enableVaporizedOil())
1479 dofFluidState.setRv(rvData[dofIdx]);
1480 else if (Indices::gasEnabled && Indices::oilEnabled)
1481 dofFluidState.setRv(0.0);
1482 }
1483
1484 if constexpr (enableDisgasInWater) {
1485 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1486 dofFluidState.setRsw(rswData[dofIdx]);
1487 }
1488
1489 if constexpr (enableVapwat) {
1490 if (FluidSystem::enableVaporizedWater())
1491 dofFluidState.setRvw(rvwData[dofIdx]);
1492 }
1493
1495 // set invB_
1497 for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1498 if (!FluidSystem::phaseIsActive(phaseIdx))
1499 continue;
1500
1501 const auto& b = FluidSystem::inverseFormationVolumeFactor(dofFluidState, phaseIdx, pvtRegionIndex(dofIdx));
1502 dofFluidState.setInvB(phaseIdx, b);
1503
1504 const auto& rho = FluidSystem::density(dofFluidState, phaseIdx, pvtRegionIndex(dofIdx));
1505 dofFluidState.setDensity(phaseIdx, rho);
1506
1507 }
1508 }
1509 }
1510
1511
1512 void processRestartSaturations_(InitialFluidState& elemFluidState, Scalar& solventSaturation)
1513 {
1514 // each phase needs to be above certain value to be claimed to be existing
1515 // this is used to recover some RESTART running with the defaulted single-precision format
1516 Scalar sumSaturation = 0.0;
1517 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1518 if (FluidSystem::phaseIsActive(phaseIdx)) {
1519 if (elemFluidState.saturation(phaseIdx) < smallSaturationTolerance_)
1520 elemFluidState.setSaturation(phaseIdx, 0.0);
1521
1522 sumSaturation += elemFluidState.saturation(phaseIdx);
1523 }
1524
1525 }
1526 if constexpr (enableSolvent) {
1527 if (solventSaturation < smallSaturationTolerance_)
1528 solventSaturation = 0.0;
1529
1530 sumSaturation += solventSaturation;
1531 }
1532
1533 assert(sumSaturation > 0.0);
1534
1535 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1536 if (FluidSystem::phaseIsActive(phaseIdx)) {
1537 const Scalar saturation = elemFluidState.saturation(phaseIdx) / sumSaturation;
1538 elemFluidState.setSaturation(phaseIdx, saturation);
1539 }
1540 }
1541 if constexpr (enableSolvent) {
1542 solventSaturation = solventSaturation / sumSaturation;
1543 }
1544 }
1545
1547 {
1548 FlowProblemType::readInitialCondition_();
1549
1550 if constexpr (enableSolvent || enablePolymer || enablePolymerMolarWeight || enableBioeffects)
1551 this->readBlackoilExtentionsInitialConditions_(this->model().numGridDof(),
1552 enableSolvent,
1553 enablePolymer,
1554 enablePolymerMolarWeight,
1555 enableBioeffects,
1556 enableMICP);
1557
1558 }
1559
1560 void handleSolventBC(const BCProp::BCFace& bc, RateVector& rate) const override
1561 {
1562 if constexpr (!enableSolvent)
1563 throw std::logic_error("solvent is disabled and you're trying to add solvent to BC");
1564
1565 rate[Indices::solventSaturationIdx] = bc.rate;
1566 }
1567
1568 void handlePolymerBC(const BCProp::BCFace& bc, RateVector& rate) const override
1569 {
1570 if constexpr (!enablePolymer)
1571 throw std::logic_error("polymer is disabled and you're trying to add polymer to BC");
1572
1573 rate[Indices::polymerConcentrationIdx] = bc.rate;
1574 }
1575
1576 void handleMicrBC(const BCProp::BCFace& bc, RateVector& rate) const override
1577 {
1578 if constexpr (!enableMICP)
1579 throw std::logic_error("MICP is disabled and you're trying to add microbes to BC");
1580
1581 rate[Indices::microbialConcentrationIdx] = bc.rate;
1582 }
1583
1584 void handleOxygBC(const BCProp::BCFace& bc, RateVector& rate) const override
1585 {
1586 if constexpr (!enableMICP)
1587 throw std::logic_error("MICP is disabled and you're trying to add oxygen to BC");
1588
1589 rate[Indices::oxygenConcentrationIdx] = bc.rate;
1590 }
1591
1592 void handleUreaBC(const BCProp::BCFace& bc, RateVector& rate) const override
1593 {
1594 if constexpr (!enableMICP)
1595 throw std::logic_error("MICP is disabled and you're trying to add urea to BC");
1596
1597 rate[Indices::ureaConcentrationIdx] = bc.rate;
1598 // since the urea concentration can be much larger than 1, then we apply a scaling factor
1599 rate[Indices::ureaConcentrationIdx] *= getPropValue<TypeTag, Properties::BlackOilUreaScalingFactor>();
1600 }
1601
1602 void updateExplicitQuantities_(const bool first_step_after_restart)
1603 {
1604 OPM_TIMEBLOCK(updateExplicitQuantities);
1605 const bool invalidateFromMaxWaterSat = this->updateMaxWaterSaturation_();
1606 const bool invalidateFromMinPressure = this->updateMinPressure_();
1607
1608 // update hysteresis and max oil saturation used in vappars
1609 const bool invalidateFromHyst = this->updateHysteresis_();
1610 const bool invalidateFromMaxOilSat = this->updateMaxOilSaturation_();
1611
1612 // deal with DRSDT and DRVDT
1613 const bool invalidateDRDT = !first_step_after_restart && this->updateCompositionChangeLimits_();
1614
1615 // the derivatives may have changed
1616 const bool invalidateIntensiveQuantities
1617 = invalidateFromMaxWaterSat || invalidateFromMinPressure || invalidateFromHyst || invalidateFromMaxOilSat || invalidateDRDT;
1618 if (invalidateIntensiveQuantities) {
1619 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
1620 this->model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0);
1621 }
1622
1623 this->updateRockCompTransMultVal_();
1624 }
1625
1627 {
1628 if (const auto nph = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)
1629 + FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)
1630 + FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
1631 nph < 2)
1632 {
1633 // Single phase runs don't need saturation functions and there's
1634 // nothing to do here. Return 'true' to tell caller that the
1635 // consistency requirements are Met.
1636 return true;
1637 }
1638
1639 const auto numSamplePoints = static_cast<std::size_t>
1640 (Parameters::Get<Parameters::NumSatfuncConsistencySamplePoints>());
1641
1642 auto sfuncConsistencyChecks =
1644 numSamplePoints, this->simulator().vanguard().eclState(),
1645 [&cmap = this->simulator().vanguard().cartesianIndexMapper()](const int elemIdx)
1646 { return cmap.cartesianIndex(elemIdx); }
1647 };
1648
1649 const auto ioRank = 0;
1650 const auto isIoRank = this->simulator().vanguard()
1651 .grid().comm().rank() == ioRank;
1652
1653 // Note: Run saturation function consistency checks on main grid
1654 // only (i.e., levelGridView(0)). These checks are not supported
1655 // for LGRs at this time.
1656 sfuncConsistencyChecks.collectFailuresTo(ioRank)
1657 .run(this->simulator().vanguard().grid().levelGridView(0),
1658 [&vg = this->simulator().vanguard(),
1659 &emap = this->simulator().model().elementMapper()]
1660 (const auto& elem)
1661 { return vg.gridIdxToEquilGridIdx(emap.index(elem)); });
1662
1663 using ViolationLevel = typename Satfunc::PhaseChecks::
1664 SatfuncConsistencyCheckManager<Scalar>::ViolationLevel;
1665
1666 auto reportFailures = [&sfuncConsistencyChecks]
1667 (const ViolationLevel level)
1668 {
1669 sfuncConsistencyChecks.reportFailures
1670 (level, [](std::string_view record)
1671 { OpmLog::info(std::string { record }); });
1672 };
1673
1674 if (sfuncConsistencyChecks.anyFailedStandardChecks()) {
1675 if (isIoRank) {
1676 OpmLog::warning("Saturation Function "
1677 "End-point Consistency Problems");
1678
1679 reportFailures(ViolationLevel::Standard);
1680 }
1681 }
1682
1683 if (sfuncConsistencyChecks.anyFailedCriticalChecks()) {
1684 if (isIoRank) {
1685 OpmLog::error("Saturation Function "
1686 "End-point Consistency Failures");
1687
1688 reportFailures(ViolationLevel::Critical);
1689 }
1690
1691 // There are "critical" check failures. Report that consistency
1692 // requirements are not Met.
1693 return false;
1694 }
1695
1696 // If we get here then there are no critical failures. Report
1697 // Met = true, i.e., that the consistency requirements ARE met.
1698 return true;
1699 }
1700
1702
1703 std::vector<InitialFluidState> initialFluidStates_;
1704
1706 std::unique_ptr<EclWriterType> eclWriter_;
1707
1708 const Scalar smallSaturationTolerance_ = 1.e-6;
1709#if HAVE_DAMARIS
1710 bool enableDamarisOutput_ = false ;
1711 std::unique_ptr<DamarisWriterType> damarisWriter_;
1712#endif
1714
1716
1717 ModuleParams moduleParams_;
1718
1720
1721private:
1732 bool episodeWillBeOver() const override
1733 {
1734 const auto currTime = this->simulator().time()
1735 + this->simulator().timeStepSize();
1736
1737 const auto nextReportStep =
1738 this->simulator().vanguard().schedule()
1739 .seconds(this->simulator().episodeIndex() + 1);
1740
1741 const auto isSubStep = (nextReportStep - currTime)
1742 > (2 * std::numeric_limits<float>::epsilon()) * nextReportStep;
1743
1744 return !isSubStep;
1745 }
1746};
1747
1748} // namespace Opm
1749
1750#endif // OPM_FLOW_PROBLEM_BLACK_HPP
Class handling Action support in simulator.
Definition: ActionHandler.hpp:52
static void setParams(BlackOilBioeffectsParams< Scalar > &&params)
Set parameters.
Definition: blackoilbioeffectsmodules.hh:131
static void setParams(BlackOilBrineParams< Scalar > &&params)
Set parameters.
Definition: blackoilbrinemodules.hh:88
static void setParams(BlackOilExtboParams< Scalar > &&params)
Set parameters.
Definition: blackoilextbomodules.hh:87
static void setParams(BlackOilFoamParams< Scalar > &&params)
Set parameters.
Definition: blackoilfoammodules.hh:88
Hybrid Newton solver extension for the black-oil model.
Definition: HybridNewton.hpp:59
void tryApplyHybridNewton()
Attempt to apply the Hybrid Newton correction at the current timestep.
Definition: HybridNewton.hpp:99
static void setParams(BlackOilPolymerParams< Scalar > &&params)
Set parameters.
Definition: blackoilpolymermodules.hh:95
static void setParams(BlackOilSolventParams< Scalar > &&params)
Set parameters.
Definition: blackoilsolventmodules.hh:99
Collects necessary output values and pass it to opm-common's ECL output.
Definition: EclWriter.hpp:115
static void registerParameters()
Definition: EclWriter.hpp:138
Computes the initial condition based on the EQUIL keyword from ECL.
Definition: EquilInitializer.hpp:59
BlackOilFluidState< Scalar, FluidSystem, energyModuleType==EnergyModules::ConstantTemperature,(energyModuleType==EnergyModules::FullyImplicitThermal||energyModuleType==EnergyModules::SequentialImplicitThermal), enableDissolution, enableVapwat, enableBrine, enableSaltPrecipitation, enableDisgasInWater, Indices::numPhases > ScalarFluidState
Definition: EquilInitializer.hpp:98
const ScalarFluidState & initialFluidState(unsigned elemIdx) const
Return the initial thermodynamic state which should be used as the initial condition.
Definition: EquilInitializer.hpp:198
void readRockParameters_(const std::vector< Scalar > &cellCenterDepths, std::function< std::array< int, 3 >(const unsigned)> ijkIndex)
Definition: FlowGenericProblem_impl.hpp:136
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblemBlackoil.hpp:84
HybridNewton hybridNewton_
Definition: FlowProblemBlackoil.hpp:1719
void updateExplicitQuantities_(int episodeIdx, int timeStepSize, const bool first_step_after_restart) override
Definition: FlowProblemBlackoil.hpp:1153
bool updateMaxPolymerAdsorption_(unsigned compressedDofIdx, const IntensiveQuantities &iq)
Definition: FlowProblemBlackoil.hpp:1173
void handlePolymerBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1568
void writeOutput(const bool verbose) override
Write the requested quantities of the current solution into the output files.
Definition: FlowProblemBlackoil.hpp:558
void readInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1546
void handleOxygBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1584
void readEquilInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1282
void handleSolventBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1560
Scalar maxGasDissolutionFactor(unsigned timeIdx, unsigned globalDofIdx) const
Returns the maximum value of the gas dissolution factor at the current time for a given degree of fre...
Definition: FlowProblemBlackoil.hpp:882
const std::vector< InitialFluidState > & initialFluidStates() const
Definition: FlowProblemBlackoil.hpp:746
void processRestartSaturations_(InitialFluidState &elemFluidState, Scalar &solventSaturation)
Definition: FlowProblemBlackoil.hpp:1512
std::vector< InitialFluidState > & initialFluidStates()
Definition: FlowProblemBlackoil.hpp:743
FlowProblemBlackoil(Simulator &simulator)
Definition: FlowProblemBlackoil.hpp:183
bool enableEclOutput_
Definition: FlowProblemBlackoil.hpp:1705
Scalar drsdtcon(unsigned elemIdx, int episodeIdx) const
Definition: FlowProblemBlackoil.hpp:964
void endStepApplyAction()
Definition: FlowProblemBlackoil.hpp:479
bool drsdtconIsActive(unsigned elemIdx, int episodeIdx) const
Definition: FlowProblemBlackoil.hpp:970
Scalar maxOilVaporizationFactor(unsigned timeIdx, unsigned globalDofIdx) const
Returns the maximum value of the oil vaporization factor at the current time for a given degree of fr...
Definition: FlowProblemBlackoil.hpp:893
std::vector< InitialFluidState > initialFluidStates_
Definition: FlowProblemBlackoil.hpp:1703
void endTimeStep() override
Called by the simulator after each time integration.
Definition: FlowProblemBlackoil.hpp:473
void updateMaxPolymerAdsorption_()
Definition: FlowProblemBlackoil.hpp:1163
const InitialFluidState & initialFluidState(unsigned globalDofIdx) const
Definition: FlowProblemBlackoil.hpp:740
void endEpisode() override
Called by the simulator after the end of an episode.
Definition: FlowProblemBlackoil.hpp:526
void setSubStepReport(const SimulatorReportSingle &report)
Definition: FlowProblemBlackoil.hpp:752
void initial(PrimaryVariables &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the initial value for a control volume.
Definition: FlowProblemBlackoil.hpp:924
void finishInit()
Called by the Opm::Simulator in order to initialize the problem.
Definition: FlowProblemBlackoil.hpp:282
void handleMicrBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1576
const FlowThresholdPressure< TypeTag > & thresholdPressure() const
Definition: FlowProblemBlackoil.hpp:1133
void finalizeOutput()
Definition: FlowProblemBlackoil.hpp:579
void boundary(BoundaryRateVector &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the boundary conditions for a boundary segment.
Definition: FlowProblemBlackoil.hpp:981
InitialFluidState boundaryFluidState(unsigned globalDofIdx, const int directionId) const
Definition: FlowProblemBlackoil.hpp:758
std::unique_ptr< EclWriterType > eclWriter_
Definition: FlowProblemBlackoil.hpp:1706
void initialSolutionApplied() override
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblemBlackoil.hpp:591
const ModuleParams & moduleParams() const
Definition: FlowProblemBlackoil.hpp:1139
void readEclRestartSolution_()
Definition: FlowProblemBlackoil.hpp:1252
FlowThresholdPressure< TypeTag > & thresholdPressure()
Definition: FlowProblemBlackoil.hpp:1136
FlowThresholdPressure< TypeTag > thresholdPressures_
Definition: FlowProblemBlackoil.hpp:1701
void readExplicitInitialCondition_() override
Definition: FlowProblemBlackoil.hpp:1297
void beginEpisode() override
Called by the simulator before an episode begins.
Definition: FlowProblemBlackoil.hpp:242
bool recycleFirstIterationStorage() const
Return if the storage term of the first iteration is identical to the storage term for the solution o...
Definition: FlowProblemBlackoil.hpp:908
LhsEval permFactTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Calculate the transmissibility multiplier due to porosity reduction.
Definition: FlowProblemBlackoil.hpp:720
void serializeOp(Serializer &serializer)
Definition: FlowProblemBlackoil.hpp:1145
MixingRateControls< FluidSystem > mixControls_
Definition: FlowProblemBlackoil.hpp:1713
void writeReports(const SimulatorTimer &timer)
Definition: FlowProblemBlackoil.hpp:546
ModuleParams moduleParams_
Definition: FlowProblemBlackoil.hpp:1717
const EclWriterType & eclWriter() const
Definition: FlowProblemBlackoil.hpp:872
void setSimulationReport(const SimulatorReport &report)
Definition: FlowProblemBlackoil.hpp:755
void addToSourceDense(RateVector &rate, unsigned globalDofIdx, unsigned timeIdx) const override
Definition: FlowProblemBlackoil.hpp:613
void computeAndSetEqWeights_()
Definition: FlowProblemBlackoil.hpp:1185
void beginTimeStep() override
Called by the simulator before each time integration.
Definition: FlowProblemBlackoil.hpp:273
void updateExplicitQuantities_(const bool first_step_after_restart)
Definition: FlowProblemBlackoil.hpp:1602
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblemBlackoil.hpp:169
ActionHandler< Scalar, IndexTraits > actionHandler_
Definition: FlowProblemBlackoil.hpp:1715
void readSolutionFromOutputModule(const int restart_step, bool fip_init)
Read simulator solution state from the outputmodule (used with restart)
Definition: FlowProblemBlackoil.hpp:1022
const EclipseIO & eclIO() const
Definition: FlowProblemBlackoil.hpp:749
Scalar thresholdPressure(unsigned elem1Idx, unsigned elem2Idx) const
Definition: FlowProblemBlackoil.hpp:1130
void handleUreaBC(const BCProp::BCFace &bc, RateVector &rate) const override
Definition: FlowProblemBlackoil.hpp:1592
EclWriterType & eclWriter()
Definition: FlowProblemBlackoil.hpp:875
bool satfuncConsistencyRequirementsMet() const
Definition: FlowProblemBlackoil.hpp:1626
bool updateCompositionChangeLimits_()
Definition: FlowProblemBlackoil.hpp:1219
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblem.hpp:95
@ enableSaltPrecipitation
Definition: FlowProblem.hpp:133
@ numComponents
Definition: FlowProblem.hpp:118
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition: FlowProblem.hpp:486
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:836
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:669
GetPropType< TypeTag, Properties::Vanguard > Vanguard
Definition: FlowProblem.hpp:108
@ gasPhaseIdx
Definition: FlowProblem.hpp:137
GetPropType< TypeTag, Properties::Scalar > Scalar
Definition: FlowProblem.hpp:102
GetPropType< TypeTag, Properties::EqVector > EqVector
Definition: FlowProblem.hpp:107
@ enablePolymer
Definition: FlowProblem.hpp:131
@ waterPhaseIdx
Definition: FlowProblem.hpp:139
GetPropType< TypeTag, Properties::ElementContext > ElementContext
Definition: FlowProblem.hpp:151
@ numPhases
Definition: FlowProblem.hpp:117
GlobalEqVector drift_
Definition: FlowProblem.hpp:1722
@ enableExperiments
Definition: FlowProblem.hpp:127
GetPropType< TypeTag, Properties::RateVector > RateVector
Definition: FlowProblem.hpp:148
@ enableFoam
Definition: FlowProblem.hpp:129
Dune::FieldMatrix< Scalar, dimWorld, dimWorld > DimMatrix
Definition: FlowProblem.hpp:165
@ numEq
Definition: FlowProblem.hpp:116
int episodeIndex() const
Definition: FlowProblem.hpp:289
GetPropType< TypeTag, Properties::Indices > Indices
Definition: FlowProblem.hpp:109
@ dimWorld
Definition: FlowProblem.hpp:113
@ gasCompIdx
Definition: FlowProblem.hpp:143
GetPropType< TypeTag, Properties::GlobalEqVector > GlobalEqVector
Definition: FlowProblem.hpp:106
@ enableMICP
Definition: FlowProblem.hpp:130
GetPropType< TypeTag, Properties::Simulator > Simulator
Definition: FlowProblem.hpp:149
@ enableBrine
Definition: FlowProblem.hpp:121
@ enableSolvent
Definition: FlowProblem.hpp:134
TracerModel tracerModel_
Definition: FlowProblem.hpp:1728
WellModel wellModel_
Definition: FlowProblem.hpp:1724
virtual void beginEpisode()
Called by the simulator before an episode begins.
Definition: FlowProblem.hpp:297
@ enablePolymerMolarWeight
Definition: FlowProblem.hpp:132
virtual void beginTimeStep()
Called by the simulator before each time integration.
Definition: FlowProblem.hpp:354
@ enableExtbo
Definition: FlowProblem.hpp:128
void readThermalParameters_()
Definition: FlowProblem.hpp:1401
@ waterCompIdx
Definition: FlowProblem.hpp:145
@ enableThermalFluxBoundaries
Definition: FlowProblem.hpp:135
GetPropType< TypeTag, Properties::IntensiveQuantities > IntensiveQuantities
Definition: FlowProblem.hpp:160
@ enableConvectiveMixing
Definition: FlowProblem.hpp:122
@ enableBioeffects
Definition: FlowProblem.hpp:120
TemperatureModel temperatureModel_
Definition: FlowProblem.hpp:1729
GetPropType< TypeTag, Properties::GridView > GridView
Definition: FlowProblem.hpp:103
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblem.hpp:182
void updatePffDofData_()
Definition: FlowProblem.hpp:1515
GetPropType< TypeTag, Properties::PrimaryVariables > PrimaryVariables
Definition: FlowProblem.hpp:147
@ oilCompIdx
Definition: FlowProblem.hpp:144
void readBoundaryConditions_()
Definition: FlowProblem.hpp:1546
Vanguard::TransmissibilityType transmissibilities_
Definition: FlowProblem.hpp:1717
static constexpr EnergyModules energyModuleType
Definition: FlowProblem.hpp:125
@ enableDispersion
Definition: FlowProblem.hpp:124
@ oilPhaseIdx
Definition: FlowProblem.hpp:138
GetPropType< TypeTag, Properties::FluidSystem > FluidSystem
Definition: FlowProblem.hpp:105
GetPropType< TypeTag, Properties::MaterialLaw > MaterialLaw
Definition: FlowProblem.hpp:157
@ dim
Definition: FlowProblem.hpp:112
@ enableDiffusion
Definition: FlowProblem.hpp:123
void readMaterialParameters_()
Definition: FlowProblem.hpp:1367
This class calculates the threshold pressure for grid faces according to the Eclipse Reference Manual...
Definition: FlowThresholdPressure.hpp:59
Class handling mixing rate controls for a FlowProblemBlackoil.
Definition: MixingRateControls.hpp:46
Definition: SatfuncConsistencyCheckManager.hpp:58
SatfuncConsistencyCheckManager & collectFailuresTo(const int root)
Definition: SatfuncConsistencyCheckManager.hpp:99
void run(const GridView &gv, GetCellIndex &&getCellIndex)
Definition: SatfuncConsistencyCheckManager.hpp:128
Definition: SimulatorTimer.hpp:39
VTK output module for the tracer model's parameters.
Definition: VtkTracerModule.hpp:58
static void registerParameters()
Register all run-time parameters for the tracer VTK output module.
Definition: VtkTracerModule.hpp:84
@ NONE
Definition: DeferredLogger.hpp:46
static constexpr int dim
Definition: structuredgridvanguard.hh:68
Definition: blackoilbioeffectsmodules.hh:43
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(....
Definition: propertysystem.hh:233
Struct holding the parameters for the BlackOilBioeffectsModule class.
Definition: blackoilbioeffectsparams.hpp:44
Struct holding the parameters for the BlackoilBrineModule class.
Definition: blackoilbrineparams.hpp:44
Struct holding the parameters for the BlackoilExtboModule class.
Definition: blackoilextboparams.hpp:49
Struct holding the parameters for the BlackoilFoamModule class.
Definition: blackoilfoamparams.hpp:46
Struct holding the parameters for the BlackOilPolymerModule class.
Definition: blackoilpolymerparams.hpp:45
Struct holding the parameters for the BlackOilSolventModule class.
Definition: blackoilsolventparams.hpp:49
Definition: SimulatorReport.hpp:122
A struct for returning timing data from a simulator to its caller.
Definition: SimulatorReport.hpp:34