24#ifndef DUMUX_EVALCFLFLUX_COATS_HH
25#define DUMUX_EVALCFLFLUX_COATS_HH
27#include <dune/common/float_cmp.hh>
38template<
class TypeTag>
53 using PrimaryVariables =
typename SolutionTypes::PrimaryVariables;
59 dim = GridView::dimension, dimWorld = GridView::dimensionworld
63 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
64 eqIdxPress = Indices::pressureEqIdx,
65 eqIdxSat = Indices::satEqIdx,
66 numPhases = getPropValue<TypeTag, Properties::NumPhases>()
71 pw = Indices::pressureW,
72 pn = Indices::pressureNw,
73 vt = Indices::velocityTotal,
74 sw = Indices::saturationW,
75 sn = Indices::saturationNw
78 using Element =
typename GridView::Traits::template Codim<0>::Entity;
79 using Intersection =
typename GridView::Intersection;
81 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
82 using DimVector = Dune::FieldVector<Scalar, dimWorld>;
83 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
89 const auto element = *problem_.gridView().template begin<0>();
90 FluidState fluidState;
91 fluidState.setPressure(wPhaseIdx, problem_.referencePressure(element));
92 fluidState.setPressure(nPhaseIdx, problem_.referencePressure(element));
93 fluidState.setTemperature(problem_.temperature(element));
94 fluidState.setSaturation(wPhaseIdx, 1.);
95 fluidState.setSaturation(nPhaseIdx, 0.);
105 void addFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
106 const Element& element,
int phaseIdx = -1)
108 addDefaultFlux(flux, phaseIdx);
116 void addFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
117 const Intersection& intersection,
int phaseIdx = -1)
119 addDefaultFlux(flux, phaseIdx);
120 addCoatsFlux(lambdaW, lambdaNw, viscosityW, viscosityNw, flux, intersection, phaseIdx);
130 Scalar cflFluxDefault = getCflFluxFunctionDefault();
132 if (rejectForTimeStepping_)
133 return 0.99 / cflFluxDefault;
137 if (isnan(cflFluxFunctionCoatsOut_) || isinf(cflFluxFunctionCoatsOut_)){cflFluxFunctionCoatsOut_ = 0.0;}
138 if (isnan(cflFluxFunctionCoatsIn_) || isinf(cflFluxFunctionCoatsIn_)){cflFluxFunctionCoatsIn_ = 0.0;}
141 Scalar cflFluxFunctionCoats = max(cflFluxFunctionCoatsIn_, cflFluxFunctionCoatsOut_);
143 if (cflFluxFunctionCoats <= 0)
145 return 0.99 / cflFluxDefault;
147 else if (cflFluxDefault > cflFluxFunctionCoats)
149 return 0.99 / cflFluxDefault;
153 return 0.99 / cflFluxFunctionCoats;
162 Scalar
getDt(
const Element& element)
165 Scalar
porosity = max(problem_.spatialParams().porosity(element), porosityThreshold_);
172 cflFluxFunctionCoatsIn_ = 0;
173 cflFluxFunctionCoatsOut_ = 0;
174 rejectForTimeStepping_ =
false;
176 fluxNonwettingOut_ = 0;
187 problem_(problem), epsDerivative_(5e-3), threshold_(1e-8)
190 density_[wPhaseIdx] = 0.;
191 density_[nPhaseIdx] = 0.;
193 porosityThreshold_ = getParam<Scalar>(
"Impet.PorosityThreshold");
197 Scalar getCflFluxFunctionDefault()
203 if (isnan(fluxIn_) || isinf(fluxIn_))
208 Scalar cFLFluxIn = fluxIn_;
211 Scalar cFLFluxOut = 0;
213 if (velocityType_ == vt)
215 if (isnan(fluxOut_) || isinf(fluxOut_))
220 cFLFluxOut = fluxOut_;
224 if (isnan(fluxWettingOut_) || isinf(fluxWettingOut_))
226 fluxWettingOut_ = 1e-100;
228 if (isnan(fluxNonwettingOut_) || isinf(fluxNonwettingOut_))
230 fluxNonwettingOut_ = 1e-100;
233 cFLFluxOut = max(fluxWettingOut_, fluxNonwettingOut_);
238 Scalar cFLFluxFunction = max(cFLFluxIn, cFLFluxOut);
240 return cFLFluxFunction;
243 void addDefaultFlux(Scalar flux,
int phaseIdx);
245 void addCoatsFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
246 const Intersection& intersection,
int phaseIdx);
249 Scalar cflFluxFunctionCoatsIn_;
250 Scalar cflFluxFunctionCoatsOut_;
251 Scalar fluxWettingOut_;
252 Scalar fluxNonwettingOut_;
255 bool rejectForTimeStepping_;
256 Scalar density_[numPhases];
257 static const int pressureType_ = getPropValue<TypeTag, Properties::PressureFormulation>();
258 static const int velocityType_ = getPropValue<TypeTag, Properties::VelocityFormulation>();
259 static const int saturationType_ = getPropValue<TypeTag, Properties::SaturationFormulation>();
260 const Scalar epsDerivative_;
261 const Scalar threshold_;
262 Scalar porosityThreshold_;
265template<
class TypeTag>
266void EvalCflFluxCoats<TypeTag>::addDefaultFlux(Scalar flux,
int phaseIdx)
275 fluxWettingOut_ += flux;
290 fluxNonwettingOut_ += flux;
320template<
class TypeTag>
321void EvalCflFluxCoats<TypeTag>::addCoatsFlux(Scalar& lambdaW, Scalar& lambdaNw,
322 Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
323 const Intersection& intersection,
int phaseIdx)
325 if (rejectForTimeStepping_)
327 else if (phaseIdx != wPhaseIdx)
330 Scalar lambdaT = (lambdaW + lambdaNw);
332 if (lambdaT <= threshold_)
335 auto element = intersection.inside();
338 const GlobalPosition& globalPos =
element.geometry().center();
341 int globalIdxI = problem_.variables().index(element);
343 CellData& cellDataI = problem_.variables().cellData(globalIdxI);
345 if (cellDataI.potential(wPhaseIdx) < 0.0 || cellDataI.potential(nPhaseIdx) < 0.0)
347 rejectForTimeStepping_ =
true;
348 cflFluxFunctionCoatsIn_ = 0;
349 cflFluxFunctionCoatsOut_ = 0;
353 int indexInInside = intersection.indexInInside();
355 Scalar satI = cellDataI.saturation(wPhaseIdx);
356 Scalar lambdaWI = cellDataI.mobility(wPhaseIdx);
357 Scalar lambdaNwI = cellDataI.mobility(nPhaseIdx);
359 const auto fluidMatrixInteraction = problem_.spatialParams().fluidMatrixInteractionAtPos(
element.geometry().center());
360 const Scalar dpc_dsI = fluidMatrixInteraction.dpc_dsw(satI);
362 const GlobalPosition& unitOuterNormal = intersection.centerUnitOuterNormal();
364 if (intersection.neighbor())
366 auto neighbor = intersection.outside();
368 int globalIdxJ = problem_.variables().index(neighbor);
370 CellData& cellDataJ = problem_.variables().cellData(globalIdxJ);
372 if (cellDataJ.potential(wPhaseIdx) < 0.0 || cellDataJ.potential(nPhaseIdx) < 0.0 )
374 rejectForTimeStepping_ =
true;
375 cflFluxFunctionCoatsIn_ = 0;
376 cflFluxFunctionCoatsOut_ = 0;
380 if (
element.level() != neighbor.level())
382 rejectForTimeStepping_ =
true;
383 cflFluxFunctionCoatsIn_ = 0;
384 cflFluxFunctionCoatsOut_ = 0;
388 bool takeNeighbor = (
element.level() < neighbor.level());
391 (takeNeighbor) ? !cellDataJ.fluxData().isUpwindCell(wPhaseIdx, intersection.indexInOutside()) :
392 cellDataI.fluxData().isUpwindCell(wPhaseIdx, indexInInside);
394 (takeNeighbor) ? !cellDataJ.fluxData().isUpwindCell(nPhaseIdx, intersection.indexInOutside()) :
395 cellDataI.fluxData().isUpwindCell(nPhaseIdx, indexInInside);
397 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
400 GlobalPosition distVec = globalPosNeighbor - globalPos;
404 Scalar dist = abs(distVec * unitOuterNormal);
406 Scalar satJ = cellDataJ.saturation(wPhaseIdx);
407 Scalar lambdaWJ = cellDataI.mobility(wPhaseIdx);
408 Scalar lambdaNwJ = cellDataI.mobility(nPhaseIdx);
410 const auto fluidMatrixInteractionNeighbor = problem_.spatialParams().fluidMatrixInteractionAtPos(neighbor.geometry().center());
411 const Scalar dpc_dsJ = fluidMatrixInteractionNeighbor.dpc_dsw(satJ);
416 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(element));
422 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(neighbor));
427 Scalar meanPermeability = 2*perm1*perm2/(perm1 + perm2);
429 Scalar transmissibility = meanPermeability * intersection.geometry().volume() / dist;
435 satUpw = max(satI, 0.0);
439 satUpw = max(satJ, 0.0);
442 Scalar ds = epsDerivative_;
444 Scalar satPlus = satUpw + epsDerivative_;
445 Scalar satMinus = satUpw;
446 if (satMinus - epsDerivative_ > 0.0)
448 satMinus -= epsDerivative_;
449 ds += epsDerivative_;
452 Scalar dLambdaWDs = fluidMatrixInteractionNeighbor.krw(abs(satPlus)) / viscosityW;
453 dLambdaWDs -= fluidMatrixInteractionNeighbor.krw(abs(satMinus)) / viscosityW;
458 satUpw = max(1 - satI, 0.0);
462 satUpw = max(1 - satJ, 0.0);
467 satPlus = satUpw + epsDerivative_;
469 if (satMinus - epsDerivative_ > 0.0)
471 satMinus -= epsDerivative_;
472 ds += epsDerivative_;
475 Scalar dLambdaNwDs = fluidMatrixInteractionNeighbor.krn(satPlus) / viscosityNw;
476 dLambdaNwDs -= fluidMatrixInteractionNeighbor.krn(satMinus) / viscosityNw;
479 Scalar lambdaWCap = 0.5 * (lambdaWI + lambdaWJ);
480 Scalar lambdaNwCap = 0.5 * (lambdaNwI + lambdaNwJ);
482 Scalar potentialDiff = cellDataI.potential(wPhaseIdx) - cellDataJ.potential(wPhaseIdx);
483 Scalar cflFlux = transmissibility * lambdaNw * dLambdaWDs * abs(potentialDiff) / lambdaT;
485 potentialDiff = cellDataI.potential(nPhaseIdx) - cellDataJ.potential(nPhaseIdx);
486 cflFlux -= transmissibility * lambdaW * dLambdaNwDs * abs(potentialDiff) / lambdaT;
488 cflFlux -= transmissibility * lambdaWCap * lambdaNwCap * (dpc_dsI + dpc_dsJ) / lambdaT;
490 if ((upwindWI && lambdaW > threshold_)|| (upwindNwI && lambdaW < threshold_))
492 cflFluxFunctionCoatsOut_ += cflFlux;
496 cflFluxFunctionCoatsIn_ += cflFlux;
502 GlobalPosition globalPosFace = intersection.geometry().center();
505 BoundaryTypes bcType;
506 problem_.boundaryTypes(bcType, intersection);
509 Dune::FieldVector < Scalar, dimWorld > distVec = globalPosFace - globalPos;
512 Scalar dist = distVec.two_norm();
519 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(element));
522 Scalar faceArea = intersection.geometry().volume();
524 Scalar transmissibility = (unitOuterNormal *
permeability) * faceArea / dist;
526 Scalar satWBound = cellDataI.saturation(wPhaseIdx);
527 if (bcType.isDirichlet(eqIdxSat))
529 PrimaryVariables bcValues;
530 problem_.dirichlet(bcValues, intersection);
531 switch (saturationType_)
535 satWBound = bcValues[eqIdxSat];
540 satWBound = 1 - bcValues[eqIdxSat];
545 DUNE_THROW(Dune::RangeError,
"saturation type not implemented");
551 Scalar potWBound = cellDataI.potential(wPhaseIdx);
552 Scalar potNwBound = cellDataI.potential(nPhaseIdx);
553 Scalar gdeltaZ = (problem_.bBoxMax()-globalPosFace) * problem_.gravity();
554 if (bcType.isDirichlet(eqIdxPress))
556 PrimaryVariables bcValues;
557 problem_.dirichlet(bcValues, intersection);
558 switch (pressureType_)
562 potWBound = bcValues[eqIdxPress] + density_[wPhaseIdx] * gdeltaZ;
563 potNwBound = bcValues[eqIdxPress] + fluidMatrixInteraction.pc(satWBound)
564 + density_[nPhaseIdx] * gdeltaZ;
569 potWBound = bcValues[eqIdxPress] - fluidMatrixInteraction.pc(satWBound)
570 + density_[wPhaseIdx] * gdeltaZ;
571 potNwBound = bcValues[eqIdxPress] + density_[nPhaseIdx] * gdeltaZ;
576 DUNE_THROW(Dune::RangeError,
"pressure type not implemented");
580 else if (bcType.isNeumann(eqIdxPress) && bcType.isDirichlet(eqIdxSat))
582 PrimaryVariables bcValues;
583 problem_.neumann(bcValues, intersection);
585 bcValues[wPhaseIdx] /= density_[wPhaseIdx];
586 bcValues[nPhaseIdx] /= density_[nPhaseIdx];
588 bcValues[wPhaseIdx] *= faceArea;
589 bcValues[nPhaseIdx] *= faceArea;
591 bool hasPotWBound =
false;
592 if (Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(lambdaW, 0.0, 1.0e-30) && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(bcValues[wPhaseIdx], 0.0, 1.0e-30))
594 potWBound -= bcValues[wPhaseIdx] / (transmissibility * lambdaW);
597 bool hasPotNwBound =
false;
598 if (Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(lambdaNw, 0.0, 1.0e-30) && Dune::FloatCmp::ne<Scalar, Dune::FloatCmp::absolute>(bcValues[nPhaseIdx], 0.0, 1.0e-30))
600 potNwBound -= bcValues[nPhaseIdx] / (transmissibility * lambdaNw);
601 hasPotNwBound =
true;
604 if (hasPotWBound && !hasPotNwBound)
606 potNwBound = potWBound + fluidMatrixInteraction.pc(satWBound)
607 + (density_[nPhaseIdx] - density_[wPhaseIdx]) * gdeltaZ;
609 else if (!hasPotWBound && hasPotNwBound)
611 potWBound = potNwBound - fluidMatrixInteraction.pc(satWBound)
612 + (density_[nPhaseIdx] - density_[wPhaseIdx]) * gdeltaZ;
615 else if (bcType.isNeumann(eqIdxPress))
617 PrimaryVariables bcValues;
618 problem_.neumann(bcValues, intersection);
620 bcValues[wPhaseIdx] /= density_[wPhaseIdx];
621 bcValues[nPhaseIdx] /= density_[nPhaseIdx];
623 bcValues[wPhaseIdx] *= faceArea;
624 bcValues[nPhaseIdx] *= faceArea;
628 if (bcValues[wPhaseIdx] > 0)
630 cflFluxFunctionCoatsOut_ += abs(bcValues[wPhaseIdx]);
634 cflFluxFunctionCoatsIn_ += abs(bcValues[wPhaseIdx]);
636 if (bcValues[nPhaseIdx] > 0)
638 cflFluxFunctionCoatsOut_ += abs(bcValues[nPhaseIdx]);
642 cflFluxFunctionCoatsIn_ += abs(bcValues[nPhaseIdx]);
649 rejectForTimeStepping_ =
true;
650 cflFluxFunctionCoatsIn_ = 0;
651 cflFluxFunctionCoatsOut_ = 0;
655 const Scalar dpc_dsBound = fluidMatrixInteraction.dpc_dsw(satWBound);
657 Scalar lambdaWBound = 0;
658 Scalar lambdaNwBound = 0;
660 Scalar
temperature = problem_.temperature(element);
661 Scalar referencePressure = problem_.referencePressure(element);
662 FluidState fluidState;
663 fluidState.setPressure(wPhaseIdx, referencePressure);
664 fluidState.setPressure(nPhaseIdx, referencePressure);
668 Scalar viscosityNwBound =
670 lambdaWBound = fluidMatrixInteraction.krw(satWBound) / viscosityWBound;
671 lambdaNwBound = fluidMatrixInteraction.krn(satWBound) / viscosityNwBound;
675 if (cellDataI.fluxData().isUpwindCell(wPhaseIdx, indexInInside))
677 satUpw = max(satI, 0.0);
681 satUpw = max(satWBound, 0.0);
684 Scalar ds = epsDerivative_;
686 Scalar satPlus = satUpw + epsDerivative_;
687 Scalar satMinus = satUpw;
688 if (satMinus - epsDerivative_ > 0.0)
690 satMinus -= epsDerivative_;
691 ds += epsDerivative_;
694 Scalar dLambdaWDs = fluidMatrixInteraction.krw(satPlus) / viscosityW;
695 dLambdaWDs -= fluidMatrixInteraction.krw(satMinus) / viscosityW;
698 if (cellDataI.fluxData().isUpwindCell(nPhaseIdx, indexInInside))
700 satUpw = max(1 - satI, 0.0);
704 satUpw = max(1 - satWBound, 0.0);
709 satPlus = satUpw + epsDerivative_;
711 if (satMinus - epsDerivative_ > 0.0)
713 satMinus -= epsDerivative_;
714 ds += epsDerivative_;
717 Scalar dLambdaNwDs = fluidMatrixInteraction.krn(satPlus) / viscosityNw;
718 dLambdaNwDs -= fluidMatrixInteraction.krn(satMinus) / viscosityNw;
721 Scalar lambdaWCap = 0.5 * (lambdaWI + lambdaWBound);
722 Scalar lambdaNwCap = 0.5 * (lambdaNwI + lambdaNwBound);
724 Scalar potDiff = cellDataI.potential(wPhaseIdx) - potWBound;
726 Scalar cflFlux = transmissibility * lambdaNw * dLambdaWDs * abs(potDiff) / lambdaT;
728 cflFlux -= transmissibility * lambdaWCap * lambdaNwCap * (dpc_dsI + dpc_dsBound) / lambdaT;
730 potDiff = cellDataI.potential(nPhaseIdx) - potNwBound;
731 cflFlux -= transmissibility * lambdaW * dLambdaNwDs * abs(potDiff) / lambdaT;
733 if ((cellDataI.fluxData().isUpwindCell(wPhaseIdx, indexInInside) && lambdaW > threshold_) ||
734 (cellDataI.fluxData().isUpwindCell(nPhaseIdx, indexInInside) && lambdaW < threshold_))
736 cflFluxFunctionCoatsOut_ += cflFlux;
740 cflFluxFunctionCoatsIn_ += cflFlux;
Base class for implementations of different kinds of fluxes to evaluate a CFL-Condition.
Base file for properties related to sequential IMPET algorithms.
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type GetProp
get the type of a property
Definition: propertysystem.hh:141
typename Properties::Detail::GetPropImpl< TypeTag, Property >::type::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:150
std::string temperature() noexcept
I/O name of temperature for equilibrium models.
Definition: name.hh:51
std::string viscosity(int phaseIdx) noexcept
I/O name of viscosity for multiphase systems.
Definition: name.hh:74
std::string permeability() noexcept
I/O name of permeability.
Definition: name.hh:143
std::string density(int phaseIdx) noexcept
I/O name of density for multiphase systems.
Definition: name.hh:65
std::string porosity() noexcept
I/O name of porosity.
Definition: name.hh:139
Base class for implementations of different kinds of fluxes to evaluate a CFL-Condition.
Definition: evalcflflux.hh:52
Cfl-flux-function to evaluate a Cfl-Condition after Coats 2003.
Definition: evalcflfluxcoats.hh:40
Scalar getDt(const Element &element)
Returns the Cfl time-step.
Definition: evalcflfluxcoats.hh:162
void reset()
Resets the Timestep-estimator.
Definition: evalcflfluxcoats.hh:170
void addFlux(Scalar &lambdaW, Scalar &lambdaNw, Scalar &viscosityW, Scalar &viscosityNw, Scalar flux, const Element &element, int phaseIdx=-1)
adds a flux to the cfl-criterion evaluation
Definition: evalcflfluxcoats.hh:105
Scalar getCflFluxFunction(const Element &element)
Returns the Cfl flux-function.
Definition: evalcflfluxcoats.hh:128
EvalCflFluxCoats(Problem &problem)
Constructs an EvalCflFluxDefault object.
Definition: evalcflfluxcoats.hh:186
void addFlux(Scalar &lambdaW, Scalar &lambdaNw, Scalar &viscosityW, Scalar &viscosityNw, Scalar flux, const Intersection &intersection, int phaseIdx=-1)
adds a flux to the cfl-criterion evaluation
Definition: evalcflfluxcoats.hh:116
void initialize()
Initializes the cfl-flux-model.
Definition: evalcflfluxcoats.hh:87