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 |