3.2-git
DUNE for Multi-{Phase, Component, Scale, Physics, ...} flow and transport in porous media
enrichmenthelper.hh
Go to the documentation of this file.
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 * See the file COPYING for full copying permissions. *
5 * *
6 * This program is free software: you can redistribute it and/or modify *
7 * it under the terms of the GNU General Public License as published by *
8 * the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
18 *****************************************************************************/
19
25#ifndef DUMUX_VERTEX_ENRICHMENT_HELPER_HH
26#define DUMUX_VERTEX_ENRICHMENT_HELPER_HH
27
28#include <cmath>
29#include <vector>
30#include <unordered_map>
31#include <unordered_set>
32
33#include <dune/common/exceptions.hh>
34#include <dune/common/reservedvector.hh>
35
36#include <dune/geometry/referenceelements.hh>
37#include <dune/grid/common/mcmgmapper.hh>
38
39#include <dumux/common/math.hh>
41
42namespace Dumux {
43
55template< class GridView, class CodimOneGridView >
57{
58 static constexpr int dim = GridView::dimension;
59 static constexpr int dimWorld = GridView::dimensionworld;
60 static_assert(dim == 2 || dim == 3, "Grid dimension must be two or three");
61 static_assert(dimWorld == int(CodimOneGridView::dimensionworld), "world dimension mismatch");
62
63 using Intersection = typename GridView::Intersection;
64 using ReferenceElements = typename Dune::ReferenceElements<typename GridView::ctype, dim>;
65 using MCMGMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GridView>;
66 using GridIndexType = typename IndexTraits<GridView>::GridIndex;
67 using Element = typename GridView::template Codim<0>::Entity;
68 using GlobalPosition = typename Element::Geometry::GlobalCoordinate;
69
70 using ElementPath = std::vector< GridIndexType >;
71 using NodalElementPaths = std::vector< std::vector<ElementPath> >;
72
73public:
74
90 template< class IndexMap, class CodimOneGridAdapter >
91 static std::size_t enrich(IndexMap& indexMap,
92 const std::vector<bool>& vertexMarkers,
93 const GridView& gridView,
94 const MCMGMapper& vertexMapper,
95 const MCMGMapper& elementMapper,
96 const CodimOneGridView& codimOneGridView,
97 const CodimOneGridAdapter& codimOneGridAdapter)
98 {
99 // determine the bulk element paths around vertices marked for enrichment
100 NodalElementPaths nodalPaths(gridView.size(dim));
101 for (const auto& e : elements(gridView))
102 {
103 const auto eIdx = elementMapper.index(e);
104
105 std::vector<unsigned int> handledFacets;
106 const auto refElement = ReferenceElements::general(e.type());
107 for (const auto& is : intersections(gridView, e))
108 {
109 // do not start path search on boundary intersections
110 if (!is.neighbor())
111 continue;
112
113 // if facet has been handled already, skip rest (necesary for e.g. Dune::FoamGrid)
114 if (std::find(handledFacets.begin(), handledFacets.end(), is.indexInInside()) != handledFacets.end())
115 continue;
116
117 // first, get indices of all vertices of this intersection
118 const auto numCorners = is.geometry().corners();
119 std::vector<GridIndexType> faceVertexIndices(numCorners);
120 for (int i = 0; i < numCorners; ++i)
121 faceVertexIndices[i] = vertexMapper.subIndex( e,
122 refElement.subEntity(is.indexInInside(), 1, i, dim),
123 dim );
124
125 // start path search on intersections that lie on a facet grid element
126 if (codimOneGridAdapter.composeFacetElement(faceVertexIndices))
127 {
128 handledFacets.push_back(is.indexInInside());
129 for (int i = 0; i < numCorners; ++i)
130 {
131 // set up path only around those vertices that are to be enriched
132 const auto vIdxGlobal = faceVertexIndices[i];
133 if (!vertexMarkers[vIdxGlobal])
134 continue;
135
136 // construct the path only if element is not yet contained in another path
137 bool found = false;
138 for (const auto& path : nodalPaths[vIdxGlobal])
139 if (std::find(path.begin(), path.end(), eIdx) != path.end())
140 { found = true; break; }
141
142 if (!found)
143 {
144 ElementPath path;
145
146 // Reserve enough memory so that reallocation during the recursive search
147 // does not happen and references are invalidated. Memory is not an issue
148 // here as after enrichment the container is thrown away again.
149 // TODO improve this!?
150 path.reserve(150);
151 path.push_back(eIdx);
152 continuePathSearch_(path, gridView, elementMapper, vertexMapper, codimOneGridAdapter, e, refElement, is, vIdxGlobal);
153 nodalPaths[vIdxGlobal].emplace_back(std::move(path));
154 }
155 }
156 }
157 }
158 }
159
160 // determine the offsets for each bulk vertex index on the basis of the paths found per vertex
161 std::vector<std::size_t> bulkVertexIndexOffsets(gridView.size(dim), 0);
162 for (const auto& v : vertices(gridView))
163 {
164 const auto vIdx = vertexMapper.index(v);
165 if (vertexMarkers[vIdx])
166 bulkVertexIndexOffsets[vIdx] = nodalPaths[vIdx].size()-1;
167 }
168
169 // ... and accumulate the offsets
170 std::size_t sumOffset = 0;
171 std::size_t size = 0;
172 for (auto& nodalOffset : bulkVertexIndexOffsets)
173 {
174 const auto os = nodalOffset;
175 nodalOffset = sumOffset;
176 sumOffset += os;
177 size += (os == 0) ? 1 : os + 1;
178 }
179
180 // Now, finally set up the new index map
181 for (const auto& e : elements(gridView))
182 {
183 const auto& eg = e.geometry();
184 const auto eIdx = elementMapper.index(e);
185 for (int i = 0; i < eg.corners(); ++i)
186 {
187 const auto origVIdx = vertexMapper.subIndex(e, i, dim);
188
189 // it the node itself is not enriched, simply add offset
190 if (!vertexMarkers[origVIdx])
191 indexMap[eIdx][i] += bulkVertexIndexOffsets[origVIdx];
192
193 // find the local index of the path the element belongs to
194 else
195 {
196 bool found = false;
197 const auto& paths = nodalPaths[ origVIdx ];
198 for (int pathIdx = 0; pathIdx < paths.size(); ++pathIdx)
199 {
200 const auto& curPath = paths[pathIdx];
201 if ( std::find(curPath.begin(), curPath.end(), eIdx) != curPath.end() )
202 {
203 indexMap[eIdx][i] += bulkVertexIndexOffsets[origVIdx] + pathIdx;
204 found = true;
205 break;
206 }
207 }
208
209 if (!found)
210 DUNE_THROW(Dune::InvalidStateException, "Element not found in any path");
211 }
212 }
213 }
214
215 // return the number of dofs after enrichment
216 return size;
217 }
218
219private:
220 template< class ReferenceElement, class CodimOneGridAdapter >
221 static void continuePathSearch_(ElementPath& path,
222 const GridView& gridView,
223 const MCMGMapper& elementMapper,
224 const MCMGMapper& vertexMapper,
225 const CodimOneGridAdapter& codimOneGridAdapter,
226 const Element& element,
227 const ReferenceElement& refElement,
228 const Intersection& prevIntersection,
229 GridIndexType vIdxGlobal)
230 {
231 // on 2d/3d grids, we need to find 1/2 more intersections at vertex
232 static constexpr int numIsToFind = dim == 3 ? 2 : 1;
233
234 // keep track of facets handled already while searching
235 unsigned int foundCounter = 0;
236 std::vector<unsigned int> handledFacets;
237 for (const auto& is : intersections(gridView, element))
238 {
239 // skip if on previous intersection again
240 if (is.indexInInside() == prevIntersection.indexInInside())
241 continue;
242
243 // skip intersection if handled already (necessary for e.g. Dune::FoamGrid)
244 if (std::count(handledFacets.begin(), handledFacets.end(), is.indexInInside()))
245 continue;
246
247 // determine all vertex indices of this face
248 const auto numCorners = is.geometry().corners();
249 std::vector<GridIndexType> faceVertexIndices(numCorners);
250 for (int i = 0; i < numCorners; ++i)
251 faceVertexIndices[i] = vertexMapper.subIndex( element,
252 refElement.subEntity(is.indexInInside(), 1, i, dim),
253 dim );
254
255 // we found another intersection at the vertex if it contains the vertex around which we rotate
256 if (std::find(faceVertexIndices.begin(), faceVertexIndices.end(), vIdxGlobal) != faceVertexIndices.end())
257 {
258 foundCounter++;
259 handledFacets.push_back(is.indexInInside());
260
261 // keep searching in the outside element only if ...
262 // ... this is a not (processor) boundary
263 if (!is.neighbor())
264 continue;
265
266 // ... this face does not lie on the facet grid
267 if (codimOneGridAdapter.composeFacetElement(faceVertexIndices))
268 continue;
269
270 // ... outside element is not contained yet in path
271 const auto outsideElement = is.outside();
272 const auto outsideElemIdx = elementMapper.index(outsideElement);
273 if (std::find(path.begin(), path.end(), outsideElemIdx) == path.end())
274 {
275 const auto idxInOutside = is.indexInOutside();
276 const auto outsideRefElement = ReferenceElements::general(outsideElement.type());
277 path.push_back(outsideElemIdx);
278
279 // on 2d grids, there is only going to be one more
280 for (const auto& outsideIs : intersections(gridView, outsideElement))
281 {
282 if (outsideIs.indexInInside() == idxInOutside)
283 {
284 // if this is the last intersection to find, return
285 if (foundCounter == numIsToFind)
286 return continuePathSearch_(path,
287 gridView,
288 elementMapper,
289 vertexMapper,
290 codimOneGridAdapter,
291 outsideElement,
292 outsideRefElement,
293 outsideIs,
294 vIdxGlobal);
295
296 // otherwise, put one more search on stack
297 else
298 continuePathSearch_(path,
299 gridView,
300 elementMapper,
301 vertexMapper,
302 codimOneGridAdapter,
303 outsideElement,
304 outsideRefElement,
305 outsideIs,
306 vIdxGlobal);
307 }
308 }
309 }
310 }
311 }
312
313 if (foundCounter != numIsToFind)
314 DUNE_THROW(Dune::InvalidStateException, "Found " << foundCounter << " instead of " << numIsToFind << " intersections around vertex");
315 }
316};
317
318} // end namespace Dumux
319
320#endif
Defines the index types used for grid and local indices.
Define some often used mathematical functions.
Definition: adapt.hh:29
typename GridView::IndexSet::IndexType GridIndex
Definition: indextraits.hh:39
Adapter that allows retrieving information on a d-dimensional grid for entities of a (d-1)-dimensiona...
Definition: codimonegridadapter.hh:53
bool composeFacetElement(const IndexStorage &bulkVertexIndices) const
Returns true if a given set of bulk vertex indices make up a facet grid element.
Definition: codimonegridadapter.hh:194
Specialization of the enrichment helper class for 2d grids. In this case, we look for two-dimensional...
Definition: enrichmenthelper.hh:57
static std::size_t enrich(IndexMap &indexMap, const std::vector< bool > &vertexMarkers, const GridView &gridView, const MCMGMapper &vertexMapper, const MCMGMapper &elementMapper, const CodimOneGridView &codimOneGridView, const CodimOneGridAdapter &codimOneGridAdapter)
Enriches the dof map subject to a (dim-1)-dimensional grid.
Definition: enrichmenthelper.hh:91