24#ifndef DUMUX_EVALCFLFLUX_COATS_HH
25#define DUMUX_EVALCFLFLUX_COATS_HH
27#include <dune/common/float_cmp.hh>
38template<
class TypeTag>
47 using MaterialLaw =
typename SpatialParams::MaterialLaw;
54 using PrimaryVariables =
typename SolutionTypes::PrimaryVariables;
60 dim = GridView::dimension, dimWorld = GridView::dimensionworld
64 wPhaseIdx = Indices::wPhaseIdx, nPhaseIdx = Indices::nPhaseIdx,
65 eqIdxPress = Indices::pressureEqIdx,
66 eqIdxSat = Indices::satEqIdx,
67 numPhases = getPropValue<TypeTag, Properties::NumPhases>()
72 pw = Indices::pressureW,
73 pn = Indices::pressureNw,
74 vt = Indices::velocityTotal,
75 sw = Indices::saturationW,
76 sn = Indices::saturationNw
79 using Element =
typename GridView::Traits::template Codim<0>::Entity;
80 using Intersection =
typename GridView::Intersection;
82 using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
83 using DimVector = Dune::FieldVector<Scalar, dimWorld>;
84 using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
90 const auto element = *problem_.gridView().template begin<0>();
91 FluidState fluidState;
92 fluidState.setPressure(wPhaseIdx, problem_.referencePressure(element));
93 fluidState.setPressure(nPhaseIdx, problem_.referencePressure(element));
94 fluidState.setTemperature(problem_.temperature(element));
95 fluidState.setSaturation(wPhaseIdx, 1.);
96 fluidState.setSaturation(nPhaseIdx, 0.);
106 void addFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
107 const Element& element,
int phaseIdx = -1)
109 addDefaultFlux(flux, phaseIdx);
117 void addFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
118 const Intersection& intersection,
int phaseIdx = -1)
120 addDefaultFlux(flux, phaseIdx);
121 addCoatsFlux(lambdaW, lambdaNw, viscosityW, viscosityNw, flux, intersection, phaseIdx);
131 Scalar cflFluxDefault = getCflFluxFunctionDefault();
133 if (rejectForTimeStepping_)
134 return 0.99 / cflFluxDefault;
138 if (isnan(cflFluxFunctionCoatsOut_) || isinf(cflFluxFunctionCoatsOut_)){cflFluxFunctionCoatsOut_ = 0.0;}
139 if (isnan(cflFluxFunctionCoatsIn_) || isinf(cflFluxFunctionCoatsIn_)){cflFluxFunctionCoatsIn_ = 0.0;}
142 Scalar cflFluxFunctionCoats = max(cflFluxFunctionCoatsIn_, cflFluxFunctionCoatsOut_);
144 if (cflFluxFunctionCoats <= 0)
146 return 0.99 / cflFluxDefault;
148 else if (cflFluxDefault > cflFluxFunctionCoats)
150 return 0.99 / cflFluxDefault;
154 return 0.99 / cflFluxFunctionCoats;
163 Scalar
getDt(
const Element& element)
166 Scalar
porosity = max(problem_.spatialParams().porosity(element), porosityThreshold_);
173 cflFluxFunctionCoatsIn_ = 0;
174 cflFluxFunctionCoatsOut_ = 0;
175 rejectForTimeStepping_ =
false;
177 fluxNonwettingOut_ = 0;
188 problem_(problem), epsDerivative_(5e-3), threshold_(1e-8)
191 density_[wPhaseIdx] = 0.;
192 density_[nPhaseIdx] = 0.;
194 porosityThreshold_ = getParam<Scalar>(
"Impet.PorosityThreshold");
198 Scalar getCflFluxFunctionDefault()
204 if (isnan(fluxIn_) || isinf(fluxIn_))
209 Scalar cFLFluxIn = fluxIn_;
212 Scalar cFLFluxOut = 0;
214 if (velocityType_ == vt)
216 if (isnan(fluxOut_) || isinf(fluxOut_))
221 cFLFluxOut = fluxOut_;
225 if (isnan(fluxWettingOut_) || isinf(fluxWettingOut_))
227 fluxWettingOut_ = 1e-100;
229 if (isnan(fluxNonwettingOut_) || isinf(fluxNonwettingOut_))
231 fluxNonwettingOut_ = 1e-100;
234 cFLFluxOut = max(fluxWettingOut_, fluxNonwettingOut_);
239 Scalar cFLFluxFunction = max(cFLFluxIn, cFLFluxOut);
241 return cFLFluxFunction;
244 void addDefaultFlux(Scalar flux,
int phaseIdx);
246 void addCoatsFlux(Scalar& lambdaW, Scalar& lambdaNw, Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
247 const Intersection& intersection,
int phaseIdx);
250 Scalar cflFluxFunctionCoatsIn_;
251 Scalar cflFluxFunctionCoatsOut_;
252 Scalar fluxWettingOut_;
253 Scalar fluxNonwettingOut_;
256 bool rejectForTimeStepping_;
257 Scalar density_[numPhases];
258 static const int pressureType_ = getPropValue<TypeTag, Properties::PressureFormulation>();
259 static const int velocityType_ = getPropValue<TypeTag, Properties::VelocityFormulation>();
260 static const int saturationType_ = getPropValue<TypeTag, Properties::SaturationFormulation>();
261 const Scalar epsDerivative_;
262 const Scalar threshold_;
263 Scalar porosityThreshold_;
266template<
class TypeTag>
267void EvalCflFluxCoats<TypeTag>::addDefaultFlux(Scalar flux,
int phaseIdx)
276 fluxWettingOut_ += flux;
291 fluxNonwettingOut_ += flux;
321template<
class TypeTag>
322void EvalCflFluxCoats<TypeTag>::addCoatsFlux(Scalar& lambdaW, Scalar& lambdaNw,
323 Scalar& viscosityW, Scalar& viscosityNw, Scalar flux,
324 const Intersection& intersection,
int phaseIdx)
326 if (rejectForTimeStepping_)
328 else if (phaseIdx != wPhaseIdx)
331 Scalar lambdaT = (lambdaW + lambdaNw);
333 if (lambdaT <= threshold_)
336 auto element = intersection.inside();
339 const GlobalPosition& globalPos = element.geometry().center();
342 int globalIdxI = problem_.variables().index(element);
344 CellData& cellDataI = problem_.variables().cellData(globalIdxI);
346 if (cellDataI.potential(wPhaseIdx) < 0.0 || cellDataI.potential(nPhaseIdx) < 0.0)
348 rejectForTimeStepping_ =
true;
349 cflFluxFunctionCoatsIn_ = 0;
350 cflFluxFunctionCoatsOut_ = 0;
354 int indexInInside = intersection.indexInInside();
356 Scalar satI = cellDataI.saturation(wPhaseIdx);
357 Scalar lambdaWI = cellDataI.mobility(wPhaseIdx);
358 Scalar lambdaNwI = cellDataI.mobility(nPhaseIdx);
360 Scalar dpc_dsI = MaterialLaw::dpc_dsw(problem_.spatialParams().materialLawParams(element), 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 Scalar dpc_dsJ = MaterialLaw::dpc_dsw(problem_.spatialParams().materialLawParams(neighbor), satJ);
415 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(element));
421 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(neighbor));
426 Scalar meanPermeability = 2*perm1*perm2/(perm1 + perm2);
428 Scalar transmissibility = meanPermeability * intersection.geometry().volume() / dist;
434 satUpw = max(satI, 0.0);
438 satUpw = max(satJ, 0.0);
441 Scalar ds = epsDerivative_;
443 Scalar satPlus = satUpw + epsDerivative_;
444 Scalar satMinus = satUpw;
445 if (satMinus - epsDerivative_ > 0.0)
447 satMinus -= epsDerivative_;
448 ds += epsDerivative_;
451 Scalar dLambdaWDs = MaterialLaw::krw(problem_.spatialParams().materialLawParams(neighbor), abs(satPlus)) / viscosityW;
452 dLambdaWDs -= MaterialLaw::krw(problem_.spatialParams().materialLawParams(neighbor), abs(satMinus)) / viscosityW;
457 satUpw = max(1 - satI, 0.0);
461 satUpw = max(1 - satJ, 0.0);
466 satPlus = satUpw + epsDerivative_;
468 if (satMinus - epsDerivative_ > 0.0)
470 satMinus -= epsDerivative_;
471 ds += epsDerivative_;
474 Scalar dLambdaNwDs = MaterialLaw::krn(problem_.spatialParams().materialLawParams(neighbor), satPlus) / viscosityNw;
475 dLambdaNwDs -= MaterialLaw::krn(problem_.spatialParams().materialLawParams(neighbor), satMinus) / viscosityNw;
478 Scalar lambdaWCap = 0.5 * (lambdaWI + lambdaWJ);
479 Scalar lambdaNwCap = 0.5 * (lambdaNwI + lambdaNwJ);
481 Scalar potentialDiff = cellDataI.potential(wPhaseIdx) - cellDataJ.potential(wPhaseIdx);
482 Scalar cflFlux = transmissibility * lambdaNw * dLambdaWDs * abs(potentialDiff) / lambdaT;
484 potentialDiff = cellDataI.potential(nPhaseIdx) - cellDataJ.potential(nPhaseIdx);
485 cflFlux -= transmissibility * lambdaW * dLambdaNwDs * abs(potentialDiff) / lambdaT;
487 cflFlux -= transmissibility * lambdaWCap * lambdaNwCap * (dpc_dsI + dpc_dsJ) / lambdaT;
489 if ((upwindWI && lambdaW > threshold_)|| (upwindNwI && lambdaW < threshold_))
491 cflFluxFunctionCoatsOut_ += cflFlux;
495 cflFluxFunctionCoatsIn_ += cflFlux;
501 GlobalPosition globalPosFace = intersection.geometry().center();
504 BoundaryTypes bcType;
505 problem_.boundaryTypes(bcType, intersection);
508 Dune::FieldVector < Scalar, dimWorld > distVec = globalPosFace - globalPos;
511 Scalar dist = distVec.two_norm();
518 problem_.spatialParams().meanK(perm, problem_.spatialParams().intrinsicPermeability(element));
521 Scalar faceArea = intersection.geometry().volume();
523 Scalar transmissibility = (unitOuterNormal *
permeability) * faceArea / dist;
525 Scalar satWBound = cellDataI.saturation(wPhaseIdx);
526 if (bcType.isDirichlet(eqIdxSat))
528 PrimaryVariables bcValues;
529 problem_.dirichlet(bcValues, intersection);
530 switch (saturationType_)
534 satWBound = bcValues[eqIdxSat];
539 satWBound = 1 - bcValues[eqIdxSat];
544 DUNE_THROW(Dune::RangeError,
"saturation type not implemented");
550 Scalar potWBound = cellDataI.potential(wPhaseIdx);
551 Scalar potNwBound = cellDataI.potential(nPhaseIdx);
552 Scalar gdeltaZ = (problem_.bBoxMax()-globalPosFace) * problem_.gravity();
553 if (bcType.isDirichlet(eqIdxPress))
555 PrimaryVariables bcValues;
556 problem_.dirichlet(bcValues, intersection);
557 switch (pressureType_)
561 potWBound = bcValues[eqIdxPress] + density_[wPhaseIdx] * gdeltaZ;
562 potNwBound = bcValues[eqIdxPress] + MaterialLaw::pc(problem_.spatialParams().materialLawParams(element), satWBound)
563 + density_[nPhaseIdx] * gdeltaZ;
568 potWBound = bcValues[eqIdxPress] - MaterialLaw::pc(problem_.spatialParams().materialLawParams(element),satWBound)
569 + density_[wPhaseIdx] * gdeltaZ;
570 potNwBound = bcValues[eqIdxPress] + density_[nPhaseIdx] * gdeltaZ;
575 DUNE_THROW(Dune::RangeError,
"pressure type not implemented");
579 else if (bcType.isNeumann(eqIdxPress) && bcType.isDirichlet(eqIdxSat))
581 PrimaryVariables bcValues;
582 problem_.neumann(bcValues, intersection);
584 bcValues[wPhaseIdx] /= density_[wPhaseIdx];
585 bcValues[nPhaseIdx] /= density_[nPhaseIdx];
587 bcValues[wPhaseIdx] *= faceArea;
588 bcValues[nPhaseIdx] *= faceArea;
590 bool hasPotWBound =
false;
591 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))
593 potWBound -= bcValues[wPhaseIdx] / (transmissibility * lambdaW);
596 bool hasPotNwBound =
false;
597 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))
599 potNwBound -= bcValues[nPhaseIdx] / (transmissibility * lambdaNw);
600 hasPotNwBound =
true;
603 if (hasPotWBound && !hasPotNwBound)
605 potNwBound = potWBound + MaterialLaw::pc(problem_.spatialParams().materialLawParams(element),satWBound)
606 + (density_[nPhaseIdx] - density_[wPhaseIdx]) * gdeltaZ;
608 else if (!hasPotWBound && hasPotNwBound)
610 potWBound = potNwBound - MaterialLaw::pc(problem_.spatialParams().materialLawParams(element),satWBound)
611 + (density_[nPhaseIdx] - density_[wPhaseIdx]) * gdeltaZ;
614 else if (bcType.isNeumann(eqIdxPress))
616 PrimaryVariables bcValues;
617 problem_.neumann(bcValues, intersection);
619 bcValues[wPhaseIdx] /= density_[wPhaseIdx];
620 bcValues[nPhaseIdx] /= density_[nPhaseIdx];
622 bcValues[wPhaseIdx] *= faceArea;
623 bcValues[nPhaseIdx] *= faceArea;
627 if (bcValues[wPhaseIdx] > 0)
629 cflFluxFunctionCoatsOut_ += abs(bcValues[wPhaseIdx]);
633 cflFluxFunctionCoatsIn_ += abs(bcValues[wPhaseIdx]);
635 if (bcValues[nPhaseIdx] > 0)
637 cflFluxFunctionCoatsOut_ += abs(bcValues[nPhaseIdx]);
641 cflFluxFunctionCoatsIn_ += abs(bcValues[nPhaseIdx]);
648 rejectForTimeStepping_ =
true;
649 cflFluxFunctionCoatsIn_ = 0;
650 cflFluxFunctionCoatsOut_ = 0;
654 Scalar dpc_dsBound = MaterialLaw::dpc_dsw(problem_.spatialParams().materialLawParams(element), satWBound);
656 Scalar lambdaWBound = 0;
657 Scalar lambdaNwBound = 0;
659 Scalar
temperature = problem_.temperature(element);
660 Scalar referencePressure = problem_.referencePressure(element);
661 FluidState fluidState;
662 fluidState.setPressure(wPhaseIdx, referencePressure);
663 fluidState.setPressure(nPhaseIdx, referencePressure);
667 Scalar viscosityNwBound =
669 lambdaWBound = MaterialLaw::krw(problem_.spatialParams().materialLawParams(element), satWBound) / viscosityWBound;
670 lambdaNwBound = MaterialLaw::krn(problem_.spatialParams().materialLawParams(element), satWBound) / viscosityNwBound;
674 if (cellDataI.fluxData().isUpwindCell(wPhaseIdx, indexInInside))
676 satUpw = max(satI, 0.0);
680 satUpw = max(satWBound, 0.0);
683 Scalar ds = epsDerivative_;
685 Scalar satPlus = satUpw + epsDerivative_;
686 Scalar satMinus = satUpw;
687 if (satMinus - epsDerivative_ > 0.0)
689 satMinus -= epsDerivative_;
690 ds += epsDerivative_;
693 Scalar dLambdaWDs = MaterialLaw::krw(problem_.spatialParams().materialLawParams(element), satPlus) / viscosityW;
694 dLambdaWDs -= MaterialLaw::krw(problem_.spatialParams().materialLawParams(element), satMinus) / viscosityW;
697 if (cellDataI.fluxData().isUpwindCell(nPhaseIdx, indexInInside))
699 satUpw = max(1 - satI, 0.0);
703 satUpw = max(1 - satWBound, 0.0);
708 satPlus = satUpw + epsDerivative_;
710 if (satMinus - epsDerivative_ > 0.0)
712 satMinus -= epsDerivative_;
713 ds += epsDerivative_;
716 Scalar dLambdaNwDs = MaterialLaw::krn(problem_.spatialParams().materialLawParams(element), satPlus) / viscosityNw;
717 dLambdaNwDs -= MaterialLaw::krn(problem_.spatialParams().materialLawParams(element), satMinus) / viscosityNw;
720 Scalar lambdaWCap = 0.5 * (lambdaWI + lambdaWBound);
721 Scalar lambdaNwCap = 0.5 * (lambdaNwI + lambdaNwBound);
723 Scalar potDiff = cellDataI.potential(wPhaseIdx) - potWBound;
725 Scalar cflFlux = transmissibility * lambdaNw * dLambdaWDs * abs(potDiff) / lambdaT;
727 cflFlux -= transmissibility * lambdaWCap * lambdaNwCap * (dpc_dsI + dpc_dsBound) / lambdaT;
729 potDiff = cellDataI.potential(nPhaseIdx) - potNwBound;
730 cflFlux -= transmissibility * lambdaW * dLambdaNwDs * abs(potDiff) / lambdaT;
732 if ((cellDataI.fluxData().isUpwindCell(wPhaseIdx, indexInInside) && lambdaW > threshold_) ||
733 (cellDataI.fluxData().isUpwindCell(nPhaseIdx, indexInInside) && lambdaW < threshold_))
735 cflFluxFunctionCoatsOut_ += cflFlux;
739 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:40
Scalar getDt(const Element &element)
Returns the Cfl time-step.
Definition: evalcflfluxcoats.hh:163
void reset()
Resets the Timestep-estimator.
Definition: evalcflfluxcoats.hh:171
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:106
Scalar getCflFluxFunction(const Element &element)
Returns the Cfl flux-function.
Definition: evalcflfluxcoats.hh:129
EvalCflFluxCoats(Problem &problem)
Constructs an EvalCflFluxDefault object.
Definition: evalcflfluxcoats.hh:187
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:117
void initialize()
Initializes the cfl-flux-model.
Definition: evalcflfluxcoats.hh:88