GCC Code Coverage Report


Directory: ../../../builds/dumux-repositories/
File: /builds/dumux-repositories/dumux/dumux/multidomain/boundary/freeflowporenetwork/couplingmapper.hh
Date: 2024-09-21 20:52:54
Exec Total Coverage
Lines: 131 134 97.8%
Functions: 9 10 90.0%
Branches: 186 262 71.0%

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 FreeFlowPoreNetworkCoupling
10 * \copydoc Dumux::StaggeredFreeFlowPoreNetworkCouplingMapper
11 */
12
13 #ifndef DUMUX_MULTIDOMAIN_FREEFLOW_POROUSMEDIUM_COUPLINGMAPPER_HH
14 #define DUMUX_MULTIDOMAIN_FREEFLOW_POROUSMEDIUM_COUPLINGMAPPER_HH
15
16 #include <algorithm>
17 #include <iostream>
18 #include <map>
19 #include <unordered_map>
20 #include <tuple>
21 #include <vector>
22
23 #include <dune/common/timer.hh>
24 #include <dune/common/exceptions.hh>
25 #include <dune/common/indices.hh>
26 #include <dune/common/reservedvector.hh>
27 #include <dune/geometry/axisalignedcubegeometry.hh>
28
29 #include <dumux/geometry/diameter.hh>
30 #include <dumux/geometry/intersectingentities.hh>
31 #include <dumux/discretization/method.hh>
32 #include <dumux/discretization/facecentered/staggered/normalaxis.hh>
33
34 namespace Dumux {
35
36 /*!
37 * \ingroup FreeFlowPoreNetworkCoupling
38 * \brief Coupling mapper for staggered free-flow and pore-network models.
39 */
40 // template<class MDTraits, class CouplingManager>
41 class StaggeredFreeFlowPoreNetworkCouplingMapper
42 {
43 using MapType = std::unordered_map<std::size_t, std::vector<std::size_t>>;
44
45 public:
46 /*!
47 * \brief Main update routine
48 */
49 template<class FreeFlowMomentumGridGeometry, class FreeFlowMassGridGeometry, class PoreNetworkGridGeometry>
50 2 void update(const FreeFlowMomentumGridGeometry& ffMomentumGridGeometry,
51 const FreeFlowMassGridGeometry& ffMassGridGeometry,
52 const PoreNetworkGridGeometry& pnmGridGeometry)
53 {
54 2 clear_();
55 2 resize_(ffMomentumGridGeometry, pnmGridGeometry);
56 2 Dune::Timer watch;
57 4 std::cout << "Initializing the coupling map..." << std::endl;
58
59 2 auto ffFvGeometry = localView(ffMomentumGridGeometry);
60 2 auto pnmFvGeometry = localView(pnmGridGeometry);
61
62 using GlobalPosition = typename FreeFlowMomentumGridGeometry::GridView::template Codim<0>::Entity::Geometry::GlobalCoordinate;
63
64
4/4
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 11 times.
✓ Branch 5 taken 2 times.
15 for (const auto& pnmElement : elements(pnmGridGeometry.gridView()))
65 {
66 22 const auto pnmElementIdx = pnmGridGeometry.elementMapper().index(pnmElement);
67 11 pnmFvGeometry.bindElement(pnmElement);
68
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 11 times.
33 for (const auto& pnmScv : scvs(pnmFvGeometry))
69 {
70 // skip the dof if it is not on the boundary
71
4/4
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 4 times.
44 if (!pnmGridGeometry.dofOnBoundary(pnmScv.dofIndex()))
72 18 continue;
73
74 // get the intersection bulk element
75 18 const auto pnmPos = pnmScv.dofPosition();
76 18 const auto pnmDofIdx = pnmScv.dofIndex();
77 18 const auto& otherPNMScv = pnmFvGeometry.scv(1 - pnmScv.indexInElement());
78 18 const auto otherPNMScvDofIdx = otherPNMScv.dofIndex();
79
80 // check for intersections, skip if no intersection was found
81 40 const auto directlyCoupledFreeFlowElements = intersectingEntities(pnmPos, ffMomentumGridGeometry.boundingBoxTree());
82
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 4 times.
36 if (directlyCoupledFreeFlowElements.empty())
83
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 continue;
84 else
85
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 isCoupledPNMDof_[pnmDofIdx] = true;
86
87 // determine the normal direction of the local coupling interface heuristically:
88 // find all element intersections touching the pore and take the normal which
89 // occurs most frequently
90 4 const std::size_t couplingNormalDirectionIndex = [&]
91 {
92 using Key = std::pair<std::size_t, bool>;
93 4 std::map<Key, std::size_t> result;
94
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
20 for (const auto eIdx : directlyCoupledFreeFlowElements)
95 {
96
3/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 16 times.
24 for (const auto& intersection : intersections(ffMomentumGridGeometry.gridView(), ffMomentumGridGeometry.element(eIdx)))
97 {
98
2/2
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 12 times.
16 if (intersectsPointGeometry(pnmPos, intersection.geometry()))
99 {
100 4 const auto& normal = intersection.centerUnitOuterNormal();
101 4 const auto normalAxis = Dumux::normalAxis(normal);
102
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
12 const Key key = std::make_pair(normalAxis, std::signbit(normal[normalAxis]));
103
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 ++result[key];
104 }
105 }
106 }
107
108 // TODO how to properly handle this corner (literally) case
109
4/8
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
8 if (directlyCoupledFreeFlowElements.size() == 1 && result.size() > 1)
110 DUNE_THROW(Dune::InvalidStateException, "Pore may not intersect with faces of different orientation when coupled to only one element");
111
112 12 return std::max_element(result.begin(), result.end(), [](const auto& x, const auto& y) { return x.second < y.second;})->first.first;
113
1/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
4 }();
114
115 using Scalar = typename FreeFlowMomentumGridGeometry::GridView::ctype;
116 4 const Scalar couplingPoreRadius = pnmGridGeometry.poreInscribedRadius(pnmDofIdx);
117 8 GlobalPosition lowerLeft = pnmPos - GlobalPosition(couplingPoreRadius);
118 8 lowerLeft[couplingNormalDirectionIndex] = pnmPos[couplingNormalDirectionIndex];
119 4 GlobalPosition upperRight = pnmPos + GlobalPosition(couplingPoreRadius);
120
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 upperRight[couplingNormalDirectionIndex] = pnmPos[couplingNormalDirectionIndex];
121
122
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 auto axes = std::move(std::bitset<FreeFlowMomentumGridGeometry::Grid::dimensionworld>{}.set());
123
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 axes.set(couplingNormalDirectionIndex, false);
124
125 using PoreIntersectionGeometryType = Dune::AxisAlignedCubeGeometry<Scalar,
126 FreeFlowMomentumGridGeometry::GridView::dimension-1,
127 FreeFlowMomentumGridGeometry::GridView::dimensionworld>;
128
129 4 PoreIntersectionGeometryType poreIntersectionGeometry(lowerLeft, upperRight, axes);
130
3/6
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 4 times.
✗ Branch 8 not taken.
12 const auto allCoupledFreeFlowElements = intersectingEntities(std::move(poreIntersectionGeometry), ffMomentumGridGeometry.boundingBoxTree());
131
132
133
4/4
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 4 times.
26 for (const auto& ffElementInfo : allCoupledFreeFlowElements)
134 {
135 14 const auto freeFlowElementIndex = ffElementInfo.second();
136
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 pnmElementToFreeFlowElementsMap_[pnmElementIdx].push_back(freeFlowElementIndex);
137
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 freeFlowElementToPNMElementMap_[freeFlowElementIndex] = pnmElementIdx;
138
139
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 pnmToFreeFlowMassStencils_[pnmElementIdx].push_back(freeFlowElementIndex);
140
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 freeFlowMassToPNMStencils_[freeFlowElementIndex].push_back(pnmDofIdx);
141
142
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 ffFvGeometry.bindElement(ffMomentumGridGeometry.element(freeFlowElementIndex));
143
1/2
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
14 const auto coupledFreeFlowMomentumDofIndices = coupledFFMomentumDofs_(ffFvGeometry, ffMassGridGeometry, pnmPos, couplingPoreRadius, couplingNormalDirectionIndex);
144
145
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 pnmToFreeFlowMomentumStencils_[pnmElementIdx].push_back(coupledFreeFlowMomentumDofIndices.coupledFrontalDof);
146
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 freeFlowMomentumToPNMStencils_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof].push_back(pnmDofIdx);
147
2/4
✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
14 freeFlowMomentumToPNMStencils_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof].push_back(otherPNMScvDofIdx);
148
149 28 isCoupledFreeFlowMomentumDof_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof] = true;
150 28 isCoupledFreeFlowMomentumDofOnInterface_[coupledFreeFlowMomentumDofIndices.coupledFrontalDof] = true;
151
152 // treat the coupled ff dofs not directly on interface
153
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 14 times.
70 for (const auto ffDofIdx : coupledFreeFlowMomentumDofIndices.coupledLateralDofs)
154 {
155
2/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
28 freeFlowMomentumToPNMStencils_[ffDofIdx].push_back(pnmDofIdx);
156
2/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
28 freeFlowMomentumToPNMStencils_[ffDofIdx].push_back(otherPNMScvDofIdx);
157 84 isCoupledFreeFlowMomentumDof_[ffDofIdx] = true;
158 }
159 }
160 }
161 }
162
163 6 std::cout << "took " << watch.elapsed() << " seconds." << std::endl;
164 2 }
165
166 /*!
167 * \brief returns an iterable container of all indices of degrees of freedom of domain j
168 * that couple with / influence the element residual of the given element of domain i
169 * \param eIdxI the index of the coupled element of domain í
170 */
171 41 const std::vector<std::size_t>& poreNetworkToFreeFlowMomentumCouplingStencil(const std::size_t eIdxI) const
172 {
173 82 if (isCoupledPoreNetworkElement(eIdxI))
174 40 return pnmToFreeFlowMomentumStencils_.at(eIdxI);
175 else
176 21 return emptyStencil_;
177 }
178
179 /*!
180 * \brief returns an iterable container of all indices of degrees of freedom of domain j
181 * that couple with / influence the element residual of the given element of domain i
182 * \param eIdxI the index of the coupled element of domain í
183 */
184 44 const std::vector<std::size_t>& poreNetworkToFreeFlowMassCouplingStencil(const std::size_t eIdxI) const
185 {
186 88 if (isCoupledPoreNetworkElement(eIdxI))
187 46 return pnmToFreeFlowMassStencils_.at(eIdxI);
188 else
189 21 return emptyStencil_;
190 }
191
192 /*!
193 * \brief returns an iterable container of all indices of degrees of freedom of domain j
194 * that couple with / influence the element residual of the given element of domain i
195 * \param eIdxI the index of the coupled element of domain i
196 */
197 1374 const std::vector<std::size_t>& freeFlowMassToPoreNetworkCouplingStencil(const std::size_t eIdxI) const
198 {
199 2748 if (isCoupledFreeFlowElement(eIdxI))
200 94 return freeFlowMassToPNMStencils_.at(eIdxI);
201 else
202 1327 return emptyStencil_;
203 }
204
205 /*!
206 * \brief returns an iterable container of all indices of degrees of freedom of domain j
207 * that couple with / influence the element residual of the given element of domain i
208 * \param dofIndex the degree of freedom index
209 */
210 5496 const std::vector<std::size_t>& freeFlowMomentumToPoreNetworkCouplingStencil(const std::size_t dofIndex) const
211 {
212 10992 if (isCoupledFreeFlowMomentumDof(dofIndex))
213 334 return freeFlowMomentumToPNMStencils_.at(dofIndex);
214 else
215 5329 return emptyStencil_;
216 }
217
218 /*!
219 * \brief Return if an element residual with index eIdx of domain i is coupled to domain j
220 */
221 bool isCoupledFreeFlowElement(std::size_t eIdx) const
222 {
223
8/8
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 933 times.
✓ Branch 6 taken 588 times.
✓ Branch 7 taken 72 times.
✓ Branch 10 taken 933 times.
✓ Branch 11 taken 42 times.
✓ Branch 13 taken 47 times.
✓ Branch 14 taken 1327 times.
63031 return static_cast<bool>(freeFlowElementToPNMElementMap_.count(eIdx));
224 }
225
226 /*!
227 * \brief Return if an element residual with index eIdx of domain i is coupled to domain j
228 */
229 bool isCoupledFreeFlowMomentumDof(std::size_t dofIdx) const
230 {
231
12/12
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 3714 times.
✓ Branch 6 taken 18 times.
✓ Branch 7 taken 3714 times.
✓ Branch 8 taken 167 times.
✓ Branch 9 taken 5329 times.
✓ Branch 10 taken 167 times.
✓ Branch 11 taken 5329 times.
18640 return isCoupledFreeFlowMomentumDof_[dofIdx];
232 }
233
234 /*!
235 * \brief Return if an element residual with index eIdx of domain i is coupled to domain j
236 */
237 bool isCoupledPoreNetworkElement(std::size_t eIdx) const
238 {
239
11/12
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 7 times.
✓ Branch 5 taken 36 times.
✓ Branch 6 taken 56 times.
✓ Branch 8 taken 66 times.
✗ Branch 9 not taken.
✓ Branch 12 taken 14 times.
✓ Branch 13 taken 10 times.
✓ Branch 15 taken 23 times.
✓ Branch 16 taken 21 times.
✓ Branch 18 taken 20 times.
✓ Branch 19 taken 21 times.
288 return static_cast<bool>(pnmElementToFreeFlowElementsMap_.count(eIdx));
240 }
241
242 /*!
243 * \brief Return if an element residual with index eIdx of domain i is coupled to domain j
244 */
245 bool isCoupledPoreNetworkDof(std::size_t dofIdx) const
246 {
247
16/16
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 51 times.
✓ Branch 3 taken 51 times.
✓ Branch 4 taken 42 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 42 times.
✓ Branch 7 taken 42 times.
✓ Branch 8 taken 168 times.
✓ Branch 9 taken 262 times.
✓ Branch 10 taken 168 times.
✓ Branch 11 taken 262 times.
✓ Branch 12 taken 14 times.
✓ Branch 13 taken 44 times.
✓ Branch 14 taken 14 times.
✓ Branch 15 taken 44 times.
1348 return isCoupledPNMDof_[dofIdx];
248 }
249
250 bool isCoupledFreeFlowMomentumScvf(std::size_t scvfIdx) const
251 {
252 return isCoupledFrontalFreeFlowMomentumScvf_.count(scvfIdx);
253 }
254
255 bool isCoupledFreeFlowMomentumLateralScvf(std::size_t scvfIdx) const
256 {
257 return isCoupledLateralFreeFlowMomentumScvf_.count(scvfIdx);
258 }
259
260 bool isCoupledFreeFlowMassScvf(std::size_t scvfIdx) const
261 {
262
8/8
✓ Branch 5 taken 32 times.
✓ Branch 6 taken 96 times.
✓ Branch 8 taken 405 times.
✓ Branch 9 taken 3151 times.
✓ Branch 11 taken 225 times.
✓ Branch 12 taken 1770 times.
✓ Branch 14 taken 288 times.
✓ Branch 15 taken 2409 times.
8376 return isCoupledFreeFlowMassScvf_.count(scvfIdx);
263 }
264
265 const auto& pnmElementToFreeFlowElementsMap() const
266 17 { return pnmElementToFreeFlowElementsMap_;}
267
268 const auto& freeFlowElementToPNMElementMap() const
269
1/2
✓ Branch 1 taken 51 times.
✗ Branch 2 not taken.
93 { return freeFlowElementToPNMElementMap_; }
270
271 private:
272
273 2 void clear_()
274 {
275 2 pnmElementToFreeFlowElementsMap_.clear();
276 2 freeFlowElementToPNMElementMap_.clear();
277 2 isCoupledPNMDof_.clear();
278 2 isCoupledFreeFlowMomentumDof_.clear();
279 2 isCoupledFreeFlowMomentumDofOnInterface_.clear();
280 2 pnmToFreeFlowMassStencils_.clear();
281 2 pnmToFreeFlowMomentumStencils_.clear();
282 2 freeFlowMassToPNMStencils_.clear();
283 2 freeFlowMomentumToPNMStencils_.clear();
284 2 }
285
286 template<class FreeFlowMomentumGridGeometry, class PoreNetworkGridGeometry>
287 2 void resize_(const FreeFlowMomentumGridGeometry& ffMomentumGridGeometry,
288 const PoreNetworkGridGeometry& pnmGridGeometry)
289 {
290 2 const auto numPNMDofs = pnmGridGeometry.numDofs();
291 2 const auto numFreeFlowMomentumDofs = ffMomentumGridGeometry.numDofs();
292 2 isCoupledPNMDof_.resize(numPNMDofs, false);
293 2 isCoupledFreeFlowMomentumDof_.resize(numFreeFlowMomentumDofs, false);
294 2 isCoupledFreeFlowMomentumDofOnInterface_.resize(numFreeFlowMomentumDofs, false);
295 2 }
296
297 //! get the free-flow momentum dofs that are coupled to the PNM dofs
298 template<class FVElementGeometry, class FreeFlowMassGridGeometry, class GlobalPosition, class Scalar>
299 14 auto coupledFFMomentumDofs_(const FVElementGeometry& fvGeometry,
300 const FreeFlowMassGridGeometry& ffMassGridGeometry,
301 const GlobalPosition& pnmPos,
302 const Scalar couplingPoreRadius,
303 const int couplingInterfaceDirectionIdx)
304 {
305
306 28 struct Result
307 {
308 Dune::ReservedVector<std::size_t, FVElementGeometry::maxNumElementScvs> coupledLateralDofs;
309 std::size_t coupledFrontalDof;
310 14 } result;
311
312
313 using std::abs;
314
4/4
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 14 times.
70 for (const auto& scv : scvs(fvGeometry))
315 {
316 56 const Scalar eps = diameter(fvGeometry.geometry(scv))*1e-6; // TODO
317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
56 assert(eps < couplingPoreRadius);
318
319
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 28 times.
56 if (scv.dofAxis() == couplingInterfaceDirectionIdx) // the free flow dofs that lie within the coupling interface
320 {
321
10/10
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 14 times.
✓ Branch 8 taken 14 times.
✓ Branch 9 taken 14 times.
140 if (abs(scv.dofPosition()[couplingInterfaceDirectionIdx] - pnmPos[couplingInterfaceDirectionIdx]) < eps)
322 {
323 14 result.coupledFrontalDof = scv.dofIndex();
324
325 // treat scvfs
326
4/4
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 56 times.
✓ Branch 4 taken 14 times.
70 for (const auto& scvf : scvfs(fvGeometry, scv))
327 {
328 // add lateral faces "standing" on coupling interface
329
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
56 if (scvf.isLateral() && !scvf.boundary())
330 28 isCoupledLateralFreeFlowMomentumScvf_[scvf.index()] = true;
331
3/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 14 times.
28 else if (scvf.isFrontal() && scvf.boundary()) // add face lying on interface
332 {
333 14 isCoupledFrontalFreeFlowMomentumScvf_[scvf.index()] = true;
334
335 28 const auto& element = ffMassGridGeometry.element(fvGeometry.elementIndex()); // this local variable is needed to prevent a memory error
336 28 const auto ffMassFVGeometry = localView(ffMassGridGeometry).bindElement(element);
337
6/6
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 42 times.
84 for (const auto& ffMassScvf : scvfs(ffMassFVGeometry))
338 {
339
10/10
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 14 times.
✓ Branch 5 taken 42 times.
✓ Branch 6 taken 14 times.
✓ Branch 7 taken 42 times.
✓ Branch 8 taken 14 times.
✓ Branch 9 taken 42 times.
280 if (abs(ffMassScvf.center()[couplingInterfaceDirectionIdx] - pnmPos[couplingInterfaceDirectionIdx]) < eps)
340 14 isCoupledFreeFlowMassScvf_[ffMassScvf.index()] = true;
341 }
342 }
343 }
344 }
345 }
346 else // the free flow dofs perpendicular to the coupling interface
347 {
348 bool isCoupledDof = false;
349
350
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 28 times.
84 for (int dimIdx = 0; dimIdx < GlobalPosition::dimension; ++dimIdx)
351 {
352
3/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
56 if (dimIdx == couplingInterfaceDirectionIdx || scv.boundary())
353 continue;
354
355 140 isCoupledDof = abs(scv.dofPosition()[dimIdx] - pnmPos[dimIdx]) < couplingPoreRadius + eps;
356 }
357
358
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (isCoupledDof)
359 {
360 28 result.coupledLateralDofs.push_back(scv.dofIndex());
361
362 // treat scvfs
363
4/4
✓ Branch 1 taken 84 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 28 times.
112 for (const auto& scvf : scvfs(fvGeometry, scv))
364 {
365
4/4
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 28 times.
84 if (scvf.isLateral() && scvf.boundary())
366 {
367 // add lateral scvfs lying on interface
368
5/10
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 28 times.
✗ Branch 9 not taken.
140 if (abs(scvf.ipGlobal()[couplingInterfaceDirectionIdx] - pnmPos[couplingInterfaceDirectionIdx]) < eps)
369 28 isCoupledLateralFreeFlowMomentumScvf_[scvf.index()] = true;
370 }
371 }
372 }
373 }
374 }
375
376 14 return result;
377 }
378
379 std::vector<std::size_t> emptyStencil_;
380
381 std::unordered_map<std::size_t, std::vector<std::size_t>> pnmElementToFreeFlowElementsMap_;
382 std::unordered_map<std::size_t, std::size_t> freeFlowElementToPNMElementMap_;
383
384 std::vector<bool> isCoupledPNMDof_;
385 std::vector<bool> isCoupledFreeFlowMomentumDof_;
386 std::vector<bool> isCoupledFreeFlowMomentumDofOnInterface_;
387
388 std::unordered_map<std::size_t, bool> isCoupledLateralFreeFlowMomentumScvf_;
389 std::unordered_map<std::size_t, bool> isCoupledFrontalFreeFlowMomentumScvf_;
390 std::unordered_map<std::size_t, bool> isCoupledFreeFlowMassScvf_;
391
392 MapType pnmToFreeFlowMassStencils_;
393 MapType pnmToFreeFlowMomentumStencils_;
394 MapType freeFlowMassToPNMStencils_;
395 MapType freeFlowMomentumToPNMStencils_;
396 };
397
398 } // end namespace Dumux
399
400 #endif
401