version 3.8
freeflow/navierstokes/momentum/fluxvariables.hh
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3//
4// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
12#ifndef DUMUX_NAVIERSTOKES_MOMENTUM_FLUXVARIABLES_HH
13#define DUMUX_NAVIERSTOKES_MOMENTUM_FLUXVARIABLES_HH
14
15#include <array>
16
18#include <dumux/common/math.hh>
22
25
26// #include "staggeredupwindhelper.hh"
27#include "velocitygradients.hh"
28
29namespace Dumux {
30
35template<class TypeTag>
37{
39
40 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
41 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
42 using VolumeVariables = typename GridVolumeVariables::VolumeVariables;
43
44 using GridFluxVariablesCache = typename GridVariables::GridFluxVariablesCache;
45 using ElementFluxVariablesCache = typename GridFluxVariablesCache::LocalView;
46 using FluxVariablesCache = typename GridFluxVariablesCache::FluxVariablesCache;
47
48 using GridGeometry = typename GridVariables::GridGeometry;
49 using FVElementGeometry = typename GridGeometry::LocalView;
50 using SubControlVolume = typename FVElementGeometry::SubControlVolume;
51 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
52
54
56 using GridView = typename GridGeometry::GridView;
57 using Element = typename GridView::template Codim<0>::Entity;
60 using Indices = typename ModelTraits::Indices;
62
63 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
64 using Extrusion = Extrusion_t<GridGeometry>;
65
67
68public:
69
71 const Element& element,
72 const FVElementGeometry& fvGeometry,
73 const SubControlVolumeFace& scvFace,
74 const ElementVolumeVariables& elemVolVars,
75 const ElementFluxVariablesCache& elemFluxVarsCache,
76 const ElementBoundaryTypes& elemBcTypes)
77 : problemPtr_(&problem)
78 , elementPtr_(&element)
79 , fvGeometryPtr_(&fvGeometry)
80 , scvFacePtr_(&scvFace)
81 , elemVolVarsPtr_(&elemVolVars)
82 , elemFluxVarsCachePtr_(&elemFluxVarsCache)
83 , elemBcTypesPtr_(&elemBcTypes)
84 {
85 static_assert(
86 std::decay_t<decltype(problem.dirichlet(element, scvFace))>::size()
87 == static_cast<std::size_t>(GridView::dimension),
88 "Expects problem.dirichlet to return an array with as many entries as dimensions."
89 );
90 }
91
92 const Problem& problem() const
93 { return *problemPtr_; }
94
95 const Element& element() const
96 { return *elementPtr_; }
97
98 const SubControlVolumeFace& scvFace() const
99 { return *scvFacePtr_; }
100
101 const FVElementGeometry& fvGeometry() const
102 { return *fvGeometryPtr_; }
103
104 const ElementVolumeVariables& elemVolVars() const
105 { return *elemVolVarsPtr_; }
106
107 const ElementFluxVariablesCache& elemFluxVarsCache() const
108 { return *elemFluxVarsCachePtr_; }
109
110 const ElementBoundaryTypes& elemBcTypes() const
111 { return *elemBcTypesPtr_; }
112
116 NumEqVector advectiveMomentumFlux() const
117 {
118 if (!this->problem().enableInertiaTerms())
119 return NumEqVector(0.0);
120
121 if (this->scvFace().isFrontal())
123 else
125 }
126
130 NumEqVector diffusiveMomentumFlux() const
131 {
132 if (this->scvFace().isFrontal())
134 else
136 }
137
157 {
158 const auto& scvf = this->scvFace();
159 assert(scvf.isFrontal());
160
161 NumEqVector result(0.0);
162 const auto& fvGeometry = this->fvGeometry();
163 const auto& elemVolVars = this->elemVolVars();
164
165 if (scvf.boundary())
166 return result;
167
168 // get the velocity gradient at the normal face's integration point
169 const auto velGradII = VelocityGradients::velocityGradII(fvGeometry, scvf, elemVolVars);
170
171 static const bool enableUnsymmetrizedVelocityGradient
172 = getParamFromGroup<bool>(this->problem().paramGroup(), "FreeFlow.EnableUnsymmetrizedVelocityGradient", false);
173 static const Scalar factor = enableUnsymmetrizedVelocityGradient ? 1.0 : 2.0;
174
175 const auto mu = this->problem().effectiveViscosity(this->element(), this->fvGeometry(), this->scvFace());
176 result -= factor * mu * velGradII * Extrusion::area(fvGeometry, scvf) * elemVolVars[scvf.insideScvIdx()].extrusionFactor() * scvf.directionSign();
177
178 static const bool enableDilatationTerm = getParamFromGroup<bool>(this->problem().paramGroup(), "FreeFlow.EnableDilatationTerm", false);
179 if (enableDilatationTerm)
180 {
181 Scalar divergence = velGradII;
182 for (const auto& scv : scvs(fvGeometry))
183 {
184 const auto otherFrontalScvf = *(scvfs(fvGeometry, scv).begin());
185 assert(otherFrontalScvf.isFrontal() && !otherFrontalScvf.boundary());
186 if (otherFrontalScvf.index() != scvf.index())
187 divergence += VelocityGradients::velocityGradII(fvGeometry, otherFrontalScvf, elemVolVars);
188 }
189
190 result += 2.0/3.0 * mu * divergence * scvf.directionSign() * Extrusion::area(fvGeometry, scvf) * elemVolVars[scvf.insideScvIdx()].extrusionFactor();
191 }
192
193 return result;
194 }
195
219 {
220 const auto& scvf = this->scvFace();
221 assert(scvf.isLateral());
222
223 NumEqVector result(0.0);
224 const auto& fvGeometry = this->fvGeometry();
225 const auto& elemVolVars = this->elemVolVars();
226 const auto& problem = this->problem();
227 const auto& scv = fvGeometry.scv(scvf.insideScvIdx());
228
229 static const bool enableUnsymmetrizedVelocityGradient
230 = getParamFromGroup<bool>(problem.paramGroup(), "FreeFlow.EnableUnsymmetrizedVelocityGradient", false);
231
232 const auto mu = this->problem().effectiveViscosity(this->element(), this->fvGeometry(), this->scvFace());
233
234 // get the velocity gradient at the lateral face's integration point
235 const auto gradV = VelocityGradients::velocityGradient(fvGeometry, scvf, elemVolVars, this->elemBcTypes(), false);
236
237 // Consider the shear stress caused by the gradient of the velocities parallel to our face of interest.
238 GlobalPosition gradVn(0.0);
239 gradV.mv(scvf.unitOuterNormal(), gradVn);
240 const Scalar velocityGrad_ij = gradVn[scv.dofAxis()];
241 result -= mu * velocityGrad_ij;
242
243 // Consider the shear stress caused by the gradient of the velocities normal to our face of interest.
244 if (!enableUnsymmetrizedVelocityGradient)
245 {
246 GlobalPosition gradVTransposedN(0.0);
247 gradV.mtv(scvf.unitOuterNormal(), gradVTransposedN);
248 const Scalar velocityGrad_ji = gradVTransposedN[scv.dofAxis()];
249 result -= mu * velocityGrad_ji;
250 }
251
252 // Account for the area of the staggered lateral face.
253 return result * Extrusion::area(fvGeometry, scvf) * elemVolVars[scvf.insideScvIdx()].extrusionFactor();
254 }
255
272 NumEqVector pressureContribution() const
273 {
274 NumEqVector result(0.0);
275 const auto& scvf = this->scvFace();
276 if (scvf.isLateral() || scvf.boundary())
277 return result;
278
279 // The pressure force needs to take the extruded scvf area into account.
280 const auto pressure = this->problem().pressure(this->element(), this->fvGeometry(), scvf);
281 result = pressure*Extrusion::area(this->fvGeometry(), scvf)*this->elemVolVars()[scvf.insideScvIdx()].extrusionFactor();
282
283 // The pressure contribution calculated above might have a much larger numerical value compared to the viscous or inertial forces.
284 // This may lead to numerical inaccuracies due to loss of significance (cancellantion) for the final residual value.
285 // In the end, we are only interested in a pressure difference between the two relevant faces so we can
286 // subtract a reference value from the actual pressure contribution. Assuming an axisparallel cartesian grid,
287 // scvf.area() will have the same value at both opposing faces such that the reference pressure contribution
288 // cancels out in the final residual which combines the pressure contribution of two adjacent elements
289 // We explicitly do extrude the area here because that might yield different results in both elements.
290 // The multiplication by scvf.area() aims at having a reference value of the same order of magnitude as the actual pressure contribution.
291 const auto referencePressure = this->problem().referencePressure(this->element(), this->fvGeometry(), scvf);
292 result -= referencePressure*scvf.area();
293
294 // Account for the orientation of the face.
295 result *= scvf.directionSign();
296 return result;
297 }
298
318 {
319 NumEqVector flux(0.0);
320 const auto& scvf = this->scvFace();
321 assert(scvf.isFrontal());
322
323 const auto& problem = this->problem();
324 const auto& elemVolVars = this->elemVolVars();
325 const auto velocitySelf = elemVolVars[scvf.insideScvIdx()].velocity();
326 const auto velocityOpposite = elemVolVars[scvf.outsideScvIdx()].velocity();
327
328 // Get the average velocity at the center of the element (i.e. the location of the staggered face).
329 const Scalar transportingVelocity = (velocitySelf + velocityOpposite) * 0.5;
330 const Scalar density = this->problem().density(this->element(), this->fvGeometry(), scvf);
331 const bool selfIsUpstream = scvf.directionSign() == sign(transportingVelocity);
332
333 // TODO use higher order helper
334 static const auto upwindWeight = getParamFromGroup<Scalar>(problem.paramGroup(), "Flux.UpwindWeight");
335 const Scalar transportedMomentum = selfIsUpstream ? (upwindWeight * velocitySelf + (1.0 - upwindWeight) * velocityOpposite) * density
336 : (upwindWeight * velocityOpposite + (1.0 - upwindWeight) * velocitySelf) * density;
337
338 return transportingVelocity * transportedMomentum * scvf.directionSign() * Extrusion::area(this->fvGeometry(), scvf) * extrusionFactor_(elemVolVars, scvf);
339 }
340
364 {
365 NumEqVector flux(0.0);
366 const auto& scvf = this->scvFace();
367 assert(scvf.isLateral());
368
369 const auto& problem = this->problem();
370 const auto& elemVolVars = this->elemVolVars();
371 const auto fvGeometry = this->fvGeometry();
372
373 // get the transporting velocity which is perpendicular to our own (inner) velocity
374 const Scalar transportingVelocity = [&]()
375 {
376 const auto& orthogonalScvf = fvGeometry.lateralOrthogonalScvf(scvf);
377 const Scalar innerTransportingVelocity = elemVolVars[orthogonalScvf.insideScvIdx()].velocity();
378
379 static const bool useOldScheme = getParam<bool>("FreeFlow.UseOldTransportingVelocity", true); // TODO how to deprecate?
380
381 if (useOldScheme)
382 {
383 if (scvf.boundary() && fvGeometry.scv(scvf.insideScvIdx()).boundary())
384 {
385 if (this->elemBcTypes()[scvf.localIndex()].isDirichlet(scvf.normalAxis()))
386 return problem.dirichlet(this->element(), scvf)[scvf.normalAxis()];
387 }
388 else
389 return innerTransportingVelocity;
390 }
391
392 // use the Dirichlet velocity as transporting velocity if the lateral face is on a Dirichlet boundary
393 if (scvf.boundary())
394 {
395 if (this->elemBcTypes()[scvf.localIndex()].isDirichlet(scvf.normalAxis()))
396 return 0.5*(problem.dirichlet(this->element(), scvf)[scvf.normalAxis()] + innerTransportingVelocity);
397 }
398
399 if (orthogonalScvf.boundary())
400 {
401 if (this->elemBcTypes()[orthogonalScvf.localIndex()].isDirichlet(scvf.normalAxis()))
402 return 0.5*(problem.dirichlet(this->element(), scvf)[scvf.normalAxis()] + innerTransportingVelocity);
403 else
404 return innerTransportingVelocity; // fallback value, should actually never be called
405 }
406
407 // average the transporting velocity by weighting with the scv volumes
408 const auto insideVolume = fvGeometry.scv(orthogonalScvf.insideScvIdx()).volume();
409 const auto outsideVolume = fvGeometry.scv(orthogonalScvf.outsideScvIdx()).volume();
410 const auto outerTransportingVelocity = elemVolVars[orthogonalScvf.outsideScvIdx()].velocity();
411 return (insideVolume*innerTransportingVelocity + outsideVolume*outerTransportingVelocity) / (insideVolume + outsideVolume);
412 }();
413
414 const Scalar transportedMomentum = [&]()
415 {
416 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
417
418 auto getDirichletMomentumFlux = [&]()
419 {
420 return problem.dirichlet(this->element(), scvf)[insideScv.dofAxis()] * this->problem().density(this->element(), insideScv);
421 };
422
423 // use the Dirichlet velocity as for transported momentum if the lateral face is on a Dirichlet boundary
424 if (scvf.boundary())
425 {
426 if (!this->elemBcTypes()[scvf.localIndex()].isDirichlet(insideScv.dofAxis()))
427 DUNE_THROW(Dune::InvalidStateException, "Neither Dirichlet nor Neumann BC set at " << scvf.ipGlobal());
428
429 return getDirichletMomentumFlux();
430 }
431 else
432 {
433 if (fvGeometry.scvfIntegrationPointInConcaveCorner(scvf))
434 {
435 // TODO: we could put this into an assert, as the construction of outsideScvfWithSameIntegrationPoint is quite expensive
436 const auto& outsideScvfWithSameIntegrationPoint = fvGeometry.outsideScvfWithSameIntegrationPoint(scvf);
437 if (!this->problem().boundaryTypes(this->element(), outsideScvfWithSameIntegrationPoint).isDirichlet(insideScv.dofAxis()))
438 DUNE_THROW(Dune::InvalidStateException, "Neither Dirichlet nor Neumann BC set at " << outsideScvfWithSameIntegrationPoint.ipGlobal());
439
440 return getDirichletMomentumFlux();
441 }
442 }
443
444 const bool selfIsUpstream = scvf.directionSign() == sign(transportingVelocity);
445
446 const auto innerVelocity = elemVolVars[scvf.insideScvIdx()].velocity();
447 const auto outerVelocity = elemVolVars[scvf.outsideScvIdx()].velocity();
448
449 const auto rho = this->problem().insideAndOutsideDensity(this->element(), fvGeometry, scvf);
450
451 const auto insideMomentum = innerVelocity * rho.first;
452 const auto outsideMomentum = outerVelocity * rho.second;
453
454 // TODO use higher order helper
455 static const auto upwindWeight = getParamFromGroup<Scalar>(problem.paramGroup(), "Flux.UpwindWeight");
456
457 return selfIsUpstream ? (upwindWeight * insideMomentum + (1.0 - upwindWeight) * outsideMomentum)
458 : (upwindWeight * outsideMomentum + (1.0 - upwindWeight) * insideMomentum);
459 }();
460
461 return transportingVelocity * transportedMomentum * scvf.directionSign() * Extrusion::area(fvGeometry, scvf) * extrusionFactor_(elemVolVars, scvf);
462 }
463
464private:
465
466 template<class ElementVolumeVariables, class SubControlVolumeFace>
467 Scalar extrusionFactor_(const ElementVolumeVariables& elemVolVars, const SubControlVolumeFace& scvf) const
468 {
469 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
470 const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()];
471 return harmonicMean(insideVolVars.extrusionFactor(), outsideVolVars.extrusionFactor());
472 }
473
474
475 const Problem* problemPtr_;
476 const Element* elementPtr_;
477 const FVElementGeometry* fvGeometryPtr_;
478 const SubControlVolumeFace* scvFacePtr_;
479 const ElementVolumeVariables* elemVolVarsPtr_;
480 const ElementFluxVariablesCache* elemFluxVarsCachePtr_;
481 const ElementBoundaryTypes* elemBcTypesPtr_;
482};
483
484} // end namespace Dumux
485
486#endif // DUMUX_NAVIERSTOKES_STAGGERED_FLUXVARIABLES_HH
The flux variables class for the Navier-Stokes model using the staggered grid discretization.
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:37
NumEqVector pressureContribution() const
Returns the frontal pressure contribution.
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:272
NumEqVector diffusiveMomentumFlux() const
Returns the diffusive momentum flux due to viscous forces.
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:130
NumEqVector frontalAdvectiveMomentumFlux() const
Returns the frontal part of the momentum flux. This treats the flux over the staggered face at the ce...
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:317
NumEqVector lateralAdvectiveMomentumFlux() const
Returns the advective momentum flux over the staggered face perpendicular to the scvf where the veloc...
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:363
NumEqVector frontalDiffusiveMomentumFlux() const
Returns the frontal part of the momentum flux. This treats the flux over the staggered face at the ce...
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:156
const ElementBoundaryTypes & elemBcTypes() const
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:110
const Problem & problem() const
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:92
const SubControlVolumeFace & scvFace() const
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:98
const FVElementGeometry & fvGeometry() const
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:101
NumEqVector advectiveMomentumFlux() const
Returns the diffusive momentum flux due to viscous forces.
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:116
NavierStokesMomentumFluxVariables(const Problem &problem, const Element &element, const FVElementGeometry &fvGeometry, const SubControlVolumeFace &scvFace, const ElementVolumeVariables &elemVolVars, const ElementFluxVariablesCache &elemFluxVarsCache, const ElementBoundaryTypes &elemBcTypes)
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:70
const ElementVolumeVariables & elemVolVars() const
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:104
const ElementFluxVariablesCache & elemFluxVarsCache() const
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:107
const Element & element() const
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:95
NumEqVector lateralDiffusiveMomentumFlux() const
Returns the diffusive momentum flux over the staggered face perpendicular to the scvf where the veloc...
Definition: freeflow/navierstokes/momentum/fluxvariables.hh:218
Helper class for calculating the velocity gradients for the Navier-Stokes model using the staggered g...
Definition: momentum/velocitygradients.hh:46
static auto velocityGradient(const FVElementGeometry &fvGeometry, const typename FVElementGeometry::SubControlVolumeFace &scvf, const ElemVolVars &elemVolVars, bool fullGradient=false)
Definition: momentum/velocitygradients.hh:50
static auto velocityGradII(const FVElementGeometry &fvGeometry, const typename FVElementGeometry::SubControlVolumeFace &scvf, const ElemVolVars &elemVolVars)
Returns the in-axis velocity gradient.
Definition: momentum/velocitygradients.hh:146
Defines all properties used in Dumux.
Some exceptions thrown in DuMux
Helper classes to compute the integration elements.
constexpr Scalar harmonicMean(Scalar x, Scalar y, Scalar wx=1.0, Scalar wy=1.0) noexcept
Calculate the (weighted) harmonic mean of two scalar values.
Definition: math.hh:57
constexpr int sign(const ValueType &value) noexcept
Sign or signum function.
Definition: math.hh:629
typename NumEqVectorTraits< PrimaryVariables >::type NumEqVector
A vector with the same size as numbers of equations This is the default implementation and has to be ...
Definition: numeqvector.hh:34
auto volume(const Geometry &geo, unsigned int integrationOrder=4)
The volume of a given geometry.
Definition: volume.hh:159
typename GetProp< TypeTag, Property >::type GetPropType
get the type alias defined in the property
Definition: propertysystem.hh:296
Define some often used mathematical functions.
The available discretization methods in Dumux.
std::string pressure(int phaseIdx) noexcept
I/O name of pressure for multiphase systems.
Definition: name.hh:22
std::string density(int phaseIdx) noexcept
I/O name of density for multiphase systems.
Definition: name.hh:53
Definition: adapt.hh:17
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition: extrusion.hh:166
A helper to deduce a vector with the same size as numbers of equations.
The infrastructure to retrieve run-time parameters from Dune::ParameterTrees.