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-FileCopyrightText: 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 | private: | ||
195 | |||
196 | template< class FractureGridAdapter > | ||
197 | void update_(const FractureGridAdapter& fractureGridAdapter) | ||
198 | { | ||
199 | scvs_.clear(); | ||
200 | scvfs_.clear(); | ||
201 | |||
202 | auto numElements = this->gridView().size(0); | ||
203 | scvs_.resize(numElements); | ||
204 | scvfs_.resize(numElements); | ||
205 | |||
206 | boundaryDofIndices_.assign(numDofs(), false); | ||
207 | fractureDofIndices_.assign(this->gridView.size(dim), false); | ||
208 | |||
209 | numScv_ = 0; | ||
210 | numScvf_ = 0; | ||
211 | numBoundaryScvf_ = 0; | ||
212 | // Build the SCV and SCV faces | ||
213 | for (const auto& element : elements(this->gridView())) | ||
214 | { | ||
215 | // fill the element map with seeds | ||
216 | auto eIdx = this->elementMapper().index(element); | ||
217 | |||
218 | // count | ||
219 | numScv_ += element.subEntities(dim); | ||
220 | numScvf_ += element.subEntities(dim-1); | ||
221 | |||
222 | // get the element geometry | ||
223 | auto elementGeometry = element.geometry(); | ||
224 | const auto refElement = referenceElement(elementGeometry); | ||
225 | |||
226 | // instantiate the geometry helper | ||
227 | GeometryHelper geometryHelper(elementGeometry); | ||
228 | |||
229 | // construct the sub control volumes | ||
230 | scvs_[eIdx].resize(elementGeometry.corners()); | ||
231 | using LocalIndexType = typename SubControlVolumeFace::Traits::LocalIndexType; | ||
232 | for (LocalIndexType scvLocalIdx = 0; scvLocalIdx < elementGeometry.corners(); ++scvLocalIdx) | ||
233 | { | ||
234 | const auto dofIdxGlobal = this->vertexMapper().subIndex(element, scvLocalIdx, dim); | ||
235 | |||
236 | scvs_[eIdx][scvLocalIdx] = SubControlVolume(geometryHelper, | ||
237 | scvLocalIdx, | ||
238 | eIdx, | ||
239 | dofIdxGlobal); | ||
240 | } | ||
241 | |||
242 | // construct the sub control volume faces | ||
243 | LocalIndexType scvfLocalIdx = 0; | ||
244 | scvfs_[eIdx].resize(element.subEntities(dim-1)); | ||
245 | for (; scvfLocalIdx < element.subEntities(dim-1); ++scvfLocalIdx) | ||
246 | { | ||
247 | // find the global and local scv indices this scvf is belonging to | ||
248 | std::vector<LocalIndexType> localScvIndices({static_cast<LocalIndexType>(refElement.subEntity(scvfLocalIdx, dim-1, 0, dim)), | ||
249 | static_cast<LocalIndexType>(refElement.subEntity(scvfLocalIdx, dim-1, 1, dim))}); | ||
250 | |||
251 | scvfs_[eIdx][scvfLocalIdx] = SubControlVolumeFace(geometryHelper, | ||
252 | element, | ||
253 | elementGeometry, | ||
254 | scvfLocalIdx, | ||
255 | std::move(localScvIndices)); | ||
256 | } | ||
257 | |||
258 | // construct the ... | ||
259 | // ... sub-control volume faces on the domain boundary | ||
260 | // ... sub-control volumes on fracture facets | ||
261 | // ... sub-control volume faces on fracture facets | ||
262 | // NOTE We do not construct fracture scvfs on boundaries here! | ||
263 | // That means specifying Neumann fluxes on only the fractures is not possible | ||
264 | // However, it is difficult to interpret this here as a fracture ending on the boundary | ||
265 | // could also be connected to a facet which is both boundary and fracture at the same time! | ||
266 | // In that case, the fracture boundary scvf wouldn't make sense. In order to do it properly | ||
267 | // we would have to find only those fractures that are at the boundary and aren't connected | ||
268 | // to a fracture which is a boundary. | ||
269 | LocalIndexType scvLocalIdx = element.subEntities(dim); | ||
270 | for (const auto& intersection : intersections(this->gridView(), element)) | ||
271 | { | ||
272 | // first, obtain all vertex indices on this intersection | ||
273 | const auto& isGeometry = intersection.geometry(); | ||
274 | const auto numCorners = isGeometry.corners(); | ||
275 | const auto idxInInside = intersection.indexInInside(); | ||
276 | |||
277 | std::vector<GridIndexType> isVertexIndices(numCorners); | ||
278 | for (unsigned int vIdxLocal = 0; vIdxLocal < numCorners; ++vIdxLocal) | ||
279 | isVertexIndices[vIdxLocal] = this->vertexMapper().subIndex(element, | ||
280 | refElement.subEntity(idxInInside, 1, vIdxLocal, dim), | ||
281 | dim); | ||
282 | // maybe add boundary scvf | ||
283 | if (intersection.boundary() && !intersection.neighbor()) | ||
284 | { | ||
285 | numScvf_ += isGeometry.corners(); | ||
286 | numBoundaryScvf_ += isGeometry.corners(); | ||
287 | |||
288 | for (unsigned int isScvfLocalIdx = 0; isScvfLocalIdx < numCorners; ++isScvfLocalIdx) | ||
289 | { | ||
290 | // find the scvs this scvf is belonging to | ||
291 | const LocalIndexType insideScvIdx = static_cast<LocalIndexType>(refElement.subEntity(idxInInside, 1, isScvfLocalIdx, dim)); | ||
292 | std::vector<LocalIndexType> localScvIndices = {insideScvIdx, insideScvIdx}; | ||
293 | scvfs_[eIdx].emplace_back(geometryHelper, | ||
294 | intersection, | ||
295 | isGeometry, | ||
296 | isScvfLocalIdx, | ||
297 | scvfLocalIdx++, | ||
298 | std::move(localScvIndices)); | ||
299 | } | ||
300 | |||
301 | // add all vertices on the intersection to the set of | ||
302 | // boundary vertices | ||
303 | const auto numFaceVerts = refElement.size(idxInInside, 1, dim); | ||
304 | for (int localVIdx = 0; localVIdx < numFaceVerts; ++localVIdx) | ||
305 | { | ||
306 | const auto vIdx = refElement.subEntity(idxInInside, 1, localVIdx, dim); | ||
307 | const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdx, dim); | ||
308 | boundaryDofIndices_[vIdxGlobal] = true; | ||
309 | } | ||
310 | } | ||
311 | // make sure we have no periodic boundaries | ||
312 | else if (intersection.boundary() && intersection.neighbor()) | ||
313 | DUNE_THROW(Dune::InvalidStateException, "Periodic boundaries are not supported by the box-dfm scheme"); | ||
314 | |||
315 | // maybe add fracture scvs & scvfs | ||
316 | if (fractureGridAdapter.composeFacetElement(isVertexIndices)) | ||
317 | { | ||
318 | for (auto vIdx : isVertexIndices) | ||
319 | fractureDofIndices_[vIdx] = true; | ||
320 | |||
321 | // add fracture scv for each vertex of intersection | ||
322 | numScv_ += numCorners; | ||
323 | const auto curNumScvs = scvs_[eIdx].size(); | ||
324 | scvs_[eIdx].reserve(curNumScvs+numCorners); | ||
325 | for (unsigned int vIdxLocal = 0; vIdxLocal < numCorners; ++vIdxLocal) | ||
326 | scvs_[eIdx].emplace_back(geometryHelper, | ||
327 | intersection, | ||
328 | isGeometry, | ||
329 | vIdxLocal, | ||
330 | static_cast<LocalIndexType>(refElement.subEntity(idxInInside, 1, vIdxLocal, dim)), | ||
331 | scvLocalIdx++, | ||
332 | idxInInside, | ||
333 | eIdx, | ||
334 | isVertexIndices[vIdxLocal]); | ||
335 | |||
336 | // add fracture scvf for each edge of the intersection in 3d | ||
337 | if (dim == 3) | ||
338 | { | ||
339 | const auto& faceRefElement = referenceElement(isGeometry); | ||
340 | for (unsigned int edgeIdx = 0; edgeIdx < faceRefElement.size(1); ++edgeIdx) | ||
341 | { | ||
342 | // inside/outside scv indices in face local node numbering | ||
343 | std::vector<LocalIndexType> localScvIndices({static_cast<LocalIndexType>(faceRefElement.subEntity(edgeIdx, 1, 0, dim-1)), | ||
344 | static_cast<LocalIndexType>(faceRefElement.subEntity(edgeIdx, 1, 1, dim-1))}); | ||
345 | |||
346 | // add offset to get the right scv indices | ||
347 | std::for_each( localScvIndices.begin(), | ||
348 | localScvIndices.end(), | ||
349 | [curNumScvs] (auto& elemLocalIdx) { elemLocalIdx += curNumScvs; } ); | ||
350 | |||
351 | // add scvf | ||
352 | numScvf_++; | ||
353 | scvfs_[eIdx].emplace_back(geometryHelper, | ||
354 | intersection, | ||
355 | isGeometry, | ||
356 | edgeIdx, | ||
357 | scvfLocalIdx++, | ||
358 | std::move(localScvIndices), | ||
359 | intersection.boundary()); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | // dim == 2, intersection is an edge, make 1 scvf | ||
364 | else | ||
365 | { | ||
366 | // inside/outside scv indices in face local node numbering | ||
367 | std::vector<LocalIndexType> localScvIndices({0, 1}); | ||
368 | |||
369 | // add offset such that the fracture scvs above are addressed | ||
370 | std::for_each( localScvIndices.begin(), | ||
371 | localScvIndices.end(), | ||
372 | [curNumScvs] (auto& elemLocalIdx) { elemLocalIdx += curNumScvs; } ); | ||
373 | |||
374 | // add scvf | ||
375 | numScvf_++; | ||
376 | scvfs_[eIdx].emplace_back(geometryHelper, | ||
377 | intersection, | ||
378 | isGeometry, | ||
379 | /*idxOnIntersection*/0, | ||
380 | scvfLocalIdx++, | ||
381 | std::move(localScvIndices), | ||
382 | intersection.boundary()); | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | |||
389 | const FeCache feCache_; | ||
390 | |||
391 | std::vector<std::vector<SubControlVolume>> scvs_; | ||
392 | std::vector<std::vector<SubControlVolumeFace>> scvfs_; | ||
393 | |||
394 | // TODO do we need those? | ||
395 | std::size_t numScv_; | ||
396 | std::size_t numScvf_; | ||
397 | std::size_t numBoundaryScvf_; | ||
398 | |||
399 | // vertices on the boundary & fracture facets | ||
400 | std::vector<bool> boundaryDofIndices_; | ||
401 | std::vector<bool> fractureDofIndices_; | ||
402 | }; | ||
403 | |||
404 | /*! | ||
405 | * \ingroup BoxDFMModel | ||
406 | * \brief Base class for the finite volume geometry vector for box schemes | ||
407 | * This builds up the sub control volumes and sub control volume faces | ||
408 | * \note For caching disabled we store only some essential index maps to build up local systems on-demand in | ||
409 | * the corresponding FVElementGeometry | ||
410 | */ | ||
411 | template<class Scalar, class GV, class Traits> | ||
412 | class BoxDfmFVGridGeometry<Scalar, GV, false, Traits> | ||
413 | : public BaseGridGeometry<GV, Traits> | ||
414 | { | ||
415 | using ThisType = BoxDfmFVGridGeometry<Scalar, GV, false, Traits>; | ||
416 | using ParentType = BaseGridGeometry<GV, Traits>; | ||
417 | using GridIndexType = typename GV::IndexSet::IndexType; | ||
418 | |||
419 | static const int dim = GV::dimension; | ||
420 | static const int dimWorld = GV::dimensionworld; | ||
421 | |||
422 | using Element = typename GV::template Codim<0>::Entity; | ||
423 | using Intersection = typename GV::Intersection; | ||
424 | using CoordScalar = typename GV::ctype; | ||
425 | |||
426 | public: | ||
427 | //! export the discretization method this geometry belongs to | ||
428 | using DiscretizationMethod = DiscretizationMethods::Box; | ||
429 | static constexpr DiscretizationMethod discMethod{}; | ||
430 | |||
431 | //! export the type of the fv element geometry (the local view type) | ||
432 | using LocalView = typename Traits::template LocalView<ThisType, false>; | ||
433 | //! export the type of sub control volume | ||
434 | using SubControlVolume = typename Traits::SubControlVolume; | ||
435 | //! export the type of sub control volume | ||
436 | using SubControlVolumeFace = typename Traits::SubControlVolumeFace; | ||
437 | //! Export the extrusion type | ||
438 | using Extrusion = Extrusion_t<Traits>; | ||
439 | //! export dof mapper type | ||
440 | using DofMapper = typename Traits::VertexMapper; | ||
441 | //! export the finite element cache type | ||
442 | using FeCache = Dune::LagrangeLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; | ||
443 | //! export the grid view type | ||
444 | using GridView = GV; | ||
445 | //! export the geometry helper type | ||
446 | using GeometryHelper = Detail::BoxDfmGeometryHelper_t<GV, Traits>; | ||
447 | |||
448 | //! Constructor | ||
449 | template< class FractureGridAdapter > | ||
450 | 6 | BoxDfmFVGridGeometry(const GridView gridView, const FractureGridAdapter& fractureGridAdapter) | |
451 | : ParentType(gridView) | ||
452 |
3/6✓ 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.
|
12 | , facetMapper_(gridView, Dune::mcmgLayout(Dune::template Codim<1>())) |
453 | { | ||
454 |
1/2✓ Branch 1 taken 6 times.
✗ Branch 2 not taken.
|
6 | update_(fractureGridAdapter); |
455 | 6 | } | |
456 | |||
457 | //! the vertex mapper is the dofMapper | ||
458 | //! this is convenience to have better chance to have the same main files for box/tpfa/mpfa... | ||
459 | 20749014 | const DofMapper& dofMapper() const | |
460 |
4/16✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✓ Branch 16 taken 2 times.
✗ Branch 17 not taken.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 1 times.
✓ Branch 19 taken 1 times.
✗ Branch 20 not taken.
|
20749014 | { return this->vertexMapper(); } |
461 | |||
462 | //! The total number of sub control volumes | ||
463 | std::size_t numScv() const | ||
464 | { return numScv_; } | ||
465 | |||
466 | //! The total number of sun control volume faces | ||
467 | std::size_t numScvf() const | ||
468 | { return numScvf_; } | ||
469 | |||
470 | //! The total number of boundary sub control volume faces | ||
471 | //! For compatibility reasons with cc methods | ||
472 | std::size_t numBoundaryScvf() const | ||
473 | { return numBoundaryScvf_; } | ||
474 | |||
475 | //! The total number of degrees of freedom | ||
476 | 48 | std::size_t numDofs() const | |
477 |
2/4✓ Branch 11 taken 6 times.
✗ Branch 12 not taken.
✓ Branch 14 taken 6 times.
✗ Branch 15 not taken.
|
30 | { return this->gridView().size(dim); } |
478 | |||
479 | //! update all fvElementGeometries (call this after grid adaption) | ||
480 | template< class FractureGridAdapter > | ||
481 | void update(const GridView& gridView, const FractureGridAdapter& fractureGridAdapter) | ||
482 | { | ||
483 | ParentType::update(gridView); | ||
484 | updateFacetMapper_(); | ||
485 | update_(fractureGridAdapter); | ||
486 | } | ||
487 | |||
488 | //! update all fvElementGeometries (call this after grid adaption) | ||
489 | template< class FractureGridAdapter > | ||
490 | void update(GridView&& gridView, const FractureGridAdapter& fractureGridAdapter) | ||
491 | { | ||
492 | ParentType::update(std::move(gridView)); | ||
493 | updateFacetMapper_(); | ||
494 | update_(fractureGridAdapter); | ||
495 | } | ||
496 | |||
497 | //! The finite element cache for creating local FE bases | ||
498 |
2/3✓ Branch 4 taken 3079314 times.
✓ Branch 5 taken 758298 times.
✗ Branch 6 not taken.
|
14299800 | const FeCache& feCache() const { return feCache_; } |
499 | //! If a vertex / d.o.f. is on the boundary | ||
500 |
2/2✓ Branch 0 taken 643678 times.
✓ Branch 1 taken 6432546 times.
|
7076224 | bool dofOnBoundary(unsigned int dofIdx) const { return boundaryDofIndices_[dofIdx]; } |
501 | //! If a vertex / d.o.f. is on a fracture | ||
502 |
2/2✓ Branch 0 taken 360 times.
✓ Branch 1 taken 3520 times.
|
3880 | bool dofOnFracture(unsigned int dofIdx) const { return fractureDofIndices_[dofIdx]; } |
503 | //! Periodic boundaries are not supported for the box-dfm scheme | ||
504 | bool dofOnPeriodicBoundary(std::size_t dofIdx) const { return false; } | ||
505 | |||
506 | //! Returns true if an intersection coincides with a fracture element | ||
507 | 7535184 | bool isOnFracture(const Element& element, const Intersection& intersection) const | |
508 | 7535184 | { return facetOnFracture_[facetMapper_.subIndex(element, intersection.indexInInside(), 1)]; } | |
509 | |||
510 | //! The index of the vertex / d.o.f. on the other side of the periodic boundary | ||
511 | std::size_t periodicallyMappedDof(std::size_t dofIdx) const | ||
512 | { DUNE_THROW(Dune::InvalidStateException, "Periodic boundaries are not supported by the box-dfm scheme"); } | ||
513 | |||
514 | private: | ||
515 | |||
516 | void updateFacetMapper_() | ||
517 | { | ||
518 | facetMapper_.update(this->gridView()); | ||
519 | } | ||
520 | |||
521 | template< class FractureGridAdapter > | ||
522 | 6 | void update_(const FractureGridAdapter& fractureGridAdapter) | |
523 | { | ||
524 | 6 | boundaryDofIndices_.assign(numDofs(), false); | |
525 | 6 | fractureDofIndices_.assign(numDofs(), false); | |
526 | 6 | facetOnFracture_.assign(this->gridView().size(1), false); | |
527 | |||
528 | // save global data on the grid's scvs and scvfs | ||
529 | // TODO do we need those information? | ||
530 | 6 | numScv_ = 0; | |
531 | 6 | numScvf_ = 0; | |
532 | 6 | numBoundaryScvf_ = 0; | |
533 |
7/10✓ Branch 2 taken 4429 times.
✓ Branch 3 taken 3 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4426 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 4426 times.
✗ Branch 12 not taken.
✓ Branch 13 taken 4426 times.
✓ Branch 14 taken 3 times.
|
17719 | for (const auto& element : elements(this->gridView())) |
534 | { | ||
535 |
1/2✓ Branch 1 taken 4426 times.
✗ Branch 2 not taken.
|
8852 | numScv_ += element.subEntities(dim); |
536 |
1/2✓ Branch 1 taken 4426 times.
✗ Branch 2 not taken.
|
8852 | numScvf_ += element.subEntities(dim-1); |
537 | |||
538 |
1/2✓ Branch 1 taken 4426 times.
✗ Branch 2 not taken.
|
8852 | const auto elementGeometry = element.geometry(); |
539 | 8852 | const auto refElement = referenceElement(elementGeometry); | |
540 | |||
541 | // store the sub control volume face indices on the domain boundary | ||
542 |
11/16✓ Branch 2 taken 4426 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4426 times.
✓ Branch 6 taken 15776 times.
✓ Branch 8 taken 7080 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 22856 times.
✓ Branch 12 taken 10870 times.
✓ Branch 13 taken 29534 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 7080 times.
✗ Branch 17 not taken.
✓ Branch 1 taken 4426 times.
✗ Branch 7 not taken.
✓ Branch 15 taken 8696 times.
✓ Branch 10 taken 8696 times.
|
141570 | for (const auto& intersection : intersections(this->gridView(), element)) |
543 | { | ||
544 | // first, obtain all vertex indices on this intersection | ||
545 |
1/2✓ Branch 1 taken 15776 times.
✗ Branch 2 not taken.
|
31552 | const auto& isGeometry = intersection.geometry(); |
546 |
1/2✓ Branch 1 taken 31552 times.
✗ Branch 2 not taken.
|
31552 | const auto numCorners = isGeometry.corners(); |
547 |
1/2✓ Branch 1 taken 31552 times.
✗ Branch 2 not taken.
|
31552 | const auto idxInInside = intersection.indexInInside(); |
548 | |||
549 |
1/4✓ Branch 1 taken 31552 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
31552 | std::vector<GridIndexType> isVertexIndices(numCorners); |
550 |
2/2✓ Branch 0 taken 80496 times.
✓ Branch 1 taken 31552 times.
|
112048 | for (unsigned int vIdxLocal = 0; vIdxLocal < numCorners; ++vIdxLocal) |
551 |
1/2✓ Branch 2 taken 80496 times.
✗ Branch 3 not taken.
|
80496 | isVertexIndices[vIdxLocal] = this->vertexMapper().subIndex(element, |
552 | refElement.subEntity(idxInInside, 1, vIdxLocal, dim), | ||
553 | dim); | ||
554 | |||
555 |
4/4✓ Branch 0 taken 950 times.
✓ Branch 1 taken 15776 times.
✓ Branch 2 taken 3436 times.
✓ Branch 3 taken 12340 times.
|
32502 | if (intersection.boundary() && !intersection.neighbor()) |
556 | { | ||
557 | 1900 | numScvf_ += numCorners; | |
558 |
1/2✓ Branch 1 taken 950 times.
✗ Branch 2 not taken.
|
1900 | numBoundaryScvf_ += numCorners; |
559 | |||
560 | // add all vertices on the intersection to the set of | ||
561 | // boundary vertices | ||
562 | 1900 | const auto fIdx = intersection.indexInInside(); | |
563 | 1900 | const auto numFaceVerts = refElement.size(fIdx, 1, dim); | |
564 |
2/2✓ Branch 1 taken 5420 times.
✓ Branch 2 taken 1900 times.
|
7320 | for (int localVIdx = 0; localVIdx < numFaceVerts; ++localVIdx) |
565 | { | ||
566 | 5420 | const auto vIdx = refElement.subEntity(fIdx, 1, localVIdx, dim); | |
567 |
1/2✓ Branch 1 taken 5420 times.
✗ Branch 2 not taken.
|
5420 | const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdx, dim); |
568 | 5420 | boundaryDofIndices_[vIdxGlobal] = true; | |
569 | } | ||
570 | } | ||
571 | |||
572 | // make sure we have no periodic boundaries | ||
573 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 14826 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
14826 | else if (intersection.boundary() && intersection.neighbor()) |
574 | ✗ | DUNE_THROW(Dune::InvalidStateException, "Periodic boundaries are not supported by the box-dfm scheme"); | |
575 | |||
576 | // maybe add fracture scvs & scvfs | ||
577 |
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)) |
578 | { | ||
579 |
1/2✓ Branch 1 taken 876 times.
✗ Branch 2 not taken.
|
876 | facetOnFracture_[facetMapper_.subIndex(element, idxInInside, 1)] = true; |
580 |
2/2✓ Branch 0 taken 2192 times.
✓ Branch 1 taken 876 times.
|
3068 | for (auto vIdx : isVertexIndices) |
581 | 2192 | fractureDofIndices_[vIdx] = true; | |
582 | |||
583 |
1/2✓ Branch 1 taken 220 times.
✗ Branch 2 not taken.
|
876 | const auto isGeometry = intersection.geometry(); |
584 |
1/2✓ Branch 1 taken 440 times.
✗ Branch 2 not taken.
|
876 | numScv_ += isGeometry.corners(); |
585 |
1/2✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
|
876 | numScvf_ += dim == 3 ? referenceElement(isGeometry).size(1) : 1; |
586 | 876 | } | |
587 | } | ||
588 | } | ||
589 | 6 | } | |
590 | |||
591 | const FeCache feCache_; | ||
592 | |||
593 | // Information on the global number of geometries | ||
594 | // TODO do we need those information? | ||
595 | std::size_t numScv_; | ||
596 | std::size_t numScvf_; | ||
597 | std::size_t numBoundaryScvf_; | ||
598 | |||
599 | // vertices on the boundary & fracture facets | ||
600 | std::vector<bool> boundaryDofIndices_; | ||
601 | std::vector<bool> fractureDofIndices_; | ||
602 | |||
603 | // facet mapper and markers which facets lie on interior boundaries | ||
604 | typename Traits::FacetMapper facetMapper_; | ||
605 | std::vector<bool> facetOnFracture_; | ||
606 | }; | ||
607 | |||
608 | } // end namespace Dumux | ||
609 | |||
610 | #endif | ||
611 |