From f18d3401bbd6a746cca6e9723bf29451ce6ca45c Mon Sep 17 00:00:00 2001 From: Kilian Weishaupt <kilian.weishaupt@iws.uni-stuttgart.de> Date: Wed, 27 Oct 2021 13:15:24 +0200 Subject: [PATCH] [staggered][gridGeometry][scvf] Restructure insertion of scvfs, add new boundary flag * write scvfs directly into vector using global index and fixed local indices * add flag in scvf for processor boundary --- .../staggered/fvelementgeometry.hh | 115 ++++--- .../facecentered/staggered/fvgridgeometry.hh | 312 +++++++----------- .../staggered/subcontrolvolumeface.hh | 24 +- 3 files changed, 210 insertions(+), 241 deletions(-) diff --git a/dumux/discretization/facecentered/staggered/fvelementgeometry.hh b/dumux/discretization/facecentered/staggered/fvelementgeometry.hh index 598e234290..58d008df61 100644 --- a/dumux/discretization/facecentered/staggered/fvelementgeometry.hh +++ b/dumux/discretization/facecentered/staggered/fvelementgeometry.hh @@ -24,16 +24,16 @@ #ifndef DUMUX_DISCRETIZATION_FACECENTERED_STAGGERED_FV_ELEMENT_GEOMETRY_HH #define DUMUX_DISCRETIZATION_FACECENTERED_STAGGERED_FV_ELEMENT_GEOMETRY_HH -#include <bitset> -#include <type_traits> #include <utility> +#include <dune/common/rangeutilities.hh> #include <dune/common/reservedvector.hh> #include <dumux/common/indextraits.hh> #include <dune/common/iteratorrange.hh> #include <dumux/discretization/scvandscvfiterators.hh> #include <dumux/discretization/facecentered/staggered/normalaxis.hh> +#include <dumux/discretization/facecentered/staggered/consistentlyorientedgrid.hh> namespace Dumux { @@ -144,9 +144,7 @@ public: //! number of sub control volumes in this fv element geometry std::size_t numScvf() const - { - return scvfIndices_().size(); - } + { return scvfIndices_().size(); } //! Returns whether one of the geometry's scvfs lies on a boundary bool hasBoundaryScvf() const @@ -244,7 +242,7 @@ public: using GridGeometry = GG; //! the maximum number of scvs per element - static constexpr std::size_t maxNumElementScvs = 2*GridView::dimension; + static constexpr std::size_t maxNumElementScvs = numScvsPerElement; FaceCenteredStaggeredFVElementGeometry(const GridGeometry& gridGeometry) : gridGeometry_(&gridGeometry) @@ -307,8 +305,8 @@ public: const SubControlVolumeFace& lateralOrthogonalScvf(const SubControlVolumeFace& scvf) const { assert(scvf.isLateral()); - const auto otherGlobalIdx = gridGeometry().lateralOrthogonalScvf(scvf); - return scvfs_[findLocalIndex_(otherGlobalIdx, scvfIndices_())]; + const auto otherLocalIdx = GridGeometry::GeometryHelper::lateralOrthogonalScvfLocalIndex(scvf.localIndex()); + return scvfs_[otherLocalIdx]; } //! Return the frontal sub control volume face on a the boundary for a given sub control volume @@ -360,12 +358,18 @@ public: */ FaceCenteredStaggeredFVElementGeometry bindElement(const Element& element) && { - this->bindElement_(element); + typename GG::LocalIntersectionMapper localIsMapper; + localIsMapper.update(gridGeometry().gridView(), element); + this->bindElement_(element, localIsMapper); return std::move(*this); } void bindElement(const Element& element) & - { this->bindElement_(element); } + { + typename GG::LocalIntersectionMapper localIsMapper; + localIsMapper.update(gridGeometry().gridView(), element); + this->bindElement_(element, localIsMapper); + } GridIndexType elementIndex() const { return eIdx_; } @@ -386,15 +390,18 @@ private: //! called by the local jacobian to prepare element assembly void bind_(const Element& element) { - bindElement(element); + typename GG::LocalIntersectionMapper localIsMapper; + localIsMapper.update(gridGeometry().gridView(), element); + + bindElement_(element, localIsMapper); neighborScvIndices_.clear(); neighborScvs_.clear(); - LocalIndexType localScvIdx = 0; for (const auto& intersection : intersections(gridGeometry().gridView(), element)) { if (intersection.neighbor()) { + const auto localScvIdx = localIsMapper.realToRefIdx(intersection.indexInInside()); const auto localOppositeScvIdx = geometryHelper_.localOppositeIdx(localScvIdx); const auto& neighborElement = intersection.outside(); const auto neighborElementIdx = gridGeometry().elementMapper().index(neighborElement); @@ -404,12 +411,16 @@ private: std::array<GridIndexType, numScvsPerElement> globalScvIndicesOfNeighborElement; std::iota(globalScvIndicesOfNeighborElement.begin(), globalScvIndicesOfNeighborElement.end(), neighborElementIdx*numScvsPerElement); - LocalIndexType localNeighborScvIdx = 0; + typename GG::LocalIntersectionMapper localNeighborIsMapper; + localNeighborIsMapper.update(gridGeometry().gridView(), neighborElement); + for (const auto& neighborIntersection : intersections(gridGeometry().gridView(), neighborElement)) { + const auto localNeighborScvIdx = localNeighborIsMapper.realToRefIdx(neighborIntersection.indexInInside()); if (localNeighborScvIdx != localScvIdx && localNeighborScvIdx != localOppositeScvIdx) { - const auto dofIndex = gridGeometry().intersectionMapper().globalIntersectionIndex(neighborElement, localNeighborScvIdx); + + const auto dofIndex = gridGeometry().intersectionMapper().globalIntersectionIndex(neighborElement, neighborIntersection.indexInInside()); neighborScvs_.push_back(SubControlVolume( neighborElementGeometry, neighborIntersection.geometry(), @@ -423,31 +434,28 @@ private: neighborScvIndices_.push_back(globalScvIndicesOfNeighborElement[localNeighborScvIdx]); } - - ++localNeighborScvIdx; } } - - ++localScvIdx; } } //! Bind only element-local - void bindElement_(const Element& element) + void bindElement_(const Element& element, const typename GG::LocalIntersectionMapper& localIsMapper) { elementPtr_ = &element; eIdx_ = gridGeometry().elementMapper().index(element); std::iota(scvIndicesOfElement_.begin(), scvIndicesOfElement_.end(), eIdx_*numScvsPerElement); scvfs_.clear(); + scvfs_.resize(minNumScvfsPerElement); - LocalIndexType localScvIdx = 0; - LocalIndexType localScvfIdx = 0; const auto& elementGeometry = element.geometry(); for (const auto& intersection : intersections(gridGeometry().gridView(), element)) { + const auto localScvIdx = localIsMapper.realToRefIdx(intersection.indexInInside()); + auto localScvfIdx = localScvIdx*(1 + numLateralScvfsPerScv); const auto& intersectionGeometry = intersection.geometry(); - const auto dofIndex = gridGeometry().intersectionMapper().globalIntersectionIndex(element, localScvIdx); + const auto dofIndex = gridGeometry().intersectionMapper().globalIntersectionIndex(element, intersection.indexInInside()); scvs_[localScvIdx] = SubControlVolume( elementGeometry, @@ -462,7 +470,7 @@ private: // the frontal sub control volume face at the element center const auto localOppositeScvIdx = geometryHelper_.localOppositeIdx(localScvIdx); - scvfs_.push_back(SubControlVolumeFace( + scvfs_[localScvfIdx] = SubControlVolumeFace( elementGeometry, intersectionGeometry, std::array{scvIndicesOfElement_[localScvIdx], scvIndicesOfElement_[localOppositeScvIdx]}, @@ -470,21 +478,19 @@ private: scvfIndices_()[localScvfIdx], intersection.centerUnitOuterNormal(), SubControlVolumeFace::FaceType::frontal, - false - )); + SubControlVolumeFace::BoundaryType::interior + ); ++localScvfIdx; // the lateral sub control volume faces - const auto lateralFaceIndices = geometryHelper_.localLaterFaceIndices(localScvIdx); - for (const auto lateralFacetIndex : lateralFaceIndices) + for (const auto lateralFacetIndex : Dune::transformedRangeView(geometryHelper_.localLaterFaceIndices(localScvIdx), + [&](auto&& idx) { return localIsMapper.refToRealIdx(idx) ;}) + ) { const auto& lateralIntersection = geometryHelper_.intersection(lateralFacetIndex, element); const auto& lateralFacet = geometryHelper_.facet(lateralFacetIndex, element); const auto& lateralFacetGeometry = lateralFacet.geometry(); - if (lateralIntersection.neighbor()) - geometryHelper_.update(element, lateralIntersection.outside()); - // helper lambda to get the lateral scvf's global inside and outside scv indices const auto globalScvIndicesForLateralFace = [&] { @@ -493,12 +499,10 @@ private: if (lateralIntersection.neighbor()) { const auto parallelElemIdx = gridGeometry().elementMapper().index(lateralIntersection.outside()); - const auto localOutsideScvIdx = geometryHelper_.localFaceIndexInOtherElement(localScvIdx); - // todo: could be done easier? std::array<GridIndexType, numScvsPerElement> globalScvIndicesOfNeighborElement; std::iota(globalScvIndicesOfNeighborElement.begin(), globalScvIndicesOfNeighborElement.end(), parallelElemIdx*numScvsPerElement); - return globalScvIndicesOfNeighborElement[localOutsideScvIdx]; + return globalScvIndicesOfNeighborElement[localScvIdx]; } else return gridGeometry().outsideVolVarIndex(scvfIndices_()[localScvfIdx]); @@ -507,7 +511,17 @@ private: return std::array{scvIndicesOfElement_[localScvIdx], globalOutsideScvIdx}; }(); - scvfs_.push_back(SubControlVolumeFace( + const auto boundaryType = [&] + { + if (onProcessorBoundary_(lateralIntersection)) + return SubControlVolumeFace::BoundaryType::processorBoundary; + else if (onDomainBoundary_(lateralIntersection)) + return SubControlVolumeFace::BoundaryType::physicalBoundary; + else + return SubControlVolumeFace::BoundaryType::interior; + }(); + + scvfs_[localScvfIdx] = SubControlVolumeFace( elementGeometry, intersectionGeometry, lateralFacetGeometry, @@ -516,23 +530,20 @@ private: scvfIndices_()[localScvfIdx], lateralIntersection.centerUnitOuterNormal(), SubControlVolumeFace::FaceType::lateral, - onDomainBoundary_(lateralIntersection) - )); + boundaryType + ); ++localScvfIdx; } - - - - ++localScvIdx; } // do a second loop over all intersections to add frontal boundary faces - localScvIdx = 0; + auto localScvfIdx = minNumScvfsPerElement; for (const auto& intersection : intersections(gridGeometry().gridView(), element)) { // the frontal sub control volume face at a domain boundary (coincides with element face) if (onDomainBoundary_(intersection)) { + const auto localScvIdx = localIsMapper.realToRefIdx(intersection.indexInInside()); // the frontal sub control volume face at the boundary scvfs_.push_back(SubControlVolumeFace( element.geometry(), @@ -542,12 +553,23 @@ private: scvfIndices_()[localScvfIdx], intersection.centerUnitOuterNormal(), SubControlVolumeFace::FaceType::frontal, - true + SubControlVolumeFace::BoundaryType::physicalBoundary )); - ++localScvfIdx; + ++localScvfIdx; } + } - ++localScvIdx; + if constexpr (!ConsistentlyOrientedGrid<typename GridView::Grid>{}) + { + static const bool makeConsistentlyOriented = getParam<bool>("Grid.MakeConsistentlyOriented", true); + if (makeConsistentlyOriented && scvfs_.size() > minNumScvfsPerElement) + { + // make sure frontal boundary scvfs are sorted correctly + std::sort(scvfs_.begin() + minNumScvfsPerElement, scvfs_.end(), + [](const auto& scvfLeft, const auto& scvfRight) + { return scvfLeft.insideScvIdx() < scvfRight.insideScvIdx(); } + ); + } } } @@ -568,6 +590,11 @@ private: return !intersection.neighbor() && intersection.boundary(); } + bool onProcessorBoundary_(const typename GridView::Intersection& intersection) const + { + return !intersection.neighbor() && !intersection.boundary(); + } + Dune::ReservedVector<SubControlVolumeFace, maxNumScvfsPerElement> scvfs_; Dune::ReservedVector<SubControlVolume, numLateralScvfsPerElement> neighborScvs_; diff --git a/dumux/discretization/facecentered/staggered/fvgridgeometry.hh b/dumux/discretization/facecentered/staggered/fvgridgeometry.hh index 6a40b4e055..7158921f2f 100644 --- a/dumux/discretization/facecentered/staggered/fvgridgeometry.hh +++ b/dumux/discretization/facecentered/staggered/fvgridgeometry.hh @@ -26,6 +26,8 @@ #include <memory> +#include <dune/common/rangeutilities.hh> + #include <dumux/common/defaultmappertraits.hh> #include <dumux/common/indextraits.hh> #include <dumux/common/intersectionmapper.hh> @@ -42,6 +44,7 @@ #include <dumux/discretization/facecentered/staggered/geometryhelper.hh> #include <dumux/discretization/facecentered/staggered/connectivitymap.hh> #include <dumux/discretization/facecentered/staggered/normalaxis.hh> +#include <dumux/discretization/facecentered/staggered/localintersectionindexmapper.hh> namespace Dumux { @@ -57,6 +60,7 @@ struct FaceCenteredStaggeredDefaultGridGeometryTraits : public DefaultMapperTrai using SubControlVolume = FaceCenteredStaggeredSubControlVolume<GridView>; using SubControlVolumeFace = FaceCenteredStaggeredSubControlVolumeFace<GridView>; using IntersectionMapper = ConformingGridIntersectionMapper<GridView>; + using LocalIntersectionMapper = FaceCenteredStaggeredLocalIntersectionIndexMapper<GridView>; using GeometryHelper = FaceCenteredStaggeredGeometryHelper<GridView, typename GridView::Grid>; template<class GridGeometry> @@ -139,6 +143,8 @@ public: using GridView = GV; //! export the geometry helper type using GeometryHelper = typename Traits::GeometryHelper; + //! export the local intersection mapper + using LocalIntersectionMapper = typename Traits::LocalIntersectionMapper; //! export static information using StaticInformation = typename Traits::StaticInfo; //! export the type of extrusion @@ -203,9 +209,9 @@ public: //! all scvs of the element-local fvGeometry. auto scvs(const LocalView& fvGeometry) const { - const auto begin = scvs_.cbegin() + numScvsPerElement*fvGeometry.elementIndex(); + auto begin = scvs_.cbegin() + numScvsPerElement*fvGeometry.elementIndex(); const auto end = begin + numScvsPerElement; - return Dune::IteratorRange<decltype(begin)>(begin, end); + return Dune::IteratorRange<std::decay_t<decltype(begin)>>(begin, end); } //! Get a sub control volume face with a global scvf index @@ -243,10 +249,6 @@ public: const std::unordered_map<GridIndexType, GridIndexType>& periodicVertexMap() const { return periodicFaceMap_; } - //! get the global index of the orthogonal face sharing a common entity - GridIndexType lateralOrthogonalScvf(const SubControlVolumeFace& scvf) const - { return lateralOrthogonalScvf_[scvf.index()]; } - private: void update_() @@ -255,15 +257,12 @@ private: scvs_.clear(); scvfs_.clear(); scvfIndicesOfElement_.clear(); - lateralOrthogonalScvf_.clear(); intersectionMapper_.update(this->gridView()); // determine size of containers const auto numElements = this->gridView().size(0); scvfIndicesOfElement_.resize(numElements); hasBoundaryScvf_.resize(numElements, false); - // on frontal + maybe boundary per face and 2*(dim-1) laterals per frontal - lateralOrthogonalScvf_.resize(numElements*(2*dim*(2 + 2*(dim-1)))); outSideBoundaryVolVarIdx_ = 0; numBoundaryScv_ = 0; @@ -271,103 +270,65 @@ private: GeometryHelper geometryHelper(this->gridView()); - // get the global scv indices first - GridIndexType scvfIdx = 0; + // get the global scvf indices first + GridIndexType numScvfs = 0; for (const auto& element : elements(this->gridView())) { assert(numScvsPerElement == element.subEntities(1)); - std::vector<GridIndexType> scvfsIndexSet; - scvfsIndexSet.reserve(1/*frontal in element*/ + 1 /*frontal on boundary*/ + numLateralScvfsPerScv); - - // keep track of frontal boundary scvfs - std::size_t numFrontalBoundaryScvfs = 0; - - // a temporary map to store pairs of common entities - std::unordered_map<GridIndexType, Dune::ReservedVector<GridIndexType, 2>> commonEntityIdxToScvfsMap; - - SmallLocalIndexType localScvIdx = 0; for (const auto& intersection : intersections(this->gridView(), element)) { - // the frontal sub control volume face at the element center - scvfsIndexSet.push_back(scvfIdx++); - - if constexpr(dim > 1) - { - // the lateral sub control volume faces - for (const auto lateralFacetIndex : geometryHelper.localLaterFaceIndices(localScvIdx)) - { - const auto& lateralIntersection = geometryHelper.intersection(lateralFacetIndex, element); - if (onProcessorBoundary_(lateralIntersection)) - continue; + // frontal scvf in element center + ++numScvfs; - scvfsIndexSet.push_back(scvfIdx); - - const auto commonEntityIdx = geometryHelper.globalCommonEntityIndex( - element, localScvIdx, lateralFacetIndex - ); - commonEntityIdxToScvfsMap[commonEntityIdx].push_back(scvfIdx); - ++scvfIdx; - } - } + // lateral scvfs + numScvfs += numLateralScvfsPerScv; // handle physical domain boundary if (onDomainBoundary_(intersection)) { ++numBoundaryScv_; // frontal face numBoundaryScv_ += numLateralScvfsPerScv; // boundary scvs for lateral faces - ++numFrontalBoundaryScvfs; - } - ++localScvIdx; - } - - // add global indices of frontal boundary scvfs last - for (std::size_t i = 0; i < numFrontalBoundaryScvfs; ++i) - scvfsIndexSet.push_back(scvfIdx++); - - // Save the scv indices belonging to this element to build up fv element geometries fast - const auto eIdx = this->elementMapper().index(element); - scvfIndicesOfElement_[eIdx] = std::move(scvfsIndexSet); - - // create the bi-directional map - for (const auto& [_, scvfs] : commonEntityIdxToScvfsMap) - { - // TODO: this maybe be less than 2 if there is a processor boundary - // are we sure that the lateral orthogonal scvf is then never needed? - if (scvfs.size() == 2) - { - lateralOrthogonalScvf_[scvfs[0]] = scvfs[1]; - lateralOrthogonalScvf_[scvfs[1]] = scvfs[0]; + // frontal scvf at boundary + ++numScvfs; } } } - // reserve memory - const auto numInteriorScvs = numElements*numScvsPerElement; - scvs_.resize(numInteriorScvs); - scvfs_.reserve((numScvsPerElement/*one interior frontal scvf per scv*/ - +numLateralScvfsPerElement)*numElements + numBoundaryScv_); + // allocate memory + const auto numScvs = numElements*numScvsPerElement; + scvs_.resize(numScvs); + scvfs_.reserve(numScvfs); // Build the scvs and scv faces + std::size_t globalScvfIdx = 0; for (const auto& element : elements(this->gridView())) { const auto eIdx = this->elementMapper().index(element); - const auto& globalScvfIndices = scvfIndicesOfElement_[eIdx]; + auto& globalScvfIndices = scvfIndicesOfElement_[eIdx]; + globalScvfIndices.resize(minNumScvfsPerElement); + globalScvfIndices.reserve(maxNumScvfsPerElement); auto getGlobalScvIdx = [&](const auto elementIdx, const auto localScvIdx) { return numScvsPerElement*elementIdx + localScvIdx; }; - SmallLocalIndexType localScvfIdx = 0; + LocalIntersectionMapper localIsMapper; + localIsMapper.update(this->gridView(), element); + for (const auto& intersection : intersections(this->gridView(), element)) { - const auto localScvIdx = intersection.indexInInside(); + const auto& intersectionUnitOuterNormal = intersection.centerUnitOuterNormal(); + const auto localScvIdx = localIsMapper.realToRefIdx(intersection.indexInInside()); + auto localScvfIdx = localScvIdx*(1 + numLateralScvfsPerScv); + const auto globalScvIdx = getGlobalScvIdx(eIdx, localScvIdx); - const auto dofIndex = intersectionMapper().globalIntersectionIndex(element, localScvIdx); + const auto dofIndex = intersectionMapper().globalIntersectionIndex(element, intersection.indexInInside()); const auto localOppositeScvIdx = geometryHelper.localOppositeIdx(localScvIdx); const auto& intersectionGeometry = intersection.geometry(); const auto& elementGeometry = element.geometry(); + assert(localIsMapper.refToRealIdx(localScvIdx) == intersection.indexInInside()); // handle periodic boundaries if (onPeriodicBoundary_(intersection)) @@ -384,7 +345,7 @@ private: if (periodicFaceFound) continue; - if (Dune::FloatCmp::eq(intersection.centerUnitOuterNormal()*otherIntersection.centerUnitOuterNormal(), -1.0, 1e-7)) + if (Dune::FloatCmp::eq(intersectionUnitOuterNormal*otherIntersection.centerUnitOuterNormal(), -1.0, 1e-7)) { const auto periodicDofIdx = intersectionMapper().globalIntersectionIndex(otherElement, otherIntersectionLocalIdx); periodicFaceMap_[dofIndex] = periodicDofIdx; @@ -396,39 +357,37 @@ private: } // the sub control volume - scvs_[globalScvIdx] = SubControlVolume(elementGeometry, - intersectionGeometry, - globalScvIdx, - localScvIdx, - dofIndex, - Dumux::normalAxis(intersection.centerUnitOuterNormal()), - this->elementMapper().index(element), - onDomainBoundary_(intersection)); + scvs_[globalScvIdx] = SubControlVolume( + elementGeometry, + intersectionGeometry, + globalScvIdx, + localScvIdx, + dofIndex, + Dumux::normalAxis(intersectionUnitOuterNormal), + this->elementMapper().index(element), + onDomainBoundary_(intersection) + ); // the frontal sub control volume face at the element center scvfs_.emplace_back(elementGeometry, - intersectionGeometry, - std::array{globalScvIdx, getGlobalScvIdx(eIdx, localOppositeScvIdx)}, - localScvfIdx, - globalScvfIndices[localScvfIdx], - intersection.centerUnitOuterNormal(), - SubControlVolumeFace::FaceType::frontal, - false); + intersectionGeometry, + std::array{globalScvIdx, getGlobalScvIdx(eIdx, localOppositeScvIdx)}, + localScvfIdx, + globalScvfIdx, + intersectionUnitOuterNormal, + SubControlVolumeFace::FaceType::frontal, + SubControlVolumeFace::BoundaryType::interior + ); + + globalScvfIndices[localScvfIdx] = globalScvfIdx++; ++localScvfIdx; // the lateral sub control volume faces - const auto lateralFaceIndices = geometryHelper.localLaterFaceIndices(localScvIdx); - for (const auto lateralFacetIndex : lateralFaceIndices) + for (const auto lateralFacetIndex : Dune::transformedRangeView(geometryHelper.localLaterFaceIndices(localScvIdx), + [&](auto&& idx) { return localIsMapper.refToRealIdx(idx) ;}) + ) { const auto& lateralIntersection = geometryHelper.intersection(lateralFacetIndex, element); - if (onProcessorBoundary_(lateralIntersection)) - continue; - - const auto& lateralFacet = geometryHelper.facet(lateralFacetIndex, element); - const auto& lateralFacetGeometry = lateralFacet.geometry(); - - if (lateralIntersection.neighbor()) // TODO: periodic? - geometryHelper.update(element, lateralIntersection.outside()); // helper lambda to get the lateral scvf's global inside and outside scv indices const auto globalScvIndicesForLateralFace = [&] @@ -438,25 +397,40 @@ private: if (lateralIntersection.neighbor()) { const auto parallelElemIdx = this->elementMapper().index(lateralIntersection.outside()); - const auto localOutsideScvIdx = geometryHelper.localFaceIndexInOtherElement(localScvIdx); - return getGlobalScvIdx(parallelElemIdx, localOutsideScvIdx); + return getGlobalScvIdx(parallelElemIdx, localScvIdx); } + else if (onDomainBoundary_(lateralIntersection)) + return numScvs + outSideBoundaryVolVarIdx_++; else - return numInteriorScvs + outSideBoundaryVolVarIdx_++; + return globalScvIdx; // fallback for parallel, won't be used anyway }(); return std::array{globalScvIdx, globalOutsideScvIdx}; }(); - scvfs_.emplace_back(elementGeometry, - intersectionGeometry, - lateralFacetGeometry, - globalScvIndicesForLateralFace, // TODO higher order - localScvfIdx, - globalScvfIndices[localScvfIdx], - lateralIntersection.centerUnitOuterNormal(), - SubControlVolumeFace::FaceType::lateral, - onDomainBoundary_(lateralIntersection)); + const auto boundaryType = [&] + { + if (onProcessorBoundary_(lateralIntersection)) + return SubControlVolumeFace::BoundaryType::processorBoundary; + else if (onDomainBoundary_(lateralIntersection)) + return SubControlVolumeFace::BoundaryType::physicalBoundary; + else + return SubControlVolumeFace::BoundaryType::interior; + }(); + + scvfs_.emplace_back( + elementGeometry, + intersectionGeometry, + geometryHelper.facet(lateralFacetIndex, element).geometry(), + globalScvIndicesForLateralFace, // TODO higher order + localScvfIdx, + globalScvfIdx, + lateralIntersection.centerUnitOuterNormal(), + SubControlVolumeFace::FaceType::lateral, + boundaryType + ); + + globalScvfIndices[localScvfIdx] = globalScvfIdx++; ++localScvfIdx; if (onDomainBoundary_(lateralIntersection)) @@ -469,24 +443,30 @@ private: } // end first loop over intersections // do a second loop over all intersections to add frontal boundary faces + int localScvfIdx = minNumScvfsPerElement; for (const auto& intersection : intersections(this->gridView(), element)) { // the frontal sub control volume face at a domain boundary (coincides with element face) if (onDomainBoundary_(intersection)) { - const auto localScvIdx = intersection.indexInInside(); + const auto localScvIdx = localIsMapper.realToRefIdx(intersection.indexInInside()); const auto globalScvIdx = getGlobalScvIdx(eIdx, localScvIdx); ++numBoundaryScvf_; // the frontal sub control volume face at the boundary - scvfs_.emplace_back(element.geometry(), - intersection.geometry(), - std::array{globalScvIdx, globalScvIdx}, // TODO outside boundary, periodic, parallel? - localScvfIdx, - globalScvfIndices[localScvfIdx], - intersection.centerUnitOuterNormal(), - SubControlVolumeFace::FaceType::frontal, - true); + scvfs_.emplace_back( + element.geometry(), + intersection.geometry(), + std::array{globalScvIdx, globalScvIdx}, // TODO outside boundary, periodic, parallel? + localScvfIdx, + globalScvfIdx, + intersection.centerUnitOuterNormal(), + SubControlVolumeFace::FaceType::frontal, + SubControlVolumeFace::BoundaryType::physicalBoundary + ); + + globalScvfIndices.push_back(globalScvfIdx); + ++globalScvfIdx; ++localScvfIdx; hasBoundaryScvf_[eIdx] = true; } @@ -494,9 +474,6 @@ private: } connectivityMap_.update(*this); - - // allow to free the non-needed memory - lateralOrthogonalScvf_.resize(scvfs_.size()); } bool onDomainBoundary_(const typename GridView::Intersection& intersection) const @@ -525,7 +502,6 @@ private: GridIndexType outSideBoundaryVolVarIdx_; std::vector<bool> hasBoundaryScvf_; - std::vector<GridIndexType> lateralOrthogonalScvf_; std::vector<std::vector<GridIndexType>> scvfIndicesOfElement_; // a map for periodic boundary vertices @@ -576,6 +552,8 @@ public: using GridView = GV; //! export the geometry helper type using GeometryHelper = typename Traits::GeometryHelper; + //! export the local intersection mapper + using LocalIntersectionMapper = typename Traits::LocalIntersectionMapper; //! export static information using StaticInformation = typename Traits::StaticInfo; //! export the type of extrusion @@ -667,10 +645,6 @@ public: const std::unordered_map<GridIndexType, GridIndexType>& periodicVertexMap() const { return periodicFaceMap_; } - //! get the global index of the orthogonal face sharing a common entity - GridIndexType lateralOrthogonalScvf(const SubControlVolumeFace& scvf) const - { return lateralOrthogonalScvf_[scvf.index()]; } - private: void update_() @@ -678,28 +652,25 @@ private: intersectionMapper_.update(this->gridView()); // clear local data - numScvs_ = 0; numScvf_ = 0; numBoundaryScv_ = 0; numBoundaryScvf_ = 0; hasBoundaryScvf_.clear(); scvfIndicesOfElement_.clear(); - lateralOrthogonalScvf_.clear(); outsideVolVarIndices_.clear(); // determine size of containers const auto numElements = this->gridView().size(0); scvfIndicesOfElement_.resize(numElements); hasBoundaryScvf_.resize(numElements, false); - // on frontal + maybe boundary per face and 2*(dim-1) laterals per frontal - lateralOrthogonalScvf_.resize(numElements*(2*dim*(2 + 2*(dim-1)))); + numScvs_ = numElements*numScvsPerElement; GeometryHelper geometryHelper(this->gridView()); // get the global scv indices first GridIndexType scvfIdx = 0; - GridIndexType neighborVolVarIdx = numElements*numScvsPerElement; + GridIndexType neighborVolVarIdx = numScvs_; for (const auto& element : elements(this->gridView())) { @@ -707,43 +678,43 @@ private: assert(numScvsPerElement == element.subEntities(1)); // the element-wise index sets for finite volume geometry - std::vector<GridIndexType> scvfsIndexSet; - scvfsIndexSet.reserve(1/*frontal in element*/ + 1 /*frontal on boundary*/ + numLateralScvfsPerScv); + auto& globalScvfIndices = scvfIndicesOfElement_[eIdx]; + globalScvfIndices.reserve(maxNumScvfsPerElement); + globalScvfIndices.resize(minNumScvfsPerElement); // keep track of frontal boundary scvfs std::size_t numFrontalBoundaryScvfs = 0; - // a temporary map to store pairs of common entities - std::unordered_map<GridIndexType, Dune::ReservedVector<GridIndexType, 2>> commonEntityIdxToScvfsMap; + using LocalIntersectionIndexMapper = FaceCenteredStaggeredLocalIntersectionIndexMapper<GridView>; + LocalIntersectionIndexMapper localIsMapper; + localIsMapper.update(this->gridView(), element); - SmallLocalIndexType localScvIdx = 0; for (const auto& intersection : intersections(this->gridView(), element)) { - ++numScvs_; + const auto localScvIdx = localIsMapper.realToRefIdx(intersection.indexInInside()); + auto localScvfIdx = localScvIdx*(1 + numLateralScvfsPerScv); + assert(localIsMapper.refToRealIdx(localScvIdx) == intersection.indexInInside()); // the frontal sub control volume face at the element center - scvfsIndexSet.push_back(scvfIdx++); + globalScvfIndices[localScvfIdx] = scvfIdx++; + ++localScvfIdx; if constexpr(dim > 1) { // the lateral sub control volume faces - for (const auto lateralFacetIndex : geometryHelper.localLaterFaceIndices(localScvIdx)) + for (const auto lateralFacetIndex : Dune::transformedRangeView(geometryHelper.localLaterFaceIndices(localScvIdx), + [&](auto idx) { return localIsMapper.refToRealIdx(idx) ;}) + ) { - const auto& lateralIntersection = geometryHelper.intersection(lateralFacetIndex, element); - if (onProcessorBoundary_(lateralIntersection)) - continue; - - if (onDomainBoundary_(lateralIntersection)) + if (onDomainBoundary_(geometryHelper.intersection(lateralFacetIndex, element))) + { outsideVolVarIndices_[scvfIdx] = neighborVolVarIdx++; + ++numBoundaryScvf_; + hasBoundaryScvf_[eIdx] = true; + } - scvfsIndexSet.push_back(scvfIdx); - - const auto commonEntityIdx = geometryHelper.globalCommonEntityIndex( - element, localScvIdx, lateralFacetIndex - ); - commonEntityIdxToScvfsMap[commonEntityIdx].push_back(scvfIdx); - - ++scvfIdx; + globalScvfIndices[localScvfIdx] = scvfIdx++; + ++localScvfIdx; } } @@ -783,43 +754,11 @@ private: ++otherIntersectionLocalIdx; } } - - // the lateral sub control volume faces - const auto lateralFaceIndices = geometryHelper.localLaterFaceIndices(localScvIdx); - for (const auto lateralFacetIndex : lateralFaceIndices) - { - const auto& lateralIntersection = geometryHelper.intersection(lateralFacetIndex, element); - if (onProcessorBoundary_(lateralIntersection)) - continue; - - if (onDomainBoundary_(lateralIntersection)) - { - ++numBoundaryScvf_; - hasBoundaryScvf_[eIdx] = true; - } - } // end loop over lateral facets - - ++localScvIdx; } // add global indices of frontal boundary scvfs last for (std::size_t i = 0; i < numFrontalBoundaryScvfs; ++i) - scvfsIndexSet.push_back(scvfIdx++); - - // Save the scv indices belonging to this element to build up fv element geometries fast - scvfIndicesOfElement_[eIdx] = std::move(scvfsIndexSet); - - // create the bi-directional map - for (const auto& [_, scvfs] : commonEntityIdxToScvfsMap) - { - // TODO: this maybe be less than 2 if there is a processor boundary - // are we sure that the lateral orthogonal scvf is then never needed? - if (scvfs.size() == 2) - { - lateralOrthogonalScvf_[scvfs[0]] = scvfs[1]; - lateralOrthogonalScvf_[scvfs[1]] = scvfs[0]; - } - } + globalScvfIndices.push_back(scvfIdx++); } // set number of subcontrolvolume faces @@ -854,7 +793,6 @@ private: std::size_t numBoundaryScvf_; std::vector<bool> hasBoundaryScvf_; - std::vector<GridIndexType> lateralOrthogonalScvf_; std::vector<std::vector<GridIndexType>> scvfIndicesOfElement_; // a map for periodic boundary vertices diff --git a/dumux/discretization/facecentered/staggered/subcontrolvolumeface.hh b/dumux/discretization/facecentered/staggered/subcontrolvolumeface.hh index d7e6c6e4ba..e5029bfbeb 100644 --- a/dumux/discretization/facecentered/staggered/subcontrolvolumeface.hh +++ b/dumux/discretization/facecentered/staggered/subcontrolvolumeface.hh @@ -77,7 +77,8 @@ public: using Traits = T; using GlobalPosition = typename T::GlobalPosition; - enum class FaceType {frontal, lateral}; + enum class FaceType : SmallLocalIndexType {frontal, lateral}; + enum class BoundaryType : SmallLocalIndexType {interior, physicalBoundary, processorBoundary}; FaceCenteredStaggeredSubControlVolumeFace() = default; @@ -89,7 +90,7 @@ public: const GridIndexType globalScvfIdx, const GlobalPosition& unitOuterNormal, const FaceType faceType, - const bool boundary) + const BoundaryType boundaryType) : globalScvIndices_(globalScvIndices) , localScvfIdx_(localScvfIdx) , globalScvfIdx_(globalScvfIdx) @@ -97,17 +98,17 @@ public: , normalAxis_(Dumux::normalAxis(unitOuterNormal)) , outerNormalSign_(sign(unitOuterNormal[normalAxis_])) , faceType_(faceType) - , boundary_(boundary) + , boundaryType_(boundaryType) { assert(faceType == FaceType::frontal); - center_ = boundary ? intersectionGeometry.center() : elementGeometry.center(); + center_ = boundary() ? intersectionGeometry.center() : elementGeometry.center(); ipGlobal_ = center_; - if (!boundary) + if (!boundary()) outerNormalSign_ *= -1.0; // the corners (coincide with intersection corners for boundary scvfs) - const auto frontalOffSet = boundary ? GlobalPosition(0.0) + const auto frontalOffSet = boundary() ? GlobalPosition(0.0) : intersectionGeometry.center() - elementGeometry.center(); for (int i = 0; i < corners_.size(); ++i) @@ -124,7 +125,7 @@ public: const GridIndexType globalScvfIdx, const GlobalPosition& unitOuterNormal, const FaceType faceType, - const bool boundary) + const BoundaryType boundaryType) : globalScvIndices_(globalScvIndices) , localScvfIdx_(localScvfIdx) , globalScvfIdx_(globalScvfIdx) @@ -132,7 +133,7 @@ public: , normalAxis_(Dumux::normalAxis(unitOuterNormal)) , outerNormalSign_(sign(unitOuterNormal[normalAxis_])) , faceType_(faceType) - , boundary_(boundary) + , boundaryType_(boundaryType) { assert(faceType == FaceType::lateral); const auto shift = intersectionGeometry.center() - elementGeometry.center(); @@ -190,7 +191,10 @@ public: { return faceType_; } bool boundary() const - { return boundary_; } + { return boundaryType_ == BoundaryType::physicalBoundary; } + + bool processorBoundary() const + { return boundaryType_ == BoundaryType::processorBoundary; } bool isFrontal() const { return faceType_ == FaceType::frontal; } @@ -232,7 +236,7 @@ private: SmallLocalIndexType normalAxis_; std::int_least8_t outerNormalSign_; FaceType faceType_; - bool boundary_; + BoundaryType boundaryType_; }; } // end namespace Dumux -- GitLab