122 enum { dimWorld = GridView::dimensionworld };
123 enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
124 enum { numPhases = FluidSystem::numPhases };
132 using Toolbox = MathToolbox<Evaluation>;
133 using DimVector = Dune::FieldVector<Scalar, dimWorld>;
134 using EvalDimVector = Dune::FieldVector<Evaluation, dimWorld>;
135 using DimMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
145 throw std::invalid_argument(
"The ECL transmissibility module does not provide an explicit intrinsic permeability");
156 throw std::invalid_argument(
"The ECL transmissibility module does not provide explicit potential gradients");
166 {
return pressureDifference_[phaseIdx]; }
176 throw std::invalid_argument(
"The ECL transmissibility module does not provide explicit filter velocities");
188 OPM_HOST_DEVICE
const Evaluation&
volumeFlux(
unsigned phaseIdx)
const
189 {
return volumeFlux_[phaseIdx]; }
201 assert(phaseIdx < numPhases);
203 return upIdx_[phaseIdx];
215 assert(phaseIdx < numPhases);
217 return dnIdx_[phaseIdx];
220 OPM_HOST_DEVICE
void updateSolvent(
const ElementContext& elemCtx,
unsigned scvfIdx,
unsigned timeIdx)
221 { asImp_().updateVolumeFluxTrans(elemCtx, scvfIdx, timeIdx); }
223 OPM_HOST_DEVICE
void updatePolymer(
const ElementContext& elemCtx,
unsigned scvfIdx,
unsigned timeIdx)
224 { asImp_().updateShearMultipliers(elemCtx, scvfIdx, timeIdx); }
228 OPM_HOST_DEVICE
static void volumeAndPhasePressureDifferences(std::array<short, numPhases>& upIdx,
229 std::array<short, numPhases>& dnIdx,
231 Evaluation (&pressureDifferences)[numPhases],
232 const ElementContext& elemCtx,
236 const auto& problem = elemCtx.problem();
237 const auto& stencil = elemCtx.stencil(timeIdx);
238 const auto& scvf = stencil.interiorFace(scvfIdx);
239 unsigned interiorDofIdx = scvf.interiorIndex();
240 unsigned exteriorDofIdx = scvf.exteriorIndex();
242 assert(interiorDofIdx != exteriorDofIdx);
244 unsigned I = stencil.globalSpaceIndex(interiorDofIdx);
245 unsigned J = stencil.globalSpaceIndex(exteriorDofIdx);
246 Scalar trans = problem.transmissibility(elemCtx, interiorDofIdx, exteriorDofIdx);
247 Scalar faceArea = scvf.area();
248 Scalar thpres = problem.thresholdPressure(I, J);
253 Scalar g = elemCtx.problem().gravity()[dimWorld - 1];
255 const auto& intQuantsIn = elemCtx.intensiveQuantities(interiorDofIdx, timeIdx);
256 const auto& intQuantsEx = elemCtx.intensiveQuantities(exteriorDofIdx, timeIdx);
263 Scalar zIn = problem.dofCenterDepth(elemCtx, interiorDofIdx, timeIdx);
264 Scalar zEx = problem.dofCenterDepth(elemCtx, exteriorDofIdx, timeIdx);
268 Scalar distZ = zIn - zEx;
270 Scalar Vin = elemCtx.dofVolume(interiorDofIdx, 0);
271 Scalar Vex = elemCtx.dofVolume(exteriorDofIdx, 0);
273 for (
unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) {
274 if (!FluidSystem::phaseIsActive(phaseIdx))
276 calculatePhasePressureDiff_(upIdx[phaseIdx],
278 pressureDifferences[phaseIdx],
290 problem.moduleParams());
292 const bool upwindIsInterior = (
static_cast<unsigned>(upIdx[phaseIdx]) == interiorDofIdx);
293 const IntensiveQuantities& up = upwindIsInterior ? intQuantsIn : intQuantsEx;
295 const Evaluation transMult = (intQuantsIn.rockCompTransMultiplier() + Toolbox::value(intQuantsEx.rockCompTransMultiplier()))/2;
297 const auto& materialLawManager = problem.materialLawManager();
298 FaceDir::DirEnum facedir = FaceDir::DirEnum::Unknown;
299 if (materialLawManager->hasDirectionalRelperms()) {
300 facedir = scvf.faceDirFromDirId();
302 if (upwindIsInterior)
304 pressureDifferences[phaseIdx]*up.mobility(phaseIdx, facedir)*transMult*(-trans/faceArea);
307 pressureDifferences[phaseIdx]*
308 (Toolbox::value(up.mobility(phaseIdx, facedir))*transMult*(-trans/faceArea));
312 template<
class EvalType>
313 OPM_HOST_DEVICE
static void calculatePhasePressureDiff_(
short& upIdx,
316 const IntensiveQuantities& intQuantsIn,
317 const IntensiveQuantities& intQuantsEx,
318 const unsigned phaseIdx,
319 const unsigned interiorDofIdx,
320 const unsigned exteriorDofIdx,
323 const unsigned globalIndexIn,
324 const unsigned globalIndexEx,
327 const ModuleParams& moduleParams)
332 if (intQuantsIn.mobility(phaseIdx) <= 0.0 &&
333 intQuantsEx.mobility(phaseIdx) <= 0.0)
335 upIdx = interiorDofIdx;
336 dnIdx = exteriorDofIdx;
343 const Evaluation& rhoIn = intQuantsIn.fluidState().density(phaseIdx);
344 Scalar rhoEx = Toolbox::value(intQuantsEx.fluidState().density(phaseIdx));
345 Evaluation rhoAvg = (rhoIn + rhoEx)/2;
347 if constexpr(enableConvectiveMixing) {
348 ConvectiveMixingModule::modifyAvgDensity(rhoAvg, intQuantsIn, intQuantsEx, phaseIdx, moduleParams.convectiveMixingModuleParam);
351 const Evaluation& pressureInterior = intQuantsIn.fluidState().pressure(phaseIdx);
352 Evaluation pressureExterior = Toolbox::value(intQuantsEx.fluidState().pressure(phaseIdx));
355 pressureExterior += Toolbox::value(rhoAvg)*(distZg);
357 pressureExterior += rhoAvg*(distZg);
366 upIdx = exteriorDofIdx;
367 dnIdx = interiorDofIdx;
370 upIdx = interiorDofIdx;
371 dnIdx = exteriorDofIdx;
377 upIdx = interiorDofIdx;
378 dnIdx = exteriorDofIdx;
380 else if (Vin < Vex) {
381 upIdx = exteriorDofIdx;
382 dnIdx = interiorDofIdx;
388 if (globalIndexIn < globalIndexEx) {
389 upIdx = interiorDofIdx;
390 dnIdx = exteriorDofIdx;
393 upIdx = exteriorDofIdx;
394 dnIdx = interiorDofIdx;
420 OPM_HOST_DEVICE
void calculateGradients_(
const ElementContext& elemCtx,
unsigned scvfIdx,
unsigned timeIdx)
422 Valgrind::SetUndefined(*
this);
424 volumeAndPhasePressureDifferences(upIdx_ , dnIdx_, volumeFlux_, pressureDifference_, elemCtx, scvfIdx, timeIdx);
430 template <
class Flu
idState>
434 const FluidState& exFluidState)
436 const auto& scvf = elemCtx.stencil(timeIdx).boundaryFace(scvfIdx);
437 const Scalar faceArea = scvf.area();
438 const Scalar zEx = scvf.integrationPos()[dimWorld - 1];
439 const auto& problem = elemCtx.problem();
440 const unsigned globalSpaceIdx = elemCtx.globalSpaceIndex(0, timeIdx);
441 const auto& intQuantsIn = elemCtx.intensiveQuantities(0, timeIdx);
453 pressureDifference_);
458 if constexpr (enableSolvent) {
459 if (upIdx_[gasPhaseIdx] == 0) {
460 const Scalar trans = problem.transmissibilityBoundary(globalSpaceIdx, scvfIdx);
461 const Scalar transModified = trans * Toolbox::value(intQuantsIn.rockCompTransMultiplier());
462 const auto solventFlux = pressureDifference_[gasPhaseIdx] * intQuantsIn.mobility(gasPhaseIdx) * (-transModified/faceArea);
463 asImp_().setSolventVolumeFlux(solventFlux);
465 asImp_().setSolventVolumeFlux(0.0);
474 template <
class Problem,
class Flu
idState,
class EvaluationContainer>
476 const unsigned globalSpaceIdx,
477 const IntensiveQuantities& intQuantsIn,
478 const unsigned bfIdx,
479 const double faceArea,
481 const FluidState& exFluidState,
482 std::array<short, numPhases>& upIdx,
483 std::array<short, numPhases>& dnIdx,
488 bool enableBoundaryMassFlux = problem.nonTrivialBoundaryConditions();
489 if (!enableBoundaryMassFlux)
492 Scalar trans = problem.transmissibilityBoundary(globalSpaceIdx, bfIdx);
497 Scalar g = problem.gravity()[dimWorld - 1];
504 Scalar zIn = problem.dofCenterDepth(globalSpaceIdx);
508 Scalar distZ = zIn - zEx;
510 for (
unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) {
511 if (!FluidSystem::phaseIsActive(phaseIdx))
516 const Evaluation& rhoIn = intQuantsIn.fluidState().density(phaseIdx);
517 const auto& rhoEx = exFluidState.density(phaseIdx);
518 Evaluation rhoAvg = (rhoIn + rhoEx)/2;
520 const Evaluation& pressureInterior = intQuantsIn.fluidState().pressure(phaseIdx);
521 Evaluation pressureExterior = exFluidState.pressure(phaseIdx);
522 pressureExterior += rhoAvg*(distZ*g);
530 const unsigned interiorDofIdx = 0;
532 upIdx[phaseIdx] = -1;
533 dnIdx[phaseIdx] = interiorDofIdx;
536 upIdx[phaseIdx] = interiorDofIdx;
537 dnIdx[phaseIdx] = -1;
540 Evaluation transModified = trans;
542 if (upIdx[phaseIdx] == interiorDofIdx) {
546 const auto& up = intQuantsIn;
549 const Scalar transMult = Toolbox::value(up.rockCompTransMultiplier());
550 transModified *= transMult;
558 const auto& matParams = problem.materialLawParams(globalSpaceIdx);
559 std::array<typename FluidState::ValueType,numPhases> kr;
560 MaterialLaw::relativePermeabilities(kr, matParams, exFluidState);
562 const auto& mob = kr[phaseIdx]/exFluidState.viscosity(phaseIdx);
577 OPM_HOST_DEVICE
void calculateBoundaryFluxes_(
const ElementContext&,
unsigned,
unsigned)
581 Implementation& asImp_()
582 {
return *
static_cast<Implementation*
>(
this); }
584 const Implementation& asImp_()
const
585 {
return *
static_cast<const Implementation*
>(
this); }
588 Evaluation volumeFlux_[numPhases];
592 Evaluation pressureDifference_[numPhases];
595 std::array<short, numPhases> upIdx_;
596 std::array<short, numPhases> dnIdx_;
static OPM_HOST_DEVICE void calculateBoundaryGradients_(const Problem &problem, const unsigned globalSpaceIdx, const IntensiveQuantities &intQuantsIn, const unsigned bfIdx, const double faceArea, const double zEx, const FluidState &exFluidState, std::array< short, numPhases > &upIdx, std::array< short, numPhases > &dnIdx, EvaluationContainer &volumeFlux, EvaluationContainer &pressureDifference)
Update the required gradients for boundary faces.
Definition NewTranFluxModule.hpp:475