24#ifndef DUMUX_EVALCFLFLUX_COATS_HH
25#define DUMUX_EVALCFLFLUX_COATS_HH
27#include <dune/common/float_cmp.hh>
40template<
class TypeTag>
55 using PrimaryVariables =
typename SolutionTypes::PrimaryVariables;
61 dim = GridView::dimension, dimWorld = GridView::dimensionworld
65 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
66 eqIdxPress = Indices::pressureEqIdx,
67 eqIdxSat = Indices::satEqIdx,
68 numPhases = getPropValue<TypeTag, Properties::NumPhases>()
73 pw = Indices::pressureW,
74 pn = Indices::pressureNw,
75 vt = Indices::velocityTotal,
76 sw = Indices::saturationW,
77 sn = Indices::saturationNw
80 using Element =
typename GridView::Traits::template Codim<0>::Entity;
81 using Intersection =
typename GridView::Intersection;
83 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
84 using DimVector = Dune::FieldVector<Scalar, dimWorld>;
85 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
91 const auto element = *problem_.gridView().template begin<0>();
92 FluidState fluidState;
93 fluidState.setPressure(wPhaseIdx, problem_.referencePressure(element));
94 fluidState.setPressure(nPhaseIdx, problem_.referencePressure(element));
95 fluidState.setTemperature(problem_.temperature(element));
96 fluidState.setSaturation(wPhaseIdx, 1.);
97 fluidState.setSaturation(nPhaseIdx, 0.);
107 void addFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
108 const Element& element,
int phaseIdx = -1)
110 addDefaultFlux(flux, phaseIdx);
118 void addFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
119 const Intersection& intersection,
int phaseIdx = -1)
121 addDefaultFlux(flux, phaseIdx);
122 addCoatsFlux(lambdaW, lambdaNw, viscosityW, viscosityNw, flux, intersection, phaseIdx);
132 Scalar cflFluxDefault = getCflFluxFunctionDefault();
134 if (rejectForTimeStepping_)
135 return 0.99 / cflFluxDefault;
139 if (isnan(cflFluxFunctionCoatsOut_) || isinf(cflFluxFunctionCoatsOut_)){cflFluxFunctionCoatsOut_ = 0.0;}
140 if (isnan(cflFluxFunctionCoatsIn_) || isinf(cflFluxFunctionCoatsIn_)){cflFluxFunctionCoatsIn_ = 0.0;}
143 Scalar cflFluxFunctionCoats = max(cflFluxFunctionCoatsIn_, cflFluxFunctionCoatsOut_);
145 if (cflFluxFunctionCoats <= 0)
147 return 0.99 / cflFluxDefault;
149 else if (cflFluxDefault > cflFluxFunctionCoats)
151 return 0.99 / cflFluxDefault;
155 return 0.99 / cflFluxFunctionCoats;
164 Scalar
getDt(
const Element& element)
167 Scalar
porosity = max(problem_.spatialParams().porosity(element), porosityThreshold_);
174 cflFluxFunctionCoatsIn_ = 0;
175 cflFluxFunctionCoatsOut_ = 0;
176 rejectForTimeStepping_ =
false;
178 fluxNonwettingOut_ = 0;
189 problem_(problem), epsDerivative_(5e-3), threshold_(1e-8)
192 density_[wPhaseIdx] = 0.;
193 density_[nPhaseIdx] = 0.;
195 porosityThreshold_ = getParam<Scalar>(
"Impet.PorosityThreshold");
199 Scalar getCflFluxFunctionDefault()
205 if (isnan(fluxIn_) || isinf(fluxIn_))
210 Scalar cFLFluxIn = fluxIn_;
213 Scalar cFLFluxOut = 0;
215 if (velocityType_ == vt)
217 if (isnan(fluxOut_) || isinf(fluxOut_))
222 cFLFluxOut = fluxOut_;
226 if (isnan(fluxWettingOut_) || isinf(fluxWettingOut_))
228 fluxWettingOut_ = 1e-100;
230 if (isnan(fluxNonwettingOut_) || isinf(fluxNonwettingOut_))
232 fluxNonwettingOut_ = 1e-100;
235 cFLFluxOut = max(fluxWettingOut_, fluxNonwettingOut_);
240 Scalar cFLFluxFunction = max(cFLFluxIn, cFLFluxOut);
242 return cFLFluxFunction;
245 void addDefaultFlux(Scalar flux,
int phaseIdx);
247 void addCoatsFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
248 const Intersection& intersection,
int phaseIdx);
251 Scalar cflFluxFunctionCoatsIn_;
252 Scalar cflFluxFunctionCoatsOut_;
253 Scalar fluxWettingOut_;
254 Scalar fluxNonwettingOut_;
257 bool rejectForTimeStepping_;
258 Scalar density_[numPhases];
259 static const int pressureType_ = getPropValue<TypeTag, Properties::PressureFormulation>();
260 static const int velocityType_ = getPropValue<TypeTag, Properties::VelocityFormulation>();
261 static const int saturationType_ = getPropValue<TypeTag, Properties::SaturationFormulation>();
262 const Scalar epsDerivative_;
263 const Scalar threshold_;
264 Scalar porosityThreshold_;
267template<
class TypeTag>
268void EvalCflFluxCoats<TypeTag>::addDefaultFlux(Scalar flux,
int phaseIdx)
277 fluxWettingOut_ += flux;
292 fluxNonwettingOut_ += flux;
322template<
class TypeTag>
323void EvalCflFluxCoats<TypeTag>::addCoatsFlux(Scalar& lambdaW, Scalar& lambdaNw,
324 Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
325 const Intersection& intersection,
int phaseIdx)
327 if (rejectForTimeStepping_)
329 else if (phaseIdx != wPhaseIdx)
332 Scalar lambdaT = (lambdaW + lambdaNw);
334 if (lambdaT <= threshold_)
337 auto element = intersection.inside();
340 const GlobalPosition& globalPos = element.geometry().center();
343 int globalIdxI = problem_.variables().index(element);
345 CellData& cellDataI = problem_.variables().cellData(globalIdxI);
347 if (cellDataI.potential(wPhaseIdx) < 0.0 || cellDataI.potential(nPhaseIdx) < 0.0)
349 rejectForTimeStepping_ =
true;
350 cflFluxFunctionCoatsIn_ = 0;
351 cflFluxFunctionCoatsOut_ = 0;
355 int indexInInside = intersection.indexInInside();
357 Scalar satI = cellDataI.saturation(wPhaseIdx);
358 Scalar lambdaWI = cellDataI.mobility(wPhaseIdx);
359 Scalar lambdaNwI = cellDataI.mobility(nPhaseIdx);
364 const auto fluidMatrixInteraction = Deprecated::makePcKrSw(Scalar{}, problem_.spatialParams(), element);
366 const Scalar dpc_dsI = fluidMatrixInteraction.dpc_dsw(satI);
368 const GlobalPosition& unitOuterNormal = intersection.centerUnitOuterNormal();
370 if (intersection.neighbor())
372 auto neighbor = intersection.outside();
374 int globalIdxJ = problem_.variables().index(neighbor);
376 CellData& cellDataJ = problem_.variables().cellData(globalIdxJ);
378 if (cellDataJ.potential(wPhaseIdx) < 0.0 || cellDataJ.potential(nPhaseIdx) < 0.0 )
380 rejectForTimeStepping_ =
true;
381 cflFluxFunctionCoatsIn_ = 0;
382 cflFluxFunctionCoatsOut_ = 0;
386 if (element.level() != neighbor.level())
388 rejectForTimeStepping_ =
true;
389 cflFluxFunctionCoatsIn_ = 0;
390 cflFluxFunctionCoatsOut_ = 0;
394 bool takeNeighbor = (element.level() < neighbor.level());
397 (takeNeighbor) ? !cellDataJ.fluxData().isUpwindCell(wPhaseIdx, intersection.indexInOutside()) :
398 cellDataI.fluxData().isUpwindCell(wPhaseIdx, indexInInside);
400 (takeNeighbor) ? !cellDataJ.fluxData().isUpwindCell(nPhaseIdx, intersection.indexInOutside()) :
401 cellDataI.fluxData().isUpwindCell(nPhaseIdx, indexInInside);
403 const GlobalPosition& globalPosNeighbor = neighbor.geometry().center();
406 GlobalPosition distVec = globalPosNeighbor - globalPos;
410 Scalar dist = abs(distVec * unitOuterNormal);
412 Scalar satJ = cellDataJ.saturation(wPhaseIdx);
413 Scalar lambdaWJ = cellDataI.mobility(wPhaseIdx);
414 Scalar lambdaNwJ = cellDataI.mobility(nPhaseIdx);
419 const auto fluidMatrixInteractionNeighbor = Deprecated::makePcKrSw(Scalar{}, problem_.spatialParams(), neighbor);
421 const Scalar dpc_dsJ = fluidMatrixInteractionNeighbor.dpc_dsw(satJ);
426 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(element));
432 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(neighbor));
437 Scalar meanPermeability = 2*perm1*perm2/(perm1 + perm2);
439 Scalar transmissibility = meanPermeability * intersection.geometry().volume() / dist;
445 satUpw = max(satI, 0.0);
449 satUpw = max(satJ, 0.0);
452 Scalar ds = epsDerivative_;
454 Scalar satPlus = satUpw + epsDerivative_;
455 Scalar satMinus = satUpw;
456 if (satMinus - epsDerivative_ > 0.0)
458 satMinus -= epsDerivative_;
459 ds += epsDerivative_;
462 Scalar dLambdaWDs = fluidMatrixInteractionNeighbor.krw(abs(satPlus)) / viscosityW;
463 dLambdaWDs -= fluidMatrixInteractionNeighbor.krw(abs(satMinus)) / viscosityW;
468 satUpw = max(1 - satI, 0.0);
472 satUpw = max(1 - satJ, 0.0);
477 satPlus = satUpw + epsDerivative_;
479 if (satMinus - epsDerivative_ > 0.0)
481 satMinus -= epsDerivative_;
482 ds += epsDerivative_;
485 Scalar dLambdaNwDs = fluidMatrixInteractionNeighbor.krn(satPlus) / viscosityNw;
486 dLambdaNwDs -= fluidMatrixInteractionNeighbor.krn(satMinus) / viscosityNw;
489 Scalar lambdaWCap = 0.5 * (lambdaWI + lambdaWJ);
490 Scalar lambdaNwCap = 0.5 * (lambdaNwI + lambdaNwJ);
492 Scalar potentialDiff = cellDataI.potential(wPhaseIdx) - cellDataJ.potential(wPhaseIdx);
493 Scalar cflFlux = transmissibility * lambdaNw * dLambdaWDs * abs(potentialDiff) / lambdaT;
495 potentialDiff = cellDataI.potential(nPhaseIdx) - cellDataJ.potential(nPhaseIdx);
496 cflFlux -= transmissibility * lambdaW * dLambdaNwDs * abs(potentialDiff) / lambdaT;
498 cflFlux -= transmissibility * lambdaWCap * lambdaNwCap * (dpc_dsI + dpc_dsJ) / lambdaT;
500 if ((upwindWI && lambdaW > threshold_)|| (upwindNwI && lambdaW < threshold_))
502 cflFluxFunctionCoatsOut_ += cflFlux;
506 cflFluxFunctionCoatsIn_ += cflFlux;
512 GlobalPosition globalPosFace = intersection.geometry().center();
515 BoundaryTypes bcType;
516 problem_.boundaryTypes(bcType, intersection);
519 Dune::FieldVector < Scalar, dimWorld > distVec = globalPosFace - globalPos;
522 Scalar dist = distVec.two_norm();
529 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(element));
532 Scalar faceArea = intersection.geometry().volume();
534 Scalar transmissibility = (unitOuterNormal *
permeability) * faceArea / dist;
536 Scalar satWBound = cellDataI.saturation(wPhaseIdx);
537 if (bcType.isDirichlet(eqIdxSat))
539 PrimaryVariables bcValues;
540 problem_.dirichlet(bcValues, intersection);
541 switch (saturationType_)
545 satWBound = bcValues[eqIdxSat];
550 satWBound = 1 - bcValues[eqIdxSat];
555 DUNE_THROW(Dune::RangeError,
"saturation type not implemented");
561 Scalar potWBound = cellDataI.potential(wPhaseIdx);
562 Scalar potNwBound = cellDataI.potential(nPhaseIdx);
563 Scalar gdeltaZ = (problem_.bBoxMax()-globalPosFace) * problem_.gravity();
564 if (bcType.isDirichlet(eqIdxPress))
566 PrimaryVariables bcValues;
567 problem_.dirichlet(bcValues, intersection);
568 switch (pressureType_)
572 potWBound = bcValues[eqIdxPress] + density_[wPhaseIdx] * gdeltaZ;
573 potNwBound = bcValues[eqIdxPress] + fluidMatrixInteraction.pc(satWBound)
574 + density_[nPhaseIdx] * gdeltaZ;
579 potWBound = bcValues[eqIdxPress] - fluidMatrixInteraction.pc(satWBound)
580 + density_[wPhaseIdx] * gdeltaZ;
581 potNwBound = bcValues[eqIdxPress] + density_[nPhaseIdx] * gdeltaZ;
586 DUNE_THROW(Dune::RangeError,
"pressure type not implemented");
590 else if (bcType.isNeumann(eqIdxPress) && bcType.isDirichlet(eqIdxSat))
592 PrimaryVariables bcValues;
593 problem_.neumann(bcValues, intersection);
595 bcValues[wPhaseIdx] /= density_[wPhaseIdx];
596 bcValues[nPhaseIdx] /= density_[nPhaseIdx];
598 bcValues[wPhaseIdx] *= faceArea;
599 bcValues[nPhaseIdx] *= faceArea;
601 bool hasPotWBound =
false;
602 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))
604 potWBound -= bcValues[wPhaseIdx] / (transmissibility * lambdaW);
607 bool hasPotNwBound =
false;
608 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))
610 potNwBound -= bcValues[nPhaseIdx] / (transmissibility * lambdaNw);
611 hasPotNwBound =
true;
614 if (hasPotWBound && !hasPotNwBound)
616 potNwBound = potWBound + fluidMatrixInteraction.pc(satWBound)
617 + (density_[nPhaseIdx] - density_[wPhaseIdx]) * gdeltaZ;
619 else if (!hasPotWBound && hasPotNwBound)
621 potWBound = potNwBound - fluidMatrixInteraction.pc(satWBound)
622 + (density_[nPhaseIdx] - density_[wPhaseIdx]) * gdeltaZ;
625 else if (bcType.isNeumann(eqIdxPress))
627 PrimaryVariables bcValues;
628 problem_.neumann(bcValues, intersection);
630 bcValues[wPhaseIdx] /= density_[wPhaseIdx];
631 bcValues[nPhaseIdx] /= density_[nPhaseIdx];
633 bcValues[wPhaseIdx] *= faceArea;
634 bcValues[nPhaseIdx] *= faceArea;
638 if (bcValues[wPhaseIdx] > 0)
640 cflFluxFunctionCoatsOut_ += abs(bcValues[wPhaseIdx]);
644 cflFluxFunctionCoatsIn_ += abs(bcValues[wPhaseIdx]);
646 if (bcValues[nPhaseIdx] > 0)
648 cflFluxFunctionCoatsOut_ += abs(bcValues[nPhaseIdx]);
652 cflFluxFunctionCoatsIn_ += abs(bcValues[nPhaseIdx]);
659 rejectForTimeStepping_ =
true;
660 cflFluxFunctionCoatsIn_ = 0;
661 cflFluxFunctionCoatsOut_ = 0;
665 const Scalar dpc_dsBound = fluidMatrixInteraction.dpc_dsw(satWBound);
667 Scalar lambdaWBound = 0;
668 Scalar lambdaNwBound = 0;
670 Scalar
temperature = problem_.temperature(element);
671 Scalar referencePressure = problem_.referencePressure(element);
672 FluidState fluidState;
673 fluidState.setPressure(wPhaseIdx, referencePressure);
674 fluidState.setPressure(nPhaseIdx, referencePressure);
678 Scalar viscosityNwBound =
680 lambdaWBound = fluidMatrixInteraction.krw(satWBound) / viscosityWBound;
681 lambdaNwBound = fluidMatrixInteraction.krn(satWBound) / viscosityNwBound;
685 if (cellDataI.fluxData().isUpwindCell(wPhaseIdx, indexInInside))
687 satUpw = max(satI, 0.0);
691 satUpw = max(satWBound, 0.0);
694 Scalar ds = epsDerivative_;
696 Scalar satPlus = satUpw + epsDerivative_;
697 Scalar satMinus = satUpw;
698 if (satMinus - epsDerivative_ > 0.0)
700 satMinus -= epsDerivative_;
701 ds += epsDerivative_;
704 Scalar dLambdaWDs = fluidMatrixInteraction.krw(satPlus) / viscosityW;
705 dLambdaWDs -= fluidMatrixInteraction.krw(satMinus) / viscosityW;
708 if (cellDataI.fluxData().isUpwindCell(nPhaseIdx, indexInInside))
710 satUpw = max(1 - satI, 0.0);
714 satUpw = max(1 - satWBound, 0.0);
719 satPlus = satUpw + epsDerivative_;
721 if (satMinus - epsDerivative_ > 0.0)
723 satMinus -= epsDerivative_;
724 ds += epsDerivative_;
727 Scalar dLambdaNwDs = fluidMatrixInteraction.krn(satPlus) / viscosityNw;
728 dLambdaNwDs -= fluidMatrixInteraction.krn(satMinus) / viscosityNw;
731 Scalar lambdaWCap = 0.5 * (lambdaWI + lambdaWBound);
732 Scalar lambdaNwCap = 0.5 * (lambdaNwI + lambdaNwBound);
734 Scalar potDiff = cellDataI.potential(wPhaseIdx) - potWBound;
736 Scalar cflFlux = transmissibility * lambdaNw * dLambdaWDs * abs(potDiff) / lambdaT;
738 cflFlux -= transmissibility * lambdaWCap * lambdaNwCap * (dpc_dsI + dpc_dsBound) / lambdaT;
740 potDiff = cellDataI.potential(nPhaseIdx) - potNwBound;
741 cflFlux -= transmissibility * lambdaW * dLambdaNwDs * abs(potDiff) / lambdaT;
743 if ((cellDataI.fluxData().isUpwindCell(wPhaseIdx, indexInInside) && lambdaW > threshold_) ||
744 (cellDataI.fluxData().isUpwindCell(nPhaseIdx, indexInInside) && lambdaW < threshold_))
746 cflFluxFunctionCoatsOut_ += cflFlux;
750 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 (equivalent to old macro GET_PROP(...))
Definition: propertysystem.hh:140
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:149
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:42
Scalar getDt(const Element &element)
Returns the Cfl time-step.
Definition: evalcflfluxcoats.hh:164
void reset()
Resets the Timestep-estimator.
Definition: evalcflfluxcoats.hh:172
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:107
Scalar getCflFluxFunction(const Element &element)
Returns the Cfl flux-function.
Definition: evalcflfluxcoats.hh:130
EvalCflFluxCoats(Problem &problem)
Constructs an EvalCflFluxDefault object.
Definition: evalcflfluxcoats.hh:188
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:118
void initialize()
Initializes the cfl-flux-model.
Definition: evalcflfluxcoats.hh:89