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