28 #ifndef EWOMS_CONVECTIVEMIXING_MODULE_HH 29 #define EWOMS_CONVECTIVEMIXING_MODULE_HH 31 #include <dune/common/fvector.hh> 33 #include <opm/common/utility/gpuistl_if_available.hpp> 34 #include <opm/input/eclipse/EclipseState/EclipseState.hpp> 36 #include <opm/input/eclipse/Schedule/OilVaporizationProperties.hpp> 37 #include <opm/input/eclipse/Schedule/Schedule.hpp> 39 #include <opm/material/common/MathToolbox.hpp> 40 #include <opm/material/common/Valgrind.hpp> 41 #include <opm/material/fluidsystems/BlackOilFluidSystem.hpp> 67 template <
class TypeTag>
68 class BlackOilConvectiveMixingModule<TypeTag, true>
77 using Toolbox = MathToolbox<Evaluation>;
80 static constexpr
int conti0EqIdx = Indices::conti0EqIdx;
81 static constexpr
int dimWorld = GridView::dimensionworld;
82 static constexpr
bool enableFullyImplicitThermal =
83 (getPropValue<TypeTag, Properties::EnergyModuleType>() == EnergyModules::FullyImplicitThermal);
84 static constexpr
unsigned contiEnergyEqIdx = Indices::contiEnergyEqIdx;
87 static void beginEpisode(
const EclipseState& eclState,
88 const Schedule& schedule,
93 std::size_t numRegions = eclState.runspec().tabdims().getNumPVTTables();
94 const auto& control = schedule[episodeIdx].oilvap();
95 if (info.active_.empty()) {
96 info.active_.resize(numRegions);
97 info.Xhi_.resize(numRegions);
98 info.Psi_.resize(numRegions);
100 for (std::size_t i = 0; i < numRegions; ++i ) {
101 info.active_[i] = control.drsdtConvective(i);
102 if (control.drsdtConvective(i)) {
103 info.Xhi_[i] = control.getMaxDRSDT(i);
104 info.Psi_[i] = control.getPsi(i);
109 template <
class CMMParam>
110 OPM_HOST_DEVICE
static void modifyAvgDensity(Evaluation& rhoAvg,
111 const IntensiveQuantities& intQuantsIn,
112 const IntensiveQuantities& intQuantsEx,
113 const unsigned phaseIdx,
114 const CMMParam& info) {
117 constexpr
int waterPhaseIdx = FluidSystem::waterPhaseIdx;
118 constexpr
int oilPhaseIdx = FluidSystem::oilPhaseIdx;
120 if (info.active_.empty()) {
123 if (!info.active_[intQuantsIn.pvtRegionIndex()] || !info.active_[intQuantsEx.pvtRegionIndex()]) {
127 FluidSystem fsys = intQuantsIn.getFluidSystem();
128 if (phaseIdx == fsys.gasPhaseIdx) {
132 const auto& liquidPhaseIdx =
133 fsys.phaseIsActive(waterPhaseIdx)
138 const auto& t_in = intQuantsIn.fluidState().temperature(liquidPhaseIdx);
139 const auto& p_in = intQuantsIn.fluidState().pressure(liquidPhaseIdx);
140 const auto& salt_in = intQuantsIn.fluidState().saltConcentration();
142 const auto& bLiquidIn =
143 fsys.phaseIsActive(waterPhaseIdx)
144 ? fsys.waterPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(),
145 t_in, p_in, Evaluation(0.0), salt_in)
146 : fsys.oilPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(),
147 t_in, p_in, Evaluation(0.0));
149 const auto& refDensityLiquidIn =
150 fsys.phaseIsActive(waterPhaseIdx)
151 ? fsys.waterPvt().waterReferenceDensity(intQuantsIn.pvtRegionIndex())
152 : fsys.oilPvt().oilReferenceDensity(intQuantsIn.pvtRegionIndex());
154 const auto& rho_in = bLiquidIn * refDensityLiquidIn;
156 const auto t_ex = Toolbox::value(intQuantsEx.fluidState().temperature(liquidPhaseIdx));
157 const auto p_ex = Toolbox::value(intQuantsEx.fluidState().pressure(liquidPhaseIdx));
158 const auto salt_ex = Toolbox::value(intQuantsEx.fluidState().saltConcentration());
160 const auto bLiquidEx =
161 fsys.phaseIsActive(waterPhaseIdx)
162 ? fsys.waterPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
163 t_ex, p_ex, Scalar{0.0}, salt_ex)
164 : fsys.oilPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
165 t_ex, p_ex, Scalar{0.0});
167 const auto& refDensityLiquidEx =
168 fsys.phaseIsActive(waterPhaseIdx)
169 ? fsys.waterPvt().waterReferenceDensity(intQuantsEx.pvtRegionIndex())
170 : fsys.oilPvt().oilReferenceDensity(intQuantsEx.pvtRegionIndex());
172 const auto rho_ex = bLiquidEx * refDensityLiquidEx;
174 rhoAvg = (rho_in + rho_ex) / 2;
177 template <
class Context>
178 OPM_HOST_DEVICE
static void addConvectiveMixingFlux(RateVector& flux,
179 const Context& elemCtx,
184 const auto& problem = elemCtx.problem();
185 const auto& stencil = elemCtx.stencil(timeIdx);
186 const auto& scvf = stencil.interiorFace(scvfIdx);
188 unsigned interiorDofIdx = scvf.interiorIndex();
189 unsigned exteriorDofIdx = scvf.exteriorIndex();
190 assert(interiorDofIdx != exteriorDofIdx);
192 const auto& globalIndexIn = stencil.globalSpaceIndex(interiorDofIdx);
193 const auto& globalIndexEx = stencil.globalSpaceIndex(exteriorDofIdx);
194 Scalar trans = problem.transmissibility(elemCtx, interiorDofIdx, exteriorDofIdx);
195 Scalar faceArea = scvf.area();
196 const Scalar g = problem.gravity()[dimWorld - 1];
197 const auto& intQuantsIn = elemCtx.intensiveQuantities(interiorDofIdx, timeIdx);
198 const auto& intQuantsEx = elemCtx.intensiveQuantities(exteriorDofIdx, timeIdx);
199 const Scalar zIn = problem.dofCenterDepth(elemCtx, interiorDofIdx, timeIdx);
200 const Scalar zEx = problem.dofCenterDepth(elemCtx, exteriorDofIdx, timeIdx);
201 const Scalar distZ = zIn - zEx;
202 addConvectiveMixingFlux(flux,
210 problem.moduleParams().convectiveMixingModuleParam);
217 template <
class RateVectorT = RateVector,
class CMMParam = ConvectiveMixingModuleParamT>
219 const IntensiveQuantities& intQuantsIn,
220 const IntensiveQuantities& intQuantsEx,
221 const unsigned globalIndexIn,
222 const unsigned globalIndexEx,
225 const Scalar faceArea,
226 const CMMParam& info)
230 constexpr
int waterPhaseIdx = FluidSystem::waterPhaseIdx;
231 constexpr
int oilPhaseIdx = FluidSystem::oilPhaseIdx;
233 const FluidSystem& fsys = intQuantsIn.getFluidSystem();
235 if (info.active_.empty()) {
239 if (!info.active_[intQuantsIn.pvtRegionIndex()] || !info.active_[intQuantsEx.pvtRegionIndex()]) {
243 const auto& liquidPhaseIdx =
244 fsys.phaseIsActive(waterPhaseIdx)
249 const auto& t_in = intQuantsIn.fluidState().temperature(liquidPhaseIdx);
250 const auto& p_in = intQuantsIn.fluidState().pressure(liquidPhaseIdx);
251 const auto& rssat_in = intQuantsIn.saturatedDissolutionFactor();
252 const auto& salt_in = intQuantsIn.fluidState().saltSaturation();
254 const auto bLiquidSatIn =
255 fsys.phaseIsActive(waterPhaseIdx)
256 ? fsys.waterPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(),
257 t_in, p_in, rssat_in, salt_in)
258 : fsys.oilPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(),
259 t_in, p_in, rssat_in);
261 const auto& densityLiquidIn =
262 fsys.phaseIsActive(waterPhaseIdx)
263 ? fsys.waterPvt().waterReferenceDensity(intQuantsIn.pvtRegionIndex())
264 : fsys.oilPvt().oilReferenceDensity(intQuantsIn.pvtRegionIndex());
266 const auto rho_in = Opm::getValue(intQuantsIn.fluidState().invB(liquidPhaseIdx)) * densityLiquidIn;
267 const auto rho_sat_in = bLiquidSatIn *
269 rssat_in * fsys.referenceDensity(fsys.gasPhaseIdx,
270 intQuantsIn.pvtRegionIndex()));
273 const auto t_ex = Opm::getValue(intQuantsEx.fluidState().temperature(liquidPhaseIdx));
274 const auto p_ex = Opm::getValue(intQuantsEx.fluidState().pressure(liquidPhaseIdx));
275 const auto rssat_ex = Opm::getValue(intQuantsEx.saturatedDissolutionFactor());
276 const auto salt_ex = Opm::getValue(intQuantsEx.fluidState().saltSaturation());
277 const auto bLiquidSatEx =
278 fsys.phaseIsActive(waterPhaseIdx)
279 ? fsys.waterPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
280 t_ex, p_ex, rssat_ex, salt_ex)
281 : fsys.oilPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
282 t_ex, p_ex, rssat_ex);
284 const auto& densityLiquidEx =
285 fsys.phaseIsActive(waterPhaseIdx)
286 ? fsys.waterPvt().waterReferenceDensity(intQuantsEx.pvtRegionIndex())
287 : fsys.oilPvt().oilReferenceDensity(intQuantsEx.pvtRegionIndex());
289 const auto rho_ex = Opm::getValue(intQuantsEx.fluidState().invB(liquidPhaseIdx)) * densityLiquidEx;
290 const auto rho_sat_ex = bLiquidSatEx *
292 rssat_ex * fsys.referenceDensity(fsys.gasPhaseIdx,
293 intQuantsEx.pvtRegionIndex()));
295 const auto delta_rho = (rho_sat_ex + rho_sat_in - rho_in - rho_ex) / 2;
296 const auto pressure_difference_convective_mixing = delta_rho * distZg;
299 if (Opm::abs(pressure_difference_convective_mixing) > 1e-12) {
301 short interiorDofIdx = 0;
302 constexpr
short exteriorDofIdx = 1;
305 if (pressure_difference_convective_mixing > 0) {
306 upIdx = exteriorDofIdx;
309 const auto& up = (upIdx == interiorDofIdx) ? intQuantsIn : intQuantsEx;
310 const auto& rssat_up = (upIdx == interiorDofIdx) ? rssat_in : rssat_ex;
311 unsigned globalUpIndex = (upIdx == interiorDofIdx) ? globalIndexIn : globalIndexEx;
313 fsys.phaseIsActive(waterPhaseIdx)
314 ? up.fluidState().Rsw()
315 : up.fluidState().Rs();
317 const Evaluation& transMult = up.rockCompTransMultiplier();
318 const auto& invB = up.fluidState().invB(liquidPhaseIdx);
319 const auto& visc = up.fluidState().viscosity(liquidPhaseIdx);
322 const Evaluation RsupRestricted = Opm::min(Rsup, rssat_up*info.Psi_[up.pvtRegionIndex()]);
324 const auto convectiveFlux = -trans * transMult * info.Xhi_[up.pvtRegionIndex()] * invB *
325 pressure_difference_convective_mixing * RsupRestricted / (visc * faceArea);
326 unsigned activeGasCompIdx = fsys.canonicalToActiveCompIdx(fsys.gasCompIdx);
327 if (globalUpIndex == globalIndexIn) {
328 flux[conti0EqIdx + activeGasCompIdx] += convectiveFlux;
331 flux[conti0EqIdx + activeGasCompIdx] += Opm::getValue(convectiveFlux);
334 if constexpr (enableFullyImplicitThermal) {
335 const auto& h = up.fluidState().enthalpy(liquidPhaseIdx) *
336 fsys.referenceDensity(fsys.gasPhaseIdx, up.pvtRegionIndex());
337 if (globalUpIndex == globalIndexIn) {
338 flux[contiEnergyEqIdx] += convectiveFlux * h;
341 flux[contiEnergyEqIdx] += Opm::getValue(h) * Opm::getValue(convectiveFlux);
355 template <
class TypeTag>
369 const auto liquidPhaseIdx =
370 FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)
371 ? FluidSystem::waterPhaseIdx
372 : FluidSystem::oilPhaseIdx;
374 const Evaluation SoMax = 0.0;
375 saturatedDissolutionFactor_ = FluidSystem::saturatedDissolutionFactor(asImp_().fluidState(),
377 asImp_().pvtRegionIndex(),
381 OPM_HOST_DEVICE
const Evaluation& saturatedDissolutionFactor()
const 382 {
return saturatedDissolutionFactor_; }
385 Implementation& asImp_()
386 {
return *
static_cast<Implementation*
>(
this); }
388 Evaluation saturatedDissolutionFactor_;
Provides the volumetric quantities required for the equations needed by the convective mixing (DRSDTC...
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
void updateSaturatedDissolutionFactor_()
Compute the intensive quantities needed to handle convective dissolution.
Definition: blackoilconvectivemixingmodule.hh:367
Defines the common properties required by the porous medium multi-phase models.
Structs needed for tpfalinearizer and its gpuparams struct extracted to be defined in one place that ...
Definition: blackoilbioeffectsmodules.hh:45
Contains classes extending the black-oil model.
Classes required for dynamic convective mixing.
Declares the properties required by the black oil model.
Declare the properties used by the infrastructure code of the finite volume discretizations.
static OPM_HOST_DEVICE void addConvectiveMixingFlux(RateVectorT &flux, const IntensiveQuantities &intQuantsIn, const IntensiveQuantities &intQuantsEx, const unsigned globalIndexIn, const unsigned globalIndexEx, const Scalar distZg, const Scalar trans, const Scalar faceArea, const CMMParam &info)
Adds the convective mixing mass flux flux to the flux vector over a flux integration point...
Definition: blackoilconvectivemixingmodule.hh:218