GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/freeflow/navierstokes/fluxoveraxisalignedsurface.hh
Date: 2024-05-04 19:09:25
Exec Total Coverage
Lines: 105 119 88.2%
Functions: 28 59 47.5%
Branches: 134 315 42.5%

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::FluxOverAxisAlignedSurface
11 */
12 #ifndef DUMUX_FREELOW_NAVIERSTOKES_FLUX_OVER_AXISALIGNED_SURFACE_HH
13 #define DUMUX_FREELOW_NAVIERSTOKES_FLUX_OVER_AXISALIGNED_SURFACE_HH
14
15 #include <algorithm>
16 #include <type_traits>
17 #include <vector>
18
19 #include <dune/common/exceptions.hh>
20 #include <dune/geometry/axisalignedcubegeometry.hh>
21
22 #include <dumux/common/parameters.hh>
23 #include <dumux/geometry/diameter.hh>
24 #include <dumux/geometry/distance.hh>
25 #include <dumux/geometry/intersectspointgeometry.hh>
26 #include <dumux/geometry/geometricentityset.hh>
27 #include <dumux/geometry/intersectingentities.hh>
28
29 namespace Dumux {
30
31 /*!
32 * \ingroup NavierStokesModel
33 * \brief Class used to calculate fluxes over axis-aligned surfaces.
34 */
35 template<class GridVariables, class SolutionVector, class LocalResidual>
36
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
9 class FluxOverAxisAlignedSurface
37 {
38 using Scalar = typename GridVariables::Scalar;
39 using GridGeometry = typename GridVariables::GridGeometry;
40 using FVElementGeometry = typename GridGeometry::LocalView;
41 using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace;
42 using GridView = typename GridGeometry::GridView;
43 using VolumeVariables = typename GridVariables::VolumeVariables;
44 using Element = typename GridView::template Codim<0>::Entity;
45 using NumEqVector = typename LocalResidual::ElementResidualVector::value_type;
46
47 static constexpr auto dim = GridView::dimension;
48 static constexpr auto dimWorld = GridView::dimensionworld;
49
50 static_assert(dim > 1, "Only implemented for dim > 1");
51
52 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
53
54 // in 2D, the surface is represented as a line
55 using SurfaceT = Dune::AxisAlignedCubeGeometry<Scalar, (dim == 2 ? 1 : 2), dimWorld>;
56
57 struct SurfaceData
58 {
59 SurfaceT surface;
60 std::size_t normalDirectionIndex;
61 NumEqVector flux;
62 };
63
64 public:
65
66 using Surface = SurfaceT;
67
68 /*!
69 * \brief The constructor
70 */
71 9 FluxOverAxisAlignedSurface(const GridVariables& gridVariables,
72 const SolutionVector& sol,
73 const LocalResidual& localResidual)
74 : gridVariables_(gridVariables)
75 , sol_(sol)
76
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 , localResidual_(localResidual)
77 {
78
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 verbose_ = getParamFromGroup<bool>(problem_().paramGroup(), "FluxOverAxisAlignedSurface.Verbose", false);
79 9 }
80
81 /*!
82 * \brief Add an axis-aligned surface with a given name
83 *
84 * \param name The name of the surface
85 * \param surface The surface to add
86 */
87 template<class T>
88 void addAxisAlignedSurface(const std::string& name, T&& surface)
89 {
90 static_assert(std::is_same_v<std::decay_t<T>, Surface>);
91 surfaces_.emplace(std::make_pair(
92 name, std::make_pair(surface, NumEqVector(0.0))
93 ));
94 }
95
96 /*!
97 * \brief Add an axis-aligned surface (segment in 2D) with a given name, specifying the surface's corner points.
98 *
99 * \param name The name of the surface
100 * \param lowerLeft Lower left corner of surface
101 * \param upperRight Upper right corner of surface
102 */
103 19 void addAxisAlignedSurface(const std::string& name,
104 const GlobalPosition& lowerLeft,
105 const GlobalPosition& upperRight)
106 {
107 using std::abs;
108 19 const GlobalPosition v = upperRight - lowerLeft;
109
8/28
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 9 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 9 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 3 times.
✓ Branch 21 taken 7 times.
✓ Branch 22 taken 3 times.
✓ Branch 23 taken 7 times.
✓ Branch 24 taken 7 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 7 times.
✗ Branch 27 not taken.
109 const auto it = std::find_if(v.begin(), v.end(), [](const auto& x){ return abs(x) < 1e-20; });
110
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
38 if (it == v.end())
111 DUNE_THROW(Dune::InvalidStateException, "Surface is not axis-parallel!");
112
113
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 19 times.
38 const std::size_t normalDirectionIndex = std::distance(v.begin(), it);
114 38 auto inSurfaceAxes = std::move(std::bitset<dimWorld>{}.set());
115 19 inSurfaceAxes.set(normalDirectionIndex, false);
116 19 auto surface = Surface(lowerLeft, upperRight, inSurfaceAxes);
117
118
3/8
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 19 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 19 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
19 surfaces_.emplace(std::make_pair(
119 name,
120 SurfaceData{
121
1/2
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
19 std::move(surface), normalDirectionIndex, NumEqVector(0.0)
122 }
123 ));
124 19 }
125
126 /*!
127 * \brief Add an axis-aligned plane (line in 2D) with a given name, specifying the planes's center and normal.
128 *
129 * \param name The name of the plane
130 * \param center Center point of the plane
131 * \param normalDirectionIndex Index of the plane's normal axis (0=x, 1=y, 2=z)
132 */
133 6 void addAxisAlignedPlane(const std::string& name,
134 const GlobalPosition& center,
135 const std::size_t normalDirectionIndex)
136 {
137 12 GlobalPosition lowerLeft = gridVariables_.gridGeometry().bBoxMin();
138 12 GlobalPosition upperRight = gridVariables_.gridGeometry().bBoxMax();
139
140 12 lowerLeft[normalDirectionIndex] = center[normalDirectionIndex];
141 12 upperRight[normalDirectionIndex] = center[normalDirectionIndex];
142
143 12 auto inSurfaceAxes = std::move(std::bitset<dimWorld>{}.set());
144 6 inSurfaceAxes.set(normalDirectionIndex, false);
145 6 auto surface = Surface(lowerLeft, upperRight, inSurfaceAxes);
146
147
3/8
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 6 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
6 surfaces_.emplace(std::make_pair(
148 name,
149 SurfaceData{
150
1/2
✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
6 std::move(surface), normalDirectionIndex, NumEqVector(0.0)
151 }
152 ));
153 6 }
154
155 /*!
156 * \brief Calculate the fluxes over all surfaces.
157 */
158 void calculateAllFluxes()
159 {
160 9 auto fluxType = [this](const auto& element,
161 const auto& fvGeometry,
162 const auto& elemVolVars,
163 const auto& scvf,
164 const auto& elemFluxVarsCache)
165 {
166 return localResidual_.evalFlux(
167 problem_(), element, fvGeometry, elemVolVars, elemFluxVarsCache, scvf
168 2428 );
169 };
170
171
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
9 calculateFluxes(fluxType);
172 }
173
174 /*!
175 * \brief Calculate the fluxes over all surfaces for a given flux type.
176 *
177 * \param fluxType The flux type. This can be a lambda of the following form:
178 * [](const auto& element,
179 const auto& fvGeometry,
180 const auto& elemVolVars,
181 const auto& scvf,
182 const auto& elemFluxVarsCache)
183 { return ... ; }
184 */
185 template<class FluxType>
186 9 void calculateFluxes(const FluxType& fluxType)
187 {
188 // make sure to reset all the values of the surfaces, in case this method has been called already before
189
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 9 times.
52 for (auto& surface : surfaces_)
190 50 surface.second.flux = 0.0;
191
192 9 snapSurfaceToClosestFace_();
193 9 calculateFluxes_(fluxType);
194 9 }
195
196 /*!
197 * \brief Return the flux over given surface
198 *
199 * \param name The name of the surface
200 */
201 const auto& flux(const std::string& name) const
202 {
203
9/15
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 7 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1 times.
✓ Branch 10 taken 6 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 3 times.
✓ Branch 13 taken 4 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 3 times.
✓ Branch 16 taken 4 times.
✗ Branch 17 not taken.
19 return surfaces_.at(name).flux;
204 }
205
206 /*!
207 * \brief Provides access to all surfaces.
208 */
209 const std::map<std::string, SurfaceData>& surfaces() const
210 { return surfaces_; }
211
212 /*!
213 * \brief Prints all fluxes.
214 */
215 4 void printAllFluxes() const
216 {
217
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 4 times.
24 for (const auto& [name, data] : surfaces_)
218 36 std::cout << "Flux over surface " << name << ": " << data.flux << std::endl;
219 4 }
220
221 private:
222
223 template<class FluxType>
224 9 void calculateFluxes_(const FluxType& fluxType)
225 {
226
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 auto fvGeometry = localView(problem_().gridGeometry());
227
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 auto elemVolVars = localView(gridVariables_.curGridVolVars());
228
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
18 auto elemFluxVarsCache = localView(gridVariables_.gridFluxVarsCache());
229
230
4/8
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 22409 times.
✗ Branch 7 not taken.
✓ Branch 11 taken 992 times.
✗ Branch 12 not taken.
44827 for (const auto& element : elements(problem_().gridGeometry().gridView()))
231 {
232
1/2
✓ Branch 1 taken 992 times.
✗ Branch 2 not taken.
22400 fvGeometry.bindElement(element);
233
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
22400 elemVolVars.bindElement(element, fvGeometry, sol_);
234
0/2
✗ Branch 1 not taken.
✗ Branch 2 not taken.
22400 elemFluxVarsCache.bindElement(element, fvGeometry, elemVolVars);
235
236
4/4
✓ Branch 0 taken 91464 times.
✓ Branch 1 taken 22400 times.
✓ Branch 2 taken 91464 times.
✓ Branch 3 taken 22400 times.
136264 for (const auto& scvf : scvfs(fvGeometry))
237 {
238 // iterate through all surfaces and check if the flux at the given position
239 // should be accounted for in the respective surface
240
2/2
✓ Branch 0 taken 192288 times.
✓ Branch 1 taken 91464 times.
466680 for (auto& [name, surfaceData] : surfaces_)
241 {
242
2/2
✓ Branch 1 taken 1214 times.
✓ Branch 2 taken 191074 times.
192288 if (considerScvf_(scvf, surfaceData))
243 {
244 2428 const auto result = fluxType(element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1214 times.
1214 surfaceData.flux += result;
246
247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1214 times.
1214 if (verbose_)
248 std::cout << "At element " << problem_().gridGeometry().elementMapper().index(element)
249 << ": Flux at face " << scvf.ipGlobal() << ": " << result << " (" << name << ")" << std::endl;
250 }
251 }
252 }
253 }
254 9 }
255
256 //! Check whether a scvf should be considered for the flux calculation
257 bool considerScvf_(const SubControlVolumeFace& scvf, const SurfaceData& SurfaceData) const
258 {
259 // In order to avoid considering scvfs at the same element intersection (and hence, the corresponding flux) twice,
260 // only use those with a unit outer normal pointing towards positive coordinate direction,
261 // unless the scvf lies on a boundary (then there is no second scvf).
262 if (scvf.boundary() || !std::signbit(scvf.unitOuterNormal()[SurfaceData.normalDirectionIndex]))
263 return intersectsPointGeometry(scvf.ipGlobal(), SurfaceData.surface);
264 else
265 return false;
266 }
267
268 9 void snapSurfaceToClosestFace_()
269 {
270 using GeometriesEntitySet = Dumux::GeometriesEntitySet<Surface>;
271 18 const auto gridView = problem_().gridGeometry().gridView();
272
273
5/8
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 9 times.
✓ Branch 3 taken 25 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 25 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 25 times.
✗ Branch 10 not taken.
52 for (auto& [name, surfaceData] : surfaces_)
274 {
275
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
50 GeometriesEntitySet entitySet({surfaceData.surface});
276
5/14
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 25 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 25 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✓ Branch 10 taken 25 times.
✓ Branch 12 taken 25 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 17 not taken.
✗ Branch 18 not taken.
75 Dumux::BoundingBoxTree<GeometriesEntitySet> geometriesTree(std::make_shared<GeometriesEntitySet>(entitySet));
277
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 const auto intersectingElements = intersectingEntities(
278
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 problem_().gridGeometry().boundingBoxTree(), geometriesTree
279 );
280
281
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
50 if (intersectingElements.empty())
282 {
283 std::cout << "surface boundaries: " << std::endl;
284 printSurfaceBoundaries_(surfaceData.surface);
285
286 DUNE_THROW(Dune::InvalidStateException, "surface " << name << " does not intersect with any element");
287 }
288
289
2/7
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
75 std::vector<std::size_t> sortedResults;
290
3/5
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
25 sortedResults.reserve(gridView.size(0));
291
292
4/4
✓ Branch 0 taken 3976 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 3976 times.
✓ Branch 3 taken 25 times.
8027 for (const auto& i : intersectingElements)
293
1/4
✓ Branch 1 taken 3976 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
3976 sortedResults.push_back(i.first());
294
295 75 std::sort(sortedResults.begin(), sortedResults.end());
296 75 sortedResults.erase(std::unique(
297 sortedResults.begin(), sortedResults.end()
298 50 ), sortedResults.end());
299
300 // pick the first intersecting element and make sure the surface snaps to the closest face with the same (or opposite facing) normal vector
301 25 GlobalPosition normalVector(0.0);
302
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 normalVector[surfaceData.normalDirectionIndex] = 1.0;
303
304
1/2
✓ Branch 1 taken 25 times.
✗ Branch 2 not taken.
25 const auto& firstIntersectingElement = problem_().gridGeometry().element(sortedResults[0]);
305 25 Scalar distance = std::numeric_limits<Scalar>::max();
306 25 bool snappingOcurred = false;
307
308 25 GlobalPosition surfaceLowerLeft = surfaceData.surface.corner(0);
309 25 GlobalPosition surfaceUpperRight = surfaceData.surface.corner(3);
310
311 25 bool surfaceAlreadyOnFaces = false;
312
11/14
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 52 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 12 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 66 times.
✓ Branch 10 taken 12 times.
✓ Branch 11 taken 66 times.
✓ Branch 12 taken 12 times.
✓ Branch 13 taken 34 times.
✓ Branch 14 taken 32 times.
✓ Branch 16 taken 66 times.
✗ Branch 17 not taken.
167 for (const auto& intersection : intersections(gridView, firstIntersectingElement))
313 {
314
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 39 times.
118 if (surfaceAlreadyOnFaces)
315 continue;
316
317 using std::abs;
318
7/7
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 14 times.
361 if (abs(1.0 - abs(normalVector * intersection.centerUnitOuterNormal())) < 1e-8)
319 {
320
321 const auto getDistance = [](const auto& p, const auto& geo)
322 {
323 if constexpr (dim == 2)
324 return distancePointSegment(p, geo);
325 else
326 return distancePointPolygon(p, geo);
327 };
328
329 43 const auto& geo = intersection.geometry();
330
2/2
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 17 times.
86 if (const Scalar d = getDistance(geo.center(), surfaceData.surface); d < 1e-8 * diameter(geo))
331 {
332 // no snapping required, face already lies on surface
333 surfaceAlreadyOnFaces = true;
334 snappingOcurred = false;
335 }
336
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 8 times.
26 else if (d < distance)
337 {
338 distance = d;
339 snappingOcurred = true;
340
341 // move the surface boundaries
342
2/2
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 18 times.
66 for (int i = 0; i < surfaceData.surface.corners(); ++i)
343 {
344 48 const auto& faceCenter = geo.center();
345 96 surfaceLowerLeft[surfaceData.normalDirectionIndex] = faceCenter[surfaceData.normalDirectionIndex];
346 144 surfaceUpperRight[surfaceData.normalDirectionIndex] = faceCenter[surfaceData.normalDirectionIndex];
347 }
348 }
349 }
350 }
351
352
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 17 times.
25 if (snappingOcurred)
353 {
354
2/4
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 8 times.
✗ Branch 7 not taken.
24 std::cout << "\n\nSurface '" << name << "' was automatically snapped to the closest faces" << std::endl;
355
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 std::cout << "Old surface boundaries: " << std::endl;
356
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 printSurfaceBoundaries_(surfaceData.surface);
357
358 // overwrite the old surface with the new boundaries
359
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
16 auto inSurfaceAxes = std::move(std::bitset<dimWorld>{}.set());
360
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 inSurfaceAxes.set(surfaceData.normalDirectionIndex, false);
361 8 surfaceData.surface = Surface{surfaceLowerLeft, surfaceUpperRight, inSurfaceAxes};
362
363
1/2
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
16 std::cout << "New surface boundaries: " << std::endl;
364
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 printSurfaceBoundaries_(surfaceData.surface);
365
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 std::cout << std::endl;
366 }
367 }
368 9 }
369
370 16 void printSurfaceBoundaries_(const Surface& surface) const
371 {
372
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 16 times.
60 for (int i = 0; i < surface.corners(); ++i)
373 88 std::cout << surface.corner(i) << std::endl;
374 16 }
375
376
9/18
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1214 times.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 12 taken 13 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 12 times.
✓ Branch 15 taken 13 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 12 times.
✓ Branch 18 taken 5 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 4 times.
✗ Branch 21 not taken.
1300 const auto& problem_() const { return gridVariables_.curGridVolVars().problem(); }
377
378 std::map<std::string, SurfaceData> surfaces_;
379 const GridVariables& gridVariables_;
380 const SolutionVector& sol_;
381 const LocalResidual localResidual_; // store a copy of the local residual
382 bool verbose_;
383 };
384
385 } // end namespace Dumux
386
387 #endif
388