90 using typename FlowProblemType::Scalar;
91 using typename FlowProblemType::Simulator;
92 using typename FlowProblemType::GridView;
93 using typename FlowProblemType::FluidSystem;
94 using typename FlowProblemType::Vanguard;
95 using typename FlowProblemType::GlobalEqVector;
96 using typename FlowProblemType::EqVector;
97 using FlowProblemType::dim;
98 using FlowProblemType::dimWorld;
99 using FlowProblemType::numEq;
100 using FlowProblemType::numPhases;
101 using FlowProblemType::numComponents;
104 using FlowProblemType::enableBioeffects;
105 using FlowProblemType::enableBrine;
106 using FlowProblemType::enableConvectiveMixing;
107 using FlowProblemType::enableDiffusion;
108 using FlowProblemType::enableDispersion;
109 using FlowProblemType::enableEnergy;
110 using FlowProblemType::enableExperiments;
111 using FlowProblemType::enableExtbo;
112 using FlowProblemType::enableFoam;
113 using FlowProblemType::enableMICP;
114 using FlowProblemType::enablePolymer;
115 using FlowProblemType::enablePolymerMolarWeight;
116 using FlowProblemType::enableSaltPrecipitation;
117 using FlowProblemType::enableSolvent;
118 using FlowProblemType::enableTemperature;
119 using FlowProblemType::enableThermalFluxBoundaries;
121 using FlowProblemType::gasPhaseIdx;
122 using FlowProblemType::oilPhaseIdx;
123 using FlowProblemType::waterPhaseIdx;
125 using FlowProblemType::waterCompIdx;
126 using FlowProblemType::oilCompIdx;
127 using FlowProblemType::gasCompIdx;
130 using typename FlowProblemType::RateVector;
131 using typename FlowProblemType::PrimaryVariables;
132 using typename FlowProblemType::Indices;
133 using typename FlowProblemType::IntensiveQuantities;
134 using typename FlowProblemType::ElementContext;
136 using typename FlowProblemType::MaterialLaw;
137 using typename FlowProblemType::DimMatrix;
139 enum { enableDissolvedGas = Indices::compositionSwitchIdx >= 0 };
155 using InitialFluidState =
typename EquilInitializer<TypeTag>::ScalarFluidState;
157 using IndexTraits =
typename FluidSystem::IndexTraitsType;
174 EclWriterType::registerParameters();
176 DamarisWriterType::registerParameters();
185 : FlowProblemType(simulator)
186 , thresholdPressures_(simulator)
187 , mixControls_(simulator.vanguard().schedule())
188 , actionHandler_(simulator.vanguard().eclState(),
189 simulator.vanguard().schedule(),
190 simulator.vanguard().actionState(),
191 simulator.vanguard().summaryState(),
193 simulator.vanguard().grid().comm())
194 , hybridNewton_(simulator)
199 const auto& vanguard = simulator.vanguard();
202 brineParams.template initFromState<enableBrine,
203 enableSaltPrecipitation>(vanguard.eclState());
206 DiffusionModule::initFromState(vanguard.eclState());
207 DispersionModule::initFromState(vanguard.eclState());
210 extboParams.template initFromState<enableExtbo>(vanguard.eclState());
214 foamParams.template initFromState<enableFoam>(vanguard.eclState());
218 bioeffectsParams.template initFromState<enableBioeffects, enableMICP>(vanguard.eclState());
222 polymerParams.template initFromState<enablePolymer, enablePolymerMolarWeight>(vanguard.eclState());
226 solventParams.template initFromState<enableSolvent>(vanguard.eclState(), vanguard.schedule());
230 eclWriter_ = std::make_unique<EclWriterType>(simulator);
235 damarisWriter_ = std::make_unique<DamarisWriterType>(simulator);
247 auto& simulator = this->simulator();
249 const int episodeIdx = simulator.episodeIndex();
250 const auto& schedule = simulator.vanguard().schedule();
255 .evalUDQAssignments(episodeIdx, simulator.vanguard().udqState());
257 if (episodeIdx >= 0) {
258 const auto& oilVap = schedule[episodeIdx].oilvap();
259 if (oilVap.getType() == OilVaporizationProperties::OilVaporization::VAPPARS) {
260 FluidSystem::setVapPars(oilVap.vap1(), oilVap.vap2());
263 FluidSystem::setVapPars(0.0, 0.0);
267 ConvectiveMixingModule::beginEpisode(simulator.vanguard().eclState(), schedule, episodeIdx,
268 this->moduleParams_.convectiveMixingModuleParam);
277 hybridNewton_.tryApplyHybridNewton();
288 FlowProblemType::finishInit();
290 auto& simulator = this->simulator();
292 auto finishTransmissibilities = [updated =
false,
this]()
mutable
294 if (updated) {
return; }
296 this->transmissibilities_.finishInit([&vg = this->simulator().vanguard()](
const unsigned int it) {
297 return vg.gridIdxToEquilGridIdx(it);
307 if (enableEclOutput_) {
308 if (simulator.vanguard().grid().comm().size() > 1) {
309 if (simulator.vanguard().grid().comm().rank() == 0)
310 eclWriter_->setTransmissibilities(&simulator.vanguard().globalTransmissibility());
312 finishTransmissibilities();
313 eclWriter_->setTransmissibilities(&simulator.problem().eclTransmissibilities());
316 std::function<
unsigned int(
unsigned int)> equilGridToGrid = [&simulator](
unsigned int i) {
317 return simulator.vanguard().gridEquilIdxToGridIdx(i);
320 this->eclWriter_->extractOutputTransAndNNC(equilGridToGrid);
322 simulator.vanguard().releaseGlobalTransmissibilities();
324 const auto& eclState = simulator.vanguard().eclState();
325 const auto& schedule = simulator.vanguard().schedule();
328 simulator.setStartTime(schedule.getStartTime());
329 simulator.setEndTime(schedule.simTime(schedule.size() - 1));
335 simulator.setEpisodeIndex(-1);
336 simulator.setEpisodeLength(0.0);
341 this->gravity_ = 0.0;
343 eclState.getInitConfig().hasGravity())
346 this->gravity_[dim - 1] = unit::gravity;
349 if (this->enableTuning_) {
352 const auto& tuning = schedule[0].tuning();
353 this->initialTimeStepSize_ = tuning.TSINIT.has_value() ? tuning.TSINIT.value() : -1.0;
354 this->maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
357 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
358 FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
359 this->maxOilSaturation_.resize(this->model().numGridDof(), 0.0);
362 this->readRockParameters_(simulator.vanguard().cellCenterDepths(),
363 [&simulator](
const unsigned idx)
365 std::array<int,dim> coords;
366 simulator.vanguard().cartesianCoordinate(idx, coords);
367 std::transform(coords.begin(), coords.end(), coords.begin(),
368 [](const auto c) { return c + 1; });
372 this->readMaterialParameters_();
373 this->readThermalParameters_();
376 if (enableEclOutput_) {
377 this->eclWriter_->writeInit();
380 finishTransmissibilities();
382 const auto& initconfig = eclState.getInitConfig();
383 this->tracerModel_.init(initconfig.restartRequested());
384 if (initconfig.restartRequested()) {
385 this->readEclRestartSolution_();
388 this->readInitialCondition_();
391 this->tracerModel_.prepareTracerBatches();
393 this->updatePffDofData_();
396 const auto& vanguard = this->simulator().vanguard();
397 const auto& gridView = vanguard.gridView();
398 const int numElements = gridView.size(0);
399 this->polymer_.maxAdsorption.resize(numElements, 0.0);
402 this->readBoundaryConditions_();
405 this->computeAndSetEqWeights_();
407 if (this->enableDriftCompensation_) {
408 this->drift_.resize(this->model().numGridDof());
415 if (!initconfig.restartRequested() && !eclState.getIOConfig().initOnly()) {
416 simulator.startNextEpisode(schedule.seconds(1));
417 simulator.setEpisodeIndex(0);
418 simulator.setTimeStepIndex(0);
421 if (Parameters::Get<Parameters::CheckSatfuncConsistency>() &&
422 ! this->satfuncConsistencyRequirementsMet())
431 this->simulator().vanguard().grid().comm().barrier();
433 throw std::domain_error {
434 "Saturation function end-points do not "
435 "meet requisite consistency conditions"
442 this->mixControls_.init(this->model().numGridDof(),
443 this->episodeIndex(),
444 eclState.runspec().tabdims().getNumPVTTables());
446 if (this->enableVtkOutput_() && eclState.getIOConfig().initOnly()) {
447 simulator.setTimeStepSize(0.0);
448 simulator.model().applyInitialSolution();
452 if (!eclState.getIOConfig().initOnly()) {
453 if (!this->enableTuning_ && eclState.getSimulationConfig().anyTUNING()) {
454 OpmLog::info(
"\nThe deck has TUNING in the SCHEDULE section, but "
455 "it is ignored due\nto the flag --enable-tuning=false. "
456 "Set this flag to true to activate it.\n"
457 "Manually tuning the simulator with the TUNING keyword may "
458 "increase run time.\nIt is recommended using the simulator's "
459 "default tuning (--enable-tuning=false).");
470 this->endStepApplyAction();
473 void endStepApplyAction()
477 this->eclWriter().mutableOutputModule().invalidateLocalData();
480 const auto& grid = this->simulator().vanguard().gridView().grid();
482 using GridType = std::remove_cv_t<std::remove_reference_t<
decltype(grid)>>;
483 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
484 if (!isCpGrid || (grid.maxLevel() == 0)) {
485 this->eclWriter_->evalSummaryState(!this->episodeWillBeOver());
489 OPM_TIMEBLOCK(applyActions);
491 const int episodeIdx = this->episodeIndex();
492 auto& simulator = this->simulator();
496 this->simulator().vanguard().schedule().clearEvents(episodeIdx);
500 .applyActions(episodeIdx, simulator.time() + simulator.timeStepSize(),
501 [
this](
const bool global)
503 using TransUpdateQuantities = typename
504 Vanguard::TransmissibilityType::TransUpdateQuantities;
506 this->transmissibilities_
507 .update(global, TransUpdateQuantities::All,
508 [&vg = this->simulator().vanguard()]
509 (const unsigned int i)
511 return vg.gridIdxToEquilGridIdx(i);
535 .evalUDQAssignments(this->episodeIndex(), this->simulator().vanguard().udqState());
542 if (this->enableEclOutput_) {
543 this->eclWriter_->writeReports(timer);
556 const auto isSubStep = !this->episodeWillBeOver();
558 auto localCellData = data::Solution {};
563 if (this->enableDamarisOutput_ && (this->damarisWriter_ !=
nullptr)) {
564 this->damarisWriter_->writeOutput(localCellData, isSubStep);
568 if (this->enableEclOutput_ && (this->eclWriter_ !=
nullptr)) {
569 this->eclWriter_->writeOutput(std::move(localCellData), isSubStep);
573 void finalizeOutput()
575 OPM_TIMEBLOCK(finalizeOutput);
592 this->thresholdPressures_.finishInit();
595 const auto& grid = this->simulator().vanguard().gridView().grid();
597 using GridType = std::remove_cv_t<std::remove_reference_t<
decltype(grid)>>;
598 constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
600 if (!isCpGrid || (grid.maxLevel() == 0)) {
601 if (this->simulator().episodeIndex() == 0) {
602 eclWriter_->writeInitialFIPReport();
607 void addToSourceDense(RateVector& rate,
608 unsigned globalDofIdx,
609 unsigned timeIdx)
const override
611 this->aquiferModel_.addToSource(rate, globalDofIdx, timeIdx);
614 const auto& source = this->simulator().vanguard().schedule()[this->episodeIndex()].source();
615 std::array<int,3> ijk;
616 this->simulator().vanguard().cartesianCoordinate(globalDofIdx, ijk);
618 if (source.hasSource(ijk)) {
619 const int pvtRegionIdx = this->pvtRegionIndex(globalDofIdx);
620 static std::array<SourceComponent, 3> sc_map = {SourceComponent::WATER, SourceComponent::OIL, SourceComponent::GAS};
621 static std::array<int, 3> phidx_map = {FluidSystem::waterPhaseIdx, FluidSystem::oilPhaseIdx, FluidSystem::gasPhaseIdx};
622 static std::array<int, 3> cidx_map = {waterCompIdx, oilCompIdx, gasCompIdx};
624 for (
unsigned i = 0; i < phidx_map.size(); ++i) {
625 const auto phaseIdx = phidx_map[i];
626 const auto sourceComp = sc_map[i];
627 const auto compIdx = cidx_map[i];
628 if (!FluidSystem::phaseIsActive(phaseIdx)) {
631 Scalar mass_rate = source.rate(ijk, sourceComp) / this->model().dofTotalVolume(globalDofIdx);
632 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
633 mass_rate /= FluidSystem::referenceDensity(phaseIdx, pvtRegionIdx);
635 rate[FluidSystem::canonicalToActiveCompIdx(compIdx)] += mass_rate;
638 if constexpr (enableSolvent) {
639 Scalar mass_rate = source.rate(ijk, SourceComponent::SOLVENT) / this->model().dofTotalVolume(globalDofIdx);
640 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
641 const auto& solventPvt = SolventModule::solventPvt();
642 mass_rate /= solventPvt.referenceDensity(pvtRegionIdx);
644 rate[Indices::contiSolventEqIdx] += mass_rate;
646 if constexpr (enablePolymer) {
647 rate[Indices::polymerConcentrationIdx] += source.rate(ijk, SourceComponent::POLYMER) / this->model().dofTotalVolume(globalDofIdx);
649 if constexpr (enableMICP) {
650 rate[Indices::microbialConcentrationIdx] += source.rate(ijk, SourceComponent::MICR) / this->model().dofTotalVolume(globalDofIdx);
651 rate[Indices::oxygenConcentrationIdx] += source.rate(ijk, SourceComponent::OXYG) / this->model().dofTotalVolume(globalDofIdx);
652 rate[Indices::ureaConcentrationIdx] += source.rate(ijk, SourceComponent::UREA) / (this->model().dofTotalVolume(globalDofIdx));
654 if constexpr (enableEnergy) {
655 for (
unsigned i = 0; i < phidx_map.size(); ++i) {
656 const auto phaseIdx = phidx_map[i];
657 if (!FluidSystem::phaseIsActive(phaseIdx)) {
660 const auto sourceComp = sc_map[i];
661 const auto source_hrate = source.hrate(ijk, sourceComp);
663 rate[Indices::contiEnergyEqIdx] += source_hrate.value() / this->model().dofTotalVolume(globalDofIdx);
665 const auto& intQuants = this->simulator().model().intensiveQuantities(globalDofIdx, 0);
666 auto fs = intQuants.fluidState();
668 const auto source_temp = source.temperature(ijk, sourceComp);
670 Scalar temperature = source_temp.value();
671 fs.setTemperature(temperature);
673 const auto& h = FluidSystem::enthalpy(fs, phaseIdx, pvtRegionIdx);
674 Scalar mass_rate = source.rate(ijk, sourceComp)/ this->model().dofTotalVolume(globalDofIdx);
675 Scalar energy_rate = getValue(h)*mass_rate;
676 rate[Indices::contiEnergyEqIdx] += energy_rate;
684 if (this->enableDriftCompensation_) {
685 const auto& simulator = this->simulator();
686 const auto& model = this->model();
691 Scalar maxCompensation = model.newtonMethod().tolerance()/10;
692 Scalar poro = this->porosity(globalDofIdx, timeIdx);
693 Scalar dt = simulator.timeStepSize();
694 EqVector dofDriftRate = this->drift_[globalDofIdx];
695 dofDriftRate /= dt*model.dofTotalVolume(globalDofIdx);
698 for (
unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
699 Scalar cnv = std::abs(dofDriftRate[eqIdx])*dt*model.eqWeight(globalDofIdx, eqIdx)/poro;
700 if (cnv > maxCompensation) {
701 dofDriftRate[eqIdx] *= maxCompensation/cnv;
705 for (
unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
706 rate[eqIdx] -= dofDriftRate[eqIdx];
715 template <
class LhsEval>
719 if constexpr (enableSaltPrecipitation) {
720 const auto& fs = intQuants.fluidState();
721 unsigned tableIdx = this->simulator().problem().satnumRegionIndex(elementIdx);
722 LhsEval porosityFactor = decay<LhsEval>(1. - fs.saltSaturation());
723 porosityFactor = min(porosityFactor, 1.0);
724 const auto& permfactTable = BrineModule::permfactTable(tableIdx);
725 return permfactTable.eval(porosityFactor,
true);
727 else if constexpr (enableBioeffects) {
728 return intQuants.permFactor().value();
736 const InitialFluidState& initialFluidState(
unsigned globalDofIdx)
const
737 {
return initialFluidStates_[globalDofIdx]; }
739 std::vector<InitialFluidState>& initialFluidStates()
740 {
return initialFluidStates_; }
742 const std::vector<InitialFluidState>& initialFluidStates()
const
743 {
return initialFluidStates_; }
745 const EclipseIO& eclIO()
const
746 {
return eclWriter_->eclIO(); }
748 void setSubStepReport(
const SimulatorReportSingle& report)
749 {
return eclWriter_->setSubStepReport(report); }
751 void setSimulationReport(
const SimulatorReport& report)
752 {
return eclWriter_->setSimulationReport(report); }
754 InitialFluidState boundaryFluidState(
unsigned globalDofIdx,
const int directionId)
const
756 OPM_TIMEBLOCK_LOCAL(boundaryFluidState, Subsystem::Assembly);
757 const auto& bcprop = this->simulator().vanguard().schedule()[this->episodeIndex()].bcprop;
758 if (bcprop.size() > 0) {
759 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
763 if (this->bcindex_(dir)[globalDofIdx] == 0)
764 return initialFluidStates_[globalDofIdx];
766 const auto& bc = bcprop[this->bcindex_(dir)[globalDofIdx]];
767 if (bc.bctype == BCType::DIRICHLET )
769 InitialFluidState fluidState;
770 const int pvtRegionIdx = this->pvtRegionIndex(globalDofIdx);
771 fluidState.setPvtRegionIndex(pvtRegionIdx);
773 switch (bc.component) {
774 case BCComponent::OIL:
775 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx))
776 throw std::logic_error(
"oil is not active and you're trying to add oil BC");
778 fluidState.setSaturation(FluidSystem::oilPhaseIdx, 1.0);
780 case BCComponent::GAS:
781 if (!FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx))
782 throw std::logic_error(
"gas is not active and you're trying to add gas BC");
784 fluidState.setSaturation(FluidSystem::gasPhaseIdx, 1.0);
786 case BCComponent::WATER:
787 if (!FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
788 throw std::logic_error(
"water is not active and you're trying to add water BC");
790 fluidState.setSaturation(FluidSystem::waterPhaseIdx, 1.0);
792 case BCComponent::SOLVENT:
793 case BCComponent::POLYMER:
794 case BCComponent::MICR:
795 case BCComponent::OXYG:
796 case BCComponent::UREA:
797 case BCComponent::NONE:
798 throw std::logic_error(
"you need to specify a valid component (OIL, WATER or GAS) when DIRICHLET type is set in BC");
800 fluidState.setTotalSaturation(1.0);
801 double pressure = initialFluidStates_[globalDofIdx].pressure(this->refPressurePhaseIdx_());
802 const auto pressure_input = bc.pressure;
803 if (pressure_input) {
804 pressure = *pressure_input;
807 std::array<Scalar, numPhases> pc = {0};
808 const auto& matParams = this->materialLawParams(globalDofIdx);
809 MaterialLaw::capillaryPressures(pc, matParams, fluidState);
810 Valgrind::CheckDefined(pressure);
811 Valgrind::CheckDefined(pc);
812 for (
unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
813 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
814 if (Indices::oilEnabled)
815 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
816 else if (Indices::gasEnabled)
817 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
818 else if (Indices::waterEnabled)
820 fluidState.setPressure(phaseIdx, pressure);
823 double temperature = initialFluidStates_[globalDofIdx].temperature(0);
824 const auto temperature_input = bc.temperature;
825 if(temperature_input)
826 temperature = *temperature_input;
827 fluidState.setTemperature(temperature);
829 if constexpr (enableDissolvedGas) {
830 if (FluidSystem::enableDissolvedGas()) {
831 fluidState.setRs(0.0);
832 fluidState.setRv(0.0);
835 if constexpr (enableDisgasInWater) {
836 if (FluidSystem::enableDissolvedGasInWater()) {
837 fluidState.setRsw(0.0);
840 if constexpr (enableVapwat) {
841 if (FluidSystem::enableVaporizedWater()) {
842 fluidState.setRvw(0.0);
846 for (
unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
847 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
849 const auto& b = FluidSystem::inverseFormationVolumeFactor(fluidState, phaseIdx, pvtRegionIdx);
850 fluidState.setInvB(phaseIdx, b);
852 const auto& rho = FluidSystem::density(fluidState, phaseIdx, pvtRegionIdx);
853 fluidState.setDensity(phaseIdx, rho);
854 if constexpr (enableEnergy) {
855 const auto& h = FluidSystem::enthalpy(fluidState, phaseIdx, pvtRegionIdx);
856 fluidState.setEnthalpy(phaseIdx, h);
859 fluidState.checkDefined();
863 return initialFluidStates_[globalDofIdx];
867 const EclWriterType& eclWriter()
const
868 {
return *eclWriter_; }
870 EclWriterType& eclWriter()
871 {
return *eclWriter_; }
879 return this->mixControls_.maxGasDissolutionFactor(timeIdx, globalDofIdx,
880 this->episodeIndex(),
890 return this->mixControls_.maxOilVaporizationFactor(timeIdx, globalDofIdx,
891 this->episodeIndex(),
905 int episodeIdx = this->episodeIndex();
906 return !this->mixControls_.drsdtActive(episodeIdx) &&
907 !this->mixControls_.drvdtActive(episodeIdx) &&
908 this->rockCompPoroMultWc_.empty() &&
909 this->rockCompPoroMult_.empty();
918 template <
class Context>
919 void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx)
const
921 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
923 values.setPvtRegionIndex(
pvtRegionIndex(context, spaceIdx, timeIdx));
924 values.assignNaive(initialFluidStates_[globalDofIdx]);
927 enableSolvent ? this->solventSaturation_[globalDofIdx] : 0.0,
928 enableSolvent ? this->solventRsw_[globalDofIdx] : 0.0);
930 if constexpr (enablePolymer)
931 values[Indices::polymerConcentrationIdx] = this->polymer_.concentration[globalDofIdx];
933 if constexpr (enablePolymerMolarWeight)
934 values[Indices::polymerMoleWeightIdx]= this->polymer_.moleWeight[globalDofIdx];
936 if constexpr (enableBrine) {
937 if (enableSaltPrecipitation && values.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp) {
938 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltSaturation();
941 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltConcentration();
945 if constexpr (enableBioeffects) {
946 values[Indices::microbialConcentrationIdx] = this->bioeffects_.microbialConcentration[globalDofIdx];
947 values[Indices::biofilmVolumeFractionIdx]= this->bioeffects_.biofilmVolumeFraction[globalDofIdx];
948 if constexpr (enableMICP) {
949 values[Indices::oxygenConcentrationIdx]= this->bioeffects_.oxygenConcentration[globalDofIdx];
950 values[Indices::ureaConcentrationIdx]= this->bioeffects_.ureaConcentration[globalDofIdx];
951 values[Indices::calciteVolumeFractionIdx]= this->bioeffects_.calciteVolumeFraction[globalDofIdx];
955 values.checkDefined();
959 Scalar drsdtcon(
unsigned elemIdx,
int episodeIdx)
const
961 return this->mixControls_.drsdtcon(elemIdx, episodeIdx,
962 this->pvtRegionIndex(elemIdx));
965 bool drsdtconIsActive(
unsigned elemIdx,
int episodeIdx)
const
967 return this->mixControls_.drsdtConvective(episodeIdx, this->pvtRegionIndex(elemIdx));
975 template <
class Context>
977 const Context& context,
979 unsigned timeIdx)
const
981 OPM_TIMEBLOCK_LOCAL(eclProblemBoundary, Subsystem::Assembly);
982 if (!context.intersection(spaceIdx).boundary())
985 if constexpr (!enableEnergy || !enableThermalFluxBoundaries)
993 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
994 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
995 values.setThermalFlow(context, spaceIdx, timeIdx, this->initialFluidStates_[globalDofIdx] );
998 if (this->nonTrivialBoundaryConditions()) {
999 unsigned indexInInside = context.intersection(spaceIdx).indexInInside();
1000 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1001 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1002 unsigned pvtRegionIdx =
pvtRegionIndex(context, spaceIdx, timeIdx);
1003 const auto [type, massrate] = this->boundaryCondition(globalDofIdx, indexInInside);
1004 if (type == BCType::THERMAL)
1005 values.setThermalFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1006 else if (type == BCType::FREE || type == BCType::DIRICHLET)
1007 values.setFreeFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1008 else if (type == BCType::RATE)
1009 values.setMassRate(massrate, pvtRegionIdx);
1019 auto& simulator = this->simulator();
1020 const auto& eclState = simulator.vanguard().eclState();
1022 std::size_t numElems = this->model().numGridDof();
1023 this->initialFluidStates_.resize(numElems);
1024 if constexpr (enableSolvent) {
1025 this->solventSaturation_.resize(numElems, 0.0);
1026 this->solventRsw_.resize(numElems, 0.0);
1029 if constexpr (enablePolymer)
1030 this->polymer_.concentration.resize(numElems, 0.0);
1032 if constexpr (enablePolymerMolarWeight) {
1033 const std::string msg {
"Support of the RESTART for polymer molecular weight "
1034 "is not implemented yet. The polymer weight value will be "
1035 "zero when RESTART begins"};
1036 OpmLog::warning(
"NO_POLYMW_RESTART", msg);
1037 this->polymer_.moleWeight.resize(numElems, 0.0);
1040 if constexpr (enableBioeffects) {
1041 this->bioeffects_.resize(numElems);
1045 this->mixControls_.init(numElems, restart_step, eclState.runspec().tabdims().getNumPVTTables());
1047 if constexpr (enableBioeffects) {
1048 this->bioeffects_ = this->eclWriter_->outputModule().getBioeffects().getSolution();
1051 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1052 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1054 this->eclWriter_->outputModule().initHysteresisParams(simulator, elemIdx);
1055 this->eclWriter_->outputModule().assignToFluidState(elemFluidState, elemIdx);
1064 auto ssol = enableSolvent
1065 ? this->eclWriter_->outputModule().getSolventSaturation(elemIdx)
1068 this->processRestartSaturations_(elemFluidState, ssol);
1070 if constexpr (enableSolvent) {
1071 this->solventSaturation_[elemIdx] = ssol;
1072 this->solventRsw_[elemIdx] = this->eclWriter_->outputModule().getSolventRsw(elemIdx);
1077 bool isThermal = eclState.getSimulationConfig().isThermal();
1078 bool needTemperature = (eclState.runspec().co2Storage() || eclState.runspec().h2Storage());
1079 if (!isThermal && needTemperature) {
1080 const auto& fp = simulator.vanguard().eclState().fieldProps();
1081 elemFluidState.setTemperature(fp.get_double(
"TEMPI")[elemIdx]);
1084 this->mixControls_.updateLastValues(elemIdx, elemFluidState.Rs(), elemFluidState.Rv());
1086 if constexpr (enablePolymer)
1087 this->polymer_.concentration[elemIdx] = this->eclWriter_->outputModule().getPolymerConcentration(elemIdx);
1091 const int episodeIdx = this->episodeIndex();
1092 this->mixControls_.updateMaxValues(episodeIdx, simulator.timeStepSize());
1097 auto& sol = this->model().solution(0);
1098 const auto& gridView = this->gridView();
1099 ElementContext elemCtx(simulator);
1100 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1101 elemCtx.updatePrimaryStencil(elem);
1102 int elemIdx = elemCtx.globalSpaceIndex(0, 0);
1103 this->
initial(sol[elemIdx], elemCtx, 0, 0);
1111 this->model().syncOverlap();
1114 this->updateReferencePorosity_();
1115 this->mixControls_.init(this->model().numGridDof(),
1116 this->episodeIndex(),
1117 eclState.runspec().tabdims().getNumPVTTables());
1125 {
return thresholdPressures_.thresholdPressure(elem1Idx, elem2Idx); }
1128 {
return thresholdPressures_; }
1130 FlowThresholdPressure<TypeTag>& thresholdPressure()
1131 {
return thresholdPressures_; }
1133 const ModuleParams& moduleParams()
const
1135 return moduleParams_;
1138 template<
class Serializer>
1139 void serializeOp(Serializer& serializer)
1141 serializer(
static_cast<FlowProblemType&
>(*
this));
1142 serializer(mixControls_);
1143 serializer(*eclWriter_);
1147 void updateExplicitQuantities_(
int episodeIdx,
int timeStepSize,
const bool first_step_after_restart)
override
1149 this->updateExplicitQuantities_(first_step_after_restart);
1151 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>())
1152 updateMaxPolymerAdsorption_();
1154 mixControls_.updateExplicitQuantities(episodeIdx, timeStepSize);
1157 void updateMaxPolymerAdsorption_()
1160 this->updateProperty_(
"FlowProblemBlackoil::updateMaxPolymerAdsorption_() failed:",
1161 [
this](
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1163 this->updateMaxPolymerAdsorption_(compressedDofIdx,iq);
1167 bool updateMaxPolymerAdsorption_(
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1169 const Scalar pa = scalarValue(iq.polymerAdsorption());
1170 auto& mpa = this->polymer_.maxAdsorption;
1171 if (mpa[compressedDofIdx] < pa) {
1172 mpa[compressedDofIdx] = pa;
1179 void computeAndSetEqWeights_()
1181 std::vector<Scalar> sumInvB(numPhases, 0.0);
1182 const auto& gridView = this->gridView();
1183 ElementContext elemCtx(this->simulator());
1184 for(
const auto& elem: elements(gridView, Dune::Partitions::interior)) {
1185 elemCtx.updatePrimaryStencil(elem);
1186 int elemIdx = elemCtx.globalSpaceIndex(0, 0);
1187 const auto& dofFluidState = this->initialFluidStates_[elemIdx];
1188 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1189 if (!FluidSystem::phaseIsActive(phaseIdx))
1192 sumInvB[phaseIdx] += dofFluidState.invB(phaseIdx);
1196 std::size_t numDof = this->model().numGridDof();
1197 const auto& comm = this->simulator().vanguard().grid().comm();
1198 comm.sum(sumInvB.data(),sumInvB.size());
1199 Scalar numTotalDof = comm.sum(numDof);
1201 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1202 if (!FluidSystem::phaseIsActive(phaseIdx))
1205 Scalar avgB = numTotalDof / sumInvB[phaseIdx];
1206 const unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
1207 const unsigned activeSolventCompIdx = FluidSystem::canonicalToActiveCompIdx(solventCompIdx);
1208 this->model().setEqWeight(activeSolventCompIdx, avgB);
1213 bool updateCompositionChangeLimits_()
1215 OPM_TIMEBLOCK(updateCompositionChangeLimits);
1218 int episodeIdx = this->episodeIndex();
1219 std::array<bool,3> active{this->mixControls_.drsdtConvective(episodeIdx),
1220 this->mixControls_.drsdtActive(episodeIdx),
1221 this->mixControls_.drvdtActive(episodeIdx)};
1222 if (!active[0] && !active[1] && !active[2]) {
1226 this->updateProperty_(
"FlowProblemBlackoil::updateCompositionChangeLimits_()) failed:",
1227 [
this,episodeIdx,active](
unsigned compressedDofIdx,
1228 const IntensiveQuantities& iq)
1230 const DimMatrix& perm = this->intrinsicPermeability(compressedDofIdx);
1231 const Scalar distZ = active[0] ? this->simulator().vanguard().cellThickness(compressedDofIdx) : 0.0;
1232 const int pvtRegionIdx = this->pvtRegionIndex(compressedDofIdx);
1233 this->mixControls_.update(compressedDofIdx,
1236 this->gravity_[dim - 1],
1237 perm[dim - 1][dim - 1],
1246 void readEclRestartSolution_()
1249 if(this->simulator().vanguard().grid().maxLevel() > 0) {
1250 throw std::invalid_argument(
"Refined grids are not yet supported for restart ");
1254 auto& simulator = this->simulator();
1255 const auto& schedule = simulator.vanguard().schedule();
1256 const auto& eclState = simulator.vanguard().eclState();
1257 const auto& initconfig = eclState.getInitConfig();
1258 const int restart_step = initconfig.getRestartStep();
1260 simulator.setTime(schedule.seconds(restart_step));
1262 simulator.startNextEpisode(simulator.startTime() + simulator.time(),
1263 schedule.stepLength(restart_step));
1264 simulator.setEpisodeIndex(restart_step);
1266 this->eclWriter_->beginRestart();
1268 Scalar dt = std::min(this->eclWriter_->restartTimeStepSize(), simulator.episodeLength());
1269 simulator.setTimeStepSize(dt);
1271 this->readSolutionFromOutputModule(restart_step,
false);
1273 this->eclWriter_->endRestart();
1276 void readEquilInitialCondition_()
override
1278 const auto& simulator = this->simulator();
1281 EquilInitializer<TypeTag> equilInitializer(simulator, *(this->materialLawManager_));
1283 std::size_t numElems = this->model().numGridDof();
1284 this->initialFluidStates_.resize(numElems);
1285 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1286 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1287 elemFluidState.assign(equilInitializer.initialFluidState(elemIdx));
1291 void readExplicitInitialCondition_()
override
1293 const auto& simulator = this->simulator();
1294 const auto& vanguard = simulator.vanguard();
1295 const auto& eclState = vanguard.eclState();
1296 const auto& fp = eclState.fieldProps();
1297 bool has_swat = fp.has_double(
"SWAT");
1298 bool has_sgas = fp.has_double(
"SGAS");
1299 bool has_rs = fp.has_double(
"RS");
1300 bool has_rsw = fp.has_double(
"RSW");
1301 bool has_rv = fp.has_double(
"RV");
1302 bool has_rvw = fp.has_double(
"RVW");
1303 bool has_pressure = fp.has_double(
"PRESSURE");
1304 bool has_salt = fp.has_double(
"SALT");
1305 bool has_saltp = fp.has_double(
"SALTP");
1308 if (Indices::numPhases > 1) {
1309 if (FluidSystem::phaseIsActive(waterPhaseIdx) && !has_swat)
1310 throw std::runtime_error(
"The ECL input file requires the presence of the SWAT keyword if "
1311 "the water phase is active");
1312 if (FluidSystem::phaseIsActive(gasPhaseIdx) && !has_sgas && FluidSystem::phaseIsActive(oilPhaseIdx))
1313 throw std::runtime_error(
"The ECL input file requires the presence of the SGAS keyword if "
1314 "the gas phase is active");
1317 throw std::runtime_error(
"The ECL input file requires the presence of the PRESSURE "
1318 "keyword if the model is initialized explicitly");
1319 if (FluidSystem::enableDissolvedGas() && !has_rs)
1320 throw std::runtime_error(
"The ECL input file requires the RS keyword to be present if"
1321 " dissolved gas is enabled and the model is initialized explicitly");
1322 if (FluidSystem::enableDissolvedGasInWater() && !has_rsw)
1323 OpmLog::warning(
"The model is initialized explicitly and the RSW keyword is not present in the"
1324 " ECL input file. The RSW values are set equal to 0");
1325 if (FluidSystem::enableVaporizedOil() && !has_rv)
1326 throw std::runtime_error(
"The ECL input file requires the RV keyword to be present if"
1327 " vaporized oil is enabled and the model is initialized explicitly");
1328 if (FluidSystem::enableVaporizedWater() && !has_rvw)
1329 throw std::runtime_error(
"The ECL input file requires the RVW keyword to be present if"
1330 " vaporized water is enabled and the model is initialized explicitly");
1331 if (enableBrine && !has_salt)
1332 throw std::runtime_error(
"The ECL input file requires the SALT keyword to be present if"
1333 " brine is enabled and the model is initialized explicitly");
1334 if (enableSaltPrecipitation && !has_saltp)
1335 throw std::runtime_error(
"The ECL input file requires the SALTP keyword to be present if"
1336 " salt precipitation is enabled and the model is initialized explicitly");
1338 std::size_t numDof = this->model().numGridDof();
1340 initialFluidStates_.resize(numDof);
1342 std::vector<double> waterSaturationData;
1343 std::vector<double> gasSaturationData;
1344 std::vector<double> pressureData;
1345 std::vector<double> rsData;
1346 std::vector<double> rswData;
1347 std::vector<double> rvData;
1348 std::vector<double> rvwData;
1349 std::vector<double> tempiData;
1350 std::vector<double> saltData;
1351 std::vector<double> saltpData;
1353 if (FluidSystem::phaseIsActive(waterPhaseIdx) && Indices::numPhases > 1)
1354 waterSaturationData = fp.get_double(
"SWAT");
1356 waterSaturationData.resize(numDof);
1358 if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(oilPhaseIdx))
1359 gasSaturationData = fp.get_double(
"SGAS");
1361 gasSaturationData.resize(numDof);
1363 pressureData = fp.get_double(
"PRESSURE");
1364 if (FluidSystem::enableDissolvedGas())
1365 rsData = fp.get_double(
"RS");
1367 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1368 rswData = fp.get_double(
"RSW");
1370 if (FluidSystem::enableVaporizedOil())
1371 rvData = fp.get_double(
"RV");
1373 if (FluidSystem::enableVaporizedWater())
1374 rvwData = fp.get_double(
"RVW");
1377 tempiData = fp.get_double(
"TEMPI");
1380 if constexpr (enableBrine)
1381 saltData = fp.get_double(
"SALT");
1384 if constexpr (enableSaltPrecipitation)
1385 saltpData = fp.get_double(
"SALTP");
1388 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1389 auto& dofFluidState = initialFluidStates_[dofIdx];
1391 dofFluidState.setPvtRegionIndex(pvtRegionIndex(dofIdx));
1396 Scalar temperatureLoc = tempiData[dofIdx];
1397 if (!std::isfinite(temperatureLoc) || temperatureLoc <= 0)
1398 temperatureLoc = FluidSystem::surfaceTemperature;
1399 dofFluidState.setTemperature(temperatureLoc);
1404 if constexpr (enableBrine)
1405 dofFluidState.setSaltConcentration(saltData[dofIdx]);
1410 if constexpr (enableSaltPrecipitation)
1411 dofFluidState.setSaltSaturation(saltpData[dofIdx]);
1416 if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
1417 dofFluidState.setSaturation(FluidSystem::waterPhaseIdx,
1418 waterSaturationData[dofIdx]);
1420 if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){
1421 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)){
1422 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1424 - waterSaturationData[dofIdx]);
1427 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1428 gasSaturationData[dofIdx]);
1430 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1431 const Scalar soil = 1.0 - waterSaturationData[dofIdx] - gasSaturationData[dofIdx];
1432 if (soil < smallSaturationTolerance_) {
1433 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, 0.0);
1436 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, soil);
1443 Scalar pressure = pressureData[dofIdx];
1447 std::array<Scalar, numPhases> pc = {0};
1448 const auto& matParams = this->materialLawParams(dofIdx);
1449 MaterialLaw::capillaryPressures(pc, matParams, dofFluidState);
1450 Valgrind::CheckDefined(pressure);
1451 Valgrind::CheckDefined(pc);
1452 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1453 if (!FluidSystem::phaseIsActive(phaseIdx))
1456 if (Indices::oilEnabled)
1457 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
1458 else if (Indices::gasEnabled)
1459 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
1460 else if (Indices::waterEnabled)
1462 dofFluidState.setPressure(phaseIdx, pressure);
1465 if constexpr (enableDissolvedGas) {
1466 if (FluidSystem::enableDissolvedGas())
1467 dofFluidState.setRs(rsData[dofIdx]);
1468 else if (Indices::gasEnabled && Indices::oilEnabled)
1469 dofFluidState.setRs(0.0);
1470 if (FluidSystem::enableVaporizedOil())
1471 dofFluidState.setRv(rvData[dofIdx]);
1472 else if (Indices::gasEnabled && Indices::oilEnabled)
1473 dofFluidState.setRv(0.0);
1476 if constexpr (enableDisgasInWater) {
1477 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1478 dofFluidState.setRsw(rswData[dofIdx]);
1481 if constexpr (enableVapwat) {
1482 if (FluidSystem::enableVaporizedWater())
1483 dofFluidState.setRvw(rvwData[dofIdx]);
1489 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1490 if (!FluidSystem::phaseIsActive(phaseIdx))
1493 const auto& b = FluidSystem::inverseFormationVolumeFactor(dofFluidState, phaseIdx, pvtRegionIndex(dofIdx));
1494 dofFluidState.setInvB(phaseIdx, b);
1496 const auto& rho = FluidSystem::density(dofFluidState, phaseIdx, pvtRegionIndex(dofIdx));
1497 dofFluidState.setDensity(phaseIdx, rho);
1504 void processRestartSaturations_(InitialFluidState& elemFluidState, Scalar& solventSaturation)
1508 Scalar sumSaturation = 0.0;
1509 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1510 if (FluidSystem::phaseIsActive(phaseIdx)) {
1511 if (elemFluidState.saturation(phaseIdx) < smallSaturationTolerance_)
1512 elemFluidState.setSaturation(phaseIdx, 0.0);
1514 sumSaturation += elemFluidState.saturation(phaseIdx);
1518 if constexpr (enableSolvent) {
1519 if (solventSaturation < smallSaturationTolerance_)
1520 solventSaturation = 0.0;
1522 sumSaturation += solventSaturation;
1525 assert(sumSaturation > 0.0);
1527 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1528 if (FluidSystem::phaseIsActive(phaseIdx)) {
1529 const Scalar saturation = elemFluidState.saturation(phaseIdx) / sumSaturation;
1530 elemFluidState.setSaturation(phaseIdx, saturation);
1533 if constexpr (enableSolvent) {
1534 solventSaturation = solventSaturation / sumSaturation;
1538 void readInitialCondition_()
override
1540 FlowProblemType::readInitialCondition_();
1542 if constexpr (enableSolvent || enablePolymer || enablePolymerMolarWeight || enableBioeffects)
1543 this->readBlackoilExtentionsInitialConditions_(this->model().numGridDof(),
1546 enablePolymerMolarWeight,
1552 void handleSolventBC(
const BCProp::BCFace& bc, RateVector& rate)
const override
1554 if constexpr (!enableSolvent)
1555 throw std::logic_error(
"solvent is disabled and you're trying to add solvent to BC");
1557 rate[Indices::solventSaturationIdx] = bc.rate;
1560 void handlePolymerBC(
const BCProp::BCFace& bc, RateVector& rate)
const override
1562 if constexpr (!enablePolymer)
1563 throw std::logic_error(
"polymer is disabled and you're trying to add polymer to BC");
1565 rate[Indices::polymerConcentrationIdx] = bc.rate;
1568 void handleMicrBC(
const BCProp::BCFace& bc, RateVector& rate)
const override
1570 if constexpr (!enableMICP)
1571 throw std::logic_error(
"MICP is disabled and you're trying to add microbes to BC");
1573 rate[Indices::microbialConcentrationIdx] = bc.rate;
1576 void handleOxygBC(
const BCProp::BCFace& bc, RateVector& rate)
const override
1578 if constexpr (!enableMICP)
1579 throw std::logic_error(
"MICP is disabled and you're trying to add oxygen to BC");
1581 rate[Indices::oxygenConcentrationIdx] = bc.rate;
1584 void handleUreaBC(
const BCProp::BCFace& bc, RateVector& rate)
const override
1586 if constexpr (!enableMICP)
1587 throw std::logic_error(
"MICP is disabled and you're trying to add urea to BC");
1589 rate[Indices::ureaConcentrationIdx] = bc.rate;
1591 rate[Indices::ureaConcentrationIdx] *= getPropValue<TypeTag, Properties::BlackOilUreaScalingFactor>();
1594 void updateExplicitQuantities_(
const bool first_step_after_restart)
1596 OPM_TIMEBLOCK(updateExplicitQuantities);
1597 const bool invalidateFromMaxWaterSat = this->updateMaxWaterSaturation_();
1598 const bool invalidateFromMinPressure = this->updateMinPressure_();
1601 const bool invalidateFromHyst = this->updateHysteresis_();
1602 const bool invalidateFromMaxOilSat = this->updateMaxOilSaturation_();
1605 const bool invalidateDRDT = !first_step_after_restart && this->updateCompositionChangeLimits_();
1608 const bool invalidateIntensiveQuantities
1609 = invalidateFromMaxWaterSat || invalidateFromMinPressure || invalidateFromHyst || invalidateFromMaxOilSat || invalidateDRDT;
1610 if (invalidateIntensiveQuantities) {
1611 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
1612 this->model().invalidateAndUpdateIntensiveQuantities(0);
1615 this->updateRockCompTransMultVal_();
1618 bool satfuncConsistencyRequirementsMet()
const
1620 if (
const auto nph = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)
1621 + FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)
1622 + FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
1631 const auto numSamplePoints =
static_cast<std::size_t
>
1632 (Parameters::Get<Parameters::NumSatfuncConsistencySamplePoints>());
1634 auto sfuncConsistencyChecks =
1635 Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar> {
1636 numSamplePoints, this->simulator().vanguard().eclState(),
1637 [&cmap = this->simulator().vanguard().cartesianIndexMapper()](
const int elemIdx)
1638 {
return cmap.cartesianIndex(elemIdx); }
1641 const auto ioRank = 0;
1642 const auto isIoRank = this->simulator().vanguard()
1643 .grid().comm().rank() == ioRank;
1648 sfuncConsistencyChecks.collectFailuresTo(ioRank)
1649 .run(this->simulator().vanguard().grid().levelGridView(0),
1650 [&vg = this->simulator().vanguard(),
1651 &emap = this->simulator().model().elementMapper()]
1653 {
return vg.gridIdxToEquilGridIdx(emap.index(elem)); });
1655 using ViolationLevel =
typename Satfunc::PhaseChecks::
1656 SatfuncConsistencyCheckManager<Scalar>::ViolationLevel;
1658 auto reportFailures = [&sfuncConsistencyChecks]
1659 (
const ViolationLevel level)
1661 sfuncConsistencyChecks.reportFailures
1662 (level, [](std::string_view record)
1663 { OpmLog::info(std::string { record }); });
1666 if (sfuncConsistencyChecks.anyFailedStandardChecks()) {
1668 OpmLog::warning(
"Saturation Function "
1669 "End-point Consistency Problems");
1671 reportFailures(ViolationLevel::Standard);
1675 if (sfuncConsistencyChecks.anyFailedCriticalChecks()) {
1677 OpmLog::error(
"Saturation Function "
1678 "End-point Consistency Failures");
1680 reportFailures(ViolationLevel::Critical);
1693 FlowThresholdPressure<TypeTag> thresholdPressures_;
1695 std::vector<InitialFluidState> initialFluidStates_;
1697 bool enableEclOutput_;
1698 std::unique_ptr<EclWriterType> eclWriter_;
1700 const Scalar smallSaturationTolerance_ = 1.e-6;
1702 bool enableDamarisOutput_ = false ;
1703 std::unique_ptr<DamarisWriterType> damarisWriter_;
1705 MixingRateControls<FluidSystem> mixControls_;
1707 ActionHandler<Scalar, IndexTraits> actionHandler_;
1709 ModuleParams moduleParams_;
1711 HybridNewton hybridNewton_;
1724 bool episodeWillBeOver()
const override
1726 const auto currTime = this->simulator().time()
1727 + this->simulator().timeStepSize();
1729 const auto nextReportStep =
1730 this->simulator().vanguard().schedule()
1731 .seconds(this->simulator().episodeIndex() + 1);
1733 const auto isSubStep = (nextReportStep - currTime)
1734 > (2 * std::numeric_limits<float>::epsilon()) * nextReportStep;