164 using Toolbox = MathToolbox<Evaluation>;
167 enum { conti0EqIdx = Indices::conti0EqIdx };
168 enum { dimWorld = GridView::dimensionworld };
169 enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
170 enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
172 static constexpr unsigned contiEnergyEqIdx = Indices::contiEnergyEqIdx;
175 static void beginEpisode(
const EclipseState& eclState,
176 const Schedule& schedule,
177 const int episodeIdx,
178 ConvectiveMixingModuleParamT& info)
181 std::size_t numRegions = eclState.runspec().tabdims().getNumPVTTables();
182 const auto& control = schedule[episodeIdx].oilvap();
183 if (info.active_.empty()) {
184 info.active_.resize(numRegions);
185 info.Xhi_.resize(numRegions);
186 info.Psi_.resize(numRegions);
188 for (std::size_t i = 0; i < numRegions; ++i ) {
189 info.active_[i] = control.drsdtConvective(i);
190 if (control.drsdtConvective(i)) {
191 info.Xhi_[i] = control.getMaxDRSDT(i);
192 info.Psi_[i] = control.getPsi(i);
197 template <
class CMMParam>
198 OPM_HOST_DEVICE
static void modifyAvgDensity(Evaluation& rhoAvg,
199 const IntensiveQuantities& intQuantsIn,
200 const IntensiveQuantities& intQuantsEx,
201 const unsigned phaseIdx,
202 const CMMParam& info) {
204 if (info.active_.empty()) {
207 if (!info.active_[intQuantsIn.pvtRegionIndex()] || !info.active_[intQuantsEx.pvtRegionIndex()]) {
211 FluidSystem fsys = intQuantsIn.getFluidSystem();
212 if (phaseIdx == fsys.gasPhaseIdx) {
216 const auto& liquidPhaseIdx =
217 fsys.phaseIsActive(fsys.waterPhaseIdx)
222 const auto& t_in = intQuantsIn.fluidState().temperature(liquidPhaseIdx);
223 const auto& p_in = intQuantsIn.fluidState().pressure(liquidPhaseIdx);
224 const auto& salt_in = intQuantsIn.fluidState().saltConcentration();
226 const auto& bLiquidIn =
227 fsys.phaseIsActive(waterPhaseIdx)
228 ? fsys.waterPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(),
229 t_in, p_in, Evaluation(0.0), salt_in)
230 : fsys.oilPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(),
231 t_in, p_in, Evaluation(0.0));
233 const auto& refDensityLiquidIn =
234 fsys.phaseIsActive(waterPhaseIdx)
235 ? fsys.waterPvt().waterReferenceDensity(intQuantsIn.pvtRegionIndex())
236 : fsys.oilPvt().oilReferenceDensity(intQuantsIn.pvtRegionIndex());
238 const auto& rho_in = bLiquidIn * refDensityLiquidIn;
240 const auto t_ex = Toolbox::value(intQuantsEx.fluidState().temperature(liquidPhaseIdx));
241 const auto p_ex = Toolbox::value(intQuantsEx.fluidState().pressure(liquidPhaseIdx));
242 const auto salt_ex = Toolbox::value(intQuantsEx.fluidState().saltConcentration());
244 const auto bLiquidEx =
245 fsys.phaseIsActive(waterPhaseIdx)
246 ? fsys.waterPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
247 t_ex, p_ex, Scalar{0.0}, salt_ex)
248 : fsys.oilPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
249 t_ex, p_ex, Scalar{0.0});
251 const auto& refDensityLiquidEx =
252 fsys.phaseIsActive(waterPhaseIdx)
253 ? fsys.waterPvt().waterReferenceDensity(intQuantsEx.pvtRegionIndex())
254 : fsys.oilPvt().oilReferenceDensity(intQuantsEx.pvtRegionIndex());
256 const auto rho_ex = bLiquidEx * refDensityLiquidEx;
258 rhoAvg = (rho_in + rho_ex) / 2;
261 template <
class Context>
262 OPM_HOST_DEVICE
static void addConvectiveMixingFlux(RateVector& flux,
263 const Context& elemCtx,
268 const auto& problem = elemCtx.problem();
269 const auto& stencil = elemCtx.stencil(timeIdx);
270 const auto& scvf = stencil.interiorFace(scvfIdx);
272 unsigned interiorDofIdx = scvf.interiorIndex();
273 unsigned exteriorDofIdx = scvf.exteriorIndex();
274 assert(interiorDofIdx != exteriorDofIdx);
276 const auto& globalIndexIn = stencil.globalSpaceIndex(interiorDofIdx);
277 const auto& globalIndexEx = stencil.globalSpaceIndex(exteriorDofIdx);
278 Scalar trans = problem.transmissibility(elemCtx, interiorDofIdx, exteriorDofIdx);
279 Scalar faceArea = scvf.area();
280 const Scalar g = problem.gravity()[dimWorld - 1];
281 const auto& intQuantsIn = elemCtx.intensiveQuantities(interiorDofIdx, timeIdx);
282 const auto& intQuantsEx = elemCtx.intensiveQuantities(exteriorDofIdx, timeIdx);
283 const Scalar zIn = problem.dofCenterDepth(elemCtx, interiorDofIdx, timeIdx);
284 const Scalar zEx = problem.dofCenterDepth(elemCtx, exteriorDofIdx, timeIdx);
285 const Scalar distZ = zIn - zEx;
286 addConvectiveMixingFlux(flux,
294 problem.moduleParams().convectiveMixingModuleParam);
301 template <
class RateVectorT = RateVector,
class CMMParam = ConvectiveMixingModuleParamT>
303 const IntensiveQuantities& intQuantsIn,
304 const IntensiveQuantities& intQuantsEx,
305 const unsigned globalIndexIn,
306 const unsigned globalIndexEx,
309 const Scalar faceArea,
310 const CMMParam& info)
312 const FluidSystem& fsys = intQuantsIn.getFluidSystem();
314 if (info.active_.empty()) {
318 if (!info.active_[intQuantsIn.pvtRegionIndex()] || !info.active_[intQuantsEx.pvtRegionIndex()]) {
322 const auto& liquidPhaseIdx =
323 fsys.phaseIsActive(fsys.waterPhaseIdx)
328 const auto& t_in = intQuantsIn.fluidState().temperature(liquidPhaseIdx);
329 const auto& p_in = intQuantsIn.fluidState().pressure(liquidPhaseIdx);
330 const auto& rssat_in = intQuantsIn.saturatedDissolutionFactor();
331 const auto& salt_in = intQuantsIn.fluidState().saltSaturation();
333 const auto bLiquidSatIn =
334 fsys.phaseIsActive(fsys.waterPhaseIdx)
335 ? fsys.waterPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(),
336 t_in, p_in, rssat_in, salt_in)
337 : fsys.oilPvt().inverseFormationVolumeFactor(intQuantsIn.pvtRegionIndex(),
338 t_in, p_in, rssat_in);
340 const auto& densityLiquidIn =
341 fsys.phaseIsActive(fsys.waterPhaseIdx)
342 ? fsys.waterPvt().waterReferenceDensity(intQuantsIn.pvtRegionIndex())
343 : fsys.oilPvt().oilReferenceDensity(intQuantsIn.pvtRegionIndex());
345 const auto rho_in = Opm::getValue(intQuantsIn.fluidState().invB(liquidPhaseIdx)) * densityLiquidIn;
346 const auto rho_sat_in = bLiquidSatIn *
348 rssat_in * fsys.referenceDensity(fsys.gasPhaseIdx,
349 intQuantsIn.pvtRegionIndex()));
352 const auto t_ex = Opm::getValue(intQuantsEx.fluidState().temperature(liquidPhaseIdx));
353 const auto p_ex = Opm::getValue(intQuantsEx.fluidState().pressure(liquidPhaseIdx));
354 const auto rssat_ex = Opm::getValue(intQuantsEx.saturatedDissolutionFactor());
355 const auto salt_ex = Opm::getValue(intQuantsEx.fluidState().saltSaturation());
356 const auto bLiquidSatEx =
357 fsys.phaseIsActive(fsys.waterPhaseIdx)
358 ? fsys.waterPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
359 t_ex, p_ex, rssat_ex, salt_ex)
360 : fsys.oilPvt().inverseFormationVolumeFactor(intQuantsEx.pvtRegionIndex(),
361 t_ex, p_ex, rssat_ex);
363 const auto& densityLiquidEx =
364 fsys.phaseIsActive(fsys.waterPhaseIdx)
365 ? fsys.waterPvt().waterReferenceDensity(intQuantsEx.pvtRegionIndex())
366 : fsys.oilPvt().oilReferenceDensity(intQuantsEx.pvtRegionIndex());
368 const auto rho_ex = Opm::getValue(intQuantsEx.fluidState().invB(liquidPhaseIdx)) * densityLiquidEx;
369 const auto rho_sat_ex = bLiquidSatEx *
371 rssat_ex * fsys.referenceDensity(fsys.gasPhaseIdx,
372 intQuantsEx.pvtRegionIndex()));
374 const auto delta_rho = (rho_sat_ex + rho_sat_in - rho_in - rho_ex) / 2;
375 const auto pressure_difference_convective_mixing = delta_rho * distZg;
378 if (Opm::abs(pressure_difference_convective_mixing) > 1e-12) {
380 short interiorDofIdx = 0;
381 constexpr short exteriorDofIdx = 1;
384 if (pressure_difference_convective_mixing > 0) {
385 upIdx = exteriorDofIdx;
388 const auto& up = (upIdx == interiorDofIdx) ? intQuantsIn : intQuantsEx;
389 const auto& rssat_up = (upIdx == interiorDofIdx) ? rssat_in : rssat_ex;
390 unsigned globalUpIndex = (upIdx == interiorDofIdx) ? globalIndexIn : globalIndexEx;
392 fsys.phaseIsActive(fsys.waterPhaseIdx)
393 ? up.fluidState().Rsw()
394 : up.fluidState().Rs();
396 const Evaluation& transMult = up.rockCompTransMultiplier();
397 const auto& invB = up.fluidState().invB(liquidPhaseIdx);
398 const auto& visc = up.fluidState().viscosity(liquidPhaseIdx);
401 const Evaluation RsupRestricted = Opm::min(Rsup, rssat_up*info.Psi_[up.pvtRegionIndex()]);
403 const auto convectiveFlux = -trans * transMult * info.Xhi_[up.pvtRegionIndex()] * invB *
404 pressure_difference_convective_mixing * RsupRestricted / (visc * faceArea);
405 unsigned activeGasCompIdx = fsys.canonicalToActiveCompIdx(fsys.gasCompIdx);
406 if (globalUpIndex == globalIndexIn) {
407 flux[conti0EqIdx + activeGasCompIdx] += convectiveFlux;
410 flux[conti0EqIdx + activeGasCompIdx] += Opm::getValue(convectiveFlux);
413 if constexpr (enableFullyImplicitThermal) {
414 const auto& h = up.fluidState().enthalpy(liquidPhaseIdx) *
415 fsys.referenceDensity(fsys.gasPhaseIdx, up.pvtRegionIndex());
416 if (globalUpIndex == globalIndexIn) {
417 flux[contiEnergyEqIdx] += convectiveFlux * h;
420 flux[contiEnergyEqIdx] += Opm::getValue(h) * Opm::getValue(convectiveFlux);