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 BoxDFMModel | ||
10 | * \brief Base class for the finite volume geometry vector for box schemes that consider | ||
11 | * extra connectivity between grid vertices on marked codim one entities. | ||
12 | * | ||
13 | * On these, an additional scvf is created accounting for the additional exchange fluxes | ||
14 | * between these degrees of freedom. | ||
15 | */ | ||
16 | |||
17 | #ifndef DUMUX_POROUSMEDIUMFLOW_BOXDFM_GRID_FVGEOMETRY_HH | ||
18 | #define DUMUX_POROUSMEDIUMFLOW_BOXDFM_GRID_FVGEOMETRY_HH | ||
19 | |||
20 | #include <utility> | ||
21 | #include <unordered_map> | ||
22 | |||
23 | #include <dune/localfunctions/lagrange/lagrangelfecache.hh> | ||
24 | #include <dune/geometry/multilineargeometry.hh> | ||
25 | #include <dune/grid/common/mcmgmapper.hh> | ||
26 | |||
27 | #include <dumux/discretization/method.hh> | ||
28 | #include <dumux/common/defaultmappertraits.hh> | ||
29 | #include <dumux/discretization/basegridgeometry.hh> | ||
30 | #include <dumux/discretization/box/boxgeometryhelper.hh> | ||
31 | #include <dumux/discretization/extrusion.hh> | ||
32 | |||
33 | #include "fvelementgeometry.hh" | ||
34 | #include "geometryhelper.hh" | ||
35 | #include "subcontrolvolume.hh" | ||
36 | #include "subcontrolvolumeface.hh" | ||
37 | |||
38 | namespace Dumux { | ||
39 | |||
40 | namespace Detail { | ||
41 | template<class GV, class T> | ||
42 | using BoxDfmGeometryHelper_t = Dune::Std::detected_or_t< | ||
43 | Dumux::BoxDfmGeometryHelper<GV, GV::dimension, typename T::SubControlVolume, typename T::SubControlVolumeFace>, | ||
44 | SpecifiesGeometryHelper, | ||
45 | T | ||
46 | >; | ||
47 | } // end namespace Detail | ||
48 | |||
49 | /*! | ||
50 | * \ingroup BoxDFMModel | ||
51 | * \brief The default traits for the box finite volume grid geometry | ||
52 | * | ||
53 | * Defines the scv and scvf types and the mapper types. | ||
54 | * | ||
55 | * \tparam the grid view type | ||
56 | */ | ||
57 | template<class GridView, class MapperTraits = DefaultMapperTraits<GridView>> | ||
58 | struct BoxDfmDefaultGridGeometryTraits | ||
59 | : public MapperTraits | ||
60 | { | ||
61 | using SubControlVolume = BoxDfmSubControlVolume<GridView>; | ||
62 | using SubControlVolumeFace = BoxDfmSubControlVolumeFace<GridView>; | ||
63 | |||
64 | template<class GridGeometry, bool enableCache> | ||
65 | using LocalView = BoxDfmFVElementGeometry<GridGeometry, enableCache>; | ||
66 | |||
67 | // Mapper type for mapping edges | ||
68 | using FacetMapper = Dune::MultipleCodimMultipleGeomTypeMapper<GridView>; | ||
69 | }; | ||
70 | |||
71 | /*! | ||
72 | * \ingroup BoxDFMModel | ||
73 | * \brief Base class for the finite volume geometry vector for box schemes | ||
74 | * | ||
75 | * This builds up the sub control volumes and sub control volume faces | ||
76 | * | ||
77 | * \note This class is specialized for versions with and without caching the fv geometries on the grid view | ||
78 | */ | ||
79 | template<class Scalar, | ||
80 | class GridView, | ||
81 | bool enableGridGeometryCache = false, | ||
82 | class Traits = BoxDfmDefaultGridGeometryTraits<GridView> > | ||
83 | class BoxDfmFVGridGeometry; | ||
84 | |||
85 | /*! | ||
86 | * \ingroup BoxDFMModel | ||
87 | * \brief Base class for the finite volume geometry vector for box schemes that consider | ||
88 | * extra connectivity between grid vertices on marked codim one entities. | ||
89 | * | ||
90 | * On these, an additional scvf is created accounting for the additional exchange fluxes | ||
91 | * between these degrees of freedom. | ||
92 | * | ||
93 | * \note For caching enabled we store the fv geometries for the whole grid view which is memory intensive but faster | ||
94 | */ | ||
95 | template<class Scalar, class GV, class Traits> | ||
96 | class BoxDfmFVGridGeometry<Scalar, GV, true, Traits> | ||
97 | : public BaseGridGeometry<GV, Traits> | ||
98 | { | ||
99 | using ThisType = BoxDfmFVGridGeometry<Scalar, GV, true, Traits>; | ||
100 | using ParentType = BaseGridGeometry<GV, Traits>; | ||
101 | using GridIndexType = typename GV::IndexSet::IndexType; | ||
102 | |||
103 | using Element = typename GV::template Codim<0>::Entity; | ||
104 | using CoordScalar = typename GV::ctype; | ||
105 | static const int dim = GV::dimension; | ||
106 | static const int dimWorld = GV::dimensionworld; | ||
107 | static_assert(dim == 2 || dim == 3, "The box-dfm GridGeometry is only implemented in 2 or 3 dimensions."); | ||
108 | |||
109 | public: | ||
110 | //! export the discretization method this geometry belongs to | ||
111 | using DiscretizationMethod = DiscretizationMethods::Box; | ||
112 | static constexpr DiscretizationMethod discMethod{}; | ||
113 | |||
114 | //! Export the type of the fv element geometry (the local view type) | ||
115 | using LocalView = typename Traits::template LocalView<ThisType, true>; | ||
116 | //! Export the type of sub control volume | ||
117 | using SubControlVolume = typename Traits::SubControlVolume; | ||
118 | //! Export the type of sub control volume | ||
119 | using SubControlVolumeFace = typename Traits::SubControlVolumeFace; | ||
120 | //! Export the extrusion type | ||
121 | using Extrusion = Extrusion_t<Traits>; | ||
122 | //! Export dof mapper type | ||
123 | using DofMapper = typename Traits::VertexMapper; | ||
124 | //! Export the finite element cache type | ||
125 | using FeCache = Dune::LagrangeLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; | ||
126 | //! Export the grid view type | ||
127 | using GridView = GV; | ||
128 | //! export the geometry helper type | ||
129 | using GeometryHelper = Detail::BoxDfmGeometryHelper_t<GV, Traits>; | ||
130 | |||
131 | //! Constructor | ||
132 | template< class FractureGridAdapter > | ||
133 | BoxDfmFVGridGeometry(const GridView gridView, const FractureGridAdapter& fractureGridAdapter) | ||
134 | : ParentType(gridView) | ||
135 | { | ||
136 | update_(fractureGridAdapter); | ||
137 | } | ||
138 | |||
139 | //! The vertex mapper is the dofMapper | ||
140 | //! This is convenience to have better chance to have the same main files for box/tpfa/mpfa... | ||
141 | const DofMapper& dofMapper() const | ||
142 | { return this->vertexMapper(); } | ||
143 | |||
144 | //! The total number of sub control volumes | ||
145 | std::size_t numScv() const | ||
146 | { return numScv_; } | ||
147 | |||
148 | //! The total number of sun control volume faces | ||
149 | std::size_t numScvf() const | ||
150 | { return numScvf_; } | ||
151 | |||
152 | //! The total number of boundary sub control volume faces | ||
153 | //! For compatibility reasons with cc methods | ||
154 | std::size_t numBoundaryScvf() const | ||
155 | { return numBoundaryScvf_; } | ||
156 | |||
157 | //! The total number of degrees of freedom | ||
158 | std::size_t numDofs() const | ||
159 | { return this->gridView().size(dim); } | ||
160 | |||
161 | //! update all fvElementGeometries (call this after grid adaption) | ||
162 | template< class FractureGridAdapter > | ||
163 | void update(const GridView& gridView, const FractureGridAdapter& fractureGridAdapter) | ||
164 | { | ||
165 | ParentType::update(gridView); | ||
166 | update_(fractureGridAdapter); | ||
167 | } | ||
168 | |||
169 | //! update all fvElementGeometries (call this after grid adaption) | ||
170 | template< class FractureGridAdapter > | ||
171 | void update(GridView&& gridView, const FractureGridAdapter& fractureGridAdapter) | ||
172 | { | ||
173 | ParentType::update(std::move(gridView)); | ||
174 | update_(fractureGridAdapter); | ||
175 | } | ||
176 | |||
177 | //! The finite element cache for creating local FE bases | ||
178 | const FeCache& feCache() const { return feCache_; } | ||
179 | //! Get the local scvs for an element | ||
180 | const std::vector<SubControlVolume>& scvs(GridIndexType eIdx) const { return scvs_[eIdx]; } | ||
181 | //! Get the local scvfs for an element | ||
182 | const std::vector<SubControlVolumeFace>& scvfs(GridIndexType eIdx) const { return scvfs_[eIdx]; } | ||
183 | //! If a vertex / d.o.f. is on the boundary | ||
184 | bool dofOnBoundary(unsigned int dofIdx) const { return boundaryDofIndices_[dofIdx]; } | ||
185 | //! If a vertex / d.o.f. is on a fracture | ||
186 | bool dofOnFracture(unsigned int dofIdx) const { return fractureDofIndices_[dofIdx]; } | ||
187 | //! Periodic boundaries are not supported for the box-dfm scheme | ||
188 | bool dofOnPeriodicBoundary(std::size_t dofIdx) const { return false; } | ||
189 | |||
190 | //! The index of the vertex / d.o.f. on the other side of the periodic boundary | ||
191 | std::size_t periodicallyMappedDof(std::size_t dofIdx) const | ||
192 | { DUNE_THROW(Dune::InvalidStateException, "Periodic boundaries are not supported by the box-dfm scheme"); } | ||
193 | |||
194 | //! Returns the map between dofs across periodic boundaries | ||
195 | [[deprecated("Will be removed after release 3.9. Implement periodicDofMap() if periodic bcs are supported.")]] | ||
196 | std::unordered_map<std::size_t, std::size_t> periodicVertexMap() const | ||
197 | { return std::unordered_map<std::size_t, std::size_t>(); } | ||
198 | |||
199 | private: | ||
200 | |||
201 | template< class FractureGridAdapter > | ||
202 | void update_(const FractureGridAdapter& fractureGridAdapter) | ||
203 | { | ||
204 | scvs_.clear(); | ||
205 | scvfs_.clear(); | ||
206 | |||
207 | auto numElements = this->gridView().size(0); | ||
208 | scvs_.resize(numElements); | ||
209 | scvfs_.resize(numElements); | ||
210 | |||
211 | boundaryDofIndices_.assign(numDofs(), false); | ||
212 | fractureDofIndices_.assign(this->gridView.size(dim), false); | ||
213 | |||
214 | numScv_ = 0; | ||
215 | numScvf_ = 0; | ||
216 | numBoundaryScvf_ = 0; | ||
217 | // Build the SCV and SCV faces | ||
218 | for (const auto& element : elements(this->gridView())) | ||
219 | { | ||
220 | // fill the element map with seeds | ||
221 | auto eIdx = this->elementMapper().index(element); | ||
222 | |||
223 | // count | ||
224 | numScv_ += element.subEntities(dim); | ||
225 | numScvf_ += element.subEntities(dim-1); | ||
226 | |||
227 | // get the element geometry | ||
228 | auto elementGeometry = element.geometry(); | ||
229 | const auto refElement = referenceElement(elementGeometry); | ||
230 | |||
231 | // instantiate the geometry helper | ||
232 | GeometryHelper geometryHelper(elementGeometry); | ||
233 | |||
234 | // construct the sub control volumes | ||
235 | scvs_[eIdx].resize(elementGeometry.corners()); | ||
236 | using LocalIndexType = typename SubControlVolumeFace::Traits::LocalIndexType; | ||
237 | for (LocalIndexType scvLocalIdx = 0; scvLocalIdx < elementGeometry.corners(); ++scvLocalIdx) | ||
238 | { | ||
239 | const auto dofIdxGlobal = this->vertexMapper().subIndex(element, scvLocalIdx, dim); | ||
240 | |||
241 | scvs_[eIdx][scvLocalIdx] = SubControlVolume(geometryHelper, | ||
242 | scvLocalIdx, | ||
243 | eIdx, | ||
244 | dofIdxGlobal); | ||
245 | } | ||
246 | |||
247 | // construct the sub control volume faces | ||
248 | LocalIndexType scvfLocalIdx = 0; | ||
249 | scvfs_[eIdx].resize(element.subEntities(dim-1)); | ||
250 | for (; scvfLocalIdx < element.subEntities(dim-1); ++scvfLocalIdx) | ||
251 | { | ||
252 | // find the global and local scv indices this scvf is belonging to | ||
253 | std::vector<LocalIndexType> localScvIndices({static_cast<LocalIndexType>(refElement.subEntity(scvfLocalIdx, dim-1, 0, dim)), | ||
254 | static_cast<LocalIndexType>(refElement.subEntity(scvfLocalIdx, dim-1, 1, dim))}); | ||
255 | |||
256 | scvfs_[eIdx][scvfLocalIdx] = SubControlVolumeFace(geometryHelper, | ||
257 | element, | ||
258 | elementGeometry, | ||
259 | scvfLocalIdx, | ||
260 | std::move(localScvIndices)); | ||
261 | } | ||
262 | |||
263 | // construct the ... | ||
264 | // ... sub-control volume faces on the domain boundary | ||
265 | // ... sub-control volumes on fracture facets | ||
266 | // ... sub-control volume faces on fracture facets | ||
267 | // NOTE We do not construct fracture scvfs on boundaries here! | ||
268 | // That means specifying Neumann fluxes on only the fractures is not possible | ||
269 | // However, it is difficult to interpret this here as a fracture ending on the boundary | ||
270 | // could also be connected to a facet which is both boundary and fracture at the same time! | ||
271 | // In that case, the fracture boundary scvf wouldn't make sense. In order to do it properly | ||
272 | // we would have to find only those fractures that are at the boundary and aren't connected | ||
273 | // to a fracture which is a boundary. | ||
274 | LocalIndexType scvLocalIdx = element.subEntities(dim); | ||
275 | for (const auto& intersection : intersections(this->gridView(), element)) | ||
276 | { | ||
277 | // first, obtain all vertex indices on this intersection | ||
278 | const auto& isGeometry = intersection.geometry(); | ||
279 | const auto numCorners = isGeometry.corners(); | ||
280 | const auto idxInInside = intersection.indexInInside(); | ||
281 | |||
282 | std::vector<GridIndexType> isVertexIndices(numCorners); | ||
283 | for (unsigned int vIdxLocal = 0; vIdxLocal < numCorners; ++vIdxLocal) | ||
284 | isVertexIndices[vIdxLocal] = this->vertexMapper().subIndex(element, | ||
285 | refElement.subEntity(idxInInside, 1, vIdxLocal, dim), | ||
286 | dim); | ||
287 | // maybe add boundary scvf | ||
288 | if (intersection.boundary() && !intersection.neighbor()) | ||
289 | { | ||
290 | numScvf_ += isGeometry.corners(); | ||
291 | numBoundaryScvf_ += isGeometry.corners(); | ||
292 | |||
293 | for (unsigned int isScvfLocalIdx = 0; isScvfLocalIdx < numCorners; ++isScvfLocalIdx) | ||
294 | { | ||
295 | // find the scvs this scvf is belonging to | ||
296 | const LocalIndexType insideScvIdx = static_cast<LocalIndexType>(refElement.subEntity(idxInInside, 1, isScvfLocalIdx, dim)); | ||
297 | std::vector<LocalIndexType> localScvIndices = {insideScvIdx, insideScvIdx}; | ||
298 | scvfs_[eIdx].emplace_back(geometryHelper, | ||
299 | intersection, | ||
300 | isGeometry, | ||
301 | isScvfLocalIdx, | ||
302 | scvfLocalIdx++, | ||
303 | std::move(localScvIndices)); | ||
304 | } | ||
305 | |||
306 | // add all vertices on the intersection to the set of | ||
307 | // boundary vertices | ||
308 | const auto numFaceVerts = refElement.size(idxInInside, 1, dim); | ||
309 | for (int localVIdx = 0; localVIdx < numFaceVerts; ++localVIdx) | ||
310 | { | ||
311 | const auto vIdx = refElement.subEntity(idxInInside, 1, localVIdx, dim); | ||
312 | const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdx, dim); | ||
313 | boundaryDofIndices_[vIdxGlobal] = true; | ||
314 | } | ||
315 | } | ||
316 | // make sure we have no periodic boundaries | ||
317 | else if (intersection.boundary() && intersection.neighbor()) | ||
318 | DUNE_THROW(Dune::InvalidStateException, "Periodic boundaries are not supported by the box-dfm scheme"); | ||
319 | |||
320 | // maybe add fracture scvs & scvfs | ||
321 | if (fractureGridAdapter.composeFacetElement(isVertexIndices)) | ||
322 | { | ||
323 | for (auto vIdx : isVertexIndices) | ||
324 | fractureDofIndices_[vIdx] = true; | ||
325 | |||
326 | // add fracture scv for each vertex of intersection | ||
327 | numScv_ += numCorners; | ||
328 | const auto curNumScvs = scvs_[eIdx].size(); | ||
329 | scvs_[eIdx].reserve(curNumScvs+numCorners); | ||
330 | for (unsigned int vIdxLocal = 0; vIdxLocal < numCorners; ++vIdxLocal) | ||
331 | scvs_[eIdx].emplace_back(geometryHelper, | ||
332 | intersection, | ||
333 | isGeometry, | ||
334 | vIdxLocal, | ||
335 | static_cast<LocalIndexType>(refElement.subEntity(idxInInside, 1, vIdxLocal, dim)), | ||
336 | scvLocalIdx++, | ||
337 | idxInInside, | ||
338 | eIdx, | ||
339 | isVertexIndices[vIdxLocal]); | ||
340 | |||
341 | // add fracture scvf for each edge of the intersection in 3d | ||
342 | if (dim == 3) | ||
343 | { | ||
344 | const auto& faceRefElement = referenceElement(isGeometry); | ||
345 | for (unsigned int edgeIdx = 0; edgeIdx < faceRefElement.size(1); ++edgeIdx) | ||
346 | { | ||
347 | // inside/outside scv indices in face local node numbering | ||
348 | std::vector<LocalIndexType> localScvIndices({static_cast<LocalIndexType>(faceRefElement.subEntity(edgeIdx, 1, 0, dim-1)), | ||
349 | static_cast<LocalIndexType>(faceRefElement.subEntity(edgeIdx, 1, 1, dim-1))}); | ||
350 | |||
351 | // add offset to get the right scv indices | ||
352 | std::for_each( localScvIndices.begin(), | ||
353 | localScvIndices.end(), | ||
354 | [curNumScvs] (auto& elemLocalIdx) { elemLocalIdx += curNumScvs; } ); | ||
355 | |||
356 | // add scvf | ||
357 | numScvf_++; | ||
358 | scvfs_[eIdx].emplace_back(geometryHelper, | ||
359 | intersection, | ||
360 | isGeometry, | ||
361 | edgeIdx, | ||
362 | scvfLocalIdx++, | ||
363 | std::move(localScvIndices), | ||
364 | intersection.boundary()); | ||
365 | } | ||
366 | } | ||
367 | |||
368 | // dim == 2, intersection is an edge, make 1 scvf | ||
369 | else | ||
370 | { | ||
371 | // inside/outside scv indices in face local node numbering | ||
372 | std::vector<LocalIndexType> localScvIndices({0, 1}); | ||
373 | |||
374 | // add offset such that the fracture scvs above are addressed | ||
375 | std::for_each( localScvIndices.begin(), | ||
376 | localScvIndices.end(), | ||
377 | [curNumScvs] (auto& elemLocalIdx) { elemLocalIdx += curNumScvs; } ); | ||
378 | |||
379 | // add scvf | ||
380 | numScvf_++; | ||
381 | scvfs_[eIdx].emplace_back(geometryHelper, | ||
382 | intersection, | ||
383 | isGeometry, | ||
384 | /*idxOnIntersection*/0, | ||
385 | scvfLocalIdx++, | ||
386 | std::move(localScvIndices), | ||
387 | intersection.boundary()); | ||
388 | } | ||
389 | } | ||
390 | } | ||
391 | } | ||
392 | } | ||
393 | |||
394 | const FeCache feCache_; | ||
395 | |||
396 | std::vector<std::vector<SubControlVolume>> scvs_; | ||
397 | std::vector<std::vector<SubControlVolumeFace>> scvfs_; | ||
398 | |||
399 | // TODO do we need those? | ||
400 | std::size_t numScv_; | ||
401 | std::size_t numScvf_; | ||
402 | std::size_t numBoundaryScvf_; | ||
403 | |||
404 | // vertices on the boundary & fracture facets | ||
405 | std::vector<bool> boundaryDofIndices_; | ||
406 | std::vector<bool> fractureDofIndices_; | ||
407 | }; | ||
408 | |||
409 | /*! | ||
410 | * \ingroup BoxDFMModel | ||
411 | * \brief Base class for the finite volume geometry vector for box schemes | ||
412 | * This builds up the sub control volumes and sub control volume faces | ||
413 | * \note For caching disabled we store only some essential index maps to build up local systems on-demand in | ||
414 | * the corresponding FVElementGeometry | ||
415 | */ | ||
416 | template<class Scalar, class GV, class Traits> | ||
417 | class BoxDfmFVGridGeometry<Scalar, GV, false, Traits> | ||
418 | : public BaseGridGeometry<GV, Traits> | ||
419 | { | ||
420 | using ThisType = BoxDfmFVGridGeometry<Scalar, GV, false, Traits>; | ||
421 | using ParentType = BaseGridGeometry<GV, Traits>; | ||
422 | using GridIndexType = typename GV::IndexSet::IndexType; | ||
423 | |||
424 | static const int dim = GV::dimension; | ||
425 | static const int dimWorld = GV::dimensionworld; | ||
426 | |||
427 | using Element = typename GV::template Codim<0>::Entity; | ||
428 | using Intersection = typename GV::Intersection; | ||
429 | using CoordScalar = typename GV::ctype; | ||
430 | |||
431 | public: | ||
432 | //! export the discretization method this geometry belongs to | ||
433 | using DiscretizationMethod = DiscretizationMethods::Box; | ||
434 | static constexpr DiscretizationMethod discMethod{}; | ||
435 | |||
436 | //! export the type of the fv element geometry (the local view type) | ||
437 | using LocalView = typename Traits::template LocalView<ThisType, false>; | ||
438 | //! export the type of sub control volume | ||
439 | using SubControlVolume = typename Traits::SubControlVolume; | ||
440 | //! export the type of sub control volume | ||
441 | using SubControlVolumeFace = typename Traits::SubControlVolumeFace; | ||
442 | //! Export the extrusion type | ||
443 | using Extrusion = Extrusion_t<Traits>; | ||
444 | //! export dof mapper type | ||
445 | using DofMapper = typename Traits::VertexMapper; | ||
446 | //! export the finite element cache type | ||
447 | using FeCache = Dune::LagrangeLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; | ||
448 | //! export the grid view type | ||
449 | using GridView = GV; | ||
450 | //! export the geometry helper type | ||
451 | using GeometryHelper = Detail::BoxDfmGeometryHelper_t<GV, Traits>; | ||
452 | |||
453 | //! Constructor | ||
454 | template< class FractureGridAdapter > | ||
455 | 6 | BoxDfmFVGridGeometry(const GridView gridView, const FractureGridAdapter& fractureGridAdapter) | |
456 | : ParentType(gridView) | ||
457 |
7/18✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 6 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 6 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 6 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 6 times.
✗ Branch 20 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 28 not taken.
✗ Branch 29 not taken.
|
12 | , facetMapper_(gridView, Dune::mcmgLayout(Dune::template Codim<1>())) |
458 | { | ||
459 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | update_(fractureGridAdapter); |
460 | 6 | } | |
461 | |||
462 | //! the vertex mapper is the dofMapper | ||
463 | //! this is convenience to have better chance to have the same main files for box/tpfa/mpfa... | ||
464 | const DofMapper& dofMapper() const | ||
465 |
8/33✗ 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 9 not taken.
✗ Branch 10 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
✗ Branch 15 not taken.
✗ Branch 16 not taken.
✗ Branch 18 not taken.
✗ Branch 19 not taken.
✗ Branch 21 not taken.
✗ Branch 22 not taken.
✗ Branch 24 not taken.
✗ Branch 25 not taken.
✓ Branch 27 taken 2 times.
✗ Branch 28 not taken.
✓ Branch 29 taken 1 times.
✓ Branch 30 taken 2 times.
✓ Branch 31 taken 2 times.
✓ Branch 32 taken 1 times.
✗ Branch 33 not taken.
✓ Branch 34 taken 2 times.
✗ Branch 35 not taken.
✓ Branch 37 taken 1 times.
✗ Branch 38 not taken.
✓ Branch 40 taken 1 times.
✗ Branch 41 not taken.
|
48022380 | { return this->vertexMapper(); } |
466 | |||
467 | //! The total number of sub control volumes | ||
468 | std::size_t numScv() const | ||
469 | { return numScv_; } | ||
470 | |||
471 | //! The total number of sun control volume faces | ||
472 | std::size_t numScvf() const | ||
473 | { return numScvf_; } | ||
474 | |||
475 | //! The total number of boundary sub control volume faces | ||
476 | //! For compatibility reasons with cc methods | ||
477 | std::size_t numBoundaryScvf() const | ||
478 | { return numBoundaryScvf_; } | ||
479 | |||
480 | //! The total number of degrees of freedom | ||
481 | std::size_t numDofs() const | ||
482 |
4/7✓ Branch 18 taken 3 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 3 times.
✓ Branch 21 taken 3 times.
✗ Branch 22 not taken.
✓ Branch 24 taken 3 times.
✗ Branch 25 not taken.
|
72 | { return this->gridView().size(dim); } |
483 | |||
484 | //! update all fvElementGeometries (call this after grid adaption) | ||
485 | template< class FractureGridAdapter > | ||
486 | void update(const GridView& gridView, const FractureGridAdapter& fractureGridAdapter) | ||
487 | { | ||
488 | ParentType::update(gridView); | ||
489 | updateFacetMapper_(); | ||
490 | update_(fractureGridAdapter); | ||
491 | } | ||
492 | |||
493 | //! update all fvElementGeometries (call this after grid adaption) | ||
494 | template< class FractureGridAdapter > | ||
495 | void update(GridView&& gridView, const FractureGridAdapter& fractureGridAdapter) | ||
496 | { | ||
497 | ParentType::update(std::move(gridView)); | ||
498 | updateFacetMapper_(); | ||
499 | update_(fractureGridAdapter); | ||
500 | } | ||
501 | |||
502 | //! The finite element cache for creating local FE bases | ||
503 |
2/3✓ Branch 4 taken 3617874 times.
✓ Branch 5 taken 758298 times.
✗ Branch 6 not taken.
|
16464312 | const FeCache& feCache() const { return feCache_; } |
504 | //! If a vertex / d.o.f. is on the boundary | ||
505 |
4/4✓ Branch 0 taken 683278 times.
✓ Branch 1 taken 7481330 times.
✓ Branch 2 taken 683278 times.
✓ Branch 3 taken 7481330 times.
|
16329216 | bool dofOnBoundary(unsigned int dofIdx) const { return boundaryDofIndices_[dofIdx]; } |
506 | //! If a vertex / d.o.f. is on a fracture | ||
507 |
4/4✓ Branch 0 taken 360 times.
✓ Branch 1 taken 3520 times.
✓ Branch 2 taken 360 times.
✓ Branch 3 taken 3520 times.
|
7760 | bool dofOnFracture(unsigned int dofIdx) const { return fractureDofIndices_[dofIdx]; } |
508 | //! Periodic boundaries are not supported for the box-dfm scheme | ||
509 | ✗ | bool dofOnPeriodicBoundary(std::size_t dofIdx) const { return false; } | |
510 | |||
511 | //! Returns true if an intersection coincides with a fracture element | ||
512 | 8761392 | bool isOnFracture(const Element& element, const Intersection& intersection) const | |
513 |
2/2✓ Branch 0 taken 154224 times.
✓ Branch 1 taken 3678624 times.
|
13142088 | { return facetOnFracture_[facetMapper_.subIndex(element, intersection.indexInInside(), 1)]; } |
514 | |||
515 | //! The index of the vertex / d.o.f. on the other side of the periodic boundary | ||
516 | ✗ | std::size_t periodicallyMappedDof(std::size_t dofIdx) const | |
517 | ✗ | { DUNE_THROW(Dune::InvalidStateException, "Periodic boundaries are not supported by the box-dfm scheme"); } | |
518 | |||
519 | //! Returns the map between dofs across periodic boundaries | ||
520 | [[deprecated("Will be removed after release 3.9. Implement periodicDofMap() if periodic bcs are supported.")]] | ||
521 | std::unordered_map<std::size_t, std::size_t> periodicVertexMap() const | ||
522 | { return std::unordered_map<std::size_t, std::size_t>(); } | ||
523 | |||
524 | private: | ||
525 | |||
526 | void updateFacetMapper_() | ||
527 | { | ||
528 | facetMapper_.update(this->gridView()); | ||
529 | } | ||
530 | |||
531 | template< class FractureGridAdapter > | ||
532 | 6 | void update_(const FractureGridAdapter& fractureGridAdapter) | |
533 | { | ||
534 | 6 | boundaryDofIndices_.assign(numDofs(), false); | |
535 | 6 | fractureDofIndices_.assign(numDofs(), false); | |
536 | 12 | facetOnFracture_.assign(this->gridView().size(1), false); | |
537 | |||
538 | // save global data on the grid's scvs and scvfs | ||
539 | // TODO do we need those information? | ||
540 | 6 | numScv_ = 0; | |
541 | 6 | numScvf_ = 0; | |
542 | 6 | numBoundaryScvf_ = 0; | |
543 |
10/12✓ Branch 2 taken 4426 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 4426 times.
✓ Branch 5 taken 3 times.
✓ Branch 6 taken 3 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 4426 times.
✓ Branch 9 taken 3 times.
✓ Branch 10 taken 4426 times.
✓ Branch 11 taken 3 times.
✓ Branch 13 taken 4426 times.
✗ Branch 14 not taken.
|
17716 | for (const auto& element : elements(this->gridView())) |
544 | { | ||
545 |
1/2✓ Branch 1 taken 4426 times.
✗ Branch 2 not taken.
|
8852 | numScv_ += element.subEntities(dim); |
546 |
1/2✓ Branch 1 taken 4426 times.
✗ Branch 2 not taken.
|
8852 | numScvf_ += element.subEntities(dim-1); |
547 | |||
548 |
2/4✓ Branch 1 taken 4426 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4426 times.
✗ Branch 5 not taken.
|
13278 | const auto elementGeometry = element.geometry(); |
549 |
1/2✓ Branch 1 taken 4426 times.
✗ Branch 2 not taken.
|
8852 | const auto refElement = referenceElement(elementGeometry); |
550 | |||
551 | // store the sub control volume face indices on the domain boundary | ||
552 |
7/15✓ Branch 1 taken 4426 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4426 times.
✓ Branch 4 taken 4426 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4426 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 40404 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✓ Branch 13 taken 15776 times.
✗ Branch 14 not taken.
✓ Branch 15 taken 15776 times.
✗ Branch 16 not taken.
|
98512 | for (const auto& intersection : intersections(this->gridView(), element)) |
553 | { | ||
554 | // first, obtain all vertex indices on this intersection | ||
555 |
2/4✓ Branch 1 taken 31552 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 31552 times.
✗ Branch 5 not taken.
|
63104 | const auto& isGeometry = intersection.geometry(); |
556 |
2/3✓ Branch 0 taken 1296 times.
✓ Branch 1 taken 30256 times.
✗ Branch 2 not taken.
|
31552 | const auto numCorners = isGeometry.corners(); |
557 |
2/3✓ Branch 0 taken 1296 times.
✓ Branch 1 taken 30256 times.
✗ Branch 2 not taken.
|
31552 | const auto idxInInside = intersection.indexInInside(); |
558 | |||
559 |
4/12✓ Branch 1 taken 31552 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 31552 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 31552 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 15776 times.
✗ Branch 9 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
126208 | std::vector<GridIndexType> isVertexIndices(numCorners); |
560 |
2/2✓ Branch 0 taken 80496 times.
✓ Branch 1 taken 31552 times.
|
112048 | for (unsigned int vIdxLocal = 0; vIdxLocal < numCorners; ++vIdxLocal) |
561 |
1/2✓ Branch 3 taken 80496 times.
✗ Branch 4 not taken.
|
160992 | isVertexIndices[vIdxLocal] = this->vertexMapper().subIndex(element, |
562 | refElement.subEntity(idxInInside, 1, vIdxLocal, dim), | ||
563 | dim); | ||
564 | |||
565 |
5/6✓ Branch 0 taken 3436 times.
✓ Branch 1 taken 13290 times.
✓ Branch 2 taken 14826 times.
✓ Branch 3 taken 950 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1900 times.
|
33452 | if (intersection.boundary() && !intersection.neighbor()) |
566 | { | ||
567 | 1900 | numScvf_ += numCorners; | |
568 | 1900 | numBoundaryScvf_ += numCorners; | |
569 | |||
570 | // add all vertices on the intersection to the set of | ||
571 | // boundary vertices | ||
572 |
2/3✓ Branch 0 taken 72 times.
✓ Branch 1 taken 1018 times.
✗ Branch 2 not taken.
|
1900 | const auto fIdx = intersection.indexInInside(); |
573 | 1900 | const auto numFaceVerts = refElement.size(fIdx, 1, dim); | |
574 |
2/2✓ Branch 1 taken 5420 times.
✓ Branch 2 taken 1900 times.
|
7320 | for (int localVIdx = 0; localVIdx < numFaceVerts; ++localVIdx) |
575 | { | ||
576 | 5420 | const auto vIdx = refElement.subEntity(fIdx, 1, localVIdx, dim); | |
577 |
2/4✓ Branch 1 taken 5420 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5420 times.
✗ Branch 5 not taken.
|
10840 | const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdx, dim); |
578 | 16260 | boundaryDofIndices_[vIdxGlobal] = true; | |
579 | } | ||
580 | } | ||
581 | |||
582 | // make sure we have no periodic boundaries | ||
583 |
2/6✓ Branch 0 taken 2486 times.
✓ Branch 1 taken 27166 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
29652 | else if (intersection.boundary() && intersection.neighbor()) |
584 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Periodic boundaries are not supported by the box-dfm scheme"); | |
585 | |||
586 | // maybe add fracture scvs & scvfs | ||
587 |
3/4✓ Branch 1 taken 31552 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 876 times.
✓ Branch 4 taken 30676 times.
|
31552 | if (fractureGridAdapter.composeFacetElement(isVertexIndices)) |
588 | { | ||
589 |
1/2✓ Branch 1 taken 876 times.
✗ Branch 2 not taken.
|
876 | facetOnFracture_[facetMapper_.subIndex(element, idxInInside, 1)] = true; |
590 |
4/4✓ Branch 0 taken 2192 times.
✓ Branch 1 taken 876 times.
✓ Branch 2 taken 2192 times.
✓ Branch 3 taken 876 times.
|
7012 | for (auto vIdx : isVertexIndices) |
591 | 6576 | fractureDofIndices_[vIdx] = true; | |
592 | |||
593 |
1/4✓ Branch 1 taken 876 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
1752 | const auto isGeometry = intersection.geometry(); |
594 |
2/3✓ Branch 0 taken 218 times.
✓ Branch 1 taken 440 times.
✗ Branch 2 not taken.
|
876 | numScv_ += isGeometry.corners(); |
595 |
4/7✓ Branch 0 taken 218 times.
✓ Branch 1 taken 440 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 220 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 220 times.
✗ Branch 6 not taken.
|
876 | numScvf_ += dim == 3 ? referenceElement(isGeometry).size(1) : 1; |
596 | } | ||
597 | } | ||
598 | } | ||
599 | 6 | } | |
600 | |||
601 | const FeCache feCache_; | ||
602 | |||
603 | // Information on the global number of geometries | ||
604 | // TODO do we need those information? | ||
605 | std::size_t numScv_; | ||
606 | std::size_t numScvf_; | ||
607 | std::size_t numBoundaryScvf_; | ||
608 | |||
609 | // vertices on the boundary & fracture facets | ||
610 | std::vector<bool> boundaryDofIndices_; | ||
611 | std::vector<bool> fractureDofIndices_; | ||
612 | |||
613 | // facet mapper and markers which facets lie on interior boundaries | ||
614 | typename Traits::FacetMapper facetMapper_; | ||
615 | std::vector<bool> facetOnFracture_; | ||
616 | }; | ||
617 | |||
618 | } // end namespace Dumux | ||
619 | |||
620 | #endif | ||
621 |