diff --git a/dumux/common/pointsource.hh b/dumux/common/pointsource.hh index eaf3b3f6bd901c2b07a52964bdb3fcf9b63ed353..2ca28690edaf53502abd10fbb1fbd0abb7f84ffe 100644 --- a/dumux/common/pointsource.hh +++ b/dumux/common/pointsource.hh @@ -316,7 +316,7 @@ public: constexpr int dim = GridGeometry::GridView::dimension; Dune::ReservedVector<std::size_t, 1<<dim> scvIndices; for (const auto& scv : scvs(fvGeometry)) - if (intersectsPointGeometry(globalPos, scv.geometry())) + if (intersectsPointGeometry(globalPos, fvGeometry.geometry(scv))) scvIndices.push_back(scv.indexInElement()); // for all scvs that tested positive add the point sources diff --git a/dumux/discretization/box/fvelementgeometry.hh b/dumux/discretization/box/fvelementgeometry.hh index 4424e4c64127ffc9c74c60327cd572a8ff50bacc..aeaf3c984e01a2db731d3d4370334e4b355ee3a9 100644 --- a/dumux/discretization/box/fvelementgeometry.hh +++ b/dumux/discretization/box/fvelementgeometry.hh @@ -28,6 +28,10 @@ #include <optional> #include <utility> +#include <unordered_map> +#include <array> +#include <vector> + #include <dune/geometry/type.hh> #include <dune/localfunctions/lagrange/pqkfactory.hh> @@ -59,6 +63,10 @@ class BoxFVElementGeometry<GG, true> using LocalIndexType = typename IndexTraits<GridView>::LocalIndex; using CoordScalar = typename GridView::ctype; using FeLocalBasis = typename GG::FeCache::FiniteElementType::Traits::LocalBasisType; + + using GeometryHelper = BoxGeometryHelper<GridView, dim, + typename GG::SubControlVolume, + typename GG::SubControlVolumeFace>; public: //! export the element type using Element = typename GridView::template Codim<0>::Entity; @@ -185,6 +193,20 @@ public: bool hasBoundaryScvf() const { return gridGeometry().hasBoundaryScvf(eIdx_); } + //! Geometry of a sub control volume + typename SubControlVolume::Traits::Geometry geometry(const SubControlVolume& scv) const + { + assert(isBound()); + return gridGeometryPtr_->geometry(element(), scv); + } + + //! Geometry of a sub control volume face + typename SubControlVolumeFace::Traits::Geometry geometry(const SubControlVolumeFace& scvf) const + { + assert(isBound()); + return gridGeometryPtr_->geometry(element(), scvf); + } + private: const GridGeometry* gridGeometryPtr_; GridIndexType eIdx_; @@ -331,7 +353,32 @@ public: bool hasBoundaryScvf() const { return hasBoundaryScvf_; } + //! Geometry of a sub control volume + typename SubControlVolume::Traits::Geometry geometry(const SubControlVolume& scv) const + { + assert(isBound()); + const auto geo = element().geometry(); + return { Dune::GeometryTypes::cube(dim), GeometryHelper(geo).getScvCorners(scv.indexInElement()) }; + } + + //! Geometry of a sub control volume face + typename SubControlVolumeFace::Traits::Geometry geometry(const SubControlVolumeFace& scvf) const + { + assert(isBound()); + const auto geo = element().geometry(); + if (scvf.boundary()) + { + const auto localBoundaryIndex = scvf.index() - numInnerScvf_(element()); + const auto& key = scvfBoundaryGeometryKeys_[localBoundaryIndex]; + return { Dune::GeometryTypes::cube(dim-1), GeometryHelper(geo).getBoundaryScvfCorners(key[0], key[1]) }; + } + else + return { Dune::GeometryTypes::cube(dim-1), GeometryHelper(geo).getScvfCorners(scvf.index()) }; + } + private: + unsigned int numInnerScvf_(const Element& element) const + { return (dim==1) ? 1 : element.subEntities(dim-1); } void makeElementGeometries_() { @@ -349,7 +396,7 @@ private: scvs_.resize(elementGeometry.corners()); for (LocalIndexType scvLocalIdx = 0; scvLocalIdx < elementGeometry.corners(); ++scvLocalIdx) { - // get asssociated dof index + // get associated dof index const auto dofIdxGlobal = gridGeometry().vertexMapper().subIndex(element, scvLocalIdx, dim); // add scv to the local container @@ -360,8 +407,9 @@ private: } // construct the sub control volume faces - const auto numInnerScvf = (dim==1) ? 1 : element.subEntities(dim-1); + const auto numInnerScvf = numInnerScvf_(element); scvfs_.resize(numInnerScvf); + scvfBoundaryGeometryKeys_.clear(); LocalIndexType scvfLocalIdx = 0; for (; scvfLocalIdx < numInnerScvf; ++scvfLocalIdx) @@ -400,6 +448,11 @@ private: std::move(localScvIndices), true); + scvfBoundaryGeometryKeys_.emplace_back(std::array<LocalIndexType, 2>{{ + static_cast<LocalIndexType>(intersection.indexInInside()), + static_cast<LocalIndexType>(isScvfLocalIdx) + }}); + // increment local counter scvfLocalIdx++; } @@ -417,6 +470,7 @@ private: //! vectors to store the geometries locally after binding an element std::vector<SubControlVolume> scvs_; std::vector<SubControlVolumeFace> scvfs_; + std::vector<std::array<LocalIndexType, 2>> scvfBoundaryGeometryKeys_; bool hasBoundaryScvf_ = false; }; diff --git a/dumux/discretization/box/fvgridgeometry.hh b/dumux/discretization/box/fvgridgeometry.hh index b26b54d3c28b628e491361870960b93b90776968..3e74e7bf25084382c1fac22c92866584cdd8cf26 100644 --- a/dumux/discretization/box/fvgridgeometry.hh +++ b/dumux/discretization/box/fvgridgeometry.hh @@ -28,6 +28,8 @@ #include <utility> #include <unordered_map> +#include <array> +#include <vector> #include <dune/localfunctions/lagrange/lagrangelfecache.hh> @@ -199,11 +201,36 @@ public: bool hasBoundaryScvf(GridIndexType eIdx) const { return hasBoundaryScvf_[eIdx]; } + //! Geometry of a sub control volume + typename SubControlVolume::Traits::Geometry geometry(const Element& element, const SubControlVolume& scv) const + { + assert(isBound()); + const auto geo = element.geometry(); + return { Dune::GeometryTypes::cube(dim), GeometryHelper(geo).getScvCorners(scv.indexInElement()) }; + } + + //! Geometry of a sub control volume face + typename SubControlVolumeFace::Traits::Geometry geometry(const Element& element, const SubControlVolumeFace& scvf) const + { + assert(isBound()); + const auto eIdx = this->elementMapper().index(element); + const auto geo = element.geometry(); + if (scvf.boundary()) + { + const auto localBoundaryIndex = scvf.index() - numInnerScvf_(element); + const auto& key = scvfBoundaryGeometryKeys_.at(eIdx)[localBoundaryIndex]; + return { Dune::GeometryTypes::cube(dim-1), GeometryHelper(geo).getBoundaryScvfCorners(key[0], key[1]) }; + } + else + return { Dune::GeometryTypes::cube(dim-1), GeometryHelper(geo).getScvfCorners(scvf.index()) }; + } + private: void update_() { scvs_.clear(); scvfs_.clear(); + scvfBoundaryGeometryKeys_.clear(); auto numElements = this->gridView().size(0); scvs_.resize(numElements); @@ -287,6 +314,11 @@ private: std::move(localScvIndices), true); + scvfBoundaryGeometryKeys_[eIdx].emplace_back(std::array<LocalIndexType, 2>{{ + static_cast<LocalIndexType>(intersection.indexInInside()), + static_cast<LocalIndexType>(isScvfLocalIdx) + }}); + // increment local counter scvfLocalIdx++; } @@ -347,10 +379,15 @@ private: DUNE_THROW(Dune::NotImplemented, "Periodic boundaries for box method for parallel simulations!"); } + unsigned int numInnerScvf_(const Element& element) const + { return (dim==1) ? 1 : element.subEntities(dim-1); } + const FeCache feCache_; std::vector<std::vector<SubControlVolume>> scvs_; std::vector<std::vector<SubControlVolumeFace>> scvfs_; + std::unordered_map<GridIndexType, std::vector<std::array<LocalIndexType, 2>>> scvfBoundaryGeometryKeys_; + // TODO do we need those? std::size_t numScv_; std::size_t numScvf_; diff --git a/test/discretization/box/test_boxfvgeometry.cc b/test/discretization/box/test_boxfvgeometry.cc index 98ae68f315d698a7415b334424143bbe38a233fa..7550d624eda1eb8de9837e3776c915b3f43d47d6 100644 --- a/test/discretization/box/test_boxfvgeometry.cc +++ b/test/discretization/box/test_boxfvgeometry.cc @@ -100,6 +100,20 @@ int main (int argc, char *argv[]) for (auto&& scv : scvs(fvGeometry)) { std::cout << "-- scv " << scv.localDofIndex() << " center at: " << scv.center() << " , volume: " << scv.volume() << std::endl; + + const auto scvGeo = fvGeometry.geometry(scv); + + if ((scv.center() - scvGeo.center()).two_norm2() > 1e-15) + DUNE_THROW(Dune::Exception, + "scv.center() and fvGeometry.geometry(scv).center() do not match! " + << scv.center() << " :: " << scvGeo.center() + ); + + if (std::abs(scv.volume() - scvGeo.volume()) > 1e-7) + DUNE_THROW(Dune::Exception, + "scv.volume() and fvGeometry.geometry(scv).volume() do not match! " + << scv.volume() << " :: " << scvGeo.volume() + ); } auto range2 = scvfs(fvGeometry); @@ -111,6 +125,21 @@ int main (int argc, char *argv[]) for (auto&& scvf : scvfs(fvGeometry)) { std::cout << "-- scvf " << scvf.index() << " ip at: " << scvf.ipGlobal() << " normal: " << scvf.unitOuterNormal(); + + const auto scvfGeo = fvGeometry.geometry(scvf); + + if ((scvf.ipGlobal() - scvfGeo.center()).two_norm2() > 1e-15) + DUNE_THROW(Dune::Exception, + "scvf.ipGlobal() and fvGeometry.geometry(scvf).center() do not match! " + << scvf.ipGlobal() << " :: " << scvfGeo.center() + ); + + if (std::abs(scvf.area() - scvfGeo.volume()) > 1e-7) + DUNE_THROW(Dune::Exception, + "scvf.area() and fvGeometry.geometry(scvf).volume() do not match! " + << scvf.area() << " :: " << scvfGeo.volume() + ); + if (scvf.boundary()) { ++boundaryCount;