Line | Branch | Exec | Source |
---|---|---|---|
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-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder | ||
5 | // SPDX-License-Identifier: GPL-3.0-or-later | ||
6 | // | ||
7 | /*! | ||
8 | * \file | ||
9 | * \ingroup NavierStokesModel | ||
10 | * \copydoc Dumux::NavierStokesFluxVariablesImpl | ||
11 | */ | ||
12 | #ifndef DUMUX_NAVIERSTOKES_STAGGERED_FLUXVARIABLES_HH | ||
13 | #define DUMUX_NAVIERSTOKES_STAGGERED_FLUXVARIABLES_HH | ||
14 | |||
15 | #include <array> | ||
16 | #include <optional> | ||
17 | #include <type_traits> | ||
18 | |||
19 | #include <dumux/common/math.hh> | ||
20 | #include <dumux/common/exceptions.hh> | ||
21 | #include <dumux/common/parameters.hh> | ||
22 | #include <dumux/common/properties.hh> | ||
23 | #include <dumux/common/typetraits/problem.hh> | ||
24 | |||
25 | #include <dumux/flux/fluxvariablesbase.hh> | ||
26 | #include <dumux/discretization/method.hh> | ||
27 | #include <dumux/discretization/extrusion.hh> | ||
28 | |||
29 | #include "staggeredupwindhelper.hh" | ||
30 | #include "velocitygradients.hh" | ||
31 | |||
32 | namespace Dumux { | ||
33 | |||
34 | /*! | ||
35 | * \ingroup NavierStokesModel | ||
36 | * \brief The flux variables class for the Navier-Stokes model using the staggered grid discretization. | ||
37 | */ | ||
38 | |||
39 | // forward declaration | ||
40 | template<class TypeTag, class DiscretizationMethod> | ||
41 | class NavierStokesFluxVariablesImpl; | ||
42 | |||
43 | template<class TypeTag> | ||
44 | class NavierStokesFluxVariablesImpl<TypeTag, DiscretizationMethods::Staggered> | ||
45 | : public FluxVariablesBase<GetPropType<TypeTag, Properties::Problem>, | ||
46 | typename GetPropType<TypeTag, Properties::GridGeometry>::LocalView, | ||
47 | typename GetPropType<TypeTag, Properties::GridVolumeVariables>::LocalView, | ||
48 | typename GetPropType<TypeTag, Properties::GridFluxVariablesCache>::LocalView> | ||
49 | { | ||
50 | using GridVariables = GetPropType<TypeTag, Properties::GridVariables>; | ||
51 | |||
52 | using GridVolumeVariables = typename GridVariables::GridVolumeVariables; | ||
53 | using ElementVolumeVariables = typename GridVolumeVariables::LocalView; | ||
54 | using VolumeVariables = typename GridVolumeVariables::VolumeVariables; | ||
55 | |||
56 | using GridFluxVariablesCache = typename GridVariables::GridFluxVariablesCache; | ||
57 | using FluxVariablesCache = typename GridFluxVariablesCache::FluxVariablesCache; | ||
58 | |||
59 | using GridFaceVariables = typename GridVariables::GridFaceVariables; | ||
60 | using ElementFaceVariables = typename GridFaceVariables::LocalView; | ||
61 | using FaceVariables = typename GridFaceVariables::FaceVariables; | ||
62 | |||
63 | using Problem = GetPropType<TypeTag, Properties::Problem>; | ||
64 | using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; | ||
65 | using FVElementGeometry = typename GridGeometry::LocalView; | ||
66 | using GridView = typename GridGeometry::GridView; | ||
67 | using Element = typename GridView::template Codim<0>::Entity; | ||
68 | using Scalar = GetPropType<TypeTag, Properties::Scalar>; | ||
69 | using ModelTraits = GetPropType<TypeTag, Properties::ModelTraits>; | ||
70 | using Indices = typename ModelTraits::Indices; | ||
71 | using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; | ||
72 | using FaceFrontalSubControlVolumeFace = typename GridGeometry::Traits::FaceFrontalSubControlVolumeFace; | ||
73 | using FaceLateralSubControlVolumeFace = typename GridGeometry::Traits::FaceLateralSubControlVolumeFace; | ||
74 | using Extrusion = Extrusion_t<GridGeometry>; | ||
75 | using CellCenterPrimaryVariables = GetPropType<TypeTag, Properties::CellCenterPrimaryVariables>; | ||
76 | using FacePrimaryVariables = GetPropType<TypeTag, Properties::FacePrimaryVariables>; | ||
77 | using BoundaryTypes = typename ProblemTraits<Problem>::BoundaryTypes; | ||
78 | using VelocityGradients = StaggeredVelocityGradients<Scalar, GridGeometry, BoundaryTypes, Indices>; | ||
79 | |||
80 | static constexpr bool normalizePressure = getPropValue<TypeTag, Properties::NormalizePressure>(); | ||
81 | |||
82 | using GlobalPosition = typename Element::Geometry::GlobalCoordinate; | ||
83 | |||
84 | static constexpr auto cellCenterIdx = GridGeometry::cellCenterIdx(); | ||
85 | static constexpr auto faceIdx = GridGeometry::faceIdx(); | ||
86 | |||
87 | static constexpr int upwindSchemeOrder = getPropValue<TypeTag, Properties::UpwindSchemeOrder>(); | ||
88 | static constexpr bool useHigherOrder = upwindSchemeOrder > 1; | ||
89 | |||
90 | public: | ||
91 | |||
92 | using HeatConductionType = GetPropType<TypeTag, Properties::HeatConductionType>; | ||
93 | |||
94 | |||
95 | /*! | ||
96 | * \brief Returns the advective flux over a sub control volume face. | ||
97 | * \param problem The object specifying the problem which ought to be simulated | ||
98 | * \param fvGeometry The element-centered finite volume geometry view | ||
99 | * \param elemVolVars All volume variables for the element | ||
100 | * \param elemFaceVars The face variables | ||
101 | * \param scvf The sub control volume face | ||
102 | * \param upwindTerm The upwind term (i.e. the advectively transported quantity) | ||
103 | */ | ||
104 | template<class UpwindTerm> | ||
105 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 542312485 times.
|
1048829720 | static Scalar advectiveFluxForCellCenter(const Problem& problem, |
106 | const FVElementGeometry& fvGeometry, | ||
107 | const ElementVolumeVariables& elemVolVars, | ||
108 | const ElementFaceVariables& elemFaceVars, | ||
109 | const SubControlVolumeFace &scvf, | ||
110 | UpwindTerm upwindTerm) | ||
111 | { | ||
112 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 542312485 times.
|
1048829720 | const Scalar velocity = elemFaceVars[scvf].velocitySelf(); |
113 |
2/2✓ Branch 0 taken 115 times.
✓ Branch 1 taken 542312485 times.
|
1048829720 | const bool insideIsUpstream = scvf.directionSign() == sign(velocity); |
114 |
4/6✓ Branch 0 taken 115 times.
✓ Branch 1 taken 542312485 times.
✓ Branch 3 taken 115 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 115 times.
✗ Branch 7 not taken.
|
1048829720 | static const Scalar upwindWeight = getParamFromGroup<Scalar>(problem.paramGroup(), "Flux.UpwindWeight"); |
115 | |||
116 | 1048829720 | const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()]; | |
117 | 1048829720 | const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()]; | |
118 | |||
119 |
2/2✓ Branch 0 taken 278252008 times.
✓ Branch 1 taken 264060592 times.
|
1048829720 | const auto& upstreamVolVars = insideIsUpstream ? insideVolVars : outsideVolVars; |
120 |
2/2✓ Branch 0 taken 278252008 times.
✓ Branch 1 taken 264060592 times.
|
1482016121 | const auto& downstreamVolVars = insideIsUpstream ? outsideVolVars : insideVolVars; |
121 | |||
122 | 1048829720 | const Scalar flux = (upwindWeight * upwindTerm(upstreamVolVars) + | |
123 | 1048829720 | (1.0 - upwindWeight) * upwindTerm(downstreamVolVars)) | |
124 | 1048829720 | * velocity * Extrusion::area(fvGeometry, scvf) * scvf.directionSign(); | |
125 | |||
126 | 1048829720 | return flux * extrusionFactor_(elemVolVars, scvf); | |
127 | } | ||
128 | |||
129 | /*! | ||
130 | * \brief Computes the flux for the cell center residual (mass balance). | ||
131 | * | ||
132 | * \verbatim | ||
133 | * scvf | ||
134 | * ---------------- | ||
135 | * | # current scvf # scvf over which fluxes are calculated | ||
136 | * | # | ||
137 | * | x #~~~~> vel.Self x dof position | ||
138 | * | # | ||
139 | * scvf | # -- element | ||
140 | * ---------------- | ||
141 | * scvf | ||
142 | * \endverbatim | ||
143 | */ | ||
144 | 107413156 | CellCenterPrimaryVariables computeMassFlux(const Problem& problem, | |
145 | const Element& element, | ||
146 | const FVElementGeometry& fvGeometry, | ||
147 | const ElementVolumeVariables& elemVolVars, | ||
148 | const ElementFaceVariables& elemFaceVars, | ||
149 | const SubControlVolumeFace& scvf, | ||
150 | const FluxVariablesCache& fluxVarsCache) | ||
151 | { | ||
152 | // The advectively transported quantity (i.e density for a single-phase system). | ||
153 | 107413156 | auto upwindTerm = [](const auto& volVars) { return volVars.density(); }; | |
154 | |||
155 | // Call the generic flux function. | ||
156 | 107413156 | CellCenterPrimaryVariables result(0.0); | |
157 | 107413156 | result[Indices::conti0EqIdx - ModelTraits::dim()] = advectiveFluxForCellCenter(problem, fvGeometry, elemVolVars, elemFaceVars, scvf, upwindTerm); | |
158 | |||
159 | return result; | ||
160 | } | ||
161 | |||
162 | /*! | ||
163 | * \brief Returns the momentum flux over all staggered faces. | ||
164 | */ | ||
165 | 47259552 | FacePrimaryVariables computeMomentumFlux(const Problem& problem, | |
166 | const Element& element, | ||
167 | const SubControlVolumeFace& scvf, | ||
168 | const FVElementGeometry& fvGeometry, | ||
169 | const ElementVolumeVariables& elemVolVars, | ||
170 | const ElementFaceVariables& elemFaceVars, | ||
171 | const GridFluxVariablesCache& gridFluxVarsCache) | ||
172 | { | ||
173 | 47259552 | return computeFrontalMomentumFlux(problem, element, scvf, fvGeometry, elemVolVars, elemFaceVars, gridFluxVarsCache) + | |
174 | 47259552 | computeLateralMomentumFlux(problem, element, scvf, fvGeometry, elemVolVars, elemFaceVars, gridFluxVarsCache); | |
175 | } | ||
176 | |||
177 | /*! | ||
178 | * \brief Returns the frontal part of the momentum flux. | ||
179 | * This treats the flux over the staggered face at the center of an element, | ||
180 | * parallel to the current scvf where the velocity dof of interest lives. | ||
181 | * | ||
182 | * \verbatim | ||
183 | * scvf | ||
184 | * ---------======= == and # staggered half-control-volume | ||
185 | * | # | current scvf | ||
186 | * | # | # staggered face over which fluxes are calculated | ||
187 | * vel.Opp <~~| #~~> x~~~~> vel.Self | ||
188 | * | # | x dof position | ||
189 | * scvf | # | | ||
190 | * --------======== -- element | ||
191 | * scvf | ||
192 | * \endverbatim | ||
193 | */ | ||
194 | 145578344 | FacePrimaryVariables computeFrontalMomentumFlux(const Problem& problem, | |
195 | const Element& element, | ||
196 | const SubControlVolumeFace& scvf, | ||
197 | const FVElementGeometry& fvGeometry, | ||
198 | const ElementVolumeVariables& elemVolVars, | ||
199 | const ElementFaceVariables& elemFaceVars, | ||
200 | const GridFluxVariablesCache& gridFluxVarsCache) | ||
201 | { | ||
202 |
2/2✓ Branch 0 taken 135725860 times.
✓ Branch 1 taken 9852484 times.
|
145578344 | FacePrimaryVariables frontalFlux(0.0); |
203 | |||
204 | // The velocities of the dof at interest and the one of the opposite scvf. | ||
205 |
2/2✓ Branch 0 taken 135725860 times.
✓ Branch 1 taken 9852484 times.
|
145578344 | const Scalar velocitySelf = elemFaceVars[scvf].velocitySelf(); |
206 |
2/2✓ Branch 0 taken 135725860 times.
✓ Branch 1 taken 9852484 times.
|
145578344 | const Scalar velocityOpposite = elemFaceVars[scvf].velocityOpposite(); |
207 | 145578344 | const auto& faceVars = elemFaceVars[scvf]; | |
208 | |||
209 | // Advective flux. | ||
210 |
2/2✓ Branch 0 taken 135725860 times.
✓ Branch 1 taken 9852484 times.
|
145578344 | if (problem.enableInertiaTerms()) |
211 | { | ||
212 | // Get the average velocity at the center of the element (i.e. the location of the staggered face). | ||
213 | 135725860 | const Scalar transportingVelocity = (velocitySelf + velocityOpposite) * 0.5; | |
214 | 135725860 | const bool selfIsUpstream = scvf.directionSign() != sign(transportingVelocity); | |
215 | |||
216 | 135725860 | StaggeredUpwindHelper<TypeTag, upwindSchemeOrder> upwindHelper(element, fvGeometry, scvf, elemFaceVars, elemVolVars, gridFluxVarsCache.staggeredUpwindMethods()); | |
217 | 135725860 | frontalFlux += upwindHelper.computeUpwindFrontalMomentum(selfIsUpstream) | |
218 | 135725860 | * transportingVelocity * -1.0 * scvf.directionSign(); | |
219 | } | ||
220 | |||
221 | // The volume variables within the current element. We only require those (and none of neighboring elements) | ||
222 | // because the fluxes are calculated over the staggered face at the center of the element. | ||
223 |
2/2✓ Branch 1 taken 51 times.
✓ Branch 2 taken 145578293 times.
|
145578344 | const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()]; |
224 | |||
225 | // Diffusive flux. | ||
226 | 145578344 | const Scalar velocityGrad_ii = VelocityGradients::velocityGradII(scvf, faceVars) * scvf.directionSign(); | |
227 | |||
228 |
3/4✓ Branch 0 taken 51 times.
✓ Branch 1 taken 145578293 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
|
145578395 | static const bool enableUnsymmetrizedVelocityGradient |
229 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
102 | = getParamFromGroup<bool>(problem.paramGroup(), "FreeFlow.EnableUnsymmetrizedVelocityGradient", false); |
230 |
1/2✓ Branch 0 taken 145578344 times.
✗ Branch 1 not taken.
|
170247852 | const Scalar factor = enableUnsymmetrizedVelocityGradient ? 1.0 : 2.0; |
231 | 145578344 | frontalFlux -= factor * insideVolVars.effectiveViscosity() * velocityGrad_ii; | |
232 | |||
233 | // The pressure term. | ||
234 | // If specified, the pressure can be normalized using the initial value on the scfv of interest. | ||
235 | // The scvf is used to normalize by the same value from the left and right side. | ||
236 | // Can potentially help to improve the condition number of the system matrix. | ||
237 | 145578344 | const Scalar pressure = normalizePressure ? | |
238 | 156766276 | insideVolVars.pressure() - problem.initial(scvf)[Indices::pressureIdx] | |
239 | : insideVolVars.pressure(); | ||
240 | |||
241 | // Account for the orientation of the staggered face's normal outer normal vector | ||
242 | // (pointing in opposite direction of the scvf's one). | ||
243 | 145578344 | frontalFlux += pressure * -1.0 * scvf.directionSign(); | |
244 | |||
245 | // Account for the staggered face's area. For rectangular elements, this equals the area of the scvf | ||
246 | // our velocity dof of interest lives on but with adjusted centroid | ||
247 | 145578344 | const auto& scv = fvGeometry.scv(scvf.insideScvIdx()); | |
248 | 145578344 | FaceFrontalSubControlVolumeFace frontalFace(scv.center(), scvf.area()); | |
249 | 145578344 | return frontalFlux * Extrusion::area(fvGeometry, frontalFace) * insideVolVars.extrusionFactor(); | |
250 | } | ||
251 | |||
252 | /*! | ||
253 | * \brief Returns the momentum flux over the staggered faces | ||
254 | * perpendicular to the scvf where the velocity dof of interest | ||
255 | * lives (coinciding with the element's scvfs). | ||
256 | * | ||
257 | * \verbatim | ||
258 | * scvf | ||
259 | * ---------####### || and # staggered half-control-volume | ||
260 | * | || | current scvf | ||
261 | * | || | # normal staggered sub faces over which fluxes are calculated | ||
262 | * | || x~~~~> vel.Self | ||
263 | * | || | x dof position | ||
264 | * scvf | || | | ||
265 | * --------######## -- element | ||
266 | * scvf | ||
267 | * \endverbatim | ||
268 | */ | ||
269 | 145578344 | FacePrimaryVariables computeLateralMomentumFlux(const Problem& problem, | |
270 | const Element& element, | ||
271 | const SubControlVolumeFace& scvf, | ||
272 | const FVElementGeometry& fvGeometry, | ||
273 | const ElementVolumeVariables& elemVolVars, | ||
274 | const ElementFaceVariables& elemFaceVars, | ||
275 | const GridFluxVariablesCache& gridFluxVarsCache) | ||
276 | { | ||
277 |
2/2✓ Branch 0 taken 2808966 times.
✓ Branch 1 taken 142769378 times.
|
145578344 | FacePrimaryVariables lateralFlux(0.0); |
278 |
2/2✓ Branch 0 taken 2808966 times.
✓ Branch 1 taken 142769378 times.
|
145578344 | const auto& faceVars = elemFaceVars[scvf]; |
279 | 145578344 | const std::size_t numSubFaces = scvf.pairData().size(); | |
280 | |||
281 | // If the current scvf is on a boundary, check if there is a Neumann BC for the stress in tangential direction. | ||
282 | // Create a boundaryTypes object (will be empty if not at a boundary). | ||
283 |
2/2✓ Branch 0 taken 2808966 times.
✓ Branch 1 taken 142769378 times.
|
145578344 | std::optional<BoundaryTypes> currentScvfBoundaryTypes; |
284 |
2/2✓ Branch 0 taken 2808966 times.
✓ Branch 1 taken 142769378 times.
|
145578344 | if (scvf.boundary()) |
285 | 2808966 | currentScvfBoundaryTypes.emplace(problem.boundaryTypes(element, scvf)); | |
286 | |||
287 | // Account for all sub faces. | ||
288 |
2/2✓ Branch 0 taken 291156688 times.
✓ Branch 1 taken 145578344 times.
|
436735032 | for (int localSubFaceIdx = 0; localSubFaceIdx < numSubFaces; ++localSubFaceIdx) |
289 | { | ||
290 |
2/2✓ Branch 0 taken 13388156 times.
✓ Branch 1 taken 228429516 times.
|
291156688 | const auto eIdx = scvf.insideScvIdx(); |
291 | // Get the face normal to the face the dof lives on. The staggered sub face coincides with half of this lateral face. | ||
292 |
2/2✓ Branch 0 taken 14652320 times.
✓ Branch 1 taken 276504368 times.
|
291156688 | const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx); |
293 | |||
294 | // Create a boundaryTypes object (will be empty if not at a boundary). | ||
295 |
2/2✓ Branch 0 taken 14652320 times.
✓ Branch 1 taken 276504368 times.
|
291156688 | std::optional<BoundaryTypes> lateralFaceBoundaryTypes; |
296 | |||
297 | // Check if there is face/element parallel to our face of interest where the dof lives on. If there is no parallel neighbor, | ||
298 | // we are on a boundary where we have to check for boundary conditions. | ||
299 |
2/2✓ Branch 0 taken 14652320 times.
✓ Branch 1 taken 276504368 times.
|
291156688 | if (lateralFace.boundary()) |
300 | { | ||
301 | // Retrieve the boundary types that correspond to the center of the lateral scvf. As a convention, we always query | ||
302 | // the type of BCs at the center of the element's "actual" lateral scvf (not the face of the staggered control volume). | ||
303 | // The value of the BC will be evaluated at the center of the staggered face. | ||
304 | // --------T######V || frontal face of staggered half-control-volume | ||
305 | // | || | current scvf # lateral staggered face of interest (may lie on a boundary) | ||
306 | // | || | x dof position | ||
307 | // | || x~~~~> vel.Self -- element boundaries | ||
308 | // | || | T position at which the type of boundary conditions will be evaluated | ||
309 | // | || | (center of lateral scvf) | ||
310 | // ---------------- V position at which the value of the boundary conditions will be evaluated | ||
311 | // (center of the staggered lateral face) | ||
312 | 14652320 | lateralFaceBoundaryTypes.emplace(problem.boundaryTypes(element, lateralFace)); | |
313 | } | ||
314 | |||
315 | // If the current scvf is on a boundary and if there is a Neumann or Beavers-Joseph-(Saffmann) BC for the stress in tangential direction, | ||
316 | // assign this value for the lateral momentum flux. No further calculations are required. We assume that all lateral faces | ||
317 | // have the same type of BC (Neumann or Beavers-Joseph-(Saffmann)), but we sample the value at their actual positions. | ||
318 |
2/2✓ Branch 0 taken 5617932 times.
✓ Branch 1 taken 285538756 times.
|
291156688 | if (currentScvfBoundaryTypes) |
319 | { | ||
320 | // Handle Neumann BCs. | ||
321 |
2/6✓ Branch 0 taken 5617932 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5617932 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
5617932 | if (currentScvfBoundaryTypes->isNeumann(Indices::velocity(lateralFace.directionIndex()))) |
322 | { | ||
323 | // Get the location of the lateral staggered face's center. | ||
324 | ✗ | FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area()); | |
325 | ✗ | const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx); | |
326 | ✗ | const auto lateralBoundaryFace = makeStaggeredBoundaryFace(scvf, lateralStaggeredFaceCenter); | |
327 | ✗ | lateralFlux += problem.neumann(element, fvGeometry, elemVolVars, elemFaceVars, lateralBoundaryFace)[Indices::velocity(lateralFace.directionIndex())] | |
328 | ✗ | * extrusionFactor_(elemVolVars, lateralFace) * Extrusion::area(fvGeometry, lateralScvf) * lateralFace.directionSign(); | |
329 | |||
330 | continue; | ||
331 | ✗ | } | |
332 | |||
333 | // Treat the edge case when our current scvf has a BJ condition while the lateral face has a Neumann BC. | ||
334 | // It is not clear how to evaluate the BJ condition here. | ||
335 | // For symmetry reasons, our own scvf should then have the same Neumann flux as the lateral face. | ||
336 | // TODO: We should clarify if this is the correct approach. | ||
337 |
4/4✓ Branch 0 taken 346772 times.
✓ Branch 1 taken 5271160 times.
✓ Branch 2 taken 18268 times.
✓ Branch 3 taken 328504 times.
|
5617932 | if (currentScvfBoundaryTypes->isBeaversJoseph(Indices::velocity(lateralFace.directionIndex())) && lateralFaceBoundaryTypes && |
338 |
2/6✓ Branch 0 taken 18268 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 18268 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
18268 | lateralFaceBoundaryTypes->isNeumann(Indices::velocity(scvf.directionIndex()))) |
339 | { | ||
340 | ✗ | FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area()); | |
341 | ✗ | const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx); | |
342 | ✗ | const auto lateralBoundaryFace = makeStaggeredBoundaryFace(lateralFace, lateralStaggeredFaceCenter); | |
343 | ✗ | lateralFlux += problem.neumann(element, fvGeometry, elemVolVars, elemFaceVars, lateralBoundaryFace)[Indices::velocity(scvf.directionIndex())] | |
344 | ✗ | * extrusionFactor_(elemVolVars, lateralFace) * Extrusion::area(fvGeometry, lateralScvf) * lateralFace.directionSign(); | |
345 | |||
346 | continue; | ||
347 | ✗ | } | |
348 | } | ||
349 | |||
350 | // Check if the lateral face (perpendicular to our current scvf) lies on a boundary. If yes, boundary conditions might need to be treated | ||
351 | // and further calculations can be skipped. | ||
352 |
2/2✓ Branch 0 taken 14652320 times.
✓ Branch 1 taken 276504368 times.
|
291156688 | if (lateralFace.boundary()) |
353 | { | ||
354 | // Check if we have a symmetry boundary condition. If yes, the tangential part of the momentum flux can be neglected | ||
355 | // and we may skip any further calculations for the given sub face. | ||
356 |
2/2✓ Branch 0 taken 832648 times.
✓ Branch 1 taken 13819672 times.
|
14652320 | if (lateralFaceBoundaryTypes->isSymmetry()) |
357 | 832648 | continue; | |
358 | |||
359 | // Handle Neumann boundary conditions. No further calculations are then required for the given sub face. | ||
360 |
2/6✓ Branch 0 taken 13819672 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13819672 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
|
13819672 | if (lateralFaceBoundaryTypes->isNeumann(Indices::velocity(scvf.directionIndex()))) |
361 | { | ||
362 | // Construct a temporary scvf which corresponds to the staggered sub face, featuring the location | ||
363 | // the staggered faces's center. | ||
364 | ✗ | FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area()); | |
365 | ✗ | const auto& lateralStaggeredFaceCenter = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx); | |
366 | ✗ | const auto lateralBoundaryFace = makeStaggeredBoundaryFace(lateralFace, lateralStaggeredFaceCenter); | |
367 | ✗ | lateralFlux += problem.neumann(element, fvGeometry, elemVolVars, elemFaceVars, lateralBoundaryFace)[Indices::velocity(scvf.directionIndex())] | |
368 | ✗ | * elemVolVars[lateralFace.insideScvIdx()].extrusionFactor() * Extrusion::area(fvGeometry, lateralScvf); | |
369 | |||
370 | continue; | ||
371 | ✗ | } | |
372 | |||
373 | // Handle wall-function fluxes (only required for RANS models) | ||
374 |
3/4✓ Branch 1 taken 3516771 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 508848 times.
✓ Branch 4 taken 3007923 times.
|
3516771 | if (incorporateWallFunction_(lateralFlux, problem, element, fvGeometry, scvf, elemVolVars, elemFaceVars, localSubFaceIdx)) |
375 | 508848 | continue; | |
376 | } | ||
377 | |||
378 | // Check the consistency of the boundary conditions, exactly one of the following must be set | ||
379 |
2/2✓ Branch 0 taken 13310824 times.
✓ Branch 1 taken 276504368 times.
|
289815192 | if (lateralFaceBoundaryTypes) |
380 | { | ||
381 |
2/2✓ Branch 0 taken 4405491 times.
✓ Branch 1 taken 8905333 times.
|
13310824 | std::bitset<3> admittableBcTypes; |
382 |
5/6✓ Branch 0 taken 4405491 times.
✓ Branch 1 taken 8905333 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8905333 times.
✓ Branch 4 taken 4660913 times.
✓ Branch 5 taken 8649911 times.
|
17716315 | admittableBcTypes.set(0, lateralFaceBoundaryTypes->isDirichlet(Indices::pressureIdx)); |
383 |
5/6✓ Branch 0 taken 4660913 times.
✓ Branch 1 taken 8649911 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4660913 times.
✓ Branch 4 taken 255422 times.
✓ Branch 5 taken 13055402 times.
|
17971737 | admittableBcTypes.set(1, lateralFaceBoundaryTypes->isDirichlet(Indices::velocity(scvf.directionIndex()))); |
384 |
3/4✓ Branch 0 taken 255422 times.
✓ Branch 1 taken 13055402 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13310824 times.
|
26621648 | admittableBcTypes.set(2, lateralFaceBoundaryTypes->isBeaversJoseph(Indices::velocity(scvf.directionIndex()))); |
385 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13310824 times.
|
13310824 | if (admittableBcTypes.count() != 1) |
386 | { | ||
387 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Invalid boundary conditions for lateral scvf " | |
388 | "for the momentum equations at global position " << lateralStaggeredFaceCenter_(scvf, localSubFaceIdx) | ||
389 | << ", current scvf global position " << scvf.center()); | ||
390 | } | ||
391 | } | ||
392 | |||
393 | // If none of the above boundary conditions apply for the given sub face, proceed to calculate the tangential momentum flux. | ||
394 |
2/2✓ Branch 0 taken 270110224 times.
✓ Branch 1 taken 19704968 times.
|
289815192 | if (problem.enableInertiaTerms()) |
395 |
1/2✓ Branch 1 taken 270110224 times.
✗ Branch 2 not taken.
|
270110224 | lateralFlux += computeAdvectivePartOfLateralMomentumFlux_(problem, fvGeometry, element, |
396 | scvf, elemVolVars, elemFaceVars, | ||
397 | gridFluxVarsCache, | ||
398 | currentScvfBoundaryTypes, lateralFaceBoundaryTypes, | ||
399 | localSubFaceIdx); | ||
400 | |||
401 |
1/2✓ Branch 1 taken 289815192 times.
✗ Branch 2 not taken.
|
289815192 | lateralFlux += computeDiffusivePartOfLateralMomentumFlux_(problem, fvGeometry, element, |
402 | scvf, elemVolVars, faceVars, | ||
403 | currentScvfBoundaryTypes, lateralFaceBoundaryTypes, | ||
404 | localSubFaceIdx); | ||
405 | } | ||
406 | 145578344 | return lateralFlux; | |
407 | } | ||
408 | |||
409 | |||
410 | /*! | ||
411 | * \brief Returns the momentum flux over an inflow or outflow boundary face. | ||
412 | * | ||
413 | * \verbatim | ||
414 | * scvf // | ||
415 | * ---------=======// == and # staggered half-control-volume | ||
416 | * | || #// current scvf | ||
417 | * | || #// # staggered boundary face over which fluxes are calculated | ||
418 | * | || x~~~~> vel.Self | ||
419 | * | || #// x dof position | ||
420 | * scvf | || #// | ||
421 | * --------========// -- element | ||
422 | * scvf // | ||
423 | * // boundary | ||
424 | * \endverbatim | ||
425 | */ | ||
426 | 2635580 | FacePrimaryVariables inflowOutflowBoundaryFlux(const Problem& problem, | |
427 | const SubControlVolumeFace& scvf, | ||
428 | const FVElementGeometry& fvGeometry, | ||
429 | const ElementVolumeVariables& elemVolVars, | ||
430 | const ElementFaceVariables& elemFaceVars) const | ||
431 | { | ||
432 | 2635580 | FacePrimaryVariables inOrOutflow(0.0); | |
433 | 2635580 | const auto& element = fvGeometry.element(); | |
434 | 2635580 | const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()]; | |
435 | |||
436 | // Advective momentum flux. | ||
437 |
2/2✓ Branch 0 taken 2564614 times.
✓ Branch 1 taken 70966 times.
|
2635580 | if (problem.enableInertiaTerms()) |
438 | { | ||
439 | 2564614 | const Scalar velocitySelf = elemFaceVars[scvf].velocitySelf(); | |
440 |
2/2✓ Branch 1 taken 18215 times.
✓ Branch 2 taken 2546399 times.
|
2564614 | const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()]; |
441 |
2/2✓ Branch 0 taken 18215 times.
✓ Branch 1 taken 2546399 times.
|
2564614 | const auto& upVolVars = (scvf.directionSign() == sign(velocitySelf)) ? |
442 | insideVolVars : outsideVolVars; | ||
443 | |||
444 | 2564614 | inOrOutflow += velocitySelf * velocitySelf * upVolVars.density(); | |
445 | } | ||
446 | |||
447 | // Apply a pressure at the boundary. | ||
448 | 2635580 | const Scalar boundaryPressure = normalizePressure | |
449 |
2/4✓ Branch 1 taken 79638 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 79638 times.
✗ Branch 5 not taken.
|
2705058 | ? (problem.dirichlet(element, scvf)[Indices::pressureIdx] - |
450 |
1/2✓ Branch 1 taken 79638 times.
✗ Branch 2 not taken.
|
2635580 | problem.initial(scvf)[Indices::pressureIdx]) |
451 | : problem.dirichlet(element, scvf)[Indices::pressureIdx]; | ||
452 | 2635580 | inOrOutflow += boundaryPressure; | |
453 | |||
454 | // Account for the orientation of the face at the boundary, | ||
455 | 2635580 | return inOrOutflow * scvf.directionSign() * Extrusion::area(fvGeometry, scvf) * insideVolVars.extrusionFactor(); | |
456 | } | ||
457 | |||
458 | private: | ||
459 | |||
460 | /*! | ||
461 | * \brief Returns the advective momentum flux over the staggered face perpendicular to the scvf | ||
462 | * where the velocity dof of interest lives (coinciding with the element's scvfs). | ||
463 | * | ||
464 | * \verbatim | ||
465 | * ---------------- | ||
466 | * | | | ||
467 | * | transp. | | ||
468 | * | vel. |~~~~> vel.Parallel | ||
469 | * | ^ | | ||
470 | * | | | | ||
471 | * scvf ---------####### || and # staggered half-control-volume | ||
472 | * | || | current scvf | ||
473 | * | || | # normal staggered faces over which fluxes are calculated | ||
474 | * | || x~~~~> vel.Self | ||
475 | * | || | x dof position | ||
476 | * scvf | || | | ||
477 | * ---------####### -- elements | ||
478 | * scvf | ||
479 | * \endverbatim | ||
480 | */ | ||
481 | 270110224 | FacePrimaryVariables computeAdvectivePartOfLateralMomentumFlux_(const Problem& problem, | |
482 | const FVElementGeometry& fvGeometry, | ||
483 | const Element& element, | ||
484 | const SubControlVolumeFace& scvf, | ||
485 | const ElementVolumeVariables& elemVolVars, | ||
486 | const ElementFaceVariables& elemFaceVars, | ||
487 | const GridFluxVariablesCache& gridFluxVarsCache, | ||
488 | const std::optional<BoundaryTypes>& currentScvfBoundaryTypes, | ||
489 | const std::optional<BoundaryTypes>& lateralFaceBoundaryTypes, | ||
490 | const int localSubFaceIdx) | ||
491 | { | ||
492 | 270110224 | const auto eIdx = scvf.insideScvIdx(); | |
493 | 270110224 | const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx); | |
494 | |||
495 | // Get the transporting velocity, located at the scvf perpendicular to the current scvf where the dof | ||
496 | // of interest is located. | ||
497 | 270110224 | const Scalar transportingVelocity = [&]() | |
498 | { | ||
499 |
2/2✓ Branch 0 taken 264880736 times.
✓ Branch 1 taken 5229488 times.
|
270110224 | const auto& faceVars = elemFaceVars[scvf]; |
500 |
2/2✓ Branch 0 taken 264880736 times.
✓ Branch 1 taken 5229488 times.
|
270110224 | if (!scvf.boundary()) |
501 | 264880736 | return faceVars.velocityLateralInside(localSubFaceIdx); | |
502 | else | ||
503 | { | ||
504 | // Create a boundaryTypes object. Get the boundary conditions. We sample the type of BC at the center of the current scvf. | ||
505 |
1/2✓ Branch 0 taken 4986472 times.
✗ Branch 1 not taken.
|
5229488 | const auto bcTypes = problem.boundaryTypes(element, scvf); |
506 | |||
507 |
2/4✓ Branch 0 taken 5229488 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5229488 times.
|
5229488 | if (bcTypes.isDirichlet(Indices::velocity(lateralFace.directionIndex()))) |
508 | { | ||
509 | // Construct a temporary scvf which corresponds to the staggered sub face, featuring the location | ||
510 | // the staggered faces's center. | ||
511 | ✗ | const auto& lateralBoundaryFacePos = lateralStaggeredFaceCenter_(scvf, localSubFaceIdx); | |
512 | ✗ | const auto lateralBoundaryFace = makeStaggeredBoundaryFace(scvf, lateralBoundaryFacePos); | |
513 | ✗ | return problem.dirichlet(element, lateralBoundaryFace)[Indices::velocity(lateralFace.directionIndex())]; | |
514 | ✗ | } | |
515 |
2/2✓ Branch 0 taken 149608 times.
✓ Branch 1 taken 5079880 times.
|
5229488 | else if (bcTypes.isBeaversJoseph(Indices::velocity(lateralFace.directionIndex()))) |
516 | { | ||
517 | 149608 | return VelocityGradients::beaversJosephVelocityAtCurrentScvf(problem, element, fvGeometry, scvf, faceVars, | |
518 | currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx); | ||
519 | } | ||
520 | else | ||
521 | 5079880 | return faceVars.velocityLateralInside(localSubFaceIdx); | |
522 | } | ||
523 | 270110224 | }(); | |
524 | |||
525 | 270110224 | const bool selfIsUpstream = lateralFace.directionSign() == sign(transportingVelocity); | |
526 | 270110224 | StaggeredUpwindHelper<TypeTag, upwindSchemeOrder> upwindHelper(element, fvGeometry, scvf, elemFaceVars, elemVolVars, gridFluxVarsCache.staggeredUpwindMethods()); | |
527 | 270110224 | FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area()); | |
528 | 270110224 | return upwindHelper.computeUpwindLateralMomentum(selfIsUpstream, lateralFace, localSubFaceIdx, currentScvfBoundaryTypes, lateralFaceBoundaryTypes) | |
529 | 270110224 | * transportingVelocity * lateralFace.directionSign() * Extrusion::area(fvGeometry, lateralScvf) * extrusionFactor_(elemVolVars, lateralFace); | |
530 | } | ||
531 | |||
532 | /*! | ||
533 | * \brief Returns the diffusive momentum flux over the staggered face perpendicular to the scvf | ||
534 | * where the velocity dof of interest lives (coinciding with the element's scvfs). | ||
535 | * | ||
536 | * \verbatim | ||
537 | * ---------------- | ||
538 | * | |vel. | ||
539 | * | in.norm. |Parallel | ||
540 | * | vel. |~~~~> | ||
541 | * | ^ | ^ out.norm.vel. | ||
542 | * | | | | | ||
543 | * scvf ---------#######::::::::: || and # staggered half-control-volume (own element) | ||
544 | * | || | curr. :: | ||
545 | * | || | scvf :: :: staggered half-control-volume (neighbor element) | ||
546 | * | || x~~~~> :: | ||
547 | * | || | vel. :: # lateral staggered faces over which fluxes are calculated | ||
548 | * scvf | || | Self :: | ||
549 | * ---------#######::::::::: x dof position | ||
550 | * scvf | ||
551 | * -- elements | ||
552 | * \endverbatim | ||
553 | */ | ||
554 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 289815141 times.
|
289815192 | FacePrimaryVariables computeDiffusivePartOfLateralMomentumFlux_(const Problem& problem, |
555 | const FVElementGeometry& fvGeometry, | ||
556 | const Element& element, | ||
557 | const SubControlVolumeFace& scvf, | ||
558 | const ElementVolumeVariables& elemVolVars, | ||
559 | const FaceVariables& faceVars, | ||
560 | const std::optional<BoundaryTypes>& currentScvfBoundaryTypes, | ||
561 | const std::optional<BoundaryTypes>& lateralFaceBoundaryTypes, | ||
562 | const int localSubFaceIdx) | ||
563 | { | ||
564 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 289815141 times.
|
289815192 | const auto eIdx = scvf.insideScvIdx(); |
565 |
2/2✓ Branch 0 taken 51 times.
✓ Branch 1 taken 289815141 times.
|
289815192 | const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx); |
566 | |||
567 | 289815192 | FacePrimaryVariables lateralDiffusiveFlux(0.0); | |
568 | |||
569 |
3/4✓ Branch 0 taken 51 times.
✓ Branch 1 taken 289815141 times.
✓ Branch 3 taken 51 times.
✗ Branch 4 not taken.
|
289815243 | static const bool enableUnsymmetrizedVelocityGradient |
570 |
1/2✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
|
102 | = getParamFromGroup<bool>(problem.paramGroup(), "FreeFlow.EnableUnsymmetrizedVelocityGradient", false); |
571 | |||
572 | // Get the volume variables of the own and the neighboring element. The neighboring | ||
573 | // element is adjacent to the staggered face normal to the current scvf | ||
574 | // where the dof of interest is located. | ||
575 | 289815192 | const auto& insideVolVars = elemVolVars[lateralFace.insideScvIdx()]; | |
576 |
2/2✓ Branch 1 taken 13310824 times.
✓ Branch 2 taken 276504368 times.
|
289815192 | const auto& outsideVolVars = elemVolVars[lateralFace.outsideScvIdx()]; |
577 | |||
578 | // Get the averaged viscosity at the staggered face normal to the current scvf. | ||
579 | 579630384 | const Scalar muAvg = lateralFace.boundary() | |
580 |
2/2✓ Branch 0 taken 13310824 times.
✓ Branch 1 taken 276504368 times.
|
289815192 | ? insideVolVars.effectiveViscosity() |
581 | 276504368 | : (insideVolVars.effectiveViscosity() + outsideVolVars.effectiveViscosity()) * 0.5; | |
582 | |||
583 | // Consider the shear stress caused by the gradient of the velocities normal to our face of interest. | ||
584 |
1/2✓ Branch 0 taken 289815192 times.
✗ Branch 1 not taken.
|
289815192 | if (!enableUnsymmetrizedVelocityGradient) |
585 | { | ||
586 | 295383776 | if (!scvf.boundary() || | |
587 |
6/8✓ Branch 0 taken 5568584 times.
✓ Branch 1 taken 284246608 times.
✓ Branch 2 taken 5568584 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5568584 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 346772 times.
✓ Branch 7 taken 5221812 times.
|
289815192 | currentScvfBoundaryTypes->isDirichlet(Indices::velocity(lateralFace.directionIndex())) || |
588 |
2/2✓ Branch 0 taken 346772 times.
✓ Branch 1 taken 5221812 times.
|
5568584 | currentScvfBoundaryTypes->isBeaversJoseph(Indices::velocity(lateralFace.directionIndex()))) |
589 | { | ||
590 | 284593380 | const Scalar velocityGrad_ji = VelocityGradients::velocityGradJI(problem, element, fvGeometry, scvf, faceVars, currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx); | |
591 | // Account for the orientation of the staggered normal face's outer normal vector. | ||
592 |
2/2✓ Branch 0 taken 13310824 times.
✓ Branch 1 taken 276504368 times.
|
289815192 | lateralDiffusiveFlux -= muAvg * velocityGrad_ji * lateralFace.directionSign(); |
593 | } | ||
594 | } | ||
595 | |||
596 | // Consider the shear stress caused by the gradient of the velocities parallel to our face of interest. | ||
597 | // If we have a Dirichlet condition for the pressure at the lateral face we assume to have a zero velocityGrad_ij velocity gradient | ||
598 | // so we can skip the computation. | ||
599 |
5/6✓ Branch 0 taken 13310824 times.
✓ Branch 1 taken 276504368 times.
✓ Branch 2 taken 8905333 times.
✓ Branch 3 taken 4405491 times.
✓ Branch 4 taken 8905333 times.
✗ Branch 5 not taken.
|
289815192 | if (!lateralFace.boundary() || !lateralFaceBoundaryTypes->isDirichlet(Indices::pressureIdx)) |
600 | { | ||
601 | 285409701 | const Scalar velocityGrad_ij = VelocityGradients::velocityGradIJ(problem, element, fvGeometry, scvf, faceVars, currentScvfBoundaryTypes, lateralFaceBoundaryTypes, localSubFaceIdx); | |
602 | 289815192 | lateralDiffusiveFlux -= muAvg * velocityGrad_ij * lateralFace.directionSign(); | |
603 | } | ||
604 | |||
605 | // Account for the area of the staggered lateral face (0.5 of the coinciding scfv). | ||
606 | 289815192 | FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area()); | |
607 | 289815192 | return lateralDiffusiveFlux * Extrusion::area(fvGeometry, lateralScvf) * extrusionFactor_(elemVolVars, lateralFace); | |
608 | } | ||
609 | |||
610 | /*! | ||
611 | * \brief Get the location of the lateral staggered face's center. | ||
612 | * Only needed for boundary conditions if the current scvf or the lateral one is on a boundary. | ||
613 | * | ||
614 | * \verbatim | ||
615 | * --------#######o || frontal face of staggered half-control-volume | ||
616 | * | || | current scvf # lateral staggered face of interest (may lie on a boundary) | ||
617 | * | || | x dof position | ||
618 | * | || x~~~~> vel.Self -- element boundaries, current scvf may lie on a boundary | ||
619 | * | || | o position at which the boundary conditions will be evaluated | ||
620 | * | || | (lateralStaggeredFaceCenter) | ||
621 | * ---------------- | ||
622 | * \endverbatim | ||
623 | */ | ||
624 | ✗ | const GlobalPosition& lateralStaggeredFaceCenter_(const SubControlVolumeFace& scvf, const int localSubFaceIdx) const | |
625 | { | ||
626 |
0/12✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 2 not taken.
✗ Branch 5 not taken.
✗ Branch 8 not taken.
✗ Branch 11 not taken.
|
271127920 | return scvf.pairData(localSubFaceIdx).lateralStaggeredFaceCenter; |
627 | }; | ||
628 | |||
629 | /*! | ||
630 | * \brief Get the location of the lateral staggered sub control volume face center. | ||
631 | * Only needed for boundary conditions if the current scvf or the lateral one is on a boundary. | ||
632 | * | ||
633 | * \verbatim | ||
634 | * --------###o#### || frontal face of staggered half-control-volume | ||
635 | * | || | current scvf # lateral staggered face of interest (may lie on a boundary) | ||
636 | * | || | x dof position | ||
637 | * | || x~~~~> vel.Self -- element boundaries, current scvf may lie on a boundary | ||
638 | * | || | o center of the lateral staggered scvf | ||
639 | * | || | | ||
640 | * ---------------- | ||
641 | * \endverbatim | ||
642 | */ | ||
643 | 270619072 | GlobalPosition lateralStaggeredSCVFCenter_(const SubControlVolumeFace& lateralFace, | |
644 | const SubControlVolumeFace& currentFace, | ||
645 | const int localSubFaceIdx) const | ||
646 | { | ||
647 | 270619072 | auto pos = lateralStaggeredFaceCenter_(currentFace, localSubFaceIdx) + lateralFace.center(); | |
648 | 270619072 | pos *= 0.5; | |
649 | 270619072 | return pos; | |
650 | } | ||
651 | |||
652 | //! helper function to get the averaged extrusion factor for a face | ||
653 | 1102746864 | static Scalar extrusionFactor_(const ElementVolumeVariables& elemVolVars, const SubControlVolumeFace& scvf) | |
654 | { | ||
655 | 1102746864 | const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()]; | |
656 | 1102746864 | const auto& outsideVolVars = elemVolVars[scvf.outsideScvIdx()]; | |
657 |
1/2✓ Branch 0 taken 1102746864 times.
✗ Branch 1 not taken.
|
1102746864 | return harmonicMean(insideVolVars.extrusionFactor(), outsideVolVars.extrusionFactor()); |
658 | } | ||
659 | |||
660 | //! do nothing if no turbulence model is used | ||
661 | template<class ...Args, bool turbulenceModel = ModelTraits::usesTurbulenceModel(), std::enable_if_t<!turbulenceModel, int> = 0> | ||
662 | bool incorporateWallFunction_(Args&&... args) const | ||
663 | { return false; } | ||
664 | |||
665 | //! if a turbulence model is used, ask the problem is a wall function shall be employed and get the flux accordingly | ||
666 | template<bool turbulenceModel = ModelTraits::usesTurbulenceModel(), std::enable_if_t<turbulenceModel, int> = 0> | ||
667 | 3516771 | bool incorporateWallFunction_(FacePrimaryVariables& lateralFlux, | |
668 | const Problem& problem, | ||
669 | const Element& element, | ||
670 | const FVElementGeometry& fvGeometry, | ||
671 | const SubControlVolumeFace& scvf, | ||
672 | const ElementVolumeVariables& elemVolVars, | ||
673 | const ElementFaceVariables& elemFaceVars, | ||
674 | const std::size_t localSubFaceIdx) const | ||
675 | { | ||
676 | 3516771 | const auto eIdx = scvf.insideScvIdx(); | |
677 | 3516771 | const auto& lateralFace = fvGeometry.scvf(eIdx, scvf.pairData(localSubFaceIdx).localLateralFaceIdx); | |
678 | |||
679 |
2/2✓ Branch 1 taken 508848 times.
✓ Branch 2 taken 3007923 times.
|
3516771 | if (problem.useWallFunction(element, lateralFace, Indices::velocity(scvf.directionIndex()))) |
680 | { | ||
681 | 508848 | FaceLateralSubControlVolumeFace lateralScvf(lateralStaggeredSCVFCenter_(lateralFace, scvf, localSubFaceIdx), 0.5*lateralFace.area()); | |
682 | 508848 | const auto lateralBoundaryFace = makeStaggeredBoundaryFace(lateralFace, lateralStaggeredFaceCenter_(scvf, localSubFaceIdx)); | |
683 |
1/2✓ Branch 1 taken 508848 times.
✗ Branch 2 not taken.
|
508848 | lateralFlux += problem.wallFunction(element, fvGeometry, elemVolVars, elemFaceVars, scvf, lateralBoundaryFace)[Indices::velocity(scvf.directionIndex())] |
684 | 508848 | * extrusionFactor_(elemVolVars, lateralFace) * Extrusion::area(fvGeometry, lateralScvf); | |
685 | 508848 | return true; | |
686 | 508848 | } | |
687 | else | ||
688 | return false; | ||
689 | } | ||
690 | }; | ||
691 | |||
692 | } // end namespace Dumux | ||
693 | |||
694 | #endif | ||
695 |