24#ifndef DUMUX_DISCRETIZATION_CC_TPFA_FORCHHEIMERS_LAW_HH
25#define DUMUX_DISCRETIZATION_CC_TPFA_FORCHHEIMERS_LAW_HH
27#include <dune/common/fvector.hh>
28#include <dune/common/fmatrix.hh>
41template<
class TypeTag, DiscretizationMethod discMethod>
42class ForchheimersLawImplementation;
52template<
class Scalar,
class Gr
idGeometry,
bool isNetwork>
60template <
class TypeTag>
63 GetPropType<TypeTag, Properties::GridGeometry>,
64 (GetPropType<TypeTag, Properties::GridGeometry>::GridView::dimension < GetPropType<TypeTag, Properties::GridGeometry>::GridView::dimensionworld)>
71template<class GridGeometry>
72class TpfaForchheimersLawCacheFiller
74 using FVElementGeometry = typename GridGeometry::LocalView;
75 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
76 using Element = typename GridGeometry::GridView::template Codim<0>::Entity;
82 template<class FluxVariablesCache, class Problem, class ElementVolumeVariables, class FluxVariablesCacheFiller>
83 static void fill(FluxVariablesCache& scvfFluxVarsCache,
84 const Problem& problem,
85 const Element& element,
86 const FVElementGeometry& fvGeometry,
87 const ElementVolumeVariables& elemVolVars,
88 const SubControlVolumeFace& scvf,
89 const FluxVariablesCacheFiller& fluxVarsCacheFiller)
91 scvfFluxVarsCache.updateAdvection(problem, element, fvGeometry, elemVolVars, scvf);
99template<class AdvectionType, class GridGeometry>
100class TpfaForchheimersLawCache
102 using Scalar = typename AdvectionType::Scalar;
103 using FVElementGeometry = typename GridGeometry::LocalView;
104 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
105 using Element = typename GridGeometry::GridView::template Codim<0>::Entity;
106 static constexpr int dimWorld = GridGeometry::GridView::dimensionworld;
107 using DimWorldMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
110 using Filler = TpfaForchheimersLawCacheFiller<GridGeometry>;
112 template<class Problem, class ElementVolumeVariables>
113 void updateAdvection(const Problem& problem,
114 const Element& element,
115 const FVElementGeometry& fvGeometry,
116 const ElementVolumeVariables& elemVolVars,
117 const SubControlVolumeFace &scvf)
119 tij_ = AdvectionType::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf);
120 harmonicMeanSqrtK_ = AdvectionType::calculateHarmonicMeanSqrtPermeability(problem, elemVolVars, scvf);
123 const Scalar& advectionTij() const
126 const DimWorldMatrix& harmonicMeanSqrtPermeability() const
127 { return harmonicMeanSqrtK_; }
131 DimWorldMatrix harmonicMeanSqrtK_;
138template<class ScalarType, class GridGeometry>
139class CCTpfaForchheimersLaw<ScalarType, GridGeometry, false>
141 using ThisType = CCTpfaForchheimersLaw<ScalarType, GridGeometry, false>;
142 using FVElementGeometry = typename GridGeometry::LocalView;
143 using SubControlVolume = typename GridGeometry::SubControlVolume;
144 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
145 using GridView = typename GridGeometry::GridView;
146 using Element = typename GridView::template Codim<0>::Entity;
148 static constexpr int dim = GridView::dimension;
149 static constexpr int dimWorld = GridView::dimensionworld;
151 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
152 using DimWorldVector = Dune::FieldVector<ScalarType, dimWorld>;
153 using DimWorldMatrix = Dune::FieldMatrix<ScalarType, dimWorld, dimWorld>;
155 using DarcysLaw = CCTpfaDarcysLaw<ScalarType, GridGeometry, false>;
159 using Scalar = ScalarType;
162 static const DiscretizationMethod discMethod = DiscretizationMethod::cctpfa;
165 using Cache = TpfaForchheimersLawCache<ThisType, GridGeometry>;
224 template<class Problem, class ElementVolumeVariables, class ElementFluxVarsCache>
225 static Scalar flux(const Problem& problem,
226 const Element& element,
227 const FVElementGeometry& fvGeometry,
228 const ElementVolumeVariables& elemVolVars,
229 const SubControlVolumeFace& scvf,
231 const ElementFluxVarsCache& elemFluxVarsCache)
233 const auto velocity = velocity_(problem, element, fvGeometry, elemVolVars, scvf, phaseIdx, elemFluxVarsCache);
234 Scalar flux = velocity * scvf.unitOuterNormal();
241 template<class Problem, class ElementVolumeVariables>
242 static Scalar calculateTransmissibility(const Problem& problem,
243 const Element& element,
244 const FVElementGeometry& fvGeometry,
245 const ElementVolumeVariables& elemVolVars,
246 const SubControlVolumeFace& scvf)
248 return DarcysLaw::calculateTransmissibility(problem, element, fvGeometry, elemVolVars, scvf);
255 template<class Problem, class ElementVolumeVariables,
256 bool scalarPerm = std::is_same<typename Problem::SpatialParams::PermeabilityType, Scalar>::value,
257 std::enable_if_t<scalarPerm, int> = 0>
258 static DimWorldMatrix calculateHarmonicMeanSqrtPermeability(const Problem& problem,
259 const ElementVolumeVariables& elemVolVars,
260 const SubControlVolumeFace& scvf)
263 Scalar harmonicMeanSqrtK(0.0);
265 const auto insideScvIdx = scvf.insideScvIdx();
266 const auto& insideVolVars = elemVolVars[insideScvIdx];
267 const Scalar Ki = getPermeability_(problem, insideVolVars, scvf.ipGlobal());
268 const Scalar sqrtKi = sqrt(Ki);
270 if (!scvf.boundary())
272 const auto outsideScvIdx = scvf.outsideScvIdx();
273 const auto& outsideVolVars = elemVolVars[outsideScvIdx];
274 const Scalar Kj = getPermeability_(problem, outsideVolVars, scvf.ipGlobal());
275 const Scalar sqrtKj = sqrt(Kj);
276 harmonicMeanSqrtK = problem.spatialParams().harmonicMean(sqrtKi, sqrtKj, scvf.unitOuterNormal());
279 harmonicMeanSqrtK = sqrtKi;
282 DimWorldMatrix result(0.0);
283 for (int i = 0; i < dimWorld; ++i)
284 result[i][i] = harmonicMeanSqrtK;
293 template<class Problem, class ElementVolumeVariables,
294 bool scalarPerm = std::is_same<typename Problem::SpatialParams::PermeabilityType, Scalar>::value,
295 std::enable_if_t<!scalarPerm, int> = 0>
296 static DimWorldMatrix calculateHarmonicMeanSqrtPermeability(const Problem& problem,
297 const ElementVolumeVariables& elemVolVars,
298 const SubControlVolumeFace& scvf)
301 DimWorldMatrix sqrtKi(0.0);
302 DimWorldMatrix sqrtKj(0.0);
303 DimWorldMatrix harmonicMeanSqrtK(0.0);
305 const auto insideScvIdx = scvf.insideScvIdx();
306 const auto& insideVolVars = elemVolVars[insideScvIdx];
307 const auto& Ki = getPermeability_(problem, insideVolVars, scvf.ipGlobal());
310 if (!isDiagonal_(Ki))
311 DUNE_THROW(Dune::NotImplemented, "Only diagonal permeability tensors are supported.");
313 for (int i = 0; i < dim; ++i)
314 sqrtKi[i][i] = sqrt(Ki[i][i]);
316 if (!scvf.boundary())
318 const auto outsideScvIdx = scvf.outsideScvIdx();
319 const auto& outsideVolVars = elemVolVars[outsideScvIdx];
320 const auto& Kj = getPermeability_(problem, outsideVolVars, scvf.ipGlobal());
322 if (!isDiagonal_(Kj))
323 DUNE_THROW(Dune::NotImplemented, "Only diagonal permeability tensors are supported.");
325 for (int i = 0; i < dim; ++i)
326 sqrtKj[i][i] = sqrt(Kj[i][i]);
328 harmonicMeanSqrtK = problem.spatialParams().harmonicMean(sqrtKi, sqrtKj, scvf.unitOuterNormal());
331 harmonicMeanSqrtK = sqrtKi;
333 return harmonicMeanSqrtK;
339 template<class Problem, class ElementVolumeVariables, class ElementFluxVarsCache>
340 static DimWorldVector velocity_(const Problem& problem,
341 const Element& element,
342 const FVElementGeometry& fvGeometry,
343 const ElementVolumeVariables& elemVolVars,
344 const SubControlVolumeFace& scvf,
346 const ElementFluxVarsCache& elemFluxVarsCache)
350 Scalar darcyFlux = DarcysLaw::flux(problem, element, fvGeometry, elemVolVars, scvf, phaseIdx, elemFluxVarsCache);
351 auto upwindTerm = [phaseIdx](const auto& volVars){ return volVars.mobility(phaseIdx); };
352 const Scalar darcyUpwindMobility = doUpwind_(scvf, elemVolVars, upwindTerm, !std::signbit(darcyFlux) );
353 darcyFlux *= darcyUpwindMobility;
356 DimWorldVector darcyVelocity = scvf.unitOuterNormal();
357 darcyVelocity *= darcyFlux / scvf.area();
360 const auto& fluxVarsCache = elemFluxVarsCache[scvf];
361 const auto& sqrtK = fluxVarsCache.harmonicMeanSqrtPermeability();
364 const Scalar forchCoeff = problem.spatialParams().forchCoeff(scvf);
367 DimWorldVector velocity = darcyVelocity;
369 DimWorldVector deltaV(0.0);
370 DimWorldVector residual(10e10);
371 DimWorldMatrix gradF(0.0);
374 static const Scalar epsilon = getParamFromGroup<Scalar>(problem.paramGroup(), "Forchheimer.NewtonTolerance", 1e-12);
375 static const std::size_t maxNumIter = getParamFromGroup<std::size_t>(problem.paramGroup(), "Forchheimer.MaxIterations", 30);
376 for (int k = 0; residual.two_norm() > epsilon ; ++k)
379 DUNE_THROW(NumericalProblem, "could not determine forchheimer velocity within "
380 << k << " iterations");
383 forchheimerResidual_(residual,
393 forchheimerDerivative_(gradF,
402 gradF.solve(deltaV, residual);
408 const Scalar forchheimerUpwindMobility = doUpwind_(scvf, elemVolVars, upwindTerm,
409 !std::signbit(velocity * scvf.unitOuterNormal()) );
412 if (forchheimerUpwindMobility > 0.0)
413 velocity /= forchheimerUpwindMobility;
419 template<class ElementVolumeVariables>
420 static void forchheimerResidual_(DimWorldVector& residual,
421 const Scalar forchCoeff,
422 const DimWorldMatrix& sqrtK,
423 const DimWorldVector& darcyVelocity,
424 const DimWorldVector& oldVelocity,
425 const ElementVolumeVariables& elemVolVars,
426 const SubControlVolumeFace& scvf,
429 residual = oldVelocity;
432 residual -= darcyVelocity;
435 auto upwindTerm = [phaseIdx](const auto& volVars){ return volVars.density(phaseIdx) / volVars.viscosity(phaseIdx); };
436 bool insideIsUpstream = !std::signbit(oldVelocity * scvf.unitOuterNormal());
437 const Scalar rhoOverMu = doUpwind_(scvf, elemVolVars, upwindTerm, insideIsUpstream);
438 sqrtK.usmv(forchCoeff * rhoOverMu * oldVelocity.two_norm(), oldVelocity, residual);
442 template<class ElementVolumeVariables>
443 static void forchheimerDerivative_(DimWorldMatrix& derivative,
444 const Scalar forchCoeff,
445 const DimWorldMatrix& sqrtK,
446 const DimWorldVector& velocity,
447 const ElementVolumeVariables& elemVolVars,
448 const SubControlVolumeFace& scvf,
456 auto upwindTerm = [phaseIdx](const auto& volVars){ return volVars.density(phaseIdx) / volVars.viscosity(phaseIdx); };
457 bool insideIsUpstream = !std::signbit(velocity * scvf.unitOuterNormal());
459 const Scalar absV = velocity.two_norm() ;
469 const Scalar rhoOverMu = doUpwind_(scvf, elemVolVars, upwindTerm, insideIsUpstream);
472 for (int i = 0; i < dim; i++)
474 for (int k = 0; k <= i; k++)
476 derivative[i][k] = sqrtK[i][i] * velocity[i] * velocity[k] * forchCoeff
480 derivative[k][i] = derivative[i][k];
487 for (int i = 0; i < dim; i++)
488 derivative[i][i] += (1.0 + (sqrtK[i][i]*forchCoeff * absV * rhoOverMu));
491 template<class ElementVolumeVariables, class UpwindTermFunction>
492 static Scalar doUpwind_(const SubControlVolumeFace& scvf,
493 const ElementVolumeVariables& elemVolVars,
494 const UpwindTermFunction& upwindTerm,
495 const bool insideIsUpstream)
497 static const Scalar upwindWeight = getParam<Scalar>("Flux.UpwindWeight");
499 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
500 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
502 if (!insideIsUpstream)
503 return (upwindWeight*upwindTerm(outsideVolVars)
504 + (1.0 - upwindWeight)*upwindTerm(insideVolVars));
506 return (upwindWeight*upwindTerm(insideVolVars)
507 + (1.0 - upwindWeight)*upwindTerm(outsideVolVars));
518 static bool isDiagonal_(const DimWorldMatrix & K)
521 for (int i = 0; i < dim; i++) {
522 for (int k = 0; k < dim; k++) {
523 if ((i != k) && (abs(K[i][k]) >= 1e-25)) {
531 template<class Problem, class VolumeVariables,
532 std::enable_if_t<!Problem::SpatialParams::evaluatePermeabilityAtScvfIP(), int> = 0>
533 static decltype(auto) getPermeability_(const Problem& problem,
534 const VolumeVariables& volVars,
535 const GlobalPosition& scvfIpGlobal)
536 { return volVars.permeability(); }
538 template<class Problem, class VolumeVariables,
539 std::enable_if_t<Problem::SpatialParams::evaluatePermeabilityAtScvfIP(), int> = 0>
540 static decltype(auto) getPermeability_(const Problem& problem,
541 const VolumeVariables& volVars,
542 const GlobalPosition& scvfIpGlobal)
543 { return problem.spatialParams().permeabilityAtPos(scvfIpGlobal); }
550template<class ScalarType, class GridGeometry>
551class CCTpfaForchheimersLaw<ScalarType, GridGeometry, true>
553 static_assert(AlwaysFalse<ScalarType>::value, "Forchheimer not implemented for network grids");
Define some often used mathematical functions.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.
The available discretization methods in Dumux.
DiscretizationMethod
The available discretization methods in Dumux.
Definition: method.hh:37
make the local view function available whenever we use the grid geometry
Definition: adapt.hh:29
forward declare
Definition: forchheimerslaw.hh:38
Forchheimer's law for cell-centered finite volume schemes with two-point flux approximation.
Definition: cctpfa/forchheimerslaw.hh:53
Declares all properties used in Dumux.
Darcy's law for cell-centered finite volume schemes with two-point flux approximation.