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 FacetCoupling | ||
10 | * \copydoc Dumux::FacetCouplingMapper | ||
11 | */ | ||
12 | #ifndef DUMUX_CCMPFA_FACETCOUPLING_MAPPER_HH | ||
13 | #define DUMUX_CCMPFA_FACETCOUPLING_MAPPER_HH | ||
14 | |||
15 | #include <dune/common/indices.hh> | ||
16 | #include <dune/common/float_cmp.hh> | ||
17 | |||
18 | #include <dumux/common/indextraits.hh> | ||
19 | #include <dumux/discretization/method.hh> | ||
20 | #include <dumux/multidomain/facet/couplingmapper.hh> | ||
21 | #include <dumux/multidomain/facet/couplingmapperbase.hh> | ||
22 | #include <dumux/multidomain/facet/codimonegridadapter.hh> | ||
23 | |||
24 | namespace Dumux { | ||
25 | |||
26 | /*! | ||
27 | * \ingroup FacetCoupling | ||
28 | * \brief Base class for the coupling mapper that sets up and stores | ||
29 | * the coupling maps between two domains of dimension d and (d-1). | ||
30 | * This specialization is for the bulk domain using the cell-centered | ||
31 | * scheme with multi-point flux approximation. | ||
32 | * | ||
33 | * \tparam BulkFVG The d-dimensional finite-volume grid geometry | ||
34 | * \tparam LowDimFVG The (d-1)-dimensional finite-volume grid geometry | ||
35 | * \tparam bulkId The index of the bulk grid within the hierarchy of grids | ||
36 | * \tparam lowDimId The index of the facet grid within the hierarchy of grids | ||
37 | */ | ||
38 | template<class BulkFVG, class LowDimFVG, std::size_t bulkId, std::size_t lowDimId> | ||
39 | 20 | class FacetCouplingMapper<BulkFVG, LowDimFVG, bulkId, lowDimId, DiscretizationMethods::CCMpfa> | |
40 | : public virtual FacetCouplingMapperBase<BulkFVG, LowDimFVG, bulkId, lowDimId> | ||
41 | { | ||
42 | using ParentType = FacetCouplingMapperBase<BulkFVG, LowDimFVG, bulkId, lowDimId>; | ||
43 | |||
44 | using BulkFVElementGeometry = typename BulkFVG::LocalView; | ||
45 | using BulkSubControlVolumeFace = typename BulkFVG::SubControlVolumeFace; | ||
46 | |||
47 | using BulkIndexType = typename IndexTraits<typename BulkFVG::GridView>::GridIndex; | ||
48 | using LowDimIndexType = typename IndexTraits<typename LowDimFVG::GridView>::GridIndex; | ||
49 | |||
50 | using LowDimElement = typename LowDimFVG::GridView::template Codim<0>::Entity; | ||
51 | using GlobalPosition = typename LowDimElement::Geometry::GlobalCoordinate; | ||
52 | static constexpr int lowDimDim = LowDimFVG::GridView::dimension; | ||
53 | |||
54 | public: | ||
55 | //! export domain ids | ||
56 | using ParentType::bulkGridId; | ||
57 | using ParentType::facetGridId; | ||
58 | |||
59 | /*! | ||
60 | * \brief Update coupling maps. This is the standard | ||
61 | * interface required by any mapper implementation. | ||
62 | * | ||
63 | * \param bulkFvGridGeometry The finite-volume grid geometry of the bulk grid | ||
64 | * \param lowDimFvGridGeometry The finite-volume grid geometry of the lower-dimensional grid | ||
65 | * \param embeddings Class that contains the embedments among the grids and entity insertion indices | ||
66 | */ | ||
67 | template< class Embeddings > | ||
68 | 16 | void update(const BulkFVG& bulkFvGridGeometry, | |
69 | const LowDimFVG& lowDimFvGridGeometry, | ||
70 | std::shared_ptr<const Embeddings> embeddings) | ||
71 | { | ||
72 | // forward to update function with instantiated vertex adapter | ||
73 | using GridAdapter = CodimOneGridAdapter<Embeddings, bulkGridId, facetGridId>; | ||
74 |
4/12✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 6 taken 16 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 16 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 16 times.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✗ Branch 16 not taken.
✗ Branch 17 not taken.
|
32 | update(bulkFvGridGeometry, lowDimFvGridGeometry, embeddings, GridAdapter(embeddings)); |
75 | 16 | } | |
76 | |||
77 | /*! | ||
78 | * \brief Update coupling maps. This is the standard | ||
79 | * interface required by any mapper implementation. | ||
80 | * | ||
81 | * \param bulkFvGridGeometry The finite-volume grid geometry of the bulk grid | ||
82 | * \param lowDimFvGridGeometry The finite-volume grid geometry of the lower-dimensional grid | ||
83 | * \param embeddings Class that contains the embedments among the grids and entity insertion indices | ||
84 | * \param codimOneGridAdapter Allows direct access to data on the bulk grid for lowdim grid entities | ||
85 | */ | ||
86 | template< class Embeddings, class CodimOneGridAdapter > | ||
87 | 16 | void update(const BulkFVG& bulkFvGridGeometry, | |
88 | const LowDimFVG& lowDimFvGridGeometry, | ||
89 | std::shared_ptr<const Embeddings> embeddings, | ||
90 | const CodimOneGridAdapter& codimOneGridAdapter) | ||
91 | { | ||
92 | // define the policy how to add map entries for given lowdim element and adjoined entity indices | ||
93 | 4276 | auto addCouplingEntryPolicy = [&] (auto&& adjoinedEntityIndices, | |
94 | const LowDimElement& lowDimElement, | ||
95 | const LowDimFVG& lowDimFvGridGeometry, | ||
96 | 508 | const BulkFVG& bulkFvGridGeometry) | |
97 | { | ||
98 | 1016 | const auto lowDimElemIdx = lowDimFvGridGeometry.elementMapper().index(lowDimElement); | |
99 | 1016 | auto& lowDimData = this->couplingMap_(facetGridId, bulkGridId)[lowDimElemIdx]; | |
100 | |||
101 | // determine corner indices (in bulk grid indices) | ||
102 | 508 | const auto& lowDimGeometry = lowDimElement.geometry(); | |
103 | 508 | const auto numElementCorners = lowDimElement.subEntities(lowDimDim); | |
104 |
1/2✓ Branch 2 taken 128 times.
✗ Branch 3 not taken.
|
1652 | std::vector<BulkIndexType> elemCornerIndices(numElementCorners); |
105 |
2/2✓ Branch 0 taken 1144 times.
✓ Branch 1 taken 508 times.
|
1652 | for (int i = 0; i < numElementCorners; ++i) |
106 |
2/6✓ Branch 1 taken 1144 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1144 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2288 | elemCornerIndices[i] = codimOneGridAdapter.bulkGridVertexIndex(lowDimElement.template subEntity<lowDimDim>(i)); |
107 | |||
108 | // Find the scvfs in the adjoined entities coinciding with the low dim element | ||
109 |
3/8✓ Branch 0 taken 64 times.
✓ Branch 1 taken 380 times.
✓ Branch 2 taken 64 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
1016 | auto fvGeometry = localView(bulkFvGridGeometry); |
110 |
4/4✓ Branch 0 taken 996 times.
✓ Branch 1 taken 508 times.
✓ Branch 2 taken 996 times.
✓ Branch 3 taken 508 times.
|
3516 | for (auto bulkElemIdx : adjoinedEntityIndices) |
111 | { | ||
112 |
1/2✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
|
1864 | const auto bulkElement = bulkFvGridGeometry.element(bulkElemIdx); |
113 |
1/2✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
|
996 | fvGeometry.bind(bulkElement); |
114 | |||
115 | 1992 | std::vector<BulkIndexType> embeddedScvfIndices; | |
116 |
5/6✓ Branch 0 taken 8552 times.
✓ Branch 1 taken 996 times.
✓ Branch 2 taken 8552 times.
✓ Branch 3 taken 996 times.
✓ Branch 4 taken 3072 times.
✗ Branch 5 not taken.
|
10544 | for (const auto& scvf : scvfs(fvGeometry)) |
117 | { | ||
118 | // for non-boundary faces, it suffices to check if one | ||
119 | // of the outside scv indices is in the set of embedments | ||
120 |
2/2✓ Branch 0 taken 8458 times.
✓ Branch 1 taken 94 times.
|
8552 | if (!scvf.boundary()) |
121 | { | ||
122 |
2/2✓ Branch 0 taken 2208 times.
✓ Branch 1 taken 6250 times.
|
42290 | if ( std::count(adjoinedEntityIndices.begin(), adjoinedEntityIndices.end(), scvf.outsideScvIdx()) ) |
123 |
1/2✓ Branch 1 taken 2208 times.
✗ Branch 2 not taken.
|
2208 | embeddedScvfIndices.push_back(scvf.index()); |
124 | } | ||
125 | |||
126 | // otherwise, do float comparison of element and scvf facet corner | ||
127 | else | ||
128 | { | ||
129 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
94 | const auto eps = lowDimGeometry.volume()*1e-8; |
130 |
1/2✓ Branch 1 taken 94 times.
✗ Branch 2 not taken.
|
110 | const auto diffVec = lowDimGeometry.center()-fvGeometry.facetCorner(scvf); |
131 | |||
132 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 54 times.
|
188 | if ( Dune::FloatCmp::eq<GlobalPosition, Dune::FloatCmp::CmpStyle::absolute>(diffVec, GlobalPosition(0.0), eps) ) |
133 |
1/2✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
|
40 | embeddedScvfIndices.push_back(scvf.index()); |
134 | } | ||
135 | } | ||
136 | |||
137 | // Error tracking. The boundary scvf detection might has to be improved for very fine grids!? | ||
138 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 996 times.
|
1992 | if ( embeddedScvfIndices.size() != numElementCorners ) |
139 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Could not find all coupling scvfs in embedment"); | |
140 | |||
141 | // add each dof in the low dim element to coupling stencil of the bulk element and vice versa | ||
142 |
2/4✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 996 times.
✗ Branch 5 not taken.
|
1992 | auto& bulkData = this->couplingMap_(bulkGridId, facetGridId)[bulkElemIdx]; |
143 |
4/10✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 996 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 996 times.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 996 times.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
|
3984 | const auto lowDimElementDofs = LowDimFVG::discMethod == DiscretizationMethods::box |
144 | ? this->extractNodalDofs_(lowDimElement, lowDimFvGridGeometry) | ||
145 | : std::vector<LowDimIndexType>( {lowDimElemIdx} ); | ||
146 | |||
147 | // add coupling info to all elements/scvfs in interaction volumes | ||
148 |
4/4✓ Branch 0 taken 996 times.
✓ Branch 1 taken 996 times.
✓ Branch 2 taken 996 times.
✓ Branch 3 taken 996 times.
|
3984 | for (auto dofIdx : lowDimElementDofs) |
149 |
4/4✓ Branch 0 taken 2248 times.
✓ Branch 1 taken 996 times.
✓ Branch 2 taken 2248 times.
✓ Branch 3 taken 996 times.
|
7484 | for (auto scvfIdx : embeddedScvfIndices) |
150 |
1/2✓ Branch 1 taken 768 times.
✗ Branch 2 not taken.
|
3728 | this->addCouplingsFromIV_(bulkFvGridGeometry, fvGeometry.scvf(scvfIdx), fvGeometry, lowDimElemIdx, dofIdx); |
151 | |||
152 | // sort the scvfs according to the corners of the low dim element if box is used | ||
153 | // that allows identifying which scvf flux enters which low dim scv later | ||
154 | if (LowDimFVG::discMethod == DiscretizationMethods::box) | ||
155 | { | ||
156 | const auto copy = embeddedScvfIndices; | ||
157 | |||
158 | for (unsigned int i = 0; i < numElementCorners; ++i) | ||
159 | { | ||
160 | const auto& scvf = fvGeometry.scvf(copy[i]); | ||
161 | auto it = std::find(elemCornerIndices.begin(), elemCornerIndices.end(), scvf.vertexIndex()); | ||
162 | assert(it != elemCornerIndices.end()); | ||
163 | embeddedScvfIndices[ std::distance(elemCornerIndices.begin(), it) ] = copy[i]; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | // add info on which scvfs coincide with which low dim element | ||
168 |
1/2✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
|
996 | auto& elemToScvfMap = bulkData.elementToScvfMap[lowDimElemIdx]; |
169 |
5/12✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 996 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 996 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 996 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 996 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
|
4980 | elemToScvfMap.insert(elemToScvfMap.end(), embeddedScvfIndices.begin(), embeddedScvfIndices.end()); |
170 | |||
171 | // add embedment | ||
172 |
1/2✓ Branch 1 taken 996 times.
✗ Branch 2 not taken.
|
996 | lowDimData.embedments.emplace_back( bulkElemIdx, std::move(embeddedScvfIndices) ); |
173 | } | ||
174 | }; | ||
175 | |||
176 | // let the parent do the update subject to the execution policy defined above | ||
177 |
2/6✓ Branch 2 taken 16 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 16 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
16 | ParentType::update_(bulkFvGridGeometry, lowDimFvGridGeometry, embeddings, addCouplingEntryPolicy); |
178 | |||
179 | // lambda to make a container unique | ||
180 | 28156 | auto makeUnique = [] (auto& c) | |
181 | { | ||
182 | 42234 | std::sort(c.begin(), c.end()); | |
183 | 70390 | c.erase( std::unique(c.begin(), c.end()), c.end() ); | |
184 | }; | ||
185 | |||
186 | // lambda to make bulk coupling map entry unique | ||
187 | 4102 | auto makeBulkMapEntryUnique = [&makeUnique] (auto& data) | |
188 | { | ||
189 | 2043 | makeUnique(data.second.couplingStencil); | |
190 | 2043 | makeUnique(data.second.couplingElementStencil); | |
191 | 6129 | std::for_each(data.second.dofToCouplingScvfMap.begin(), | |
192 | data.second.dofToCouplingScvfMap.end(), | ||
193 | 9484 | [&makeUnique] (auto& pair) { makeUnique(pair.second); }); | |
194 | }; | ||
195 | |||
196 | // make bulk map unique | ||
197 | 16 | auto& bulkCouplingData = this->couplingMap_(bulkGridId, facetGridId); | |
198 | 48 | std::for_each(bulkCouplingData.begin(), bulkCouplingData.end(), makeBulkMapEntryUnique); | |
199 | |||
200 | // coupling stencils might not be unique in lowdim domain | ||
201 | 16 | auto& lowDimCouplingData = this->couplingMap_(facetGridId, bulkGridId); | |
202 | 48 | std::for_each(lowDimCouplingData.begin(), | |
203 | lowDimCouplingData.end(), | ||
204 | 508 | [&makeUnique] (auto& pair) { makeUnique(pair.second.couplingStencil); }); | |
205 | 16 | } | |
206 | |||
207 | private: | ||
208 | void addCouplingsFromIV_(const BulkFVG& bulkFvGridGeometry, | ||
209 | const BulkSubControlVolumeFace& scvf, | ||
210 | const BulkFVElementGeometry& fvGeometry, | ||
211 | LowDimIndexType lowDimElemIdx, | ||
212 | LowDimIndexType lowDimDofIdx) | ||
213 | { | ||
214 |
1/2✓ Branch 1 taken 2248 times.
✗ Branch 2 not taken.
|
2248 | const auto& gridIvIndexSets = bulkFvGridGeometry.gridInteractionVolumeIndexSets(); |
215 | 2248 | if (bulkFvGridGeometry.vertexUsesSecondaryInteractionVolume(scvf.vertexIndex())) | |
216 | addCouplingsFromIVIndexSet_(gridIvIndexSets.secondaryIndexSet(scvf), fvGeometry, lowDimElemIdx, lowDimDofIdx); | ||
217 | else | ||
218 |
2/4✓ Branch 1 taken 2248 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2248 times.
✗ Branch 5 not taken.
|
4496 | addCouplingsFromIVIndexSet_(gridIvIndexSets.primaryIndexSet(scvf), fvGeometry, lowDimElemIdx, lowDimDofIdx); |
219 | } | ||
220 | |||
221 | template< class IVIndexSet > | ||
222 | 2248 | void addCouplingsFromIVIndexSet_(const IVIndexSet& indexSet, | |
223 | const BulkFVElementGeometry& fvGeometry, | ||
224 | LowDimIndexType lowDimElemIdx, | ||
225 | LowDimIndexType lowDimDofIdx) | ||
226 | { | ||
227 | 4496 | auto& lowDimData = this->couplingMap_(facetGridId, bulkGridId)[lowDimElemIdx]; | |
228 |
4/4✓ Branch 0 taken 24010 times.
✓ Branch 1 taken 2248 times.
✓ Branch 2 taken 24010 times.
✓ Branch 3 taken 2248 times.
|
33002 | for (auto bulkElemIdx : indexSet.gridScvIndices()) |
229 | { | ||
230 | 48020 | auto& bulkData = this->couplingMap_(bulkGridId, facetGridId)[bulkElemIdx]; | |
231 | |||
232 | 24010 | lowDimData.couplingStencil.push_back( bulkElemIdx ); | |
233 | 24010 | bulkData.couplingStencil.push_back( lowDimDofIdx ); | |
234 | 24010 | bulkData.couplingElementStencil.push_back( lowDimElemIdx ); | |
235 | } | ||
236 | |||
237 | // insert scvf couplings stemming from this interaction volume | ||
238 |
4/4✓ Branch 0 taken 65332 times.
✓ Branch 1 taken 2248 times.
✓ Branch 2 taken 65332 times.
✓ Branch 3 taken 2248 times.
|
139656 | for (auto scvfIdx : indexSet.gridScvfIndices()) |
239 | { | ||
240 | 65332 | const auto& scvf = fvGeometry.scvf(scvfIdx); | |
241 | 130664 | auto& bulkData = this->couplingMap_(bulkGridId, facetGridId)[scvf.insideScvIdx()]; | |
242 | 65332 | auto& couplingScvfs = bulkData.dofToCouplingScvfMap[lowDimDofIdx]; | |
243 | 195996 | couplingScvfs.insert(couplingScvfs.end(), scvfIdx); | |
244 | } | ||
245 | 2248 | } | |
246 | }; | ||
247 | |||
248 | } // end namespace Dumux | ||
249 | |||
250 | #endif | ||
251 |