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> 47 #include <opm/output/eclipse/EclipseIO.hpp> 49 #include <opm/input/eclipse/Units/Units.hpp> 51 #include <opm/simulators/flow/ActionHandler.hpp> 58 #include <opm/simulators/flow/HybridNewton.hpp> 59 #include <opm/simulators/flow/HybridNewtonConfig.hpp> 61 #include <opm/simulators/utils/satfunc/SatfuncConsistencyCheckManager.hpp> 74 #include <string_view> 85 template <
class TypeTag>
93 using typename FlowProblemType::Scalar;
94 using typename FlowProblemType::Simulator;
95 using typename FlowProblemType::GridView;
96 using typename FlowProblemType::FluidSystem;
97 using typename FlowProblemType::Vanguard;
98 using typename FlowProblemType::GlobalEqVector;
99 using typename FlowProblemType::EqVector;
100 using FlowProblemType::dim;
101 using FlowProblemType::dimWorld;
102 using FlowProblemType::numEq;
103 using FlowProblemType::numPhases;
104 using FlowProblemType::numComponents;
107 using FlowProblemType::enableBioeffects;
108 using FlowProblemType::enableBrine;
109 using FlowProblemType::enableConvectiveMixing;
110 using FlowProblemType::enableDiffusion;
111 using FlowProblemType::enableDispersion;
112 using FlowProblemType::energyModuleType;
113 using FlowProblemType::enableExperiments;
114 using FlowProblemType::enableExtbo;
115 using FlowProblemType::enableFoam;
116 using FlowProblemType::enableMICP;
117 using FlowProblemType::enablePolymer;
118 using FlowProblemType::enablePolymerMolarWeight;
119 using FlowProblemType::enableSaltPrecipitation;
120 using FlowProblemType::enableSolvent;
121 using FlowProblemType::enableThermalFluxBoundaries;
123 using FlowProblemType::gasPhaseIdx;
124 using FlowProblemType::oilPhaseIdx;
125 using FlowProblemType::waterPhaseIdx;
127 using FlowProblemType::waterCompIdx;
128 using FlowProblemType::oilCompIdx;
129 using FlowProblemType::gasCompIdx;
132 using typename FlowProblemType::RateVector;
133 using typename FlowProblemType::PrimaryVariables;
134 using typename FlowProblemType::Indices;
135 using typename FlowProblemType::IntensiveQuantities;
136 using typename FlowProblemType::ElementContext;
138 using typename FlowProblemType::MaterialLaw;
139 using typename FlowProblemType::DimMatrix;
141 static constexpr
bool enableDissolvedGas =
142 Indices::compositionSwitchIdx != std::numeric_limits<unsigned>::max();
143 enum { enableVapwat = getPropValue<TypeTag, Properties::EnableVapwat>() };
144 enum { enableDisgasInWater = getPropValue<TypeTag, Properties::EnableDisgasInWater>() };
145 enum { enableGeochemistry = getPropValue<TypeTag, Properties::EnableGeochemistry>() };
146 enum { enableMech = getPropValue<TypeTag, Properties::EnableMech>() };
148 using BioeffectsModule = BlackOilBioeffectsModule<TypeTag, enableBioeffects>;
149 using BrineModule = BlackOilBrineModule<TypeTag, enableBrine>;
150 using ConvectiveMixingModule = BlackOilConvectiveMixingModule<TypeTag, enableConvectiveMixing>;
153 using ExtboModule = BlackOilExtboModule<TypeTag, enableExtbo>;
155 using PolymerModule = BlackOilPolymerModule<TypeTag, enablePolymer>;
156 using SolventModule = BlackOilSolventModule<TypeTag, enableSolvent>;
159 using IndexTraits =
typename FluidSystem::IndexTraitsType;
160 using InitialFluidState =
typename EquilInitializer<TypeTag>::ScalarFluidState;
179 EclWriterType::registerParameters();
181 DamarisWriterType::registerParameters();
191 , thresholdPressures_(simulator)
192 , mixControls_(simulator.vanguard().schedule())
193 , actionHandler_(simulator.vanguard().eclState(),
194 simulator.vanguard().schedule(),
195 simulator.vanguard().actionState(),
196 simulator.vanguard().summaryState(),
198 simulator.vanguard().grid().comm())
199 , hybridNewton_(simulator)
204 const auto& vanguard = simulator.vanguard();
206 if constexpr (enableBrine) {
208 brineParams.template initFromState<enableBrine,
209 enableSaltPrecipitation>(vanguard.eclState());
210 BrineModule::setParams(std::move(brineParams));
213 if constexpr (enableDiffusion) {
214 DiffusionModule::initFromState(vanguard.eclState());
217 if constexpr (enableDispersion) {
218 DispersionModule::initFromState(vanguard.eclState());
221 if constexpr (enableExtbo) {
223 extboParams.template initFromState<enableExtbo>(vanguard.eclState());
224 ExtboModule::setParams(std::move(extboParams));
227 if constexpr (enableFoam) {
229 foamParams.template initFromState<enableFoam>(vanguard.eclState());
230 FoamModule::setParams(std::move(foamParams));
233 if constexpr (enableBioeffects) {
235 bioeffectsParams.template initFromState<enableBioeffects, enableMICP>(vanguard.eclState());
236 BioeffectsModule::setParams(std::move(bioeffectsParams));
239 if constexpr (enablePolymer) {
241 polymerParams.template initFromState<enablePolymer, enablePolymerMolarWeight>(vanguard.eclState());
242 PolymerModule::setParams(std::move(polymerParams));
245 if constexpr (enableSolvent) {
247 solventParams.template initFromState<enableSolvent>(vanguard.eclState(), vanguard.schedule());
248 SolventModule::setParams(std::move(solventParams));
252 eclWriter_ = std::make_unique<EclWriterType>(simulator);
253 enableEclOutput_ = Parameters::Get<Parameters::EnableEclOutput>();
256 if constexpr (!enableGeochemistry) {
257 if (vanguard.eclState().runspec().geochem().enabled()) {
258 throw std::runtime_error(
"GEOCHEM keyword in the deck but geochemistry module " 259 "was disabled at compile time!");
264 if constexpr (!enableMech) {
265 const auto& rspec = vanguard.eclState().runspec();
266 if (rspec.mech() && rspec.mechSolver().tpsa()) {
267 throw std::runtime_error(
"TPSA solver enabled in the deck, but geomechanics " 268 "module was disabled at compile time!");
274 damarisWriter_ = std::make_unique<DamarisWriterType>(simulator);
275 enableDamarisOutput_ = Parameters::Get<Parameters::EnableDamarisOutput>();
286 auto& simulator = this->simulator();
288 const int episodeIdx = simulator.episodeIndex();
289 const auto& schedule = simulator.vanguard().schedule();
294 .evalUDQAssignments(episodeIdx, simulator.vanguard().udqState());
296 if (episodeIdx >= 0) {
297 const auto& oilVap = schedule[episodeIdx].oilvap();
298 if (oilVap.getType() == OilVaporizationProperties::OilVaporization::VAPPARS) {
299 FluidSystem::setVapPars(oilVap.vap1(), oilVap.vap2());
302 FluidSystem::setVapPars(0.0, 0.0);
305 if constexpr (enableConvectiveMixing) {
306 ConvectiveMixingModule::beginEpisode(simulator.vanguard().eclState(), schedule, episodeIdx,
307 this->moduleParams_.convectiveMixingModuleParam);
329 FlowProblemType::finishInit();
331 auto& simulator = this->simulator();
333 auto finishTransmissibilities = [updated =
false,
this]()
mutable 335 if (updated) {
return; }
337 this->transmissibilities_.finishInit([&vg = this->simulator().vanguard()](
const unsigned int it) {
338 return vg.gridIdxToEquilGridIdx(it);
348 if (enableEclOutput_) {
349 if (simulator.vanguard().grid().comm().size() > 1) {
350 if (simulator.vanguard().grid().comm().rank() == 0)
351 eclWriter_->setTransmissibilities(&simulator.vanguard().globalTransmissibility());
353 finishTransmissibilities();
354 eclWriter_->setTransmissibilities(&simulator.problem().eclTransmissibilities());
357 std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](
unsigned int i) {
358 return simulator.vanguard().gridEquilIdxToGridIdx(i);
361 this->eclWriter_->extractOutputTransAndNNC(equilGridToGrid);
363 simulator.vanguard().releaseGlobalTransmissibilities();
365 const auto& eclState = simulator.vanguard().eclState();
366 const auto& schedule = simulator.vanguard().schedule();
369 simulator.setStartTime(schedule.getStartTime());
370 simulator.setEndTime(schedule.simTime(schedule.size() - 1));
376 simulator.setEpisodeIndex(-1);
377 simulator.setEpisodeLength(0.0);
382 this->gravity_ = 0.0;
383 if (Parameters::Get<Parameters::EnableGravity>() &&
384 eclState.getInitConfig().hasGravity())
387 this->gravity_[dim - 1] = unit::gravity;
390 if (this->enableTuning_) {
393 const auto& tuning = schedule[0].tuning();
394 this->initialTimeStepSize_ = tuning.TSINIT.has_value() ? tuning.TSINIT.value() : -1.0;
395 this->maxTimeStepAfterWellEvent_ = tuning.TMAXWC;
400 bool isThermal = eclState.getSimulationConfig().isThermal();
401 bool isTemp = eclState.getSimulationConfig().isTemp();
402 bool conserveInnerEnergy = isTemp || (isThermal && Parameters::Get<Parameters::ConserveInnerEnergyThermal>());
403 FluidSystem::setEnergyEqualEnthalpy(conserveInnerEnergy);
405 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) &&
406 FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) {
407 this->maxOilSaturation_.resize(this->model().numGridDof(), 0.0);
410 this->readRockParameters_(simulator.vanguard().cellCenterDepths(),
411 [&simulator](
const unsigned idx)
413 std::array<int,dim> coords;
414 simulator.vanguard().cartesianCoordinate(idx, coords);
415 std::ranges::transform(coords, coords.begin(),
416 [](
const auto c) {
return c + 1; });
420 this->readMaterialParameters_();
421 this->readThermalParameters_();
424 if (enableEclOutput_) {
425 this->eclWriter_->writeInit();
428 finishTransmissibilities();
430 const auto& initconfig = eclState.getInitConfig();
431 this->tracerModel_.init(initconfig.restartRequested());
432 if (initconfig.restartRequested()) {
433 this->readEclRestartSolution_();
436 this->readInitialCondition_();
438 this->temperatureModel_.init();
439 this->tracerModel_.prepareTracerBatches();
441 this->updatePffDofData_();
443 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>()) {
444 const auto& vanguard = this->simulator().vanguard();
445 const auto& gridView = vanguard.gridView();
446 const int numElements = gridView.size(0);
447 this->polymer_.maxAdsorption.resize(numElements, 0.0);
450 this->readBoundaryConditions_();
453 this->computeAndSetEqWeights_();
455 if (this->enableDriftCompensation_ || this->enableDriftCompensationTemp_) {
456 this->drift_.resize(this->model().numGridDof());
463 if (!initconfig.restartRequested() && !eclState.getIOConfig().initOnly()) {
464 simulator.startNextEpisode(schedule.seconds(1));
465 simulator.setEpisodeIndex(0);
466 simulator.setTimeStepIndex(0);
469 if (Parameters::Get<Parameters::CheckSatfuncConsistency>() &&
470 ! this->satfuncConsistencyRequirementsMet())
479 this->simulator().vanguard().grid().comm().barrier();
481 throw std::domain_error {
482 "Saturation function end-points do not " 483 "meet requisite consistency conditions" 490 this->mixControls_.init(this->model().numGridDof(),
491 this->episodeIndex(),
492 eclState.runspec().tabdims().getNumPVTTables());
494 if (this->enableVtkOutput_() && eclState.getIOConfig().initOnly()) {
495 simulator.setTimeStepSize(0.0);
496 simulator.model().applyInitialSolution();
500 if (!eclState.getIOConfig().initOnly()) {
501 if (!this->enableTuning_ && eclState.getSimulationConfig().anyTUNING()) {
502 OpmLog::info(
"\nThe deck has TUNING in the SCHEDULE section, but " 503 "it is ignored due\nto the flag --enable-tuning=false. " 504 "Set this flag to true to activate it.\n" 505 "Manually tuning the simulator with the TUNING keyword may " 506 "increase run time.\nIt is recommended using the simulator's " 507 "default tuning (--enable-tuning=false).");
518 this->endStepApplyAction();
521 void endStepApplyAction()
525 this->eclWriter().mutableOutputModule().invalidateLocalData();
528 const auto& grid = this->simulator().vanguard().gridView().grid();
530 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
531 constexpr
bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
532 if (!isCpGrid || (grid.maxLevel() == 0)) {
533 this->eclWriter_->evalSummaryState(!this->episodeWillBeOver());
537 OPM_TIMEBLOCK(applyActions);
539 const int episodeIdx = this->episodeIndex();
540 auto& simulator = this->simulator();
544 this->simulator().vanguard().schedule().clearEvents(episodeIdx);
548 .applyActions(episodeIdx, simulator.time() + simulator.timeStepSize(),
549 [
this](
const bool global)
551 using TransUpdateQuantities =
typename 552 Vanguard::TransmissibilityType::TransUpdateQuantities;
554 this->transmissibilities_
555 .update(global, TransUpdateQuantities::All,
556 [&vg = this->simulator().vanguard()]
557 (
const unsigned int i)
559 return vg.gridIdxToEquilGridIdx(i);
583 .evalUDQAssignments(this->episodeIndex(), this->simulator().vanguard().udqState());
590 if (this->enableEclOutput_) {
591 this->eclWriter_->writeReports(timer);
604 const auto isSubStep = !this->episodeWillBeOver();
606 auto localCellData = data::Solution {};
611 if (this->enableDamarisOutput_ && (this->damarisWriter_ !=
nullptr)) {
612 this->damarisWriter_->writeOutput(localCellData, isSubStep);
616 if (this->enableEclOutput_ && (this->eclWriter_ !=
nullptr)) {
617 this->eclWriter_->writeOutput(std::move(localCellData), isSubStep,
618 this->simulator().vanguard().schedule()
619 .exitStatus().has_value());
623 void finalizeOutput()
625 OPM_TIMEBLOCK(finalizeOutput);
642 this->thresholdPressures_.finishInit();
645 const auto& grid = this->simulator().vanguard().gridView().grid();
647 using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
648 constexpr
bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
650 if (!isCpGrid || (grid.maxLevel() == 0)) {
651 if (this->simulator().episodeIndex() == 0) {
652 eclWriter_->writeInitialFIPReport();
657 void addToSourceDense(RateVector& rate,
658 unsigned globalDofIdx,
659 unsigned timeIdx)
const override 661 this->aquiferModel_.addToSource(rate, globalDofIdx, timeIdx);
664 const auto&
source = this->simulator().vanguard().schedule()[this->episodeIndex()].source();
665 std::array<int,3> ijk;
666 this->simulator().vanguard().cartesianCoordinate(globalDofIdx, ijk);
668 if (
source.hasSource(ijk)) {
670 static std::array<SourceComponent, 3> sc_map = {SourceComponent::WATER, SourceComponent::OIL, SourceComponent::GAS};
671 static std::array<int, 3> phidx_map = {FluidSystem::waterPhaseIdx, FluidSystem::oilPhaseIdx, FluidSystem::gasPhaseIdx};
672 static std::array<int, 3> cidx_map = {waterCompIdx, oilCompIdx, gasCompIdx};
674 for (
unsigned i = 0; i < phidx_map.size(); ++i) {
675 const auto phaseIdx = phidx_map[i];
676 const auto sourceComp = sc_map[i];
677 const auto compIdx = cidx_map[i];
678 if (!FluidSystem::phaseIsActive(phaseIdx)) {
681 Scalar mass_rate =
source.rate(ijk, sourceComp) / this->model().dofTotalVolume(globalDofIdx);
682 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
683 mass_rate /= FluidSystem::referenceDensity(phaseIdx, pvtRegionIdx);
685 rate[FluidSystem::canonicalToActiveCompIdx(compIdx)] += mass_rate;
688 if constexpr (enableSolvent) {
689 Scalar mass_rate =
source.rate(ijk, SourceComponent::SOLVENT) / this->model().dofTotalVolume(globalDofIdx);
690 if constexpr (getPropValue<TypeTag, Properties::BlackoilConserveSurfaceVolume>()) {
691 const auto& solventPvt = SolventModule::solventPvt();
692 mass_rate /= solventPvt.referenceDensity(pvtRegionIdx);
694 rate[Indices::contiSolventEqIdx] += mass_rate;
696 if constexpr (enablePolymer) {
697 rate[Indices::polymerConcentrationIdx] +=
source.rate(ijk, SourceComponent::POLYMER) / this->model().dofTotalVolume(globalDofIdx);
699 if constexpr (enableMICP) {
700 rate[Indices::microbialConcentrationIdx] +=
source.rate(ijk, SourceComponent::MICR) / this->model().dofTotalVolume(globalDofIdx);
701 rate[Indices::oxygenConcentrationIdx] +=
source.rate(ijk, SourceComponent::OXYG) / this->model().dofTotalVolume(globalDofIdx);
702 rate[Indices::ureaConcentrationIdx] +=
source.rate(ijk, SourceComponent::UREA) / (this->model().dofTotalVolume(globalDofIdx));
704 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
705 for (
unsigned i = 0; i < phidx_map.size(); ++i) {
706 const auto phaseIdx = phidx_map[i];
707 if (!FluidSystem::phaseIsActive(phaseIdx)) {
710 const auto sourceComp = sc_map[i];
711 const auto source_hrate =
source.hrate(ijk, sourceComp);
713 rate[Indices::contiEnergyEqIdx] += source_hrate.value() / this->model().dofTotalVolume(globalDofIdx);
715 const auto& intQuants = this->simulator().model().intensiveQuantities(globalDofIdx, 0);
716 auto fs = intQuants.fluidState();
718 const auto source_temp =
source.temperature(ijk, sourceComp);
723 const auto& h = FluidSystem::enthalpy(fs, phaseIdx, pvtRegionIdx);
724 Scalar mass_rate =
source.rate(ijk, sourceComp)/ this->model().dofTotalVolume(globalDofIdx);
725 Scalar energy_rate = getValue(h)*mass_rate;
726 rate[Indices::contiEnergyEqIdx] += energy_rate;
734 if (this->enableDriftCompensation_) {
735 const auto& simulator = this->simulator();
736 const auto& model = this->model();
741 Scalar maxCompensation = model.newtonMethod().tolerance()/10;
742 Scalar poro = this->
porosity(globalDofIdx, timeIdx);
743 Scalar dt = simulator.timeStepSize();
744 EqVector dofDriftRate = this->drift_[globalDofIdx];
745 dofDriftRate /= dt*model.dofTotalVolume(globalDofIdx);
748 for (
unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx) {
749 Scalar cnv = std::abs(dofDriftRate[eqIdx])*dt*model.eqWeight(globalDofIdx, eqIdx)/poro;
750 if (cnv > maxCompensation) {
751 dofDriftRate[eqIdx] *= maxCompensation/cnv;
755 for (
unsigned eqIdx = 0; eqIdx < numEq; ++ eqIdx)
756 rate[eqIdx] -= dofDriftRate[eqIdx];
763 template <
class LhsEval,
class Callback>
767 if constexpr (enableSaltPrecipitation) {
768 const auto& fs = intQuants.fluidState();
769 unsigned tableIdx = this->simulator().problem().satnumRegionIndex(elementIdx);
770 LhsEval porosityFactor = obtain(1. - fs.saltSaturation());
771 porosityFactor = min(porosityFactor, 1.0);
772 const auto& permfactTable = BrineModule::permfactTable(tableIdx);
773 return permfactTable.eval(porosityFactor,
true);
775 else if constexpr (enableBioeffects) {
776 return obtain(intQuants.permFactor());
784 const InitialFluidState& initialFluidState(
unsigned globalDofIdx)
const 785 {
return initialFluidStates_[globalDofIdx]; }
787 std::vector<InitialFluidState>& initialFluidStates()
788 {
return initialFluidStates_; }
790 const std::vector<InitialFluidState>& initialFluidStates()
const 791 {
return initialFluidStates_; }
793 const EclipseIO& eclIO()
const 794 {
return eclWriter_->eclIO(); }
796 void setSubStepReport(
const SimulatorReportSingle& report)
797 {
return eclWriter_->setSubStepReport(report); }
799 void setSimulationReport(
const SimulatorReport& report)
800 {
return eclWriter_->setSimulationReport(report); }
802 InitialFluidState boundaryFluidState(
unsigned globalDofIdx,
const int directionId)
const 804 OPM_TIMEBLOCK_LOCAL(boundaryFluidState, Subsystem::Assembly);
805 const auto& bcprop = this->simulator().vanguard().schedule()[this->episodeIndex()].bcprop;
806 if (bcprop.size() > 0) {
807 FaceDir::DirEnum dir = FaceDir::FromIntersectionIndex(directionId);
811 if (this->bcindex_(dir)[globalDofIdx] == 0)
812 return initialFluidStates_[globalDofIdx];
814 const auto& bc = bcprop[this->bcindex_(dir)[globalDofIdx]];
815 if (bc.bctype == BCType::DIRICHLET )
817 InitialFluidState fluidState;
819 fluidState.setPvtRegionIndex(pvtRegionIdx);
821 switch (bc.component) {
822 case BCComponent::OIL:
823 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx))
824 throw std::logic_error(
"oil is not active and you're trying to add oil BC");
826 fluidState.setSaturation(FluidSystem::oilPhaseIdx, 1.0);
828 case BCComponent::GAS:
829 if (!FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx))
830 throw std::logic_error(
"gas is not active and you're trying to add gas BC");
832 fluidState.setSaturation(FluidSystem::gasPhaseIdx, 1.0);
834 case BCComponent::WATER:
835 if (!FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
836 throw std::logic_error(
"water is not active and you're trying to add water BC");
838 fluidState.setSaturation(FluidSystem::waterPhaseIdx, 1.0);
840 case BCComponent::SOLVENT:
841 case BCComponent::POLYMER:
842 case BCComponent::MICR:
843 case BCComponent::OXYG:
844 case BCComponent::UREA:
845 case BCComponent::NONE:
846 throw std::logic_error(
"you need to specify a valid component (OIL, WATER or GAS) when DIRICHLET type is set in BC");
848 fluidState.setTotalSaturation(1.0);
849 double pressure = initialFluidStates_[globalDofIdx].pressure(this->refPressurePhaseIdx_());
850 const auto pressure_input = bc.pressure;
851 if (pressure_input) {
852 pressure = *pressure_input;
855 std::array<Scalar, numPhases> pc = {0};
857 MaterialLaw::capillaryPressures(pc, matParams, fluidState);
858 Valgrind::CheckDefined(pressure);
859 Valgrind::CheckDefined(pc);
860 for (
unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
861 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
862 if (Indices::oilEnabled)
863 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
864 else if (Indices::gasEnabled)
865 fluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
866 else if (Indices::waterEnabled)
868 fluidState.setPressure(phaseIdx, pressure);
870 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
871 double temperature = initialFluidStates_[globalDofIdx].temperature(0);
872 const auto temperature_input = bc.temperature;
873 if(temperature_input)
878 if constexpr (enableDissolvedGas) {
879 if (FluidSystem::enableDissolvedGas()) {
880 fluidState.setRs(0.0);
881 fluidState.setRv(0.0);
884 if constexpr (enableDisgasInWater) {
885 if (FluidSystem::enableDissolvedGasInWater()) {
886 fluidState.setRsw(0.0);
889 if constexpr (enableVapwat) {
890 if (FluidSystem::enableVaporizedWater()) {
891 fluidState.setRvw(0.0);
895 for (
unsigned activePhaseIdx = 0; activePhaseIdx < FluidSystem::numActivePhases(); ++activePhaseIdx) {
896 const auto phaseIdx = FluidSystem::activeToCanonicalPhaseIdx(activePhaseIdx);
898 const auto& b = FluidSystem::inverseFormationVolumeFactor(fluidState, phaseIdx, pvtRegionIdx);
899 fluidState.setInvB(phaseIdx, b);
901 const auto& rho = FluidSystem::density(fluidState, phaseIdx, pvtRegionIdx);
902 fluidState.setDensity(phaseIdx, rho);
903 if constexpr (energyModuleType == EnergyModules::FullyImplicitThermal) {
904 const auto& h = FluidSystem::enthalpy(fluidState, phaseIdx, pvtRegionIdx);
905 fluidState.setEnthalpy(phaseIdx, h);
908 fluidState.checkDefined();
912 return initialFluidStates_[globalDofIdx];
916 const EclWriterType& eclWriter()
const 917 {
return *eclWriter_; }
919 EclWriterType& eclWriter()
920 {
return *eclWriter_; }
928 return this->mixControls_.maxGasDissolutionFactor(timeIdx, globalDofIdx,
929 this->episodeIndex(),
939 return this->mixControls_.maxOilVaporizationFactor(timeIdx, globalDofIdx,
940 this->episodeIndex(),
957 const auto& rspec = this->simulator().vanguard().eclState().runspec();
958 const bool tpsaActive = rspec.mech() && rspec.mechSolver().tpsa();
963 int episodeIdx = this->episodeIndex();
964 return !this->mixControls_.drsdtActive(episodeIdx) &&
965 !this->mixControls_.drvdtActive(episodeIdx) &&
966 this->rockCompPoroMultWc_.empty() &&
967 this->rockCompPoroMult_.empty();
976 template <
class Context>
977 void initial(PrimaryVariables& values,
const Context& context,
unsigned spaceIdx,
unsigned timeIdx)
const 979 unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
981 values.setPvtRegionIndex(
pvtRegionIndex(context, spaceIdx, timeIdx));
982 values.assignNaive(initialFluidStates_[globalDofIdx]);
984 if constexpr (enableSolvent) {
985 SolventModule::assignPrimaryVars(values,
986 this->solventSaturation_[globalDofIdx],
987 this->solventRsw_[globalDofIdx]);
990 if constexpr (enablePolymer) {
991 values[Indices::polymerConcentrationIdx] = this->polymer_.concentration[globalDofIdx];
994 if constexpr (enablePolymerMolarWeight) {
995 values[Indices::polymerMoleWeightIdx]= this->polymer_.moleWeight[globalDofIdx];
998 if constexpr (enableBrine) {
999 if (enableSaltPrecipitation && values.primaryVarsMeaningBrine() == PrimaryVariables::BrineMeaning::Sp) {
1000 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltSaturation();
1003 values[Indices::saltConcentrationIdx] = initialFluidStates_[globalDofIdx].saltConcentration();
1007 if constexpr (enableBioeffects) {
1008 values[Indices::microbialConcentrationIdx] = this->bioeffects_.microbialConcentration[globalDofIdx];
1009 values[Indices::biofilmVolumeFractionIdx] = this->bioeffects_.biofilmVolumeFraction[globalDofIdx];
1010 if constexpr (enableMICP) {
1011 values[Indices::oxygenConcentrationIdx] = this->bioeffects_.oxygenConcentration[globalDofIdx];
1012 values[Indices::ureaConcentrationIdx] = this->bioeffects_.ureaConcentration[globalDofIdx];
1013 values[Indices::calciteVolumeFractionIdx] = this->bioeffects_.calciteVolumeFraction[globalDofIdx];
1017 values.checkDefined();
1021 Scalar drsdtcon(
unsigned elemIdx,
int episodeIdx)
const 1023 return this->mixControls_.drsdtcon(elemIdx, episodeIdx,
1027 bool drsdtconIsActive(
unsigned elemIdx,
int episodeIdx)
const 1029 return this->mixControls_.drsdtConvective(episodeIdx, this->
pvtRegionIndex(elemIdx));
1037 template <
class Context>
1039 const Context& context,
1041 unsigned timeIdx)
const 1043 OPM_TIMEBLOCK_LOCAL(eclProblemBoundary, Subsystem::Assembly);
1044 if (!context.intersection(spaceIdx).boundary())
1047 if constexpr (energyModuleType != EnergyModules::FullyImplicitThermal || !enableThermalFluxBoundaries)
1055 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1056 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1057 values.setThermalFlow(context, spaceIdx, timeIdx, this->initialFluidStates_[globalDofIdx] );
1060 if (this->nonTrivialBoundaryConditions()) {
1061 unsigned indexInInside = context.intersection(spaceIdx).indexInInside();
1062 unsigned interiorDofIdx = context.interiorScvIndex(spaceIdx, timeIdx);
1063 unsigned globalDofIdx = context.globalSpaceIndex(interiorDofIdx, timeIdx);
1064 unsigned pvtRegionIdx =
pvtRegionIndex(context, spaceIdx, timeIdx);
1065 const auto [type, massrate] = this->boundaryCondition(globalDofIdx, indexInInside);
1066 if (type == BCType::THERMAL)
1067 values.setThermalFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1068 else if (type == BCType::FREE || type == BCType::DIRICHLET)
1069 values.setFreeFlow(context, spaceIdx, timeIdx, this->boundaryFluidState(globalDofIdx, indexInInside));
1070 else if (type == BCType::RATE)
1071 values.setMassRate(massrate, pvtRegionIdx);
1081 auto& simulator = this->simulator();
1082 const auto& eclState = simulator.vanguard().eclState();
1084 std::size_t numElems = this->model().numGridDof();
1085 this->initialFluidStates_.resize(numElems);
1086 if constexpr (enableSolvent) {
1087 this->solventSaturation_.resize(numElems, 0.0);
1088 this->solventRsw_.resize(numElems, 0.0);
1091 if constexpr (enablePolymer)
1092 this->polymer_.concentration.resize(numElems, 0.0);
1094 if constexpr (enablePolymerMolarWeight) {
1095 const std::string msg {
"Support of the RESTART for polymer molecular weight " 1096 "is not implemented yet. The polymer weight value will be " 1097 "zero when RESTART begins"};
1098 OpmLog::warning(
"NO_POLYMW_RESTART", msg);
1099 this->polymer_.moleWeight.resize(numElems, 0.0);
1102 if constexpr (enableBioeffects) {
1103 this->bioeffects_.resize(numElems);
1107 this->mixControls_.init(numElems, restart_step, eclState.runspec().tabdims().getNumPVTTables());
1109 if constexpr (enableBioeffects) {
1110 this->bioeffects_ = this->eclWriter_->outputModule().getBioeffects().getSolution();
1113 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1114 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1116 this->eclWriter_->outputModule().initHysteresisParams(simulator, elemIdx);
1117 this->eclWriter_->outputModule().assignToFluidState(elemFluidState, elemIdx);
1126 auto ssol = enableSolvent
1127 ? this->eclWriter_->outputModule().getSolventSaturation(elemIdx)
1130 this->processRestartSaturations_(elemFluidState, ssol);
1132 if constexpr (enableSolvent) {
1133 this->solventSaturation_[elemIdx] = ssol;
1134 this->solventRsw_[elemIdx] = this->eclWriter_->outputModule().getSolventRsw(elemIdx);
1139 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1140 bool needTemperature = (eclState.runspec().co2Storage() || eclState.runspec().h2Storage());
1141 if (needTemperature) {
1142 const auto& fp = simulator.vanguard().eclState().fieldProps();
1143 elemFluidState.setTemperature(fp.get_double(
"TEMPI")[elemIdx]);
1147 this->mixControls_.updateLastValues(elemIdx, elemFluidState.Rs(), elemFluidState.Rv());
1149 if constexpr (enablePolymer)
1150 this->polymer_.concentration[elemIdx] = this->eclWriter_->outputModule().getPolymerConcentration(elemIdx);
1154 const int episodeIdx = this->episodeIndex();
1155 this->mixControls_.updateMaxValues(episodeIdx, simulator.timeStepSize());
1160 auto& sol = this->model().solution(0);
1161 const auto& gridView = this->gridView();
1162 ElementContext elemCtx(simulator);
1163 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
1164 elemCtx.updatePrimaryStencil(elem);
1165 int elemIdx = elemCtx.globalSpaceIndex(0, 0);
1166 this->
initial(sol[elemIdx], elemCtx, 0, 0);
1174 this->model().syncOverlap();
1177 this->updateReferencePorosity_();
1178 this->mixControls_.init(this->model().numGridDof(),
1179 this->episodeIndex(),
1180 eclState.runspec().tabdims().getNumPVTTables());
1188 {
return thresholdPressures_.thresholdPressure(elem1Idx, elem2Idx); }
1191 {
return thresholdPressures_; }
1193 FlowThresholdPressure<TypeTag>& thresholdPressure()
1194 {
return thresholdPressures_; }
1196 const ModuleParams& moduleParams()
const 1198 return moduleParams_;
1201 template<
class Serializer>
1202 void serializeOp(Serializer& serializer)
1204 serializer(static_cast<FlowProblemType&>(*
this));
1205 serializer(mixControls_);
1206 serializer(*eclWriter_);
1210 void updateExplicitQuantities_(
int episodeIdx,
int timeStepSize,
const bool first_step_after_restart)
override 1212 this->updateExplicitQuantities_(first_step_after_restart);
1214 if constexpr (getPropValue<TypeTag, Properties::EnablePolymer>())
1215 updateMaxPolymerAdsorption_();
1217 mixControls_.updateExplicitQuantities(episodeIdx, timeStepSize);
1220 void updateMaxPolymerAdsorption_()
1223 this->updateProperty_(
"FlowProblemBlackoil::updateMaxPolymerAdsorption_() failed:",
1224 [
this](
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1226 this->updateMaxPolymerAdsorption_(compressedDofIdx,iq);
1230 bool updateMaxPolymerAdsorption_(
unsigned compressedDofIdx,
const IntensiveQuantities& iq)
1232 const Scalar pa = scalarValue(iq.polymerAdsorption());
1233 auto& mpa = this->polymer_.maxAdsorption;
1234 if (mpa[compressedDofIdx] < pa) {
1235 mpa[compressedDofIdx] = pa;
1242 void computeAndSetEqWeights_()
1244 std::vector<Scalar> sumInvB(numPhases, 0.0);
1245 const auto& gridView = this->gridView();
1246 ElementContext elemCtx(this->simulator());
1247 for(
const auto& elem: elements(gridView, Dune::Partitions::interior)) {
1248 elemCtx.updatePrimaryStencil(elem);
1249 int elemIdx = elemCtx.globalSpaceIndex(0, 0);
1250 const auto& dofFluidState = this->initialFluidStates_[elemIdx];
1251 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1252 if (!FluidSystem::phaseIsActive(phaseIdx))
1255 sumInvB[phaseIdx] += dofFluidState.invB(phaseIdx);
1259 std::size_t numDof = this->model().numGridDof();
1260 const auto& comm = this->simulator().vanguard().grid().comm();
1261 comm.sum(sumInvB.data(),sumInvB.size());
1262 Scalar numTotalDof = comm.sum(numDof);
1264 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1265 if (!FluidSystem::phaseIsActive(phaseIdx))
1268 Scalar avgB = numTotalDof / sumInvB[phaseIdx];
1269 const unsigned solventCompIdx = FluidSystem::solventComponentIndex(phaseIdx);
1270 const unsigned activeSolventCompIdx = FluidSystem::canonicalToActiveCompIdx(solventCompIdx);
1271 this->model().setEqWeight(activeSolventCompIdx, avgB);
1276 bool updateCompositionChangeLimits_()
1278 OPM_TIMEBLOCK(updateCompositionChangeLimits);
1281 int episodeIdx = this->episodeIndex();
1282 std::array<bool,3> active{this->mixControls_.drsdtConvective(episodeIdx),
1283 this->mixControls_.drsdtActive(episodeIdx),
1284 this->mixControls_.drvdtActive(episodeIdx)};
1285 if (!active[0] && !active[1] && !active[2]) {
1289 this->updateProperty_(
"FlowProblemBlackoil::updateCompositionChangeLimits_()) failed:",
1290 [
this,episodeIdx,active](
unsigned compressedDofIdx,
1291 const IntensiveQuantities& iq)
1294 const Scalar distZ = active[0] ? this->simulator().vanguard().cellThickness(compressedDofIdx) : 0.0;
1296 this->mixControls_.update(compressedDofIdx,
1299 this->gravity_[dim - 1],
1300 perm[dim - 1][dim - 1],
1309 void readEclRestartSolution_()
1312 if(this->simulator().vanguard().grid().maxLevel() > 0) {
1313 throw std::invalid_argument(
"Refined grids are not yet supported for restart ");
1317 auto& simulator = this->simulator();
1318 const auto& schedule = simulator.vanguard().schedule();
1319 const auto& eclState = simulator.vanguard().eclState();
1320 const auto& initconfig = eclState.getInitConfig();
1321 const int restart_step = initconfig.getRestartStep();
1323 simulator.setTime(schedule.seconds(restart_step));
1325 simulator.startNextEpisode(simulator.startTime() + simulator.time(),
1326 schedule.stepLength(restart_step));
1327 simulator.setEpisodeIndex(restart_step);
1329 this->eclWriter_->beginRestart();
1331 Scalar dt = std::min(this->eclWriter_->restartTimeStepSize(), simulator.episodeLength());
1332 simulator.setTimeStepSize(dt);
1336 this->eclWriter_->endRestart();
1339 void readEquilInitialCondition_()
override 1341 const auto& simulator = this->simulator();
1344 EquilInitializer<TypeTag> equilInitializer(simulator, *(this->materialLawManager_));
1346 std::size_t numElems = this->model().numGridDof();
1347 this->initialFluidStates_.resize(numElems);
1348 for (std::size_t elemIdx = 0; elemIdx < numElems; ++elemIdx) {
1349 auto& elemFluidState = this->initialFluidStates_[elemIdx];
1350 elemFluidState.assign(equilInitializer.initialFluidState(elemIdx));
1354 void readExplicitInitialCondition_()
override 1356 const auto& simulator = this->simulator();
1357 const auto& vanguard = simulator.vanguard();
1358 const auto& eclState = vanguard.eclState();
1359 const auto& fp = eclState.fieldProps();
1360 bool has_swat = fp.has_double(
"SWAT");
1361 bool has_sgas = fp.has_double(
"SGAS");
1362 bool has_rs = fp.has_double(
"RS");
1363 bool has_rsw = fp.has_double(
"RSW");
1364 bool has_rv = fp.has_double(
"RV");
1365 bool has_rvw = fp.has_double(
"RVW");
1366 bool has_pressure = fp.has_double(
"PRESSURE");
1367 bool has_salt = fp.has_double(
"SALT");
1368 bool has_saltp = fp.has_double(
"SALTP");
1371 if (Indices::numPhases > 1) {
1372 if (FluidSystem::phaseIsActive(waterPhaseIdx) && !has_swat)
1373 throw std::runtime_error(
"The ECL input file requires the presence of the SWAT keyword if " 1374 "the water phase is active");
1375 if (FluidSystem::phaseIsActive(gasPhaseIdx) && !has_sgas && FluidSystem::phaseIsActive(oilPhaseIdx))
1376 throw std::runtime_error(
"The ECL input file requires the presence of the SGAS keyword if " 1377 "the gas phase is active");
1380 throw std::runtime_error(
"The ECL input file requires the presence of the PRESSURE " 1381 "keyword if the model is initialized explicitly");
1382 if (FluidSystem::enableDissolvedGas() && !has_rs)
1383 throw std::runtime_error(
"The ECL input file requires the RS keyword to be present if" 1384 " dissolved gas is enabled and the model is initialized explicitly");
1385 if (FluidSystem::enableDissolvedGasInWater() && !has_rsw)
1386 OpmLog::warning(
"The model is initialized explicitly and the RSW keyword is not present in the" 1387 " ECL input file. The RSW values are set equal to 0");
1388 if (FluidSystem::enableVaporizedOil() && !has_rv)
1389 throw std::runtime_error(
"The ECL input file requires the RV keyword to be present if" 1390 " vaporized oil is enabled and the model is initialized explicitly");
1391 if (FluidSystem::enableVaporizedWater() && !has_rvw)
1392 throw std::runtime_error(
"The ECL input file requires the RVW keyword to be present if" 1393 " vaporized water is enabled and the model is initialized explicitly");
1394 if (enableBrine && !has_salt)
1395 throw std::runtime_error(
"The ECL input file requires the SALT keyword to be present if" 1396 " brine is enabled and the model is initialized explicitly");
1397 if (enableSaltPrecipitation && !has_saltp)
1398 throw std::runtime_error(
"The ECL input file requires the SALTP keyword to be present if" 1399 " salt precipitation is enabled and the model is initialized explicitly");
1401 std::size_t numDof = this->model().numGridDof();
1403 initialFluidStates_.resize(numDof);
1405 std::vector<double> waterSaturationData;
1406 std::vector<double> gasSaturationData;
1407 std::vector<double> pressureData;
1408 std::vector<double> rsData;
1409 std::vector<double> rswData;
1410 std::vector<double> rvData;
1411 std::vector<double> rvwData;
1412 std::vector<double> tempiData;
1413 std::vector<double> saltData;
1414 std::vector<double> saltpData;
1416 if (FluidSystem::phaseIsActive(waterPhaseIdx) && Indices::numPhases > 1)
1417 waterSaturationData = fp.get_double(
"SWAT");
1419 waterSaturationData.resize(numDof);
1421 if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(oilPhaseIdx))
1422 gasSaturationData = fp.get_double(
"SGAS");
1424 gasSaturationData.resize(numDof);
1426 pressureData = fp.get_double(
"PRESSURE");
1427 if (FluidSystem::enableDissolvedGas())
1428 rsData = fp.get_double(
"RS");
1430 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1431 rswData = fp.get_double(
"RSW");
1433 if (FluidSystem::enableVaporizedOil())
1434 rvData = fp.get_double(
"RV");
1436 if (FluidSystem::enableVaporizedWater())
1437 rvwData = fp.get_double(
"RVW");
1440 tempiData = fp.get_double(
"TEMPI");
1443 if constexpr (enableBrine)
1444 saltData = fp.get_double(
"SALT");
1447 if constexpr (enableSaltPrecipitation)
1448 saltpData = fp.get_double(
"SALTP");
1451 for (std::size_t dofIdx = 0; dofIdx < numDof; ++dofIdx) {
1452 auto& dofFluidState = initialFluidStates_[dofIdx];
1459 if constexpr (energyModuleType != EnergyModules::NoTemperature) {
1460 Scalar temperatureLoc = tempiData[dofIdx];
1461 if (!std::isfinite(temperatureLoc) || temperatureLoc <= 0)
1462 temperatureLoc = FluidSystem::surfaceTemperature;
1463 dofFluidState.setTemperature(temperatureLoc);
1469 if constexpr (enableBrine)
1470 dofFluidState.setSaltConcentration(saltData[dofIdx]);
1475 if constexpr (enableSaltPrecipitation)
1476 dofFluidState.setSaltSaturation(saltpData[dofIdx]);
1481 if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx))
1482 dofFluidState.setSaturation(FluidSystem::waterPhaseIdx,
1483 waterSaturationData[dofIdx]);
1485 if (FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){
1486 if (!FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)){
1487 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1489 - waterSaturationData[dofIdx]);
1492 dofFluidState.setSaturation(FluidSystem::gasPhaseIdx,
1493 gasSaturationData[dofIdx]);
1495 if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) {
1496 const Scalar soil = 1.0 - waterSaturationData[dofIdx] - gasSaturationData[dofIdx];
1497 if (soil < smallSaturationTolerance_) {
1498 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, 0.0);
1501 dofFluidState.setSaturation(FluidSystem::oilPhaseIdx, soil);
1508 Scalar pressure = pressureData[dofIdx];
1512 std::array<Scalar, numPhases> pc = {0};
1514 MaterialLaw::capillaryPressures(pc, matParams, dofFluidState);
1515 Valgrind::CheckDefined(pressure);
1516 Valgrind::CheckDefined(pc);
1517 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1518 if (!FluidSystem::phaseIsActive(phaseIdx))
1521 if (Indices::oilEnabled)
1522 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[oilPhaseIdx]));
1523 else if (Indices::gasEnabled)
1524 dofFluidState.setPressure(phaseIdx, pressure + (pc[phaseIdx] - pc[gasPhaseIdx]));
1525 else if (Indices::waterEnabled)
1527 dofFluidState.setPressure(phaseIdx, pressure);
1530 if constexpr (enableDissolvedGas) {
1531 if (FluidSystem::enableDissolvedGas())
1532 dofFluidState.setRs(rsData[dofIdx]);
1533 else if (Indices::gasEnabled && Indices::oilEnabled)
1534 dofFluidState.setRs(0.0);
1535 if (FluidSystem::enableVaporizedOil())
1536 dofFluidState.setRv(rvData[dofIdx]);
1537 else if (Indices::gasEnabled && Indices::oilEnabled)
1538 dofFluidState.setRv(0.0);
1541 if constexpr (enableDisgasInWater) {
1542 if (FluidSystem::enableDissolvedGasInWater() && has_rsw)
1543 dofFluidState.setRsw(rswData[dofIdx]);
1546 if constexpr (enableVapwat) {
1547 if (FluidSystem::enableVaporizedWater())
1548 dofFluidState.setRvw(rvwData[dofIdx]);
1554 for (
unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1555 if (!FluidSystem::phaseIsActive(phaseIdx))
1558 const auto& b = FluidSystem::inverseFormationVolumeFactor(dofFluidState, phaseIdx,
pvtRegionIndex(dofIdx));
1559 dofFluidState.setInvB(phaseIdx, b);
1561 const auto& rho = FluidSystem::density(dofFluidState, phaseIdx,
pvtRegionIndex(dofIdx));
1562 dofFluidState.setDensity(phaseIdx, rho);
1569 void processRestartSaturations_(InitialFluidState& elemFluidState, Scalar&
solventSaturation)
1573 Scalar sumSaturation = 0.0;
1574 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1575 if (FluidSystem::phaseIsActive(phaseIdx)) {
1576 if (elemFluidState.saturation(phaseIdx) < smallSaturationTolerance_)
1577 elemFluidState.setSaturation(phaseIdx, 0.0);
1579 sumSaturation += elemFluidState.saturation(phaseIdx);
1583 if constexpr (enableSolvent) {
1590 assert(sumSaturation > 0.0);
1592 for (std::size_t phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
1593 if (FluidSystem::phaseIsActive(phaseIdx)) {
1594 const Scalar saturation = elemFluidState.saturation(phaseIdx) / sumSaturation;
1595 elemFluidState.setSaturation(phaseIdx, saturation);
1598 if constexpr (enableSolvent) {
1603 void readInitialCondition_()
override 1605 FlowProblemType::readInitialCondition_();
1607 if constexpr (enableSolvent || enablePolymer || enablePolymerMolarWeight || enableBioeffects)
1608 this->readBlackoilExtentionsInitialConditions_(this->model().numGridDof(),
1611 enablePolymerMolarWeight,
1617 void handleSolventBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1619 if constexpr (!enableSolvent)
1620 throw std::logic_error(
"solvent is disabled and you're trying to add solvent to BC");
1622 rate[Indices::solventSaturationIdx] = bc.rate;
1625 void handlePolymerBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1627 if constexpr (!enablePolymer)
1628 throw std::logic_error(
"polymer is disabled and you're trying to add polymer to BC");
1630 rate[Indices::polymerConcentrationIdx] = bc.rate;
1633 void handleMicrBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1635 if constexpr (!enableMICP)
1636 throw std::logic_error(
"MICP is disabled and you're trying to add microbes to BC");
1638 rate[Indices::microbialConcentrationIdx] = bc.rate;
1641 void handleOxygBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1643 if constexpr (!enableMICP)
1644 throw std::logic_error(
"MICP is disabled and you're trying to add oxygen to BC");
1646 rate[Indices::oxygenConcentrationIdx] = bc.rate;
1649 void handleUreaBC(
const BCProp::BCFace& bc, RateVector& rate)
const override 1651 if constexpr (!enableMICP)
1652 throw std::logic_error(
"MICP is disabled and you're trying to add urea to BC");
1654 rate[Indices::ureaConcentrationIdx] = bc.rate;
1656 rate[Indices::ureaConcentrationIdx] *= getPropValue<TypeTag, Properties::BlackOilUreaScalingFactor>();
1659 void updateExplicitQuantities_(
const bool first_step_after_restart)
1661 OPM_TIMEBLOCK(updateExplicitQuantities);
1662 const bool invalidateFromMaxWaterSat = this->updateMaxWaterSaturation_();
1663 const bool invalidateFromMinPressure = this->updateMinPressure_();
1666 const bool invalidateFromHyst = this->updateHysteresis_();
1667 const bool invalidateFromMaxOilSat = this->updateMaxOilSaturation_();
1670 const bool invalidateDRDT = !first_step_after_restart && this->updateCompositionChangeLimits_();
1673 const bool invalidateIntensiveQuantities
1674 = invalidateFromMaxWaterSat || invalidateFromMinPressure || invalidateFromHyst || invalidateFromMaxOilSat || invalidateDRDT;
1675 if (invalidateIntensiveQuantities) {
1676 OPM_TIMEBLOCK(beginTimeStepInvalidateIntensiveQuantities);
1677 this->model().invalidateAndUpdateIntensiveQuantities(0);
1680 this->updateRockCompTransMultVal_();
1683 bool satfuncConsistencyRequirementsMet()
const 1685 if (
const auto nph = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)
1686 + FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)
1687 + FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
1696 const auto numSamplePoints =
static_cast<std::size_t
> 1697 (Parameters::Get<Parameters::NumSatfuncConsistencySamplePoints>());
1699 auto sfuncConsistencyChecks =
1700 Satfunc::PhaseChecks::SatfuncConsistencyCheckManager<Scalar> {
1701 numSamplePoints, this->simulator().vanguard().eclState(),
1702 [&cmap = this->simulator().vanguard().cartesianIndexMapper()](
const int elemIdx)
1703 {
return cmap.cartesianIndex(elemIdx); }
1706 const auto ioRank = 0;
1707 const auto isIoRank = this->simulator().vanguard()
1708 .grid().comm().rank() == ioRank;
1713 sfuncConsistencyChecks.collectFailuresTo(ioRank)
1714 .run(this->simulator().vanguard().grid().levelGridView(0),
1715 [&vg = this->simulator().vanguard(),
1716 &emap = this->simulator().model().elementMapper()]
1718 {
return vg.gridIdxToEquilGridIdx(emap.index(elem)); });
1723 auto reportFailures = [&sfuncConsistencyChecks]
1724 (
const ViolationLevel level)
1726 sfuncConsistencyChecks.reportFailures
1727 (level, [](std::string_view record)
1728 { OpmLog::info(std::string { record }); });
1731 if (sfuncConsistencyChecks.anyFailedStandardChecks()) {
1733 OpmLog::warning(
"Saturation Function " 1734 "End-point Consistency Problems");
1736 reportFailures(ViolationLevel::Standard);
1740 if (sfuncConsistencyChecks.anyFailedCriticalChecks()) {
1742 OpmLog::error(
"Saturation Function " 1743 "End-point Consistency Failures");
1745 reportFailures(ViolationLevel::Critical);
1758 FlowThresholdPressure<TypeTag> thresholdPressures_;
1760 std::vector<InitialFluidState> initialFluidStates_;
1762 bool enableEclOutput_;
1763 std::unique_ptr<EclWriterType> eclWriter_;
1765 const Scalar smallSaturationTolerance_ = 1.e-6;
1767 bool enableDamarisOutput_ = false ;
1768 std::unique_ptr<DamarisWriterType> damarisWriter_;
1770 MixingRateControls<FluidSystem> mixControls_;
1772 ActionHandler<Scalar, IndexTraits> actionHandler_;
1774 ModuleParams moduleParams_;
1776 HybridNewton hybridNewton_;
1789 bool episodeWillBeOver()
const override 1791 const auto currTime = this->simulator().time()
1792 + this->simulator().timeStepSize();
1794 const auto nextReportStep =
1795 this->simulator().vanguard().schedule()
1796 .seconds(this->simulator().episodeIndex() + 1);
1798 const auto isSubStep = (nextReportStep - currTime)
1799 > (2 * std::numeric_limits<float>::epsilon()) * nextReportStep;
1807 #endif // OPM_FLOW_PROBLEM_BLACK_HPP This problem simulates an input file given in the data format used by the commercial ECLiPSE simulato...
Definition: FlowProblemBlackoil.hpp:86
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:926
void boundary(BoundaryRateVector &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the boundary conditions for a boundary segment.
Definition: FlowProblemBlackoil.hpp:1038
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
Definition: blackoilfoammodules.hh:57
void tryApplyHybridNewton()
Attempt to apply the Hybrid Newton correction at the current timestep.
Definition: HybridNewton.hpp:101
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:901
void initial(PrimaryVariables &values, const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Evaluate the initial value for a control volume.
Definition: FlowProblemBlackoil.hpp:977
const MaterialLawParams & materialLawParams(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:806
virtual void beginTimeStep()
Called by the simulator before each time integration.
Definition: FlowProblem.hpp:366
Scalar temperature(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:947
This class calculates the threshold pressure for grid faces according to the Eclipse Reference Manual...
Definition: FlowThresholdPressure.hpp:55
void beginTimeStep() override
Called by the simulator before each time integration.
Definition: FlowProblemBlackoil.hpp:315
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:568
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:937
FlowProblemBlackoil(Simulator &simulator)
Definition: FlowProblemBlackoil.hpp:189
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:600
Hybrid Newton solver extension for the black-oil model.
Definition: HybridNewton.hpp:59
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:764
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Scalar porosity(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:701
Contains classes extending the black-oil model.
void beginEpisode() override
Called by the simulator before an episode begins.
Definition: FlowProblemBlackoil.hpp:282
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:515
Classes required for dynamic convective mixing.
void finishInit()
Called by the Opm::Simulator in order to initialize the problem.
Definition: FlowProblemBlackoil.hpp:324
Scalar thresholdPressure(unsigned elem1Idx, unsigned elem2Idx) const
Definition: FlowProblemBlackoil.hpp:1187
const DimMatrix & intrinsicPermeability(const Context &context, unsigned spaceIdx, unsigned timeIdx) const
Definition: FlowProblem.hpp:534
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:175
virtual void beginEpisode()
Called by the simulator before an episode begins.
Definition: FlowProblem.hpp:307
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:114
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:438
Struct holding the parameters for the BlackOilPolymerModule class.
Definition: blackoilpolymerparams.hpp:43
Provides the auxiliary methods required for consideration of the dispersion equation.
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:1052
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:495
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:186
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:635
virtual void initialSolutionApplied()
Callback used by the model to indicate that the initial solution has been determined for all degrees ...
Definition: FlowProblem.hpp:1019
virtual void writeOutput(bool verbose)
Write the requested quantities of the current solution into the output files.
Definition: FlowProblem.hpp:518
Scalar solventSaturation(unsigned elemIdx) const
Returns the initial solvent saturation for a given a cell index.
Definition: FlowGenericProblem_impl.hpp:649
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:1079
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.
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:955