GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/freeflow/navierstokes/momentum/velocitygradients.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 68 94 72.3%
Functions: 113 126 89.7%
Branches: 42 161 26.1%

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-FileCopyrightInfo: 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::StaggeredVelocityGradients
11 */
12 #ifndef DUMUX_NAVIERSTOKES_STAGGERED_VELOCITYGRADIENTS_HH
13 #define DUMUX_NAVIERSTOKES_STAGGERED_VELOCITYGRADIENTS_HH
14
15 #include <optional>
16 #include <dumux/common/exceptions.hh>
17 #include <dumux/common/parameters.hh>
18 #include <dune/common/fmatrix.hh>
19 #include <dumux/common/typetraits/problem.hh>
20 #include <dumux/discretization/facecentered/staggered/elementboundarytypes.hh>
21
22 // forward declare
23 namespace Dune {
24
25 template<class ct, int dim, template< int > class Ref, class Comm>
26 class SPGrid;
27 }
28
29 namespace Dumux {
30
31 namespace Detail
32 {
33
34 template<class Grid>
35 struct SupportsPeriodicity : public std::false_type {};
36
37 template<class ct, int dim, template< int > class Ref, class Comm>
38 struct SupportsPeriodicity<Dune::SPGrid<ct, dim, Ref, Comm>> : public std::true_type {};
39 }
40
41 /*!
42 * \ingroup NavierStokesModel
43 * \brief Helper class for calculating the velocity gradients for the Navier-Stokes model using the staggered grid discretization.
44 */
45 class StaggeredVelocityGradients
46 {
47 public:
48
49 template<class FVElementGeometry, class ElemVolVars>
50 static auto velocityGradient(const FVElementGeometry& fvGeometry,
51 const typename FVElementGeometry::SubControlVolumeFace& scvf,
52 const ElemVolVars& elemVolVars,
53 bool fullGradient = false)
54 {
55 const auto& problem = elemVolVars.gridVolVars().problem();
56 using BoundaryTypes = typename ProblemTraits<std::decay_t<decltype(problem)>>::BoundaryTypes;
57 using ElementBoundaryTypes = FaceCenteredStaggeredElementBoundaryTypes<BoundaryTypes>;
58 ElementBoundaryTypes elemBcTypes;
59 elemBcTypes.update(problem, fvGeometry.element(), fvGeometry);
60 return velocityGradient(fvGeometry, scvf, elemVolVars, elemBcTypes, fullGradient);
61 }
62
63 template<class FVElementGeometry, class ElemVolVars, class BoundaryTypes>
64 186226016 static auto velocityGradient(const FVElementGeometry& fvGeometry,
65 const typename FVElementGeometry::SubControlVolumeFace& scvf,
66 const ElemVolVars& elemVolVars,
67 const FaceCenteredStaggeredElementBoundaryTypes<BoundaryTypes>& elemBcTypes,
68 bool fullGradient = false)
69 {
70 using Scalar = typename FVElementGeometry::GridGeometry::GlobalCoordinate::value_type;
71 static constexpr auto dim = FVElementGeometry::GridGeometry::GlobalCoordinate::dimension;
72
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
186226016 Dune::FieldMatrix<Scalar, dim, dim> gradient(0.0);
73
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 182152912 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 182152912 times.
372452032 const auto& scv = fvGeometry.scv(scvf.insideScvIdx());
74
75
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 186226016 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
186226016 if (scvf.isFrontal() && !scvf.boundary())
76 {
77 gradient[scv.dofAxis()][scv.dofAxis()] = velocityGradII(fvGeometry, scvf, elemVolVars);
78
79 if (fullGradient)
80 {
81 Dune::FieldMatrix<std::size_t, dim, dim> counter(0.0);
82
83 for (const auto& otherScvf : scvfs(fvGeometry))
84 {
85 if (otherScvf.index() == scvf.index())
86 continue;
87
88 const auto& otherScv = fvGeometry.scv(otherScvf.insideScvIdx());
89
90 if (otherScvf.isFrontal() && !otherScvf.boundary())
91 gradient[otherScv.dofAxis()][otherScv.dofAxis()] = velocityGradII(fvGeometry, otherScvf, elemVolVars);
92 else if (otherScvf.isLateral())
93 {
94 assert(otherScv.dofAxis() != otherScvf.normalAxis());
95 const auto i = otherScv.dofAxis();
96 const auto j = otherScvf.normalAxis();
97
98 if (!fvGeometry.hasBoundaryScvf() || !elemBcTypes[otherScvf.localIndex()].isNeumann(i))
99 {
100 gradient[i][j] += velocityGradIJ(fvGeometry, otherScvf, elemVolVars);
101 ++counter[i][j];
102 }
103 if (!fvGeometry.hasBoundaryScvf() || !otherScv.boundary() ||
104 !elemBcTypes[fvGeometry.frontalScvfOnBoundary(otherScv).localIndex()].isNeumann(j))
105 {
106 gradient[j][i] += velocityGradJI(fvGeometry, otherScvf, elemVolVars);
107 ++counter[j][i];
108 }
109 }
110 }
111
112 for (int i = 0; i < dim; ++i)
113 for (int j = 0; j < dim; ++j)
114 if (i != j)
115 gradient[i][j] /= counter[i][j];
116 }
117 }
118 else
119 {
120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186226016 times.
186226016 if (fullGradient)
121 DUNE_THROW(Dune::NotImplemented, "Full gradient for lateral staggered faces not implemented");
122
123 186226016 gradient[scv.dofAxis()][scvf.normalAxis()] = velocityGradIJ(fvGeometry, scvf, elemVolVars);
124 186226016 gradient[scvf.normalAxis()][scv.dofAxis()] = velocityGradJI(fvGeometry, scvf, elemVolVars);
125 }
126
127 186226016 return gradient;
128 }
129
130 /*!
131 * \brief Returns the in-axis velocity gradient.
132 *
133 * \verbatim
134 * ---------======= == and # staggered half-control-volume
135 * | # | current scv
136 * | # | # staggered face over which fluxes are calculated
137 * vel.Opp <~~| O~~> x~~~~> vel.Self
138 * | # | x dof position
139 * | # |
140 * --------======== -- element
141 *
142 * O position at which gradient is evaluated (integration point)
143 * \endverbatim
144 */
145 template<class FVElementGeometry, class ElemVolVars>
146 93210817 static auto velocityGradII(const FVElementGeometry& fvGeometry,
147 const typename FVElementGeometry::SubControlVolumeFace& scvf,
148 const ElemVolVars& elemVolVars)
149 {
150
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 93210817 times.
93210817 assert(scvf.isFrontal());
151 // The velocities of the dof at interest and the one of the opposite scvf.
152 186421634 const auto velocitySelf = elemVolVars[scvf.insideScvIdx()].velocity();
153
1/2
✗ Branch 2 not taken.
✓ Branch 3 taken 91158249 times.
186421634 const auto velocityOpposite = elemVolVars[scvf.outsideScvIdx()].velocity();
154
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 91158249 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 91158249 times.
279254817 const auto distance = (fvGeometry.scv(scvf.outsideScvIdx()).dofPosition() - fvGeometry.scv(scvf.insideScvIdx()).dofPosition()).two_norm();
155
156 93210817 return (velocityOpposite - velocitySelf) / distance * scvf.directionSign();
157 }
158
159 /*!
160 * \brief Returns the velocity gradient perpendicular to the orientation of our current scvf.
161 *
162 * \verbatim
163 * ----------------
164 * | |outer || and # staggered half-control-volume (own element)
165 * | |vel. gradient
166 * | |~~~~> -------> :: staggered half-control-volume (neighbor element)
167 * | | ------>
168 * | lateral scvf | -----> x dof position
169 * ---------######O::::::::: ---->
170 * | || | :: ---> -- elements
171 * | || | :: -->
172 * | || scv x~~~~> :: -> O position at which gradient is evaluated (integration point)
173 * | || | inner ::
174 * | || | vel. ::
175 * ---------#######:::::::::
176 *
177 *
178 * \endverbatim
179 */
180 template<class FVElementGeometry, class ElemVolVars>
181 186594868 static auto velocityGradIJ(const FVElementGeometry& fvGeometry,
182 const typename FVElementGeometry::SubControlVolumeFace& scvf,
183 const ElemVolVars& elemVolVars)
184 {
185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186594868 times.
186594868 assert(scvf.isLateral());
186 373189736 const auto innerVelocity = elemVolVars[scvf.insideScvIdx()].velocity();
187 373189736 const auto outerVelocity = elemVolVars[scvf.outsideScvIdx()].velocity();
188 186594868 const auto distance = getDistanceIJ_(fvGeometry, scvf);
189 186594868 return (outerVelocity - innerVelocity) / distance * scvf.directionSign();
190 }
191
192 /*!
193 * \brief Returns the velocity gradient in line with our current scvf.
194 *
195 * \verbatim
196 * ^ gradient
197 * | ^
198 * | | ^
199 * | | | ^
200 * | | | | ^
201 * | | | | | ^ || and # staggered half-control-volume (own element)
202 * | | | | | |
203 * :: staggered half-control-volume (neighbor element)
204 * ----------------
205 * | inner | outer x dof position (of own scv)
206 * | vel. | vel.
207 * | ^ | ^ -- elements
208 * | | lat. | |
209 * | | scvf | | O position at which gradient is evaluated (integration point)
210 * ---------######O:::::::::
211 * | || ~ :: ~ ~ orthogonal scvf
212 * | || ~ ::
213 * | || scv x ::
214 * | || | ::
215 * | || | ::
216 * ---------#######:::::::::
217 *
218 *
219 * \endverbatim
220 */
221 template<class FVElementGeometry, class ElemVolVars>
222 186604142 static auto velocityGradJI(const FVElementGeometry& fvGeometry,
223 const typename FVElementGeometry::SubControlVolumeFace& scvf,
224 const ElemVolVars& elemVolVars)
225 {
226
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 186604142 times.
186604142 assert(scvf.isLateral());
227 186604142 const auto& orthogonalScvf = fvGeometry.lateralOrthogonalScvf(scvf);
228 373208284 const auto innerVelocity = elemVolVars[orthogonalScvf.insideScvIdx()].velocity();
229 373208284 const auto outerVelocity = elemVolVars[orthogonalScvf.outsideScvIdx()].velocity();
230 186604142 const auto distance = getDistanceJI_(fvGeometry, scvf, orthogonalScvf);
231 186604142 return (outerVelocity - innerVelocity) / distance * orthogonalScvf.directionSign();
232 }
233
234 private:
235
236 template<class FVElementGeometry>
237 186594868 static auto getDistanceIJ_(const FVElementGeometry& fvGeometry,
238 const typename FVElementGeometry::SubControlVolumeFace& scvf)
239 {
240
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 182504516 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 182504516 times.
373189736 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
241 // The scvf is on a boundary, hence there is no outer DOF.
242 // We take the distance to the boundary instead.
243
2/2
✓ Branch 0 taken 2490746 times.
✓ Branch 1 taken 184104122 times.
186594868 if (scvf.boundary())
244 2490746 return getDistanceToBoundary_(insideScv, scvf);
245
246 368208244 const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx());
247
248 // The standard case: Our grid does not support periodic boundaries.
249 if constexpr (!Detail::SupportsPeriodicity<typename FVElementGeometry::GridGeometry::Grid>())
250 184088362 return getStandardDistance_(insideScv, outsideScv);
251 else
252 {
253 15760 const auto& gridGeometry = fvGeometry.gridGeometry();
254 15760 const auto& orthogonalScvf = fvGeometry.lateralOrthogonalScvf(scvf);
255
2/4
✓ Branch 0 taken 15760 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 15760 times.
✗ Branch 3 not taken.
31520 const auto& orthogonalInsideScv = fvGeometry.scv(orthogonalScvf.insideScvIdx());
256
257 // The standard case: Our grid is not periodic or the lateral scvf does not lie on a periodic boundary.
258
3/4
✓ Branch 0 taken 15760 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 14968 times.
✓ Branch 4 taken 792 times.
15760 if (!gridGeometry.isPeriodic() || !gridGeometry.dofOnPeriodicBoundary(orthogonalInsideScv.dofIndex()))
259 14968 return getStandardDistance_(insideScv, outsideScv);
260
261 // Treating periodic boundaries is more involved:
262 // 1. Consider the outside scv within the element adjacent to the other periodic boundary.
263 // 2. Iterate over this scv's faces until you find the face parallel to our own scvf.
264 // This face would lie directly next to our own scvf if the grid was not periodic.
265 // 3. Calculate the total distance by summing up the distances between the DOFs and the respective integration points
266 // corresponding to the inside and outside scvfs.
267 792 auto periodicFvGeometry = localView(gridGeometry);
268 792 const auto& periodicElement = gridGeometry.element(outsideScv.elementIndex());
269 792 periodicFvGeometry.bindElement(periodicElement);
270
271
2/4
✓ Branch 1 taken 1980 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1980 times.
✗ Branch 4 not taken.
1980 for (const auto& outsideScvf : scvfs(periodicFvGeometry, outsideScv))
272 {
273
4/4
✓ Branch 0 taken 1188 times.
✓ Branch 1 taken 792 times.
✓ Branch 2 taken 396 times.
✓ Branch 3 taken 792 times.
1980 if (outsideScvf.normalAxis() == scvf.normalAxis() && outsideScvf.directionSign() != scvf.directionSign())
274 {
275 3168 const auto insideDistance = (insideScv.dofPosition() - scvf.ipGlobal()).two_norm();
276 3168 const auto outsideDistance = (outsideScv.dofPosition() - outsideScvf.ipGlobal()).two_norm();
277 792 return insideDistance + outsideDistance;
278 }
279 }
280 DUNE_THROW(Dune::InvalidStateException, "Could not find scvf in periodic element");
281 }
282 }
283
284 //! Get the distance between the DOFs at which the inner and outer velocities are defined.
285 template<class FVElementGeometry>
286 182516254 static auto getDistanceJI_(const FVElementGeometry& fvGeometry,
287 const typename FVElementGeometry::SubControlVolumeFace& scvf,
288 const typename FVElementGeometry::SubControlVolumeFace& orthogonalScvf)
289 {
290
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 182516254 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 182516254 times.
365032508 const auto& orthogonalInsideScv = fvGeometry.scv(orthogonalScvf.insideScvIdx());
291
292 // The orthogonal scvf is on a boundary, hence there is no outer DOF.
293 // We take the distance to the boundary instead.
294
2/2
✓ Branch 0 taken 3584 times.
✓ Branch 1 taken 182512670 times.
182516254 if (orthogonalScvf.boundary())
295 3584 return getDistanceToBoundary_(orthogonalInsideScv, orthogonalScvf);
296
297
2/4
✓ Branch 0 taken 16560 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16560 times.
✗ Branch 3 not taken.
365025340 const auto& orthogonalOutsideScv = fvGeometry.scv(orthogonalScvf.outsideScvIdx());
298
299 // The standard case: Our grid does not support periodic boundaries.
300 if constexpr (!Detail::SupportsPeriodicity<typename FVElementGeometry::GridGeometry::Grid>())
301 182496110 return getStandardDistance_(orthogonalInsideScv, orthogonalOutsideScv);
302 else
303 {
304 16560 const auto& gridGeometry = fvGeometry.gridGeometry();
305
2/4
✓ Branch 0 taken 16560 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 16560 times.
✗ Branch 3 not taken.
33120 const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx());
306
307 // The standard case: Our grid is not periodic or our own DOF does not lie on a periodic boundary.
308
3/4
✓ Branch 0 taken 16560 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 15696 times.
✓ Branch 4 taken 864 times.
16560 if (!gridGeometry.isPeriodic() || !gridGeometry.dofOnPeriodicBoundary(insideScv.dofIndex()))
309 15696 return getStandardDistance_(orthogonalInsideScv, orthogonalOutsideScv);
310
311 // Treating periodic boundaries is more involved:
312 // 1. Consider the orthogonal outside scv within the element adjacent to the other periodic boundary.
313 // 2. Iterate over this scv's faces until you find the orthogonal face parallel to our own orthogonal scvf.
314 // This face would lie directly next to our own orthogonal scvf if the grid was not periodic.
315 // 3. Calculate the total distance by summing up the distances between the DOFs and the respective integration points
316 // corresponding to the orthogonal scvfs.
317 864 auto periodicFvGeometry = localView(gridGeometry);
318 864 const auto& periodicElement = gridGeometry.element(orthogonalOutsideScv.elementIndex());
319 864 periodicFvGeometry.bindElement(periodicElement);
320
321
2/4
✓ Branch 1 taken 2160 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2160 times.
✗ Branch 4 not taken.
2160 for (const auto& outsideOrthogonalScvf : scvfs(periodicFvGeometry, orthogonalOutsideScv))
322 {
323
4/4
✓ Branch 0 taken 1296 times.
✓ Branch 1 taken 864 times.
✓ Branch 2 taken 432 times.
✓ Branch 3 taken 864 times.
2160 if (outsideOrthogonalScvf.normalAxis() == orthogonalScvf.normalAxis() && outsideOrthogonalScvf.directionSign() != orthogonalScvf.directionSign())
324 {
325 3456 const auto insideDistance = (orthogonalInsideScv.dofPosition() - orthogonalScvf.ipGlobal()).two_norm();
326 3456 const auto outsideDistance = (orthogonalOutsideScv.dofPosition() - outsideOrthogonalScvf.ipGlobal()).two_norm();
327 864 return insideDistance + outsideDistance;
328 }
329 }
330 DUNE_THROW(Dune::InvalidStateException, "Could not find scvf in periodic element");
331 }
332 }
333
334 template<class SubControlVolume>
335 370703024 static auto getStandardDistance_(const SubControlVolume& insideScv,
336 const SubControlVolume& outsideScv)
337 {
338 1480216144 return (insideScv.dofPosition() - outsideScv.dofPosition()).two_norm();
339 }
340
341 template<class SubControlVolume, class SubControlVolumeFace>
342 2494330 static auto getDistanceToBoundary_(const SubControlVolume& scv,
343 const SubControlVolumeFace& scvf)
344 {
345 9873040 return (scv.dofPosition() - scvf.ipGlobal()).two_norm();
346 }
347 };
348
349 } // end namespace Dumux
350
351 #endif // DUMUX_NAVIERSTOKES_STAGGERED_VELOCITYGRADIENTS_HH
352