GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: dumux/dumux/porousmediumflow/velocity.hh
Date: 2025-04-12 19:19:20
Exec Total Coverage
Lines: 120 142 84.5%
Functions: 114 293 38.9%
Branches: 118 341 34.6%

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 PorousmediumflowModels
10 * \brief Velocity computation for implicit (porous media) models.
11 */
12
13 #ifndef DUMUX_POROUSMEDIUMFLOW_VELOCITY_HH
14 #define DUMUX_POROUSMEDIUMFLOW_VELOCITY_HH
15
16 #include <vector>
17 #include <type_traits>
18
19 #include <dune/common/fvector.hh>
20 #include <dune/common/float_cmp.hh>
21 #include <dune/common/reservedvector.hh>
22 #include <dune/geometry/type.hh>
23 #include <dune/geometry/referenceelements.hh>
24
25 #include <dumux/common/parameters.hh>
26 #include <dumux/discretization/extrusion.hh>
27 #include <dumux/discretization/method.hh>
28 #include <dumux/discretization/elementsolution.hh>
29 #include <dumux/flux/traits.hh>
30
31 namespace Dumux {
32
33 #ifndef DOXYGEN
34 namespace Detail {
35 // helper structs and functions detecting if the model is compositional
36
37 template <typename T, typename ...Ts>
38 using MoleFractionDetector = decltype(std::declval<T>().moleFraction(std::declval<Ts>()...));
39
40 template<class T, typename ...Args>
41 static constexpr bool hasMoleFraction()
42 { return Dune::Std::is_detected<MoleFractionDetector, T, Args...>::value; }
43
44 template <typename T, typename ...Ts>
45 using MassFractionDetector = decltype(std::declval<T>().massFraction(std::declval<Ts>()...));
46
47 template<class T, typename ...Args>
48 static constexpr bool hasMassFraction()
49 { return Dune::Std::is_detected<MassFractionDetector, T, Args...>::value; }
50
51 } // end namespace Detail
52 #endif // DOXYGEN
53
54 /*!
55 * \ingroup PorousmediumflowModels
56 * \brief Velocity computation for implicit (porous media) models.
57 */
58 template<class GridVariables, class FluxVariables>
59 99 class PorousMediumFlowVelocity
60 {
61 using GridGeometry = typename GridVariables::GridGeometry;
62 using Extrusion = Extrusion_t<GridGeometry>;
63 using FVElementGeometry = typename GridGeometry::LocalView;
64 using SubControlVolume = typename GridGeometry::SubControlVolume;
65 using SubControlVolumeFace = typename GridGeometry::SubControlVolumeFace;
66 using GridView = typename GridGeometry::GridView;
67 using Element = typename GridView::template Codim<0>::Entity;
68 using GridVolumeVariables = typename GridVariables::GridVolumeVariables;
69 using ElementFluxVarsCache = typename GridVariables::GridFluxVariablesCache::LocalView;
70 using VolumeVariables = typename GridVariables::VolumeVariables;
71 using ElementVolumeVariables = typename GridVolumeVariables::LocalView;
72 using FluidSystem = typename VolumeVariables::FluidSystem;
73 using Scalar = typename GridVariables::Scalar;
74 using FluxTraits = typename Dumux::FluxTraits<FluxVariables>;
75 using AdvectionType = typename FluxVariables::AdvectionType;
76
77 static constexpr int dim = GridView::dimension;
78 static constexpr int dimWorld = GridView::dimensionworld;
79 static constexpr bool isBox = GridGeometry::discMethod == DiscretizationMethods::box;
80 static constexpr bool isDiamond = GridGeometry::discMethod == DiscretizationMethods::fcdiamond;
81 static constexpr bool stationaryVelocityField = FluxTraits::hasStationaryVelocityField();
82
83 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
84
85 using Problem = typename GridVolumeVariables::Problem;
86
87 static constexpr bool modelIsCompositional = Detail::hasMoleFraction<typename GridVolumeVariables::VolumeVariables, int, int>() ||
88 Detail::hasMassFraction<typename GridVolumeVariables::VolumeVariables, int, int>();
89
90 static_assert(VolumeVariables::numFluidPhases() >= 1, "Velocity output only makes sense for models with fluid phases.");
91
92 using Velocity = Dune::FieldVector<Scalar, dimWorld>;
93 using ReferenceElementVelocity = Dune::FieldVector<Scalar, dim>;
94 public:
95 static constexpr int numFluidPhases = VolumeVariables::numFluidPhases();
96 using VelocityVector = std::vector<Velocity>;
97
98 /*!
99 * \brief Constructor initializes the static data with the initial solution.
100 *
101 * \param gridVariables The grid variables
102 */
103
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
99 PorousMediumFlowVelocity(const GridVariables& gridVariables)
104
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
99 : problem_(gridVariables.curGridVolVars().problem())
105
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
99 , gridGeometry_(gridVariables.gridGeometry())
106
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
99 , gridVariables_(gridVariables)
107 {
108 // set the number of scvs the vertices are connected to
109 if constexpr (isBox && dim > 1)
110 {
111 // resize to the number of vertices of the grid
112
2/5
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 35 times.
✗ Branch 5 not taken.
✗ Branch 3 not taken.
35 cellNum_.assign(gridGeometry_.gridView().size(dim), 0);
113
114
4/12
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19850 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 13 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✓ Branch 6 taken 3278 times.
✗ Branch 3 not taken.
39691 for (const auto& element : elements(gridGeometry_.gridView()))
115
4/5
✓ Branch 1 taken 32940 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13112 times.
✓ Branch 4 taken 3278 times.
✓ Branch 0 taken 66200 times.
99140 for (unsigned int vIdx = 0; vIdx < element.subEntities(dim); ++vIdx)
116
1/2
✓ Branch 1 taken 79312 times.
✗ Branch 2 not taken.
79312 ++cellNum_[gridGeometry_.vertexMapper().subIndex(element, vIdx, dim)];
117 }
118 35 }
119
120 //! Calculates the velocities for the scvs in the element.
121 //! We assume the local containers to be bound to the complete stencil.
122 1227640 void calculateVelocity(VelocityVector& velocity,
123 const Element& element,
124 const FVElementGeometry& fvGeometry,
125 const ElementVolumeVariables& elemVolVars,
126 const ElementFluxVarsCache& elemFluxVarsCache,
127 int phaseIdx) const
128 {
129
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
1227640 const auto geometry = element.geometry();
130 1227640 const Dune::GeometryType geomType = geometry.type();
131
132 // the upwind term to be used for the volume flux evaluation
133
4/10
✓ Branch 0 taken 174854 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 174854 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 131746 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 131746 times.
✗ Branch 7 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
6687059 auto upwindTerm = [phaseIdx](const auto& volVars) { return volVars.mobility(phaseIdx); };
134
135 if constexpr (isBox && dim == 1)
136 {
137 2960 Velocity tmpVelocity(0.0);
138 2960 tmpVelocity = (geometry.corner(1) - geometry.corner(0));
139 2960 tmpVelocity /= tmpVelocity.two_norm();
140
141
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2960 times.
✓ Branch 2 taken 2996 times.
✓ Branch 3 taken 2960 times.
5956 for (auto&& scvf : scvfs(fvGeometry))
142 {
143
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 2960 times.
2996 if (scvf.boundary())
144 36 continue;
145
146 // instantiate the flux variables
147 2960 FluxVariables fluxVars;
148 2960 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
149
150 // get the volume flux divided by the area of the
151 // subcontrolvolume face in the reference element
152 2960 Scalar localArea = scvfReferenceArea_(geomType, scvf.index());
153 2960 Scalar flux = fluxVars.advectiveFlux(phaseIdx, upwindTerm) / localArea;
154 2960 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
155 2960 flux /= insideVolVars.extrusionFactor() * Extrusion::area(fvGeometry, scvf) / scvf.area();
156 2960 tmpVelocity *= flux;
157
158 2960 const int eIdxGlobal = gridGeometry_.elementMapper().index(element);
159 2960 velocity[eIdxGlobal] = tmpVelocity;
160 }
161 return;
162 }
163
164 // get the transposed Jacobian of the element mapping
165 using Dune::referenceElement;
166
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 800 times.
1224680 const auto localPos = referenceElement(geometry).position(0, 0);
167
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
1224680 const auto jacobianT2 = geometry.jacobianTransposed(localPos);
168
169 if constexpr (isBox)
170 {
171 using ScvVelocities = Dune::BlockVector<Velocity>;
172
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
365772 ScvVelocities scvVelocities(fvGeometry.numScv());
173 731544 scvVelocities = 0;
174
175
4/4
✓ Branch 0 taken 338644 times.
✓ Branch 1 taken 1463088 times.
✓ Branch 2 taken 1801732 times.
✓ Branch 3 taken 365772 times.
2167504 for (auto&& scvf : scvfs(fvGeometry))
176 {
177
2/2
✓ Branch 0 taken 338644 times.
✓ Branch 1 taken 1463088 times.
1801732 if (scvf.boundary())
178 338644 continue;
179
180 // local position of integration point
181
2/4
✓ Branch 1 taken 311888 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 311888 times.
✗ Branch 5 not taken.
1463088 const auto localPosIP = geometry.local(scvf.ipGlobal());
182
183 // Transformation of the global normal vector to normal vector in the reference element
184 1463088 const auto jacobianT1 = geometry.jacobianTransposed(localPosIP);
185 1463088 const auto globalNormal = scvf.unitOuterNormal();
186 1463088 GlobalPosition localNormal(0);
187
2/2
✓ Branch 0 taken 2926176 times.
✓ Branch 1 taken 1463088 times.
4389264 jacobianT1.mv(globalNormal, localNormal);
188 2926176 localNormal /= localNormal.two_norm();
189
190 // instantiate the flux variables
191 1463088 FluxVariables fluxVars;
192
1/2
✓ Branch 1 taken 1463088 times.
✗ Branch 2 not taken.
1463088 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
193
194 // get the volume flux divided by the area of the
195 // subcontrolvolume face in the reference element
196
1/2
✓ Branch 1 taken 1463088 times.
✗ Branch 2 not taken.
1463088 Scalar localArea = scvfReferenceArea_(geomType, scvf.index());
197
1/2
✓ Branch 1 taken 1463088 times.
✗ Branch 2 not taken.
1463088 Scalar flux = fluxVars.advectiveFlux(phaseIdx, upwindTerm) / localArea;
198 1463088 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
199 1463088 flux /= insideVolVars.extrusionFactor() * Extrusion::area(fvGeometry, scvf) / scvf.area();
200
201 // transform the volume flux into a velocity vector
202 1463088 Velocity tmpVelocity = localNormal;
203 1463088 tmpVelocity *= flux;
204
205
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1463088 times.
2926176 scvVelocities[scvf.insideScvIdx()] += tmpVelocity;
206 2926176 scvVelocities[scvf.outsideScvIdx()] += tmpVelocity;
207 }
208
209 // transform vertex velocities from local to global coordinates
210
2/2
✓ Branch 0 taken 1463088 times.
✓ Branch 1 taken 365772 times.
1828860 for (auto&& scv : scvs(fvGeometry))
211 {
212 1463088 int vIdxGlobal = scv.dofIndex();
213
214 // calculate the subcontrolvolume velocity by the Piola transformation
215 1463088 Velocity scvVelocity(0);
216
217
2/3
✓ Branch 0 taken 2302400 times.
✓ Branch 1 taken 1463088 times.
✗ Branch 2 not taken.
5228576 jacobianT2.mtv(scvVelocities[scv.indexInElement()], scvVelocity);
218 1463088 scvVelocity /= geometry.integrationElement(localPos)*cellNum_[vIdxGlobal];
219 // add up the wetting phase subcontrolvolume velocities for each vertex
220 2926176 velocity[vIdxGlobal] += scvVelocity;
221 }
222 365772 }
223 else if constexpr (isDiamond)
224 DUNE_THROW(Dune::NotImplemented, "Velocity output with diamond discretization");
225 else
226 {
227 // For the number of scvfs per facet (mpfa) we simply obtain the number of
228 // corners of the first facet as prisms/pyramids are not supported here anyway
229 // -> for prisms/pyramids the number of scvfs would differ from facet to facet
230 static constexpr bool isMpfa = GridGeometry::discMethod == DiscretizationMethods::ccmpfa;
231
4/8
✓ Branch 1 taken 828528 times.
✓ Branch 2 taken 27800 times.
✓ Branch 4 taken 2400 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2400 times.
✗ Branch 7 not taken.
✗ Branch 0 not taken.
✗ Branch 3 not taken.
866300 const int numScvfsPerFace = isMpfa ? element.template subEntity<1>(0).geometry().corners() : 1;
232
233
2/5
✓ Branch 1 taken 853736 times.
✓ Branch 2 taken 5172 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 0 not taken.
858908 if (fvGeometry.numScvf() != element.subEntities(1)*numScvfsPerFace)
234
1/22
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
✓ Branch 33 taken 5172 times.
✗ Branch 34 not taken.
5172 DUNE_THROW(Dune::NotImplemented, "Velocity output for non-conforming grids");
235
236
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
853736 if (!geomType.isCube() && !geomType.isSimplex())
237
0/20
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
853736 DUNE_THROW(Dune::NotImplemented, "Velocity output for other geometry types than cube and simplex");
238
239 // first we extract the corner indices for each scv for the CIV method
240 // for network grids there might be multiple intersection with the same geometryInInside
241 // we identify those by the indexInInside for now (assumes conforming grids at branching facets)
242 // here we keep track of them
243
1/2
✓ Branch 1 taken 858908 times.
✗ Branch 2 not taken.
858908 std::vector<bool> handledScvf;
244 if (dim < dimWorld)
245 handledScvf.resize(element.subEntities(1), false);
246
247 // find the local face indices of the scvfs (for conforming meshes)
248
1/2
✓ Branch 1 taken 858908 times.
✗ Branch 2 not taken.
858908 std::vector<unsigned int> scvfIndexInInside(fvGeometry.numScvf());
249 858908 int localScvfIdx = 0;
250
9/14
✓ Branch 1 taken 858908 times.
✓ Branch 2 taken 3413344 times.
✓ Branch 7 taken 5172 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 25860 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 9412 times.
✓ Branch 12 taken 11276 times.
✓ Branch 4 taken 3330092 times.
✓ Branch 5 taken 86834 times.
✗ Branch 6 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 3 taken 1590 times.
4329144 for (const auto& intersection : intersections(gridGeometry_.gridView(), element))
251 {
252 if (dim < dimWorld)
253 if (handledScvf[intersection.indexInInside()])
254 continue;
255
256
4/5
✓ Branch 0 taken 173688 times.
✓ Branch 1 taken 20688 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9412 times.
✓ Branch 4 taken 11276 times.
215064 if (intersection.neighbor() || intersection.boundary())
257 {
258
2/2
✓ Branch 0 taken 3555600 times.
✓ Branch 1 taken 3434032 times.
6989632 for (int i = 0; i < numScvfsPerFace; ++i)
259 3555600 scvfIndexInInside[localScvfIdx++] = intersection.indexInInside();
260
261 // for surface and network grids mark that we handled this face
262 if (dim < dimWorld)
263 handledScvf[intersection.indexInInside()] = true;
264 }
265 }
266
267
1/2
✓ Branch 1 taken 5172 times.
✗ Branch 2 not taken.
858908 Dune::ReservedVector<Scalar, 2*dim> scvfFluxes(element.subEntities(1), 0.0);
268 858908 localScvfIdx = 0;
269
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3555600 times.
✓ Branch 2 taken 858908 times.
✗ Branch 3 not taken.
4414508 for (auto&& scvf : scvfs(fvGeometry))
270 {
271
2/3
✓ Branch 1 taken 3365612 times.
✓ Branch 2 taken 189988 times.
✗ Branch 0 not taken.
3555600 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
272
2/2
✓ Branch 0 taken 3365612 times.
✓ Branch 1 taken 189988 times.
3555600 if (!scvf.boundary())
273 {
274 3365612 FluxVariables fluxVars;
275
1/2
✓ Branch 1 taken 3365612 times.
✗ Branch 2 not taken.
3365612 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
276
1/2
✓ Branch 1 taken 3365612 times.
✗ Branch 2 not taken.
3365612 scvfFluxes[scvfIndexInInside[localScvfIdx]] += fluxVars.advectiveFlux(phaseIdx, upwindTerm)/insideVolVars.extrusionFactor();
277 }
278 else
279 {
280
4/4
✓ Branch 0 taken 11513 times.
✓ Branch 1 taken 178475 times.
✓ Branch 2 taken 3644 times.
✓ Branch 3 taken 1436 times.
191708 auto bcTypes = problem_.boundaryTypes(element, scvf);
281
2/2
✓ Branch 0 taken 17519 times.
✓ Branch 1 taken 172469 times.
189988 if (bcTypes.hasOnlyDirichlet())
282 {
283 17519 FluxVariables fluxVars;
284
1/2
✓ Branch 1 taken 17519 times.
✗ Branch 2 not taken.
17519 fluxVars.init(problem_, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
285
1/2
✓ Branch 1 taken 17519 times.
✗ Branch 2 not taken.
17519 scvfFluxes[scvfIndexInInside[localScvfIdx]] += fluxVars.advectiveFlux(phaseIdx, upwindTerm)/insideVolVars.extrusionFactor();
286 }
287 }
288
289 // increment scvf counter
290 3555600 localScvfIdx++;
291 }
292
293 // Correct boundary fluxes in case of Neumann conditions.
294 // In this general setting, it would be very difficult to
295 // calculate correct phase, i.e., volume, fluxes from arbitrary
296 // Neumann conditions. We approximate the Neumann flux by the
297 // flux on the opposite face. For extremely distorted grids this can
298 // lead to unexpected results (but then TPFA also leads to unexpected results).
299 858908 localScvfIdx = 0;
300
4/4
✓ Branch 0 taken 189988 times.
✓ Branch 1 taken 3365612 times.
✓ Branch 2 taken 3555600 times.
✓ Branch 3 taken 858908 times.
4414508 for (auto&& scvf : scvfs(fvGeometry))
301 {
302
2/2
✓ Branch 0 taken 189988 times.
✓ Branch 1 taken 3365612 times.
3555600 if (scvf.boundary())
303 {
304
4/4
✓ Branch 0 taken 165831 times.
✓ Branch 1 taken 24157 times.
✓ Branch 2 taken 1436 times.
✓ Branch 3 taken 3644 times.
191708 auto bcTypes = problem_.boundaryTypes(element, scvf);
305
2/2
✓ Branch 0 taken 172469 times.
✓ Branch 1 taken 17519 times.
189988 if (bcTypes.hasNeumann())
306 {
307 // for stationary velocity fields we can easily compute the correct velocity
308 // this special treatment makes sure that the velocity field is also correct on Neumann boundaries
309 // of tracer problems where the velocity field is given.
310 // (For Dirichlet boundaries no special treatment is necessary.)
311 if (stationaryVelocityField)
312 {
313 21836 const auto flux = AdvectionType::flux(problem_, element, fvGeometry, elemVolVars,
314 scvf, phaseIdx, elemFluxVarsCache);
315
316 21836 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
317 21836 scvfFluxes[scvfIndexInInside[localScvfIdx]] += flux / insideVolVars.extrusionFactor();
318 }
319 else
320 {
321 // check if we have Neumann no flow, we can just use 0
322
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 115105 times.
✗ Branch 2 not taken.
150633 const auto neumannFlux = problem_.neumann(element, fvGeometry, elemVolVars, elemFluxVarsCache, scvf);
323 using NumEqVector = std::decay_t<decltype(neumannFlux)>;
324
4/4
✓ Branch 0 taken 509469 times.
✓ Branch 1 taken 143244 times.
✓ Branch 2 taken 138864 times.
✓ Branch 3 taken 3273 times.
798439 if (Dune::FloatCmp::eq<NumEqVector, Dune::FloatCmp::CmpStyle::absolute>(neumannFlux, NumEqVector(0.0), 1e-30))
325 142980 scvfFluxes[scvfIndexInInside[localScvfIdx]] = 0;
326
327 // otherwise, we try some reconstruction
328 // for cubes
329
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
7553 else if (dim == 1 || geomType.isCube())
330 {
331
2/2
✓ Branch 0 taken 2203 times.
✓ Branch 1 taken 30 times.
7653 const auto fIdx = scvfIndexInInside[localScvfIdx];
332
333 if constexpr (!modelIsCompositional)
334 {
335 // We assume that the density at the face equals the one at the cell center and reconstruct a volume flux from the Neumann mass flux.
336 5420 const auto& insideVolVars = elemVolVars[scvf.insideScvIdx()];
337 5420 const auto eqIdx = VolumeVariables::Indices::conti0EqIdx + phaseIdx;
338 5420 scvfFluxes[fIdx] += neumannFlux[eqIdx] / insideVolVars.density(phaseIdx) * scvf.area();
339 }
340 else
341 {
342 // For compositional models, we generally can't reconstruct the volume flow from the Neumann flux (which is a species flux rather
343 // than a phase flux here). Instead, we use the velocity of the opposing face.
344
2/2
✓ Branch 0 taken 2203 times.
✓ Branch 1 taken 30 times.
2233 const auto fIdxOpposite = fIdx%2 ? fIdx-1 : fIdx+1;
345 2233 scvfFluxes[fIdx] = -scvfFluxes[fIdxOpposite];
346 }
347 }
348
349 // for simplices
350 else if (geomType.isSimplex())
351 scvfFluxes[scvfIndexInInside[localScvfIdx]] = 0;
352
353 else
354
0/20
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
150633 DUNE_THROW(Dune::NotImplemented, "Velocity computation at Neumann boundaries for cell-centered and prism/pyramid");
355 }
356 }
357 }
358
359 // increment scvf counter
360 3555600 localScvfIdx++;
361 }
362
363
364
2/2
✓ Branch 0 taken 5172 times.
✓ Branch 1 taken 800 times.
858908 ReferenceElementVelocity refVelocity;
365 // cubes: On the reference element simply average over opposite fluxes
366 // note that this is equal to a corner velocity interpolation method
367
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 858108 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
858108 if (dim == 1 || geomType.isCube())
368 {
369
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 858908 times.
858908 assert(scvfFluxes.size() == 2*dim);
370
2/2
✓ Branch 0 taken 1717016 times.
✓ Branch 1 taken 858908 times.
2575924 for (int i = 0; i < dim; ++i)
371 1717016 refVelocity[i] = 0.5 * (scvfFluxes[2*i + 1] - scvfFluxes[2*i]);
372 }
373
374 // simplices: Raviart-Thomas-0 interpolation evaluated at the cell center
375 else if (geomType.isSimplex())
376 {
377 assert(scvfFluxes.size() == dim+1);
378 for (int i = 0; i < dim; ++i)
379 {
380 refVelocity[i] = -scvfFluxes[dim - 1 - i];
381 for (int fIdx = 0; fIdx < dim + 1; ++fIdx)
382 refVelocity[i] += scvfFluxes[fIdx]/(dim + 1);
383 }
384 }
385
386 // 3D prism and pyramids
387 else
388
0/20
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
✗ Branch 19 not taken.
✗ Branch 20 not taken.
✗ Branch 22 not taken.
✗ Branch 23 not taken.
✗ Branch 25 not taken.
✗ Branch 26 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
852936 DUNE_THROW(Dune::NotImplemented, "Velocity computation for cell-centered and prism/pyramid");
389
390 858108 Velocity scvVelocity(0);
391
2/3
✓ Branch 0 taken 1705872 times.
✓ Branch 1 taken 858108 times.
✗ Branch 2 not taken.
2564780 jacobianT2.mtv(refVelocity, scvVelocity);
392
393
2/2
✓ Branch 0 taken 1716216 times.
✓ Branch 1 taken 858108 times.
2575124 scvVelocity /= geometry.integrationElement(localPos);
394
395
1/2
✓ Branch 1 taken 5172 times.
✗ Branch 2 not taken.
858908 int eIdxGlobal = gridGeometry_.elementMapper().index(element);
396
397 858908 velocity[eIdxGlobal] = scvVelocity;
398
399 858908 } // cell-centered
400 1224680 }
401
402 private:
403 // The area of a subcontrolvolume face in a reference element.
404 // The 3d non-cube values have been calculated with quadrilateralArea3D
405 // of boxfvelementgeometry.hh.
406
1/2
✓ Branch 0 taken 1463088 times.
✗ Branch 1 not taken.
1463088 static Scalar scvfReferenceArea_(Dune::GeometryType geomType, int fIdx)
407 {
408
0/2
✗ Branch 0 not taken.
✗ Branch 1 not taken.
1463088 if (dim == 1 || geomType.isCube())
409 {
410 return 1.0/(1 << (dim-1));
411 }
412 else if (geomType.isTriangle())
413 {
414 static const Scalar faceToArea[] = {0.372677996249965,
415 0.372677996249965,
416 0.235702260395516};
417 return faceToArea[fIdx];
418 }
419 else if (geomType.isTetrahedron())
420 {
421 static const Scalar faceToArea[] = {0.102062072615966,
422 0.102062072615966,
423 0.058925565098879,
424 0.102062072615966,
425 0.058925565098879,
426 0.058925565098879};
427 return faceToArea[fIdx];
428 }
429 else if (geomType.isPyramid())
430 {
431 static const Scalar faceToArea[] = {0.130437298687488,
432 0.130437298687488,
433 0.130437298687488,
434 0.130437298687488,
435 0.150923085635624,
436 0.1092906420717,
437 0.1092906420717,
438 0.0781735959970571};
439 return faceToArea[fIdx];
440 }
441 else if (geomType.isPrism())
442 {
443 static const Scalar faceToArea[] = {0.166666666666667,
444 0.166666666666667,
445 0.166666666666667,
446 0.186338998124982,
447 0.186338998124982,
448 0.117851130197758,
449 0.186338998124982,
450 0.186338998124982,
451 0.117851130197758};
452 return faceToArea[fIdx];
453 }
454 else {
455 DUNE_THROW(Dune::NotImplemented, "scvf area for unknown GeometryType");
456 }
457 }
458
459 private:
460 const Problem& problem_;
461 const GridGeometry& gridGeometry_;
462 const GridVariables& gridVariables_;
463
464 std::vector<int> cellNum_;
465 };
466
467 } // end namespace Dumux
468
469 #endif
470