version 3.10.0
Loading...
Searching...
No Matches
discretization/box/fvgridgeometry.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// SPDX-FileCopyrightText: Copyright © DuMux Project contributors, see AUTHORS.md in root folder
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
14#ifndef DUMUX_DISCRETIZATION_BOX_GRID_FVGEOMETRY_HH
15#define DUMUX_DISCRETIZATION_BOX_GRID_FVGEOMETRY_HH
16
17#include <utility>
18#include <unordered_map>
19#include <array>
20#include <vector>
21
22#include <dune/localfunctions/lagrange/lagrangelfecache.hh>
23
33
35
36namespace Dumux {
37
38namespace Detail {
39template<class GV, class T>
40using BoxGeometryHelper_t = Dune::Std::detected_or_t<
43 T
44>;
45} // end namespace Detail
46
53template<class GridView, class MapperTraits = DefaultMapperTraits<GridView>>
63
70template<class Scalar,
71 class GridView,
72 bool enableGridGeometryCache = false,
75
82template<class Scalar, class GV, class Traits>
83class BoxFVGridGeometry<Scalar, GV, true, Traits>
84: public BaseGridGeometry<GV, Traits>
85{
87 using ParentType = BaseGridGeometry<GV, Traits>;
88 using GridIndexType = typename IndexTraits<GV>::GridIndex;
89 using LocalIndexType = typename IndexTraits<GV>::LocalIndex;
90
91 using Element = typename GV::template Codim<0>::Entity;
92 using CoordScalar = typename GV::ctype;
93 static const int dim = GV::dimension;
94 static const int dimWorld = GV::dimensionworld;
95
96public:
98 using DiscretizationMethod = DiscretizationMethods::Box;
99 static constexpr DiscretizationMethod discMethod{};
100
104 using LocalView = typename Traits::template LocalView<ThisType, true>;
106 using SubControlVolume = typename Traits::SubControlVolume;
108 using SubControlVolumeFace = typename Traits::SubControlVolumeFace;
112 using DofMapper = typename Traits::VertexMapper;
114 using FeCache = Dune::LagrangeLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>;
116 using GridView = GV;
119
121 BoxFVGridGeometry(std::shared_ptr<BasicGridGeometry> gg)
122 : ParentType(std::move(gg))
123 , cache_(*this)
124 , periodicGridTraits_(this->gridView().grid())
125 {
126 update_();
127 }
128
130 BoxFVGridGeometry(const GridView& gridView)
131 : BoxFVGridGeometry(std::make_shared<BasicGridGeometry>(gridView))
132 {}
133
136 const DofMapper& dofMapper() const
137 { return this->vertexMapper(); }
138
140 std::size_t numScv() const
141 { return numScv_; }
142
144 std::size_t numScvf() const
145 { return numScvf_; }
146
149 std::size_t numBoundaryScvf() const
150 { return numBoundaryScvf_; }
151
153 std::size_t numDofs() const
154 { return this->vertexMapper().size(); }
155
156
158 void update(const GridView& gridView)
159 {
160 ParentType::update(gridView);
161 update_();
162 }
163
165 void update(GridView&& gridView)
166 {
167 ParentType::update(std::move(gridView));
168 update_();
169 }
170
172 const FeCache& feCache() const
173 { return feCache_; }
174
176 bool dofOnBoundary(GridIndexType dofIdx) const
177 { return boundaryDofIndices_[dofIdx]; }
178
180 bool dofOnPeriodicBoundary(GridIndexType dofIdx) const
181 { return periodicDofMap_.count(dofIdx); }
182
184 GridIndexType periodicallyMappedDof(GridIndexType dofIdx) const
185 { return periodicDofMap_.at(dofIdx); }
186
188 const std::unordered_map<GridIndexType, GridIndexType>& periodicDofMap() const
189 { return periodicDofMap_; }
190
192 friend inline LocalView localView(const BoxFVGridGeometry& gg)
193 { return { gg.cache_ }; }
194
195private:
196
197 class BoxGridGeometryCache
198 {
199 friend class BoxFVGridGeometry;
200 public:
202 using GeometryHelper = Detail::BoxGeometryHelper_t<GV, Traits>;
203
204 explicit BoxGridGeometryCache(const BoxFVGridGeometry& gg)
205 : gridGeometry_(&gg)
206 {}
207
208 const BoxFVGridGeometry& gridGeometry() const
209 { return *gridGeometry_; }
210
212 const std::vector<SubControlVolume>& scvs(GridIndexType eIdx) const
213 { return scvs_[eIdx]; }
214
216 const std::vector<SubControlVolumeFace>& scvfs(GridIndexType eIdx) const
217 { return scvfs_[eIdx]; }
218
220 bool hasBoundaryScvf(GridIndexType eIdx) const
221 { return hasBoundaryScvf_[eIdx]; }
222
224 const std::vector<std::array<LocalIndexType, 2>>& scvfBoundaryGeometryKeys(GridIndexType eIdx) const
225 { return scvfBoundaryGeometryKeys_.at(eIdx); }
226
227 private:
228 void clear_()
229 {
230 scvs_.clear();
231 scvfs_.clear();
232 hasBoundaryScvf_.clear();
233 scvfBoundaryGeometryKeys_.clear();
234 }
235
236 std::vector<std::vector<SubControlVolume>> scvs_;
237 std::vector<std::vector<SubControlVolumeFace>> scvfs_;
238 std::vector<bool> hasBoundaryScvf_;
239 std::unordered_map<GridIndexType, std::vector<std::array<LocalIndexType, 2>>> scvfBoundaryGeometryKeys_;
240
241 const BoxFVGridGeometry* gridGeometry_;
242 };
243
244public:
247 using Cache = BoxGridGeometryCache;
248
249private:
250 using GeometryHelper = typename Cache::GeometryHelper;
251
252 void update_()
253 {
254 cache_.clear_();
255
256 const auto numElements = this->gridView().size(0);
257 cache_.scvs_.resize(numElements);
258 cache_.scvfs_.resize(numElements);
259 cache_.hasBoundaryScvf_.resize(numElements, false);
260
261 boundaryDofIndices_.assign(numDofs(), false);
262
263 numScv_ = 0;
264 numScvf_ = 0;
265 numBoundaryScvf_ = 0;
266 // Build the SCV and SCV faces
267 for (const auto& element : elements(this->gridView()))
268 {
269 // fill the element map with seeds
270 const auto eIdx = this->elementMapper().index(element);
271
272 // count
273 numScv_ += element.subEntities(dim);
274 numScvf_ += element.subEntities(dim-1);
275
276 // get the element geometry
277 auto elementGeometry = element.geometry();
278 const auto refElement = referenceElement(elementGeometry);
279
280 // instantiate the geometry helper
281 GeometryHelper geometryHelper(elementGeometry);
282
283 // construct the sub control volumes
284 cache_.scvs_[eIdx].resize(elementGeometry.corners());
285 for (LocalIndexType scvLocalIdx = 0; scvLocalIdx < elementGeometry.corners(); ++scvLocalIdx)
286 {
287 const auto dofIdxGlobal = this->vertexMapper().subIndex(element, scvLocalIdx, dim);
288
289 cache_.scvs_[eIdx][scvLocalIdx] = SubControlVolume(
290 geometryHelper.getScvCorners(scvLocalIdx),
291 scvLocalIdx,
292 eIdx,
293 dofIdxGlobal
294 );
295 }
296
297 // construct the sub control volume faces
298 LocalIndexType scvfLocalIdx = 0;
299 cache_.scvfs_[eIdx].resize(element.subEntities(dim-1));
300 for (; scvfLocalIdx < element.subEntities(dim-1); ++scvfLocalIdx)
301 {
302 // find the global and local scv indices this scvf is belonging to
303 std::vector<LocalIndexType> localScvIndices({static_cast<LocalIndexType>(refElement.subEntity(scvfLocalIdx, dim-1, 0, dim)),
304 static_cast<LocalIndexType>(refElement.subEntity(scvfLocalIdx, dim-1, 1, dim))});
305
306 const auto& corners = geometryHelper.getScvfCorners(scvfLocalIdx);
307 cache_.scvfs_[eIdx][scvfLocalIdx] = SubControlVolumeFace(
308 corners,
309 geometryHelper.normal(corners, localScvIndices),
310 element,
311 elementGeometry,
312 scvfLocalIdx,
313 std::move(localScvIndices),
314 false
315 );
316 }
317
318 // construct the sub control volume faces on the domain boundary
319 for (const auto& intersection : intersections(this->gridView(), element))
320 {
321 if (intersection.boundary() && !intersection.neighbor())
322 {
323 const auto isGeometry = intersection.geometry();
324 cache_.hasBoundaryScvf_[eIdx] = true;
325
326 // count
327 numScvf_ += isGeometry.corners();
328 numBoundaryScvf_ += isGeometry.corners();
329
330 for (unsigned int isScvfLocalIdx = 0; isScvfLocalIdx < isGeometry.corners(); ++isScvfLocalIdx)
331 {
332 // find the scvs this scvf is belonging to
333 const LocalIndexType insideScvIdx = static_cast<LocalIndexType>(refElement.subEntity(intersection.indexInInside(), 1, isScvfLocalIdx, dim));
334 std::vector<LocalIndexType> localScvIndices = {insideScvIdx, insideScvIdx};
335
336 cache_.scvfs_[eIdx].emplace_back(
337 geometryHelper.getBoundaryScvfCorners(intersection.indexInInside(), isScvfLocalIdx),
338 intersection.centerUnitOuterNormal(),
339 intersection,
340 isGeometry,
341 isScvfLocalIdx,
342 scvfLocalIdx,
343 std::move(localScvIndices),
344 true
345 );
346
347 cache_.scvfBoundaryGeometryKeys_[eIdx].emplace_back(std::array<LocalIndexType, 2>{{
348 static_cast<LocalIndexType>(intersection.indexInInside()),
349 static_cast<LocalIndexType>(isScvfLocalIdx)
350 }});
351
352 // increment local counter
353 scvfLocalIdx++;
354 }
355
356 // add all vertices on the intersection to the set of
357 // boundary vertices
358 const auto fIdx = intersection.indexInInside();
359 const auto numFaceVerts = refElement.size(fIdx, 1, dim);
360 for (int localVIdx = 0; localVIdx < numFaceVerts; ++localVIdx)
361 {
362 const auto vIdx = refElement.subEntity(fIdx, 1, localVIdx, dim);
363 const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdx, dim);
364 boundaryDofIndices_[vIdxGlobal] = true;
365 }
366 }
367
368 // inform the grid geometry if we have periodic boundaries
369 else if (periodicGridTraits_.isPeriodic(intersection))
370 {
371 this->setPeriodic();
372
373 // find the mapped periodic vertex of all vertices on periodic boundaries
374 const auto fIdx = intersection.indexInInside();
375 const auto numFaceVerts = refElement.size(fIdx, 1, dim);
376 const auto eps = 1e-7*(elementGeometry.corner(1) - elementGeometry.corner(0)).two_norm();
377 for (int localVIdx = 0; localVIdx < numFaceVerts; ++localVIdx)
378 {
379 const auto vIdx = refElement.subEntity(fIdx, 1, localVIdx, dim);
380 const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdx, dim);
381 const auto vPos = elementGeometry.corner(vIdx);
382
383 const auto& outside = intersection.outside();
384 const auto outsideGeometry = outside.geometry();
385 for (const auto& isOutside : intersections(this->gridView(), outside))
386 {
387 // only check periodic vertices of the periodic neighbor
388 if (periodicGridTraits_.isPeriodic(isOutside))
389 {
390 const auto fIdxOutside = isOutside.indexInInside();
391 const auto numFaceVertsOutside = refElement.size(fIdxOutside, 1, dim);
392 for (int localVIdxOutside = 0; localVIdxOutside < numFaceVertsOutside; ++localVIdxOutside)
393 {
394 const auto vIdxOutside = refElement.subEntity(fIdxOutside, 1, localVIdxOutside, dim);
395 const auto vPosOutside = outsideGeometry.corner(vIdxOutside);
396 const auto shift = std::abs((this->bBoxMax()-this->bBoxMin())*intersection.centerUnitOuterNormal());
397 if (std::abs((vPosOutside-vPos).two_norm() - shift) < eps)
398 periodicDofMap_[vIdxGlobal] = this->vertexMapper().subIndex(outside, vIdxOutside, dim);
399 }
400 }
401 }
402 }
403 }
404 }
405 }
406
407 // error check: periodic boundaries currently don't work for box in parallel
408 if (this->isPeriodic() && this->gridView().comm().size() > 1)
409 DUNE_THROW(Dune::NotImplemented, "Periodic boundaries for box method for parallel simulations!");
410 }
411
412 const FeCache feCache_;
413
414 std::size_t numScv_;
415 std::size_t numScvf_;
416 std::size_t numBoundaryScvf_;
417
418 // vertices on the boundary
419 std::vector<bool> boundaryDofIndices_;
420
421 // a map for periodic boundary vertices
422 std::unordered_map<GridIndexType, GridIndexType> periodicDofMap_;
423
424 Cache cache_;
425
426 PeriodicGridTraits<typename GridView::Grid> periodicGridTraits_;
427};
428
436template<class Scalar, class GV, class Traits>
437class BoxFVGridGeometry<Scalar, GV, false, Traits>
438: public BaseGridGeometry<GV, Traits>
439{
440 using ThisType = BoxFVGridGeometry<Scalar, GV, false, Traits>;
441 using ParentType = BaseGridGeometry<GV, Traits>;
442 using GridIndexType = typename IndexTraits<GV>::GridIndex;
443
444 static const int dim = GV::dimension;
445 static const int dimWorld = GV::dimensionworld;
446
447 using Element = typename GV::template Codim<0>::Entity;
448 using CoordScalar = typename GV::ctype;
449
450public:
452 using DiscretizationMethod = DiscretizationMethods::Box;
453 static constexpr DiscretizationMethod discMethod{};
454
456 using BasicGridGeometry = BasicGridGeometry_t<GV, Traits>;
458 using LocalView = typename Traits::template LocalView<ThisType, false>;
460 using SubControlVolume = typename Traits::SubControlVolume;
462 using SubControlVolumeFace = typename Traits::SubControlVolumeFace;
464 using Extrusion = Extrusion_t<Traits>;
466 using DofMapper = typename Traits::VertexMapper;
468 using FeCache = Dune::LagrangeLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>;
470 using GridView = GV;
472 using SupportsPeriodicity = typename PeriodicGridTraits<typename GV::Grid>::SupportsPeriodicity;
473
475 BoxFVGridGeometry(std::shared_ptr<BasicGridGeometry> gg)
476 : ParentType(std::move(gg))
477 , cache_(*this)
478 , periodicGridTraits_(this->gridView().grid())
479 {
480 update_();
481 }
482
484 BoxFVGridGeometry(const GridView& gridView)
485 : BoxFVGridGeometry(std::make_shared<BasicGridGeometry>(gridView))
486 {}
487
490 const DofMapper& dofMapper() const
491 { return this->vertexMapper(); }
492
494 std::size_t numScv() const
495 { return numScv_; }
496
498 std::size_t numScvf() const
499 { return numScvf_; }
500
503 std::size_t numBoundaryScvf() const
504 { return numBoundaryScvf_; }
505
507 std::size_t numDofs() const
508 { return this->vertexMapper().size(); }
509
510
512 void update(const GridView& gridView)
513 {
514 ParentType::update(gridView);
515 update_();
516 }
517
519 void update(GridView&& gridView)
520 {
521 ParentType::update(std::move(gridView));
522 update_();
523 }
524
526 const FeCache& feCache() const
527 { return feCache_; }
528
530 bool dofOnBoundary(GridIndexType dofIdx) const
531 { return boundaryDofIndices_[dofIdx]; }
532
534 bool dofOnPeriodicBoundary(GridIndexType dofIdx) const
535 { return periodicDofMap_.count(dofIdx); }
536
538 GridIndexType periodicallyMappedDof(GridIndexType dofIdx) const
539 { return periodicDofMap_.at(dofIdx); }
540
542 const std::unordered_map<GridIndexType, GridIndexType>& periodicDofMap() const
543 { return periodicDofMap_; }
544
546 friend inline LocalView localView(const BoxFVGridGeometry& gg)
547 { return { gg.cache_ }; }
548
549private:
550
551 class BoxGridGeometryCache
552 {
553 friend class BoxFVGridGeometry;
554 public:
556 using GeometryHelper = Detail::BoxGeometryHelper_t<GV, Traits>;
557
558 explicit BoxGridGeometryCache(const BoxFVGridGeometry& gg)
559 : gridGeometry_(&gg)
560 {}
561
562 const BoxFVGridGeometry& gridGeometry() const
563 { return *gridGeometry_; }
564
565 private:
566 const BoxFVGridGeometry* gridGeometry_;
567 };
568
569public:
572 using Cache = BoxGridGeometryCache;
573
574private:
575
576 void update_()
577 {
578 boundaryDofIndices_.assign(numDofs(), false);
579
580 // save global data on the grid's scvs and scvfs
581 // TODO do we need those information?
582 numScv_ = 0;
583 numScvf_ = 0;
584 numBoundaryScvf_ = 0;
585 for (const auto& element : elements(this->gridView()))
586 {
587 numScv_ += element.subEntities(dim);
588 numScvf_ += element.subEntities(dim-1);
589
590 const auto elementGeometry = element.geometry();
591 const auto refElement = referenceElement(elementGeometry);
592
593 // store the sub control volume face indices on the domain boundary
594 for (const auto& intersection : intersections(this->gridView(), element))
595 {
596 if (intersection.boundary() && !intersection.neighbor())
597 {
598 const auto isGeometry = intersection.geometry();
599 numScvf_ += isGeometry.corners();
600 numBoundaryScvf_ += isGeometry.corners();
601
602 // add all vertices on the intersection to the set of
603 // boundary vertices
604 const auto fIdx = intersection.indexInInside();
605 const auto numFaceVerts = refElement.size(fIdx, 1, dim);
606 for (int localVIdx = 0; localVIdx < numFaceVerts; ++localVIdx)
607 {
608 const auto vIdx = refElement.subEntity(fIdx, 1, localVIdx, dim);
609 const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdx, dim);
610 boundaryDofIndices_[vIdxGlobal] = true;
611 }
612 }
613
614 // inform the grid geometry if we have periodic boundaries
615 else if (periodicGridTraits_.isPeriodic(intersection))
616 {
617 this->setPeriodic();
618
619 // find the mapped periodic vertex of all vertices on periodic boundaries
620 const auto fIdx = intersection.indexInInside();
621 const auto numFaceVerts = refElement.size(fIdx, 1, dim);
622 const auto eps = 1e-7*(elementGeometry.corner(1) - elementGeometry.corner(0)).two_norm();
623 for (int localVIdx = 0; localVIdx < numFaceVerts; ++localVIdx)
624 {
625 const auto vIdx = refElement.subEntity(fIdx, 1, localVIdx, dim);
626 const auto vIdxGlobal = this->vertexMapper().subIndex(element, vIdx, dim);
627 const auto vPos = elementGeometry.corner(vIdx);
628
629 const auto& outside = intersection.outside();
630 const auto outsideGeometry = outside.geometry();
631 for (const auto& isOutside : intersections(this->gridView(), outside))
632 {
633 // only check periodic vertices of the periodic neighbor
634 if (periodicGridTraits_.isPeriodic(isOutside))
635 {
636 const auto fIdxOutside = isOutside.indexInInside();
637 const auto numFaceVertsOutside = refElement.size(fIdxOutside, 1, dim);
638 for (int localVIdxOutside = 0; localVIdxOutside < numFaceVertsOutside; ++localVIdxOutside)
639 {
640 const auto vIdxOutside = refElement.subEntity(fIdxOutside, 1, localVIdxOutside, dim);
641 const auto vPosOutside = outsideGeometry.corner(vIdxOutside);
642 const auto shift = std::abs((this->bBoxMax()-this->bBoxMin())*intersection.centerUnitOuterNormal());
643 if (std::abs((vPosOutside-vPos).two_norm() - shift) < eps)
644 periodicDofMap_[vIdxGlobal] = this->vertexMapper().subIndex(outside, vIdxOutside, dim);
645 }
646 }
647 }
648 }
649 }
650 }
651 }
652
653 // error check: periodic boundaries currently don't work for box in parallel
654 if (this->isPeriodic() && this->gridView().comm().size() > 1)
655 DUNE_THROW(Dune::NotImplemented, "Periodic boundaries for box method for parallel simulations!");
656 }
657
658 const FeCache feCache_;
659
660 // Information on the global number of geometries
661 // TODO do we need those information?
662 std::size_t numScv_;
663 std::size_t numScvf_;
664 std::size_t numBoundaryScvf_;
665
666 // vertices on the boundary
667 std::vector<bool> boundaryDofIndices_;
668
669 // a map for periodic boundary vertices
670 std::unordered_map<GridIndexType, GridIndexType> periodicDofMap_;
671
672 Cache cache_;
673
674 PeriodicGridTraits<typename GridView::Grid> periodicGridTraits_;
675};
676
677} // end namespace Dumux
678
679#endif
Base class for grid geometries.
Helper class constructing the dual grid finite volume geometries for the box discretizazion method.
Base class for all grid geometries.
Definition basegridgeometry.hh:52
An implementation of a grid geometry with some basic features.
Definition basicgridgeometry.hh:37
Base class for the finite volume geometry vector for box models This builds up the sub control volume...
Definition discretization/box/fvelementgeometry.hh:41
Base class for the finite volume geometry vector for box schemes This builds up the sub control volum...
Definition discretization/box/fvgridgeometry.hh:74
Create sub control volumes and sub control volume face geometries.
Definition boxgeometryhelper.hh:257
Class for a sub control volume face in the box method, i.e a part of the boundary of a sub control vo...
Definition discretization/box/subcontrolvolumeface.hh:62
the sub control volume for the box scheme
Definition discretization/box/subcontrolvolume.hh:60
Traits extracting the public Extrusion type from T Defaults to NoExtrusion if no such type is found.
Definition extrusion.hh:155
Definition periodicgridtraits.hh:121
Defines the default element and vertex mapper types.
Base class for the local finite volume geometry for box models This builds up the sub control volumes...
the sub control volume for the box scheme
Base class for a sub control volume face.
Helper classes to compute the integration elements.
GridCache::LocalView localView(const GridCache &gridCache)
Free function to get the local view of a grid cache object.
Definition localview.hh:26
Dune::Std::detected_or_t< Dumux::BasicGridGeometry< GV, typename T::ElementMapper, typename T::VertexMapper >, Detail::SpecifiesBaseGridGeometry, T > BasicGridGeometry_t
Type of the basic grid geometry implementation used as backend.
Definition basegridgeometry.hh:38
@ element
Definition fieldtype.hh:23
Defines the index types used for grid and local indices.
The available discretization methods in Dumux.
Distance implementation details.
Definition cvfelocalresidual.hh:25
Dune::Std::detected_or_t< Dumux::BoxGeometryHelper< GV, GV::dimension, typename T::SubControlVolume, typename T::SubControlVolumeFace >, SpecifiesGeometryHelper, T > BoxGeometryHelper_t
Definition discretization/box/fvgridgeometry.hh:40
typename T::GeometryHelper SpecifiesGeometryHelper
Definition basegridgeometry.hh:30
CVFE< CVFEMethods::PQ1 > Box
Definition method.hh:94
Definition adapt.hh:17
typename Extrusion< T >::type Extrusion_t
Convenience alias for obtaining the extrusion type.
Definition extrusion.hh:166
Grid properties related to periodicity.
The default traits for the box finite volume grid geometry Defines the scv and scvf types and the map...
Definition discretization/box/fvgridgeometry.hh:56
BoxSubControlVolume< GridView > SubControlVolume
Definition discretization/box/fvgridgeometry.hh:57
BoxSubControlVolumeFace< GridView > SubControlVolumeFace
Definition discretization/box/fvgridgeometry.hh:58
BoxFVElementGeometry< GridGeometry, enableCache > LocalView
Definition discretization/box/fvgridgeometry.hh:61
typename GridView::IndexSet::IndexType GridIndex
Definition indextraits.hh:27
unsigned int LocalIndex
Definition indextraits.hh:28
Definition periodicgridtraits.hh:34