31 #ifndef OPM_FLOW_PROBLEM_BLACK_HPP 32 #define OPM_FLOW_PROBLEM_BLACK_HPP 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 #include <opm/material/fluidsystems/blackoilpvt/ConstantRsDeadOilPvt.hpp> 44 #include <opm/models/blackoil/blackoilmoduleparams.hh> 46 #include <opm/output/eclipse/EclipseIO.hpp> 48 #include <opm/input/eclipse/Units/Units.hpp> 50 #include <opm/simulators/flow/ActionHandler.hpp> 57 #include <opm/simulators/flow/HybridNewton.hpp> 58 #include <opm/simulators/flow/HybridNewtonConfig.hpp> 60 #include <opm/simulators/utils/satfunc/SatfuncConsistencyCheckManager.hpp> 73 #include <string_view> 84 template <
class TypeTag>
92 using typename FlowProblemType::Scalar;
93 using typename FlowProblemType::Simulator;
94 using typename FlowProblemType::GridView;
95 using typename FlowProblemType::FluidSystem;
96 using typename FlowProblemType::Vanguard;
97 using typename FlowProblemType::GlobalEqVector;
98 using typename FlowProblemType::EqVector;
99 using FlowProblemType::dim;
100 using FlowProblemType::dimWorld;
101 using FlowProblemType::numEq;
102 using FlowProblemType::numPhases;
103 using FlowProblemType::numComponents;
106 using FlowProblemType::enableBioeffects;
107 using FlowProblemType::enableBrine;
108 using FlowProblemType::enableConvectiveMixing;
109 using FlowProblemType::enableDiffusion;
110 using FlowProblemType::enableDispersion;
111 using FlowProblemType::energyModuleType;
112 using FlowProblemType::enableExperiments;
113 using FlowProblemType::enableExtbo;
114 using FlowProblemType::enableFoam;
115 using FlowProblemType::enableMICP;
116 using FlowProblemType::enablePolymer;
117 using FlowProblemType::enablePolymerMolarWeight;
118 using FlowProblemType::enableSaltPrecipitation;
119 using FlowProblemType::enableSolvent;
120 using FlowProblemType::enableThermalFluxBoundaries;
122 using FlowProblemType::gasPhaseIdx;
123 using FlowProblemType::oilPhaseIdx;
124 using FlowProblemType::waterPhaseIdx;
126 using FlowProblemType::waterCompIdx;
127 using FlowProblemType::oilCompIdx;
128 using FlowProblemType::gasCompIdx;
131 using typename FlowProblemType::RateVector;
132 using typename FlowProblemType::PrimaryVariables;
133 using typename FlowProblemType::Indices;
134 using typename FlowProblemType::IntensiveQuantities;
135 using typename FlowProblemType::ElementContext;
137 using typename FlowProblemType::MaterialLaw;
138 using typename FlowProblemType::DimMatrix;
140 enum { enableDissolvedGas = Indices::compositionSwitchIdx >= 0 };
141 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
142 enum { enableDisgasInWater = getPropValue<TypeTag, Properties::EnableDisgasInWater>() };
143 enum { enableGeochemistry = getPropValue<TypeTag, Properties::EnableGeochemistry>() };
144 enum { enableMech = getPropValue<TypeTag, Properties::EnableMech>() };
158 using InitialFluidState =
typename EquilInitializer<TypeTag>::ScalarFluidState;
160 using IndexTraits =
typename FluidSystem::IndexTraitsType;
177 EclWriterType::registerParameters();
179 DamarisWriterType::registerParameters();
189 , thresholdPressures_(simulator)
190 , mixControls_(simulator.vanguard().schedule())
191 , actionHandler_(simulator.vanguard().eclState(),
192 simulator.vanguard().schedule(),
193 simulator.vanguard().actionState(),
194 simulator.vanguard().summaryState(),
196 simulator.vanguard().grid().comm())
197 , hybridNewton_(simulator)
202 const auto& vanguard = simulator.vanguard();
205 brineParams.template initFromState<enableBrine,
206 enableSaltPrecipitation>(vanguard.eclState());
209 DiffusionModule::initFromState(vanguard.eclState());
210 DispersionModule::initFromState(vanguard.eclState());
213 extboParams.template initFromState<enableExtbo>(vanguard.eclState());
217 foamParams.template initFromState<enableFoam>(vanguard.eclState());
221 bioeffectsParams.template initFromState<enableBioeffects, enableMICP>(vanguard.eclState());
225 polymerParams.template initFromState<enablePolymer, enablePolymerMolarWeight>(vanguard.eclState());
229 solventParams.template initFromState<enableSolvent>(vanguard.eclState(), vanguard.schedule());
233 eclWriter_ = std::make_unique<EclWriterType>(simulator);
234 enableEclOutput_ = Parameters::Get<Parameters::EnableEclOutput>();
237 if constexpr (!enableGeochemistry) {
238 if (vanguard.eclState().runspec().geochem().enabled()) {
239 throw std::runtime_error(
"GEOCHEM keyword in the deck but geochemistry module " 240 "was disabled at compile time!");
245 if constexpr (!enableMech) {
246 const auto& rspec = vanguard.eclState().runspec();
247 if (rspec.mech() && rspec.mechSolver().tpsa()) {
248 throw std::runtime_error(
"TPSA solver enabled in the deck, but geomechanics " 249 "module was disabled at compile time!");
255 damarisWriter_ = std::make_unique<DamarisWriterType>(simulator);
256 enableDamarisOutput_ = Parameters::Get<Parameters::EnableDamarisOutput>();
267 auto& simulator = this->simulator();
269 const int episodeIdx = simulator.episodeIndex();
270 const auto& schedule = simulator.vanguard().schedule();
275 .evalUDQAssignments(episodeIdx, simulator.vanguard().udqState());
277 if (episodeIdx >= 0) {
278 const auto& oilVap = schedule[episodeIdx].oilvap();
279 if (oilVap.getType() == OilVaporizationProperties::OilVaporization::VAPPARS) {
280 FluidSystem::setVapPars(oilVap.vap1(), oilVap.vap2());
283 FluidSystem::setVapPars(0.0, 0.0);
287 ConvectiveMixingModule::beginEpisode(simulator.vanguard().eclState(), schedule, episodeIdx,
288 this->moduleParams_.convectiveMixingModuleParam);
308 FlowProblemType::finishInit();
310 auto& simulator = this->simulator();
312 auto finishTransmissibilities = [updated =
false,
this]()
mutable 314 if (updated) {
return; }
316 this->transmissibilities_.finishInit([&vg = this->simulator().vanguard()](
const unsigned int it) {
317 return vg.gridIdxToEquilGridIdx(it);
327 if (enableEclOutput_) {
328 if (simulator.vanguard().grid().comm().size() > 1) {
329 if (simulator.vanguard().grid().comm().rank() == 0)
330 eclWriter_->setTransmissibilities(&simulator.vanguard().globalTransmissibility());
332 finishTransmissibilities();
333 eclWriter_->setTransmissibilities(&simulator.problem().eclTransmissibilities());
336 std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](
unsigned int i) {
337 return simulator.vanguard().gridEquilIdxToGridIdx(i);
340 this->eclWriter_->extractOutputTransAndNNC(equilGridToGrid);
342 simulator.vanguard().releaseGlobalTransmissibilities();
344 const auto& eclState = simulator.vanguard().eclState();
345 const auto& schedule = simulator.vanguard().schedule();
348 simulator.setStartTime(schedule.getStartTime());
349 simulator.setEndTime(schedule.simTime(schedule.size() - 1));
355 simulator.setEpisodeIndex(-1);
356 simulator.setEpisodeLength(0.0);
361 this->gravity_ = 0.0;
362 if (Parameters::Get<Parameters::EnableGravity>() &&
363 eclState.getInitConfig().hasGravity())
366 this->gravity_[dim - 1] = unit::gravity;
369 if (this->enableTuning_) {
372 const auto& tuning = schedule[0].tuning();
373 this->initialTimeStepSize_ = tuning.TSINIT.has_value() ? tuning.TSINIT.value() : -1.0;
374 this->maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
379 bool isThermal = eclState.getSimulationConfig().isThermal();
380 bool isTemp = eclState.getSimulationConfig().isTemp();
381 bool conserveInnerEnergy = isTemp || (isThermal && Parameters::Get<Parameters::ConserveInnerEnergyThermal>());
382 FluidSystem::setEnergyEqualEnthalpy(conserveInnerEnergy);
384 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
385 FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
386 this->maxOilSaturation_.resize(this->model().numGridDof(), 0.0);
389 this->readRockParameters_(simulator.vanguard().cellCenterDepths(),
390 [&simulator](
const unsigned idx)
392 std::array<int,dim> coords;
393 simulator.vanguard().cartesianCoordinate(idx, coords);
394 std::ranges::transform(coords, coords.begin(),
395 [](
const auto c) {
return c + 1; });
399 this->readMaterialParameters_();
400 this->readThermalParameters_();
403 if (enableEclOutput_) {
404 this->eclWriter_->writeInit();
407 finishTransmissibilities();
409 const auto& initconfig = eclState.getInitConfig();
410 this->tracerModel_.init(initconfig.restartRequested());
411 if (initconfig.restartRequested()) {
412 this->readEclRestartSolution_();
415 this->readInitialCondition_();
417 this->temperatureModel_.init();
418 this->tracerModel_.prepareTracerBatches();
420 this->updatePffDofData_();
422 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>()) {
423 const auto& vanguard = this->simulator().vanguard();
424 const auto& gridView = vanguard.gridView();
425 const int numElements = gridView.size(0);
426 this->polymer_.maxAdsorption.resize(numElements, 0.0);
429 this->readBoundaryConditions_();
432 this->computeAndSetEqWeights_();
434 if (this->enableDriftCompensation_ || this->enableDriftCompensationTemp_) {
435 this->drift_.resize(this->model().numGridDof());
442 if (!initconfig.restartRequested() && !eclState.getIOConfig().initOnly()) {
443 simulator.startNextEpisode(schedule.seconds(1));
444 simulator.setEpisodeIndex(0);
445 simulator.setTimeStepIndex(0);
448 if (Parameters::Get<Parameters::CheckSatfuncConsistency>() &&
449 ! this->satfuncConsistencyRequirementsMet())
458 this->simulator().vanguard().grid().comm().barrier();
460 throw std::domain_error {
461 "Saturation function end-points do not " 462 "meet requisite consistency conditions" 469 this->mixControls_.init(this->model().numGridDof(),
470 this->episodeIndex(),
471 eclState.runspec().tabdims().getNumPVTTables());
473 if (this->enableVtkOutput_() && eclState.getIOConfig().initOnly()) {
474 simulator.setTimeStepSize(0.0);
475 simulator.model().applyInitialSolution();
479 if (!eclState.getIOConfig().initOnly()) {
480 if (!this->enableTuning_ && eclState.getSimulationConfig().anyTUNING()) {
481 OpmLog::info(
"\nThe deck has TUNING in the SCHEDULE section, but " 482 "it is ignored due\nto the flag --enable-tuning=false. " 483 "Set this flag to true to activate it.\n" 484 "Manually tuning the simulator with the TUNING keyword may " 485 "increase run time.\nIt is recommended using the simulator's " 486 "default tuning (--enable-tuning=false).");
497 this->endStepApplyAction();
500 void endStepApplyAction()
504 this->eclWriter().mutableOutputModule().invalidateLocalData();
507 const auto& grid = this->simulator().vanguard().gridView().grid();
509 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
510 constexpr
bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
511 if (!isCpGrid || (grid.maxLevel() == 0)) {
512 this->eclWriter_->evalSummaryState(!this->episodeWillBeOver());
516 OPM_TIMEBLOCK(applyActions);
518 const int episodeIdx = this->episodeIndex();
519 auto& simulator = this->simulator();
523 this->simulator().vanguard().schedule().clearEvents(episodeIdx);
527 .applyActions(episodeIdx, simulator.time() + simulator.timeStepSize(),
528 [
this](
const bool global)
530 using TransUpdateQuantities =
typename 531 Vanguard::TransmissibilityType::TransUpdateQuantities;
533 this->transmissibilities_
534 .update(global, TransUpdateQuantities::All,
535 [&vg = this->simulator().vanguard()]
536 (
const unsigned int i)
538 return vg.gridIdxToEquilGridIdx(i);
562 .evalUDQAssignments(this->episodeIndex(), this->simulator().vanguard().udqState());
569 if (this->enableEclOutput_) {
570 this->eclWriter_->writeReports(timer);
583 const auto isSubStep = !this->episodeWillBeOver();
585 auto localCellData = data::Solution {};
590 if (this->enableDamarisOutput_ && (this->damarisWriter_ !=
nullptr)) {
591 this->damarisWriter_->writeOutput(localCellData, isSubStep);
595 if (this->enableEclOutput_ && (this->eclWriter_ !=
nullptr)) {
596 this->eclWriter_->writeOutput(std::move(localCellData), isSubStep,
597 this->simulator().vanguard().schedule()
598 .exitStatus().has_value());
602 void finalizeOutput()
604 OPM_TIMEBLOCK(finalizeOutput);
621 this->thresholdPressures_.finishInit();
624 const auto& grid = this->simulator().vanguard().gridView().grid();
626 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
627 constexpr
bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
629 if (!isCpGrid || (grid.maxLevel() == 0)) {
630 if (this->simulator().episodeIndex() == 0) {
631 eclWriter_->writeInitialFIPReport();
636 void addToSourceDense(RateVector& rate,
637 unsigned globalDofIdx,
638 unsigned timeIdx)
const override 640 this->aquiferModel_.addToSource(rate, globalDofIdx, timeIdx);
643 const auto&
source = this->simulator().vanguard().schedule()[this->episodeIndex()].source();
644 std::array<int,3> ijk;
645 this->simulator().vanguard().cartesianCoordinate(globalDofIdx, ijk);
647 if (
source.hasSource(ijk)) {
649 static std::array<SourceComponent, 3> sc_map = {SourceComponent::WATER, SourceComponent::OIL, SourceComponent::GAS};
650 static std::array<int, 3> phidx_map = {FluidSystem::waterPhaseIdx, FluidSystem::oilPhaseIdx, FluidSystem::gasPhaseIdx};
651 static std::array<int, 3> cidx_map = {waterCompIdx, oilCompIdx, gasCompIdx};
653 for (
unsigned i = 0; i < phidx_map.size(); ++i) {
654 const auto phaseIdx = phidx_map[i];
655 const auto sourceComp = sc_map[i];
656 const auto compIdx = cidx_map[i];
657 if (!FluidSystem::phaseIsActive(phaseIdx)) {
660 Scalar mass_rate =
source.rate(ijk, sourceComp) / this->model().dofTotalVolume(globalDofIdx);
661 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
662 mass_rate /= FluidSystem::referenceDensity(phaseIdx, pvtRegionIdx);
664 rate[FluidSystem::canonicalToActiveCompIdx(compIdx)] += mass_rate;
667 if constexpr (enableSolvent) {
668 Scalar mass_rate =
source.rate(ijk, SourceComponent::SOLVENT) / this->model().dofTotalVolume(globalDofIdx);
669 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
670 const auto& solventPvt = SolventModule::solventPvt();
671 mass_rate /= solventPvt.referenceDensity(pvtRegionIdx);
673 rate[Indices::contiSolventEqIdx] += mass_rate;
675 if constexpr (enablePolymer) {
676 rate[Indices::polymerConcentrationIdx] +=
source.rate(ijk, SourceComponent::POLYMER) / this->model().dofTotalVolume(globalDofIdx);
678 if constexpr (enableMICP) {
679 rate[Indices::microbialConcentrationIdx] +=
source.rate(ijk, SourceComponent::MICR) / this->model().dofTotalVolume(globalDofIdx);
680 rate[Indices::oxygenConcentrationIdx] +=
source.rate(ijk, SourceComponent::OXYG) / this->model().dofTotalVolume(globalDofIdx);
681 rate[Indices::ureaConcentrationIdx] +=
source.rate(ijk, SourceComponent::UREA) / (this->model().dofTotalVolume(globalDofIdx));
683 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
684 for (
unsigned i = 0; i < phidx_map.size(); ++i) {
685 const auto phaseIdx = phidx_map[i];
686 if (!FluidSystem::phaseIsActive(phaseIdx)) {
689 const auto sourceComp = sc_map[i];
690 const auto source_hrate =
source.hrate(ijk, sourceComp);
692 rate[Indices::contiEnergyEqIdx] += source_hrate.value() / this->model().dofTotalVolume(globalDofIdx);
694 const auto& intQuants = this->simulator().model().intensiveQuantities(globalDofIdx, 0);
695 auto fs = intQuants.fluidState();
697 const auto source_temp =
source.temperature(ijk, sourceComp);
702 const auto& h = FluidSystem::enthalpy(fs, phaseIdx, pvtRegionIdx);
703 Scalar mass_rate =
source.rate(ijk, sourceComp)/ this->model().dofTotalVolume(globalDofIdx);
704 Scalar energy_rate = getValue(h)*mass_rate;
705 rate[Indices::contiEnergyEqIdx] += energy_rate;
713 if (this->enableDriftCompensation_) {
714 const auto& simulator = this->simulator();
715 const auto& model = this->model();
720 Scalar maxCompensation = model.newtonMethod().tolerance()/10;
721 Scalar poro = this->
porosity(globalDofIdx, timeIdx);
722 Scalar dt = simulator.timeStepSize();
723 EqVector dofDriftRate = this->drift_[globalDofIdx];
724 dofDriftRate /= dt*model.dofTotalVolume(globalDofIdx);
727 for (
unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
728 Scalar cnv = std::abs(dofDriftRate[eqIdx])*dt*model.eqWeight(globalDofIdx, eqIdx)/poro;
729 if (cnv > maxCompensation) {
730 dofDriftRate[eqIdx] *= maxCompensation/cnv;
734 for (
unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
735 rate[eqIdx] -= dofDriftRate[eqIdx];
742 template <
class LhsEval,
class Callback>
746 if constexpr (enableSaltPrecipitation) {
747 const auto& fs = intQuants.fluidState();
748 unsigned tableIdx = this->simulator().problem().satnumRegionIndex(elementIdx);
749 LhsEval porosityFactor = obtain(1. - fs.saltSaturation());
750 porosityFactor = min(porosityFactor, 1.0);
751 const auto& permfactTable = BrineModule::permfactTable(tableIdx);
752 return permfactTable.eval(porosityFactor,
true);
754 else if constexpr (enableBioeffects) {
755 return obtain(intQuants.permFactor());
763 const InitialFluidState& initialFluidState(
unsigned globalDofIdx)
const 764 {
return initialFluidStates_[globalDofIdx]; }
766 std::vector<InitialFluidState>& initialFluidStates()
767 {
return initialFluidStates_; }
769 const std::vector<InitialFluidState>& initialFluidStates()
const 770 {
return initialFluidStates_; }
772 const EclipseIO& eclIO()
const 773 {
return eclWriter_->eclIO(); }
775 void setSubStepReport(
const SimulatorReportSingle& report)
776 {
return eclWriter_->setSubStepReport(report); }
778 void setSimulationReport(
const SimulatorReport& report)
779 {
return eclWriter_->setSimulationReport(report); }
781 InitialFluidState boundaryFluidState(
unsigned globalDofIdx,
const int directionId)
const 783 OPM_TIMEBLOCK_LOCAL(boundaryFluidState, Subsystem::Assembly);
784 const auto& bcprop = this->simulator().vanguard().schedule()[this->episodeIndex()].bcprop;
785 if (bcprop.size() > 0) {
786 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
790 if (this->bcindex_(dir)[globalDofIdx] == 0)
791 return initialFluidStates_[globalDofIdx];
793 const auto& bc = bcprop[this->bcindex_(dir)[globalDofIdx]];
794 if (bc.bctype == BCType::DIRICHLET )
796 InitialFluidState fluidState;
798 fluidState.setPvtRegionIndex(pvtRegionIdx);
800 switch (bc.component) {
801 case BCComponent::OIL:
802 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx))
803 throw std::logic_error(
"oil is not active and you're trying to add oil BC");
805 fluidState.setSaturation(FluidSystem::oilPhaseIdx, 1.0);
807 case BCComponent::GAS:
808 if (!FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx))
809 throw std::logic_error(
"gas is not active and you're trying to add gas BC");
811 fluidState.setSaturation(FluidSystem::gasPhaseIdx, 1.0);
813 case BCComponent::WATER:
814 if (!FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
815 throw std::logic_error(
"water is not active and you're trying to add water BC");
817 fluidState.setSaturation(FluidSystem::waterPhaseIdx, 1.0);
819 case BCComponent::SOLVENT:
820 case BCComponent::POLYMER:
821 case BCComponent::MICR:
822 case BCComponent::OXYG:
823 case BCComponent::UREA:
824 case BCComponent::NONE:
825 throw std::logic_error(
"you need to specify a valid component (OIL, WATER or GAS) when DIRICHLET type is set in BC");
827 fluidState.setTotalSaturation(1.0);
828 double pressure = initialFluidStates_[globalDofIdx].pressure(this->refPressurePhaseIdx_());
829 const auto pressure_input = bc.pressure;
830 if (pressure_input) {
831 pressure = *pressure_input;
834 std::array<Scalar, numPhases> pc = {0};
836 MaterialLaw::capillaryPressures(pc, matParams, fluidState);
837 Valgrind::CheckDefined(pressure);
838 Valgrind::CheckDefined(pc);
839 for (
unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
840 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
841 if (Indices::oilEnabled)
842 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
843 else if (Indices::gasEnabled)
844 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
845 else if (Indices::waterEnabled)
847 fluidState.setPressure(phaseIdx, pressure);
849 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
850 double temperature = initialFluidStates_[globalDofIdx].temperature(0);
851 const auto temperature_input = bc.temperature;
852 if(temperature_input)
857 if constexpr (enableDissolvedGas) {
858 if (FluidSystem::enableDissolvedGas()) {
859 fluidState.setRs(0.0);
860 fluidState.setRv(0.0);
863 if constexpr (enableDisgasInWater) {
864 if (FluidSystem::enableDissolvedGasInWater()) {
865 fluidState.setRsw(0.0);
868 if constexpr (enableVapwat) {
869 if (FluidSystem::enableVaporizedWater()) {
870 fluidState.setRvw(0.0);
874 for (
unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
875 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
877 const auto& b = FluidSystem::inverseFormationVolumeFactor(fluidState, phaseIdx, pvtRegionIdx);
878 fluidState.setInvB(phaseIdx, b);
880 const auto& rho = FluidSystem::density(fluidState, phaseIdx, pvtRegionIdx);
881 fluidState.setDensity(phaseIdx, rho);
882 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
883 const auto& h = FluidSystem::enthalpy(fluidState, phaseIdx, pvtRegionIdx);
884 fluidState.setEnthalpy(phaseIdx, h);
887 fluidState.checkDefined();
891 return initialFluidStates_[globalDofIdx];
895 const EclWriterType& eclWriter()
const 896 {
return *eclWriter_; }
898 EclWriterType& eclWriter()
899 {
return *eclWriter_; }
907 return this->mixControls_.maxGasDissolutionFactor(timeIdx, globalDofIdx,
908 this->episodeIndex(),
918 return this->mixControls_.maxOilVaporizationFactor(timeIdx, globalDofIdx,
919 this->episodeIndex(),
933 int episodeIdx = this->episodeIndex();
934 return !this->mixControls_.drsdtActive(episodeIdx) &&
935 !this->mixControls_.drvdtActive(episodeIdx) &&
936 this->rockCompPoroMultWc_.empty() &&
937 this->rockCompPoroMult_.empty();
946 template <
class Context>
947 void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx)
const 949 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
951 values.setPvtRegionIndex(
pvtRegionIndex(context, spaceIdx, timeIdx));
952 values.assignNaive(initialFluidStates_[globalDofIdx]);
955 enableSolvent ? this->solventSaturation_[globalDofIdx] : 0.0,
956 enableSolvent ? this->solventRsw_[globalDofIdx] : 0.0);
958 if constexpr (enablePolymer)
959 values[Indices::polymerConcentrationIdx] = this->polymer_.concentration[globalDofIdx];
961 if constexpr (enablePolymerMolarWeight)
962 values[Indices::polymerMoleWeightIdx]= this->polymer_.moleWeight[globalDofIdx];
964 if constexpr (enableBrine) {
965 if (enableSaltPrecipitation && values.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp) {
966 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltSaturation();
969 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltConcentration();
973 if constexpr (enableBioeffects) {
974 values[Indices::microbialConcentrationIdx] = this->bioeffects_.microbialConcentration[globalDofIdx];
975 values[Indices::biofilmVolumeFractionIdx]= this->bioeffects_.biofilmVolumeFraction[globalDofIdx];
976 if constexpr (enableMICP) {
977 values[Indices::oxygenConcentrationIdx]= this->bioeffects_.oxygenConcentration[globalDofIdx];
978 values[Indices::ureaConcentrationIdx]= this->bioeffects_.ureaConcentration[globalDofIdx];
979 values[Indices::calciteVolumeFractionIdx]= this->bioeffects_.calciteVolumeFraction[globalDofIdx];
983 values.checkDefined();
987 Scalar drsdtcon(
unsigned elemIdx,
int episodeIdx)
const 989 return this->mixControls_.drsdtcon(elemIdx, episodeIdx,
993 bool drsdtconIsActive(
unsigned elemIdx,
int episodeIdx)
const 995 return this->mixControls_.drsdtConvective(episodeIdx, this->
pvtRegionIndex(elemIdx));
1003 template <
class Context>
1005 const Context& context,
1007 unsigned timeIdx)
const 1009 OPM_TIMEBLOCK_LOCAL(eclProblemBoundary, Subsystem::Assembly);
1010 if (!context.intersection(spaceIdx).boundary())
1013 if constexpr (energyModuleType != EnergyModules::FullyImplicitThermal || !enableThermalFluxBoundaries)
1021 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1022 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1023 values.setThermalFlow(context, spaceIdx, timeIdx, this->initialFluidStates_[globalDofIdx] );
1026 if (this->nonTrivialBoundaryConditions()) {
1027 unsigned indexInInside = context.intersection(spaceIdx).indexInInside();
1028 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1029 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1030 unsigned pvtRegionIdx =
pvtRegionIndex(context, spaceIdx, timeIdx);
1031 const auto [type, massrate] = this->boundaryCondition(globalDofIdx, indexInInside);
1032 if (type == BCType::THERMAL)
1033 values.setThermalFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1034 else if (type == BCType::FREE || type == BCType::DIRICHLET)
1035 values.setFreeFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1036 else if (type == BCType::RATE)
1037 values.setMassRate(massrate, pvtRegionIdx);
1047 auto& simulator = this->simulator();
1048 const auto& eclState = simulator.vanguard().eclState();
1050 std::size_t numElems = this->model().numGridDof();
1051 this->initialFluidStates_.resize(numElems);
1052 if constexpr (enableSolvent) {
1053 this->solventSaturation_.resize(numElems, 0.0);
1054 this->solventRsw_.resize(numElems, 0.0);
1057 if constexpr (enablePolymer)
1058 this->polymer_.concentration.resize(numElems, 0.0);
1060 if constexpr (enablePolymerMolarWeight) {
1061 const std::string msg {
"Support of the RESTART for polymer molecular weight " 1062 "is not implemented yet. The polymer weight value will be " 1063 "zero when RESTART begins"};
1064 OpmLog::warning(
"NO_POLYMW_RESTART", msg);
1065 this->polymer_.moleWeight.resize(numElems, 0.0);
1068 if constexpr (enableBioeffects) {
1069 this->bioeffects_.resize(numElems);
1073 this->mixControls_.init(numElems, restart_step, eclState.runspec().tabdims().getNumPVTTables());
1075 if constexpr (enableBioeffects) {
1076 this->bioeffects_ = this->eclWriter_->outputModule().getBioeffects().getSolution();
1079 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1080 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1082 this->eclWriter_->outputModule().initHysteresisParams(simulator, elemIdx);
1083 this->eclWriter_->outputModule().assignToFluidState(elemFluidState, elemIdx);
1092 auto ssol = enableSolvent
1093 ? this->eclWriter_->outputModule().getSolventSaturation(elemIdx)
1096 this->processRestartSaturations_(elemFluidState, ssol);
1098 if constexpr (enableSolvent) {
1099 this->solventSaturation_[elemIdx] = ssol;
1100 this->solventRsw_[elemIdx] = this->eclWriter_->outputModule().getSolventRsw(elemIdx);
1105 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1106 bool needTemperature = (eclState.runspec().co2Storage() || eclState.runspec().h2Storage());
1107 if (needTemperature) {
1108 const auto& fp = simulator.vanguard().eclState().fieldProps();
1109 elemFluidState.setTemperature(fp.get_double(
"TEMPI")[elemIdx]);
1113 this->mixControls_.updateLastValues(elemIdx, elemFluidState.Rs(), elemFluidState.Rv());
1115 if constexpr (enablePolymer)
1116 this->polymer_.concentration[elemIdx] = this->eclWriter_->outputModule().getPolymerConcentration(elemIdx);
1120 const int episodeIdx = this->episodeIndex();
1121 this->mixControls_.updateMaxValues(episodeIdx, simulator.timeStepSize());
1126 auto& sol = this->model().solution(0);
1127 const auto& gridView = this->gridView();
1128 ElementContext elemCtx(simulator);
1129 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1130 elemCtx.updatePrimaryStencil(elem);
1131 int elemIdx = elemCtx.globalSpaceIndex(0, 0);
1132 this->
initial(sol[elemIdx], elemCtx, 0, 0);
1140 this->model().syncOverlap();
1143 this->updateReferencePorosity_();
1144 this->mixControls_.init(this->model().numGridDof(),
1145 this->episodeIndex(),
1146 eclState.runspec().tabdims().getNumPVTTables());
1154 {
return thresholdPressures_.thresholdPressure(elem1Idx, elem2Idx); }
1157 {
return thresholdPressures_; }
1159 FlowThresholdPressure<TypeTag>& thresholdPressure()
1160 {
return thresholdPressures_; }
1162 const ModuleParams& moduleParams()
const 1164 return moduleParams_;
1167 template<
class Serializer>
1168 void serializeOp(Serializer& serializer)
1170 serializer(static_cast<FlowProblemType&>(*
this));
1171 serializer(mixControls_);
1172 serializer(*eclWriter_);
1176 void updateExplicitQuantities_(
int episodeIdx,
int timeStepSize,
const bool first_step_after_restart)
override 1178 this->updateExplicitQuantities_(first_step_after_restart);
1180 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>())
1181 updateMaxPolymerAdsorption_();
1183 mixControls_.updateExplicitQuantities(episodeIdx, timeStepSize);
1186 void updateMaxPolymerAdsorption_()
1189 this->updateProperty_(
"FlowProblemBlackoil::updateMaxPolymerAdsorption_() failed:",
1190 [
this](
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1192 this->updateMaxPolymerAdsorption_(compressedDofIdx,iq);
1196 bool updateMaxPolymerAdsorption_(
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1198 const Scalar pa = scalarValue(iq.polymerAdsorption());
1199 auto& mpa = this->polymer_.maxAdsorption;
1200 if (mpa[compressedDofIdx] < pa) {
1201 mpa[compressedDofIdx] = pa;
1208 void computeAndSetEqWeights_()
1210 std::vector<Scalar> sumInvB(numPhases, 0.0);
1211 const auto& gridView = this->gridView();
1212 ElementContext elemCtx(this->simulator());
1213 for(
const auto& elem: elements(gridView, Dune::Partitions::interior)) {
1214 elemCtx.updatePrimaryStencil(elem);
1215 int elemIdx = elemCtx.globalSpaceIndex(0, 0);
1216 const auto& dofFluidState = this->initialFluidStates_[elemIdx];
1217 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1218 if (!FluidSystem::phaseIsActive(phaseIdx))
1221 sumInvB[phaseIdx] += dofFluidState.invB(phaseIdx);
1225 std::size_t numDof = this->model().numGridDof();
1226 const auto& comm = this->simulator().vanguard().grid().comm();
1227 comm.sum(sumInvB.data(),sumInvB.size());
1228 Scalar numTotalDof = comm.sum(numDof);
1230 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1231 if (!FluidSystem::phaseIsActive(phaseIdx))
1234 Scalar avgB = numTotalDof / sumInvB[phaseIdx];
1235 const unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
1236 const unsigned activeSolventCompIdx = FluidSystem::canonicalToActiveCompIdx(solventCompIdx);
1237 this->model().setEqWeight(activeSolventCompIdx, avgB);
1242 bool updateCompositionChangeLimits_()
1244 OPM_TIMEBLOCK(updateCompositionChangeLimits);
1247 int episodeIdx = this->episodeIndex();
1248 std::array<bool,3> active{this->mixControls_.drsdtConvective(episodeIdx),
1249 this->mixControls_.drsdtActive(episodeIdx),
1250 this->mixControls_.drvdtActive(episodeIdx)};
1251 if (!active[0] && !active[1] && !active[2]) {
1255 this->updateProperty_(
"FlowProblemBlackoil::updateCompositionChangeLimits_()) failed:",
1256 [
this,episodeIdx,active](
unsigned compressedDofIdx,
1257 const IntensiveQuantities& iq)
1260 const Scalar distZ = active[0] ? this->simulator().vanguard().cellThickness(compressedDofIdx) : 0.0;
1262 this->mixControls_.update(compressedDofIdx,
1265 this->gravity_[dim - 1],
1266 perm[dim - 1][dim - 1],
1275 void readEclRestartSolution_()
1278 if(this->simulator().vanguard().grid().maxLevel() > 0) {
1279 throw std::invalid_argument(
"Refined grids are not yet supported for restart ");
1283 auto& simulator = this->simulator();
1284 const auto& schedule = simulator.vanguard().schedule();
1285 const auto& eclState = simulator.vanguard().eclState();
1286 const auto& initconfig = eclState.getInitConfig();
1287 const int restart_step = initconfig.getRestartStep();
1289 simulator.setTime(schedule.seconds(restart_step));
1291 simulator.startNextEpisode(simulator.startTime() + simulator.time(),
1292 schedule.stepLength(restart_step));
1293 simulator.setEpisodeIndex(restart_step);
1295 this->eclWriter_->beginRestart();
1297 Scalar dt = std::min(this->eclWriter_->restartTimeStepSize(), simulator.episodeLength());
1298 simulator.setTimeStepSize(dt);
1302 this->eclWriter_->endRestart();
1305 void readEquilInitialCondition_()
override 1307 const auto& simulator = this->simulator();
1310 EquilInitializer<TypeTag> equilInitializer(simulator, *(this->materialLawManager_));
1312 std::size_t numElems = this->model().numGridDof();
1313 this->initialFluidStates_.resize(numElems);
1314 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1315 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1316 elemFluidState.assign(equilInitializer.initialFluidState(elemIdx));
1320 void readExplicitInitialCondition_()
override 1322 const auto& simulator = this->simulator();
1323 const auto& vanguard = simulator.vanguard();
1324 const auto& eclState = vanguard.eclState();
1325 const auto& fp = eclState.fieldProps();
1326 bool has_swat = fp.has_double(
"SWAT");
1327 bool has_sgas = fp.has_double(
"SGAS");
1328 bool has_rs = fp.has_double(
"RS");
1329 bool has_rsw = fp.has_double(
"RSW");
1330 bool has_rv = fp.has_double(
"RV");
1331 bool has_rvw = fp.has_double(
"RVW");
1332 bool has_pressure = fp.has_double(
"PRESSURE");
1333 bool has_salt = fp.has_double(
"SALT");
1334 bool has_saltp = fp.has_double(
"SALTP");
1337 if (Indices::numPhases > 1) {
1338 if (FluidSystem::phaseIsActive(waterPhaseIdx) && !has_swat)
1339 throw std::runtime_error(
"The ECL input file requires the presence of the SWAT keyword if " 1340 "the water phase is active");
1341 if (FluidSystem::phaseIsActive(gasPhaseIdx) && !has_sgas && FluidSystem::phaseIsActive(oilPhaseIdx))
1342 throw std::runtime_error(
"The ECL input file requires the presence of the SGAS keyword if " 1343 "the gas phase is active");
1346 throw std::runtime_error(
"The ECL input file requires the presence of the PRESSURE " 1347 "keyword if the model is initialized explicitly");
1348 if (FluidSystem::enableDissolvedGas() && !has_rs)
1349 throw std::runtime_error(
"The ECL input file requires the RS keyword to be present if" 1350 " dissolved gas is enabled and the model is initialized explicitly");
1351 if (FluidSystem::enableDissolvedGasInWater() && !has_rsw)
1352 OpmLog::warning(
"The model is initialized explicitly and the RSW keyword is not present in the" 1353 " ECL input file. The RSW values are set equal to 0");
1354 if (FluidSystem::enableVaporizedOil() && !has_rv)
1355 throw std::runtime_error(
"The ECL input file requires the RV keyword to be present if" 1356 " vaporized oil is enabled and the model is initialized explicitly");
1357 if (FluidSystem::enableVaporizedWater() && !has_rvw)
1358 throw std::runtime_error(
"The ECL input file requires the RVW keyword to be present if" 1359 " vaporized water is enabled and the model is initialized explicitly");
1360 if (enableBrine && !has_salt)
1361 throw std::runtime_error(
"The ECL input file requires the SALT keyword to be present if" 1362 " brine is enabled and the model is initialized explicitly");
1363 if (enableSaltPrecipitation && !has_saltp)
1364 throw std::runtime_error(
"The ECL input file requires the SALTP keyword to be present if" 1365 " salt precipitation is enabled and the model is initialized explicitly");
1367 std::size_t numDof = this->model().numGridDof();
1369 initialFluidStates_.resize(numDof);
1371 std::vector<double> waterSaturationData;
1372 std::vector<double> gasSaturationData;
1373 std::vector<double> pressureData;
1374 std::vector<double> rsData;
1375 std::vector<double> rswData;
1376 std::vector<double> rvData;
1377 std::vector<double> rvwData;
1378 std::vector<double> tempiData;
1379 std::vector<double> saltData;
1380 std::vector<double> saltpData;
1382 if (FluidSystem::phaseIsActive(waterPhaseIdx) && Indices::numPhases > 1)
1383 waterSaturationData = fp.get_double(
"SWAT");
1385 waterSaturationData.resize(numDof);
1387 if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(oilPhaseIdx))
1388 gasSaturationData = fp.get_double(
"SGAS");
1390 gasSaturationData.resize(numDof);
1392 pressureData = fp.get_double(
"PRESSURE");
1393 if (FluidSystem::enableDissolvedGas())
1394 rsData = fp.get_double(
"RS");
1396 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1397 rswData = fp.get_double(
"RSW");
1399 if (FluidSystem::enableVaporizedOil())
1400 rvData = fp.get_double(
"RV");
1402 if (FluidSystem::enableVaporizedWater())
1403 rvwData = fp.get_double(
"RVW");
1406 tempiData = fp.get_double(
"TEMPI");
1409 if constexpr (enableBrine)
1410 saltData = fp.get_double(
"SALT");
1413 if constexpr (enableSaltPrecipitation)
1414 saltpData = fp.get_double(
"SALTP");
1417 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1418 auto& dofFluidState = initialFluidStates_[dofIdx];
1425 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1426 Scalar temperatureLoc = tempiData[dofIdx];
1427 if (!std::isfinite(temperatureLoc) || temperatureLoc <= 0)
1428 temperatureLoc = FluidSystem::surfaceTemperature;
1429 dofFluidState.setTemperature(temperatureLoc);
1435 if constexpr (enableBrine)
1436 dofFluidState.setSaltConcentration(saltData[dofIdx]);
1441 if constexpr (enableSaltPrecipitation)
1442 dofFluidState.setSaltSaturation(saltpData[dofIdx]);
1447 if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
1448 dofFluidState.setSaturation(FluidSystem::waterPhaseIdx,
1449 waterSaturationData[dofIdx]);
1451 if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){
1452 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)){
1453 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1455 - waterSaturationData[dofIdx]);
1458 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1459 gasSaturationData[dofIdx]);
1461 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1462 const Scalar soil = 1.0 - waterSaturationData[dofIdx] - gasSaturationData[dofIdx];
1463 if (soil < smallSaturationTolerance_) {
1464 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, 0.0);
1467 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, soil);
1474 Scalar pressure = pressureData[dofIdx];
1478 std::array<Scalar, numPhases> pc = {0};
1480 MaterialLaw::capillaryPressures(pc, matParams, dofFluidState);
1481 Valgrind::CheckDefined(pressure);
1482 Valgrind::CheckDefined(pc);
1483 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1484 if (!FluidSystem::phaseIsActive(phaseIdx))
1487 if (Indices::oilEnabled)
1488 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
1489 else if (Indices::gasEnabled)
1490 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
1491 else if (Indices::waterEnabled)
1493 dofFluidState.setPressure(phaseIdx, pressure);
1496 if constexpr (enableDissolvedGas) {
1497 if (FluidSystem::enableDissolvedGas())
1498 dofFluidState.setRs(rsData[dofIdx]);
1499 else if (Indices::gasEnabled && Indices::oilEnabled)
1500 dofFluidState.setRs(0.0);
1501 if (FluidSystem::enableVaporizedOil())
1502 dofFluidState.setRv(rvData[dofIdx]);
1503 else if (Indices::gasEnabled && Indices::oilEnabled)
1504 dofFluidState.setRv(0.0);
1507 if constexpr (enableDisgasInWater) {
1508 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1509 dofFluidState.setRsw(rswData[dofIdx]);
1512 if constexpr (enableVapwat) {
1513 if (FluidSystem::enableVaporizedWater())
1514 dofFluidState.setRvw(rvwData[dofIdx]);
1520 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1521 if (!FluidSystem::phaseIsActive(phaseIdx))
1524 const auto& b = FluidSystem::inverseFormationVolumeFactor(dofFluidState, phaseIdx,
pvtRegionIndex(dofIdx));
1525 dofFluidState.setInvB(phaseIdx, b);
1527 const auto& rho = FluidSystem::density(dofFluidState, phaseIdx,
pvtRegionIndex(dofIdx));
1528 dofFluidState.setDensity(phaseIdx, rho);
1535 void processRestartSaturations_(InitialFluidState& elemFluidState, Scalar&
solventSaturation)
1539 Scalar sumSaturation = 0.0;
1540 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1541 if (FluidSystem::phaseIsActive(phaseIdx)) {
1542 if (elemFluidState.saturation(phaseIdx) < smallSaturationTolerance_)
1543 elemFluidState.setSaturation(phaseIdx, 0.0);
1545 sumSaturation += elemFluidState.saturation(phaseIdx);
1549 if constexpr (enableSolvent) {
1556 assert(sumSaturation > 0.0);
1558 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1559 if (FluidSystem::phaseIsActive(phaseIdx)) {
1560 const Scalar saturation = elemFluidState.saturation(phaseIdx) / sumSaturation;
1561 elemFluidState.setSaturation(phaseIdx, saturation);
1564 if constexpr (enableSolvent) {
1569 void readInitialCondition_()
override 1571 FlowProblemType::readInitialCondition_();
1573 if constexpr (enableSolvent || enablePolymer || enablePolymerMolarWeight || enableBioeffects)
1574 this->readBlackoilExtentionsInitialConditions_(this->model().numGridDof(),
1577 enablePolymerMolarWeight,
1583 void handleSolventBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1585 if constexpr (!enableSolvent)
1586 throw std::logic_error(
"solvent is disabled and you're trying to add solvent to BC");
1588 rate[Indices::solventSaturationIdx] = bc.rate;
1591 void handlePolymerBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1593 if constexpr (!enablePolymer)
1594 throw std::logic_error(
"polymer is disabled and you're trying to add polymer to BC");
1596 rate[Indices::polymerConcentrationIdx] = bc.rate;
1599 void handleMicrBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1601 if constexpr (!enableMICP)
1602 throw std::logic_error(
"MICP is disabled and you're trying to add microbes to BC");
1604 rate[Indices::microbialConcentrationIdx] = bc.rate;
1607 void handleOxygBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1609 if constexpr (!enableMICP)
1610 throw std::logic_error(
"MICP is disabled and you're trying to add oxygen to BC");
1612 rate[Indices::oxygenConcentrationIdx] = bc.rate;
1615 void handleUreaBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1617 if constexpr (!enableMICP)
1618 throw std::logic_error(
"MICP is disabled and you're trying to add urea to BC");
1620 rate[Indices::ureaConcentrationIdx] = bc.rate;
1622 rate[Indices::ureaConcentrationIdx] *= getPropValue<TypeTag, Properties::BlackOilUreaScalingFactor>();
1625 void updateExplicitQuantities_(
const bool first_step_after_restart)
1627 OPM_TIMEBLOCK(updateExplicitQuantities);
1628 const bool invalidateFromMaxWaterSat = this->updateMaxWaterSaturation_();
1629 const bool invalidateFromMinPressure = this->updateMinPressure_();
1632 const bool invalidateFromHyst = this->updateHysteresis_();
1633 const bool invalidateFromMaxOilSat = this->updateMaxOilSaturation_();
1636 const bool invalidateDRDT = !first_step_after_restart && this->updateCompositionChangeLimits_();
1639 const bool invalidateIntensiveQuantities
1640 = invalidateFromMaxWaterSat || invalidateFromMinPressure || invalidateFromHyst || invalidateFromMaxOilSat || invalidateDRDT;
1641 if (invalidateIntensiveQuantities) {
1642 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
1643 this->model().invalidateAndUpdateIntensiveQuantities(0);
1646 this->updateRockCompTransMultVal_();
1649 bool satfuncConsistencyRequirementsMet()
const 1651 if (
const auto nph = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)
1652 + FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)
1653 + FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
1662 const auto numSamplePoints =
static_cast<std::size_t
> 1663 (Parameters::Get<Parameters::NumSatfuncConsistencySamplePoints>());
1665 auto sfuncConsistencyChecks =
1666 Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar> {
1667 numSamplePoints, this->simulator().vanguard().eclState(),
1668 [&cmap = this->simulator().vanguard().cartesianIndexMapper()](
const int elemIdx)
1669 {
return cmap.cartesianIndex(elemIdx); }
1672 const auto ioRank = 0;
1673 const auto isIoRank = this->simulator().vanguard()
1674 .grid().comm().rank() == ioRank;
1679 sfuncConsistencyChecks.collectFailuresTo(ioRank)
1680 .run(this->simulator().vanguard().grid().levelGridView(0),
1681 [&vg = this->simulator().vanguard(),
1682 &emap = this->simulator().model().elementMapper()]
1684 {
return vg.gridIdxToEquilGridIdx(emap.index(elem)); });
1689 auto reportFailures = [&sfuncConsistencyChecks]
1690 (
const ViolationLevel level)
1692 sfuncConsistencyChecks.reportFailures
1693 (level, [](std::string_view record)
1694 { OpmLog::info(std::string { record }); });
1697 if (sfuncConsistencyChecks.anyFailedStandardChecks()) {
1699 OpmLog::warning(
"Saturation Function " 1700 "End-point Consistency Problems");
1702 reportFailures(ViolationLevel::Standard);
1706 if (sfuncConsistencyChecks.anyFailedCriticalChecks()) {
1708 OpmLog::error(
"Saturation Function " 1709 "End-point Consistency Failures");
1711 reportFailures(ViolationLevel::Critical);
1724 FlowThresholdPressure<TypeTag> thresholdPressures_;
1726 std::vector<InitialFluidState> initialFluidStates_;
1728 bool enableEclOutput_;
1729 std::unique_ptr<EclWriterType> eclWriter_;
1731 const Scalar smallSaturationTolerance_ = 1.e-6;
1733 bool enableDamarisOutput_ = false ;
1734 std::unique_ptr<DamarisWriterType> damarisWriter_;
1736 MixingRateControls<FluidSystem> mixControls_;
1738 ActionHandler<Scalar, IndexTraits> actionHandler_;
1740 ModuleParams moduleParams_;
1742 HybridNewton hybridNewton_;
1755 bool episodeWillBeOver()
const override 1757 const auto currTime = this->simulator().time()
1758 + this->simulator().timeStepSize();
1760 const auto nextReportStep =
1761 this->simulator().vanguard().schedule()
1762 .seconds(this->simulator().episodeIndex() + 1);
1764 const auto isSubStep = (nextReportStep - currTime)
1765 > (2 * std::numeric_limits<float>::epsilon()) * nextReportStep;
1773 #endif // OPM_FLOW_PROBLEM_BLACK_HPP Contains the high level supplements required to extend the black oil model by solvents.
Definition: blackoilsolventmodules.hh:68
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblemBlackoil.hpp:85
static void assignPrimaryVars(PrimaryVariables &priVars, Scalar solventSaturation, Scalar solventRsw)
Assign the solvent specific primary variables to a PrimaryVariables object.
Definition: blackoilsolventmodules.hh:288
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
This class calculates the threshold pressure for grid faces according to the Eclipse Reference Manual...
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:905
void boundary(BoundaryRateVector &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the boundary conditions for a boundary segment.
Definition: FlowProblemBlackoil.hpp:1004
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
Contains the high level supplements required to extend the black oil model to include the effects of ...
Definition: blackoilfoammodules.hh:59
void tryApplyHybridNewton()
Attempt to apply the Hybrid Newton correction at the current timestep.
Definition: HybridNewton.hpp:99
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblem.hpp:92
unsigned pvtRegionIndex(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Returns the index of the relevant region for thermodynmic properties.
Definition: FlowProblem.hpp:878
void initial(PrimaryVariables &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the initial value for a control volume.
Definition: FlowProblemBlackoil.hpp:947
const MaterialLawParams & materialLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:786
virtual void beginTimeStep()
Called by the simulator before each time integration.
Definition: FlowProblem.hpp:364
Scalar temperature(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:924
static void setParams(BlackOilExtboParams< Scalar > &¶ms)
Set parameters.
Definition: blackoilextbomodules.hh:89
This class calculates the threshold pressure for grid faces according to the Eclipse Reference Manual...
Definition: FlowThresholdPressure.hpp:55
Classes required for dynamic convective mixing.
void beginTimeStep() override
Called by the simulator before each time integration.
Definition: FlowProblemBlackoil.hpp:294
Struct holding the parameters for the BlackOilBioeffectsModule class.
Definition: blackoilbioeffectsparams.hpp:41
void endEpisode() override
Called by the simulator after the end of an episode.
Definition: FlowProblemBlackoil.hpp:547
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:916
static void setParams(BlackOilBrineParams< Scalar > &¶ms)
Set parameters.
Definition: blackoilbrinemodules.hh:90
static void setParams(BlackOilPolymerParams< Scalar > &¶ms)
Set parameters.
Definition: blackoilpolymermodules.hh:96
static void setParams(BlackOilSolventParams< Scalar > &¶ms)
Set parameters.
Definition: blackoilsolventmodules.hh:101
FlowProblemBlackoil(Simulator &simulator)
Definition: FlowProblemBlackoil.hpp:187
VTK output module for the tracer model's parameters.
Definition: VtkTracerModule.hpp:57
void writeOutput(const bool verbose) override
Write the requested quantities of the current solution into the output files.
Definition: FlowProblemBlackoil.hpp:579
Hybrid Newton solver extension for the black-oil model.
Definition: HybridNewton.hpp:58
Collects necessary output values and pass them to Damaris server processes.
Definition: DamarisWriter.hpp:85
LhsEval permFactTransMultiplier(const IntensiveQuantities &intQuants, unsigned elementIdx, Callback &obtain) const
Calculate the transmissibility multiplier due to porosity reduction.
Definition: FlowProblemBlackoil.hpp:743
Contains the high level supplements required to extend the black oil model by brine.
Definition: blackoilbrinemodules.hh:57
This file contains a set of helper functions used by VFPProd / VFPInj.
Definition: blackoilbioeffectsmodules.hh:45
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:681
void beginEpisode() override
Called by the simulator before an episode begins.
Definition: FlowProblemBlackoil.hpp:263
Struct holding the parameters for the BlackoilFoamModule class.
Definition: blackoilfoamparams.hpp:43
void endTimeStep() override
Called by the simulator after each time integration.
Definition: FlowProblemBlackoil.hpp:494
void finishInit()
Called by the Opm::Simulator in order to initialize the problem.
Definition: FlowProblemBlackoil.hpp:303
static void setParams(BlackOilBioeffectsParams< Scalar > &¶ms)
Set parameters.
Definition: blackoilbioeffectsmodules.hh:133
Scalar thresholdPressure(unsigned elem1Idx, unsigned elem2Idx) const
Definition: FlowProblemBlackoil.hpp:1153
Definition: blackoilconvectivemixingmodule.hh:99
const DimMatrix & intrinsicPermeability(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:514
Struct holding the parameters for the BlackoilBrineModule class.
Definition: blackoilbrineparams.hpp:41
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblemBlackoil.hpp:173
virtual void beginEpisode()
Called by the simulator before an episode begins.
Definition: FlowProblem.hpp:305
Collects necessary output values and pass them to Damaris server processes.
VTK output module for the tracer model's parameters.
Collects necessary output values and pass it to opm-common's ECL output.
Definition: EclWriter.hpp:110
This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
virtual void endTimeStep()
Called by the simulator after each time integration.
Definition: FlowProblem.hpp:418
Struct holding the parameters for the BlackOilPolymerModule class.
Definition: blackoilpolymerparams.hpp:43
Provides the auxiliary methods required for consideration of the dispersion equation.
Definition: blackoildispersionmodule.hh:56
void source(RateVector &rate, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the source term for all phases within a given sub-control-volume.
Definition: FlowProblem.hpp:1029
Struct holding the parameters for the BlackOilSolventModule class.
Definition: blackoilsolventparams.hpp:46
virtual void endEpisode()
Called by the simulator after the end of an episode.
Definition: FlowProblem.hpp:475
Struct holding the parameters for the BlackoilExtboModule class.
Definition: blackoilextboparams.hpp:46
static void registerParameters()
Registers all available parameters for the problem and the model.
Definition: FlowProblem.hpp:185
Output module for the results black oil model writing in ECL binary format.
typename SatfuncConsistencyChecks< Scalar >::ViolationLevel ViolationLevel
Severity level for consistency condition violation.
Definition: SatfuncConsistencyCheckManager.hpp:71
void initialSolutionApplied() override
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblemBlackoil.hpp:614
virtual void initialSolutionApplied()
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblem.hpp:996
Contains the high level supplements required to extend the black oil model.
Definition: blackoilextbomodules.hh:63
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition: FlowProblem.hpp:498
Scalar solventSaturation(unsigned elemIdx) const
Returns the initial solvent saturation for a given a cell index.
Definition: FlowGenericProblem_impl.hpp:649
Contains the high level supplements required to extend the black oil model by bioeffects.
Definition: blackoilbioeffectsmodules.hh:94
Definition: SimulatorTimer.hpp:38
void readSolutionFromOutputModule(const int restart_step, bool fip_init)
Read simulator solution state from the outputmodule (used with restart)
Definition: FlowProblemBlackoil.hpp:1045
Contains the high level supplements required to extend the black oil model by polymer.
Definition: blackoilpolymermodules.hh:64
static void registerParameters()
Register all run-time parameters for the tracer VTK output module.
Definition: VtkTracerModule.hpp:84
Provides the auxiliary methods required for consideration of the diffusion equation.
Definition: blackoildiffusionmodule.hh:54
static void setParams(BlackOilFoamParams< Scalar > &¶ms)
Set parameters.
Definition: blackoilfoammodules.hh:90
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:931