diff --git a/CHANGELOG.md b/CHANGELOG.md index 3aa4e623a626a72f7cb6f4ed7388628cbccbf0e0..25da3d04c98c34b547193ddad852ca41016e81ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ be evaluated with the function values provided in the same order as the names wh - __Compositional Staggered__: The staggered discretization method has been updated to fix inconsistencies in handling density when evaluating diffusive boundary fluxes. In addition, a total mass balance is now always considered, rather than a total mole balance. - __Parameters__: The template argument for `getParam` and `getParamFromGroup` now defaults to `std::string`, such that for string parameters one can simply write `const auto param = getParam("MyParam");` - __Compositional Freeflow FCSFV__: Compositional transport has been implemented for the overhauled face-centered staggered finite volume scheme (FCSFV) discretization method. Ported tests are available in the testing suite. +- __GridGeometry__: No longer store the corners/geometry for scv/scvfs also for cc-mpfa and staggered discretizations. This improves the memory footprint a lot. Geometries can be obtained via the local view of the grid geometry. ### Immediate interface changes not allowing/requiring a deprecation period: @@ -41,6 +42,7 @@ be evaluated with the function values provided in the same order as the names wh - `HAVE_PVPYTHON` to `DUMUX_HAVE_PVPYTHON` ### Deprecated properties/classes/functions/files, to be removed after 3.8: +- __MPFA__: `scvf.corners()/facetCorner()/vertexCorner()` have been deprecated. Use functions from the local view of the grid geometry instead. diff --git a/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh b/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh index b4de9dd31bcb9266a688d47419e2743718b2d948..e1c7531bcdaebc36a86fb1bbdd0bf52071540b1c 100644 --- a/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh +++ b/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh @@ -19,6 +19,7 @@ #include <dune/common/exceptions.hh> #include <dune/common/iteratorrange.hh> +#include <dune/geometry/type.hh> #include <dumux/common/parameters.hh> #include <dumux/common/indextraits.hh> @@ -26,6 +27,66 @@ namespace Dumux { +#ifndef DOXYGEN +namespace Detail::Mpfa { + +template<typename GridGeometry, typename SubControlVolumeFace> +typename SubControlVolumeFace::Traits::Geometry makeScvfGeometry(const GridGeometry& gridGeometry, + const SubControlVolumeFace& scvf) +{ + static constexpr int dim = GridGeometry::GridView::dimension; + + const auto& facetInfo = scvf.facetInfo(); + const auto element = gridGeometry.element(facetInfo.elementIndex); + const auto elemGeo = element.geometry(); + const auto refElement = referenceElement(elemGeo); + for (const auto& is : intersections(gridGeometry.gridView(), element)) + { + if (is.indexInInside() == facetInfo.facetIndex) + { + const auto numCorners = is.geometry().corners(); + const auto isPositions = GridGeometry::MpfaHelper::computeScvfCornersOnIntersection( + elemGeo, refElement, facetInfo.facetIndex, numCorners + ); + return { + Dune::GeometryTypes::cube(dim-1), + GridGeometry::MpfaHelper::getScvfCorners( + isPositions, numCorners, facetInfo.facetCornerIndex + ) + }; + } + } + DUNE_THROW(Dune::InvalidStateException, "Could not construct scvf geometry"); +} + +template<typename GridGeometry, typename SubControlVolumeFace> +auto getVertexCorner(const GridGeometry& gridGeometry, const SubControlVolumeFace& scvf) +{ + static constexpr int dim = GridGeometry::GridView::dimension; + + const auto& facetInfo = scvf.facetInfo(); + const auto element = gridGeometry.element(facetInfo.elementIndex); + const auto elemGeo = element.geometry(); + const auto refElement = referenceElement(elemGeo); + return elemGeo.global(refElement.position( + refElement.subEntity(facetInfo.facetIndex, 1, facetInfo.facetCornerIndex, dim), + dim + )); +} + +template<typename GridGeometry, typename SubControlVolumeFace> +auto getFacetCorner(const GridGeometry& gridGeometry, const SubControlVolumeFace& scvf) +{ + const auto& facetInfo = scvf.facetInfo(); + const auto element = gridGeometry.element(facetInfo.elementIndex); + const auto elemGeo = element.geometry(); + const auto refElement = referenceElement(elemGeo); + return elemGeo.global(refElement.position(facetInfo.facetIndex, 1)); +} + +} // namespace Detail::Mpfa +#endif // DOXYGEN + /*! * \ingroup CCMpfaDiscretization * \brief Stencil-local finite volume geometry (scvs and scvfs) for cell-centered mpfa models @@ -52,6 +113,7 @@ class CCMpfaFVElementGeometry<GG, true> using GridIndexType = typename IndexTraits<GridView>::GridIndex; static constexpr int dim = GridView::dimension; + static constexpr int dimWorld = GridView::dimensionworld; public: //! export type of the element @@ -184,16 +246,17 @@ public: typename Element::Geometry geometry(const SubControlVolume& scv) const { return gridGeometryPtr_->element(scv.dofIndex()).geometry(); } - // suppress warnings due to current implementation - // these interfaces should be used! - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - //! Create the geometry of a given sub control volume face typename SubControlVolumeFace::Traits::Geometry geometry(const SubControlVolumeFace& scvf) const - { return scvf.geometry(); } + { return Detail::Mpfa::makeScvfGeometry(gridGeometry(), scvf); } + + //! Return the position of the scvf corner that coincides with an element vertex + typename SubControlVolumeFace::Traits::GlobalPosition vertexCorner(const SubControlVolumeFace& scvf) const + { return Detail::Mpfa::getVertexCorner(gridGeometry(), scvf); } - #pragma GCC diagnostic pop + //! Return the corner of the scvf that is inside the facet the scvf is embedded in + typename SubControlVolumeFace::Traits::GlobalPosition facetCorner(const SubControlVolumeFace& scvf) const + { return Detail::Mpfa::getFacetCorner(gridGeometry(), scvf); } private: @@ -215,8 +278,8 @@ class CCMpfaFVElementGeometry<GG, false> using GridIndexType = typename IndexTraits<GridView>::GridIndex; using MpfaHelper = typename GG::MpfaHelper; - static const int dim = GridView::dimension; - static const int dimWorld = GridView::dimensionworld; + static constexpr int dim = GridView::dimension; + static constexpr int dimWorld = GridView::dimensionworld; using CoordScalar = typename GridView::ctype; public: @@ -345,20 +408,21 @@ public: bool hasBoundaryScvf() const { return hasBoundaryScvf_; } - // suppress warnings due to current implementation - // these interfaces should be used! - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - //! Create the geometry of a given sub control volume typename SubControlVolume::Traits::Geometry geometry(const SubControlVolume& scv) const - { return scv.geometry(); } + { return gridGeometryPtr_->element(scv.dofIndex()).geometry(); } //! Create the geometry of a given sub control volume face typename SubControlVolumeFace::Traits::Geometry geometry(const SubControlVolumeFace& scvf) const - { return scvf.geometry(); } + { return Detail::Mpfa::makeScvfGeometry(gridGeometry(), scvf); } - #pragma GCC diagnostic pop + //! Return the position of the scvf corner that coincides with an element vertex + typename SubControlVolumeFace::Traits::GlobalPosition vertexCorner(const SubControlVolumeFace& scvf) const + { return Detail::Mpfa::getVertexCorner(gridGeometry(), scvf); } + + //! Return the corner of the scvf that is inside the facet the scvf is embedded in + typename SubControlVolumeFace::Traits::GlobalPosition facetCorner(const SubControlVolumeFace& scvf) const + { return Detail::Mpfa::getFacetCorner(gridGeometry(), scvf); } private: @@ -489,10 +553,15 @@ private: continue; hasBoundaryScvf_ = (hasBoundaryScvf_ || is.boundary()); - + typename SubControlVolumeFace::FacetInfo facetInfo{ + gridGeometry().elementMapper().index(e), + useNeighbor ? is.indexInOutside() : is.indexInInside(), + c + }; scvfs_.emplace_back(MpfaHelper(), MpfaHelper::getScvfCorners(isPositions, numCorners, c), is, + std::move(facetInfo), vIdxGlobal, vIdxLocal, scvFaceIndices[scvfCounter], @@ -580,9 +649,15 @@ private: } // build scvf + typename SubControlVolumeFace::FacetInfo facetInfo{ + gridGeometry().elementMapper().index(e), + useNeighbor ? is.indexInOutside() : is.indexInInside(), + c + }; neighborScvfs_.emplace_back(MpfaHelper(), MpfaHelper::getScvfCorners(isPositions, numCorners, c), is, + std::move(facetInfo), vIdxGlobal, vIdxLocal, scvFaceIndices[scvfCounter], diff --git a/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh b/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh index f89340ab07379df227f2ad2355b35ad62cca05e2..5ddc0345db8ce1887ecc71ae5133b14760942a8e 100644 --- a/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh +++ b/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh @@ -308,7 +308,7 @@ private: const bool usesSecondaryIV = secondaryIvIndicator_(element, is, isBranchingPoint); // make the scv faces belonging to each corner of the intersection - for (std::size_t c = 0; c < numCorners; ++c) + for (int c = 0; c < numCorners; ++c) { // get the global vertex index the scv face is connected to const auto vIdxLocal = refElement.subEntity(indexInElement, 1, c, dim); @@ -337,9 +337,15 @@ private: } (); scvfIndexSet.push_back(scvfIdx); + typename SubControlVolumeFace::FacetInfo facetInfo{ + this->elementMapper().index(e), + useNeighbor ? is.indexInOutside() : is.indexInInside(), + c + }; scvfs_.emplace_back(MpfaHelper(), MpfaHelper::getScvfCorners(isPositions, numCorners, c), is, + std::move(facetInfo), vIdxGlobal, vIdxLocal, scvfIdx, diff --git a/dumux/discretization/cellcentered/mpfa/omethod/scvgeometryhelper.hh b/dumux/discretization/cellcentered/mpfa/omethod/scvgeometryhelper.hh index 4d772a3982d24288adfc4f208fce38675953f4c0..4db457755c16f2df866bade3aec9e8461c734867 100644 --- a/dumux/discretization/cellcentered/mpfa/omethod/scvgeometryhelper.hh +++ b/dumux/discretization/cellcentered/mpfa/omethod/scvgeometryhelper.hh @@ -71,9 +71,9 @@ public: typename MLGTraits::template CornerStorage<dim, dimWorld>::Type corners; corners[0] = fvGeometry.scv( scv.gridScvIndex() ).center(); - corners[1] = firstGridScvf.facetCorner(); - corners[2] = secondGridScvf.facetCorner(); - corners[3] = secondGridScvf.vertexCorner(); + corners[1] = fvGeometry.facetCorner(firstGridScvf); + corners[2] = fvGeometry.facetCorner(secondGridScvf); + corners[3] = fvGeometry.vertexCorner(secondGridScvf); using std::swap; typename LocalScvType::LocalBasis basis; diff --git a/dumux/discretization/cellcentered/mpfa/subcontrolvolumeface.hh b/dumux/discretization/cellcentered/mpfa/subcontrolvolumeface.hh index d677c55da6d041b04515784f3eb6aeb4c1887dc1..7249250cadb874fbc9dc5f62fadbab7d90c5aa51 100644 --- a/dumux/discretization/cellcentered/mpfa/subcontrolvolumeface.hh +++ b/dumux/discretization/cellcentered/mpfa/subcontrolvolumeface.hh @@ -12,6 +12,7 @@ #ifndef DUMUX_DISCRETIZATION_CC_MPFA_SUBCONTROLVOLUMEFACE_HH #define DUMUX_DISCRETIZATION_CC_MPFA_SUBCONTROLVOLUMEFACE_HH +#include <utility> #include <vector> #include <array> @@ -92,6 +93,14 @@ class CCMpfaSubControlVolumeFace using BoundaryFlag = typename T::BoundaryFlag; public: + // Information on the intersection from which this scvf was constructed + struct FacetInfo + { + GridIndexType elementIndex; + int facetIndex; + int facetCornerIndex; + }; + //! export the type used for global coordinates using GlobalPosition = typename T::GlobalPosition; //! state the traits public and thus export all types @@ -103,6 +112,7 @@ public: * \param helper The helper class for mpfa schemes * \param corners The corners of the scv face * \param intersection The intersection + * \param facetInfo Information on the facet from which this scvf is constructed * \param vIdxGlobal The global vertex index the scvf is connected to * \param vIdxLocal The element-local vertex index the scvf is connected to * \param scvfIndex The global index of this scv face @@ -116,6 +126,7 @@ public: CCMpfaSubControlVolumeFace(const MpfaHelper& helper, CornerStorage&& corners, const Intersection& intersection, + FacetInfo facetInfo, GridIndexType vIdxGlobal, unsigned int vIdxLocal, GridIndexType scvfIndex, @@ -133,6 +144,7 @@ public: , center_(0.0) , unitOuterNormal_(intersection.centerUnitOuterNormal()) , boundaryFlag_{intersection} + , facetInfo_{std::move(facetInfo)} { // compute the center of the scvf for (const auto& corner : corners_) @@ -182,14 +194,17 @@ public: { return outsideScvIndices_; } //! Returns the number of corners + [[deprecated("Will be removed after 3.8. Use fvGeometry.geometry(scvf).corners().")]] std::size_t corners() const { return corners_.size(); } //! Returns the global position of the vertex the scvf is connected to + [[deprecated("Will be removed after 3.8. Use fvGeometry.vertexCorner(scvf)")]] const GlobalPosition& vertexCorner() const { return corners_.back(); } //! Returns the global position of the center of the element facet this scvf is embedded in + [[deprecated("Will be removed after 3.8. Use fvGeometry.facetCorner(scvf)")]] const GlobalPosition& facetCorner() const { return corners_[0]; } @@ -205,15 +220,14 @@ public: const GlobalPosition& unitOuterNormal() const { return unitOuterNormal_; } - //! The geometry of the sub control volume face - [[deprecated("Will be removed after 3.7. Use fvGeometry.geometry(scvf).")]] - Geometry geometry() const - { return Geometry(Dune::GeometryTypes::cube(Geometry::mydimension), corners_); } - //! Return the boundary flag typename BoundaryFlag::value_type boundaryFlag() const { return boundaryFlag_.get(); } + //! Return information on the facet from which this scvf was constructed + const FacetInfo& facetInfo() const + { return facetInfo_; } + private: bool boundary_; GridIndexType vertexIndex_; @@ -228,6 +242,7 @@ private: GlobalPosition unitOuterNormal_; Scalar area_; BoundaryFlag boundaryFlag_; + FacetInfo facetInfo_; }; } // end namespace Dumux diff --git a/dumux/discretization/facecentered/staggered/fvelementgeometry.hh b/dumux/discretization/facecentered/staggered/fvelementgeometry.hh index 5d4bc1024f7b6362b2058a816a614a3372d3d0eb..297df24ade3f394cd87d9b9c04fbb38f92d55bdb 100644 --- a/dumux/discretization/facecentered/staggered/fvelementgeometry.hh +++ b/dumux/discretization/facecentered/staggered/fvelementgeometry.hh @@ -13,6 +13,7 @@ #define DUMUX_DISCRETIZATION_FACECENTERED_STAGGERED_FV_ELEMENT_GEOMETRY_HH #include <utility> +#include <bitset> #include <dune/common/rangeutilities.hh> #include <dune/common/reservedvector.hh> @@ -26,6 +27,73 @@ namespace Dumux { +#ifndef DOXYGEN +namespace Detail::FCStaggered { + +template<class FVElementGeometry, class SubControlVolume> +typename SubControlVolume::Traits::Geometry scvGeometry(const FVElementGeometry& fvGeometry, + const SubControlVolume& scv) +{ + typename SubControlVolume::Traits::CornerStorage corners{}; + // select the containing element + const auto elementGeometry = (scv.elementIndex() != fvGeometry.elementIndex()) ? + fvGeometry.element().geometry() : + fvGeometry.gridGeometry().element(scv.elementIndex()).geometry(); + + const auto center = elementGeometry.center(); + const auto dofAxis = scv.dofAxis(); + for (int i = 0; i < corners.size(); ++i) + { + auto& corner = corners[i]; + + // copy the corner of the corresponding element + corner = elementGeometry.corner(i); + + // shift the corner such that the scv covers half of the element + // (keep the corner positions at the face with the staggered dof) + if ((corner[dofAxis] - center[dofAxis]) * scv.directionSign() < 0.0) + corner[dofAxis] = center[dofAxis]; + } + + return {corners.front(), corners.back()}; +} + +template<class FVElementGeometry, class SubControlVolumeFace> +typename SubControlVolumeFace::Traits::Geometry scvfGeometry(const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvf) +{ + const auto normalAxis = scvf.normalAxis(); + const auto center = scvf.center(); + const auto shift = scvf.ipGlobal() - center; + const auto dofAxis = scvf.isLateral() ? Dumux::normalAxis(shift) : normalAxis; + const auto insideElementIndex = (fvGeometry.scv(scvf.insideScvIdx())).elementIndex(); + const auto elementGeometry = (insideElementIndex != fvGeometry.elementIndex()) ? + fvGeometry.element().geometry() : + fvGeometry.gridGeometry().element(insideElementIndex).geometry(); + + auto corners = std::array{ + elementGeometry.corner(0), + elementGeometry.corner(elementGeometry.corners() - 1) + }; + + // shift corners to scvf plane and halve lateral faces + for (int i = 0; i < corners.size(); ++i) + { + auto& corner = corners[i]; + corner[normalAxis] = center[normalAxis]; + if (scvf.isLateral() && (corner - center)*shift < 0.0) + corner[dofAxis] = elementGeometry.center()[dofAxis]; + } + + auto inPlaneAxes = std::move(std::bitset<SubControlVolumeFace::Traits::dimWorld>{}.set()); + inPlaneAxes.set(normalAxis, false); + + return {corners[0], corners[1], inPlaneAxes}; +} + +} // end namespace Detail::FCStaggered +#endif // DOXYGEN + template<class GG, bool cachingEnabled> class FaceCenteredStaggeredFVElementGeometry; @@ -209,20 +277,17 @@ public: DUNE_THROW(Dune::InvalidStateException, "No outside scvf found"); } - // suppress warnings due to current implementation - // these interfaces should be used! - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - //! Create the geometry of a given sub control volume typename SubControlVolume::Traits::Geometry geometry(const SubControlVolume& scv) const - { return scv.geometry(); } + { + return Detail::FCStaggered::scvGeometry(*this, scv); + } //! Create the geometry of a given sub control volume face typename SubControlVolumeFace::Traits::Geometry geometry(const SubControlVolumeFace& scvf) const - { return scvf.geometry(); } - - #pragma GCC diagnostic pop + { + return Detail::FCStaggered::scvfGeometry(*this, scvf); + } private: @@ -436,20 +501,17 @@ public: DUNE_THROW(Dune::InvalidStateException, "No outside scvf found"); } - // suppress warnings due to current implementation - // these interfaces should be used! - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - //! Create the geometry of a given sub control volume typename SubControlVolume::Traits::Geometry geometry(const SubControlVolume& scv) const - { return scv.geometry(); } + { + return Detail::FCStaggered::scvGeometry(*this, scv); + } //! Create the geometry of a given sub control volume face typename SubControlVolumeFace::Traits::Geometry geometry(const SubControlVolumeFace& scvf) const - { return scvf.geometry(); } - - #pragma GCC diagnostic pop + { + return Detail::FCStaggered::scvfGeometry(*this, scvf); + } private: //! Binding of an element preparing the geometries of the whole stencil diff --git a/dumux/discretization/facecentered/staggered/subcontrolvolume.hh b/dumux/discretization/facecentered/staggered/subcontrolvolume.hh index a33bc9656bf6183bce4cbb277939f132c086f0f6..9dab0bedfcfff1f663690cd4d78ceeb6d153ef2c 100644 --- a/dumux/discretization/facecentered/staggered/subcontrolvolume.hh +++ b/dumux/discretization/facecentered/staggered/subcontrolvolume.hh @@ -86,21 +86,6 @@ public: , eIdx_(eIdx) , boundary_(boundary) { - for (int i = 0; i < corners_.size(); ++i) - { - auto& corner = corners_[i]; - - // copy the corner of the corresponding element - corner = elementGeometry.corner(i); - - // shift the corner such that the scvf covers half of the lateral facet - // (keep the outer corner positions) - using std::abs; - const auto eps = 1e-8; // TODO - if (abs(corner[dofAxis] - intersectionGeometry.center()[dofAxis]) > eps) - corner[dofAxis] = elementGeometry.center()[dofAxis]; - } - directionSign_ = (indexInElement % 2) ? 1.0 : -1.0; } @@ -139,17 +124,9 @@ public: bool boundary() const { return boundary_; } - //! The geometry of the sub control volume face - [[deprecated("Will be removed after 3.7. Use fvGeometry.geometry(scv).")]] - Geometry geometry() const - { - return Geometry(corners_.front(), corners_.back()); - } - private: GlobalPosition center_; GlobalPosition dofPosition_; - CornerStorage corners_; Scalar volume_; GridIndexType globalIndex_; SmallLocalIndexType indexInElement_; diff --git a/dumux/discretization/facecentered/staggered/subcontrolvolumeface.hh b/dumux/discretization/facecentered/staggered/subcontrolvolumeface.hh index 9adb53bb86e59e2504a2b38880d81af5e899c237..bc7a5a8ec25dd9bc1e83b802d7d3cd70602bb5f9 100644 --- a/dumux/discretization/facecentered/staggered/subcontrolvolumeface.hh +++ b/dumux/discretization/facecentered/staggered/subcontrolvolumeface.hh @@ -13,7 +13,6 @@ #define DUMUX_DISCRETIZATION_FACECENTERED_STAGGERED_SUBCONTROLVOLUMEFACE_HH #include <array> -#include <utility> #include <dune/common/fvector.hh> #include <dune/geometry/type.hh> @@ -98,13 +97,6 @@ public: if (!boundary()) outerNormalSign_ *= -1.0; - - // the corners (coincide with intersection corners for boundary scvfs) - const auto frontalOffSet = boundary() ? GlobalPosition(0.0) - : intersectionGeometry.center() - elementGeometry.center(); - - for (int i = 0; i < corners_.size(); ++i) - corners_[i] = intersectionGeometry.corner(i) + frontalOffSet; } //! The constructor for lateral faces @@ -131,22 +123,6 @@ public: const auto shift = intersectionGeometry.center() - elementGeometry.center(); ipGlobal_ = lateralFacetGeometry.center() + shift; center_ = 0.5*(lateralFacetGeometry.center() + ipGlobal_); - - const auto dofAxis = Dumux::normalAxis(shift); - const auto eps = shift.two_norm() * 1e-8; - - for (int i = 0; i < corners_.size(); ++i) - { - // copy the corner of the corresponding lateral facet - auto& corner = corners_[i]; - corner = lateralFacetGeometry.corner(i); - - // shift the corner such that the scvf covers half of the lateral facet - // (keep the outer corner positions) - using std::abs; - if (abs(corner[dofAxis] - intersectionGeometry.center()[dofAxis]) > eps) - corner[dofAxis] = elementGeometry.center()[dofAxis]; - } } //! The center of the sub control volume face @@ -203,19 +179,9 @@ public: std::int_least8_t directionSign() const { return outerNormalSign_; } - //! The geometry of the sub control volume face - [[deprecated("Will be removed after 3.7. Use fvGeometry.geometry(scvf).")]] - Geometry geometry() const - { - auto inPlaneAxes = std::move(std::bitset<T::dimWorld>{}.set()); - inPlaneAxes.set(normalAxis_, false); - return { corners_.front(), corners_.back(), inPlaneAxes }; - } - private: GlobalPosition center_; GlobalPosition ipGlobal_; - CornerStorage corners_; std::array<GridIndexType, 2> globalScvIndices_; SmallLocalIndexType localScvfIdx_; GridIndexType globalScvfIdx_; diff --git a/dumux/discretization/staggered/freeflow/subcontrolvolumeface.hh b/dumux/discretization/staggered/freeflow/subcontrolvolumeface.hh index 5caf10a4e67d368336885a8be6f793abcd08d954..219fcc9f7e7c0692598e72df92c01a8720b89862 100644 --- a/dumux/discretization/staggered/freeflow/subcontrolvolumeface.hh +++ b/dumux/discretization/staggered/freeflow/subcontrolvolumeface.hh @@ -19,7 +19,6 @@ #include <dune/geometry/multilineargeometry.hh> #include <dumux/common/indextraits.hh> -#include <dumux/common/typetraits/isvalid.hh> #include <dumux/discretization/subcontrolvolumefacebase.hh> #include <dumux/discretization/staggered/subcontrolvolumeface.hh> #include <dumux/discretization/staggered/freeflow/staggeredgeometryhelper.hh> @@ -28,22 +27,6 @@ namespace Dumux { -#ifndef DOXYGEN -namespace Detail { -// helper struct detecting if the container class storing the scvf's corners has a resize function -struct HasResize -{ - template<class Container> auto operator()(Container&& c) - -> decltype(c.resize(1)) {} -}; - -template<class C> -constexpr bool hasResize() -{ return decltype(isValid(HasResize{})(std::declval<C>()))::value; } - -} // end namespace Detail -#endif - /*! * \ingroup StaggeredDiscretization * \brief Default traits class to be used for the sub-control volume faces @@ -65,22 +48,9 @@ struct FreeFlowStaggeredDefaultScvfGeometryTraits static constexpr int dim = Grid::dimension; static constexpr int dimWorld = Grid::dimensionworld; - // we use geometry traits that use static corner vectors to and a fixed geometry type - template <class ct> - struct ScvfMLGTraits : public Dune::MultiLinearGeometryTraits<ct> - { - // we use static vectors to store the corners as we know - // the number of corners in advance (2^(dim-1) corners (1<<(dim-1)) - template< int mydim, int cdim > - struct CornerStorage - { - using Type = std::array< Dune::FieldVector< ct, cdim >, (1<<(dim-1)) >; - }; - }; - - using Geometry = Dune::MultiLinearGeometry<Scalar, dim-1, dimWorld, ScvfMLGTraits<Scalar> >; - using CornerStorage = typename ScvfMLGTraits<Scalar>::template CornerStorage<dim-1, dimWorld>::Type; - using GlobalPosition = typename CornerStorage::value_type; + using Element = typename GridView::template Codim<0>::Entity; + using GlobalPosition = typename Element::Geometry::GlobalCoordinate; + using Geometry = Dune::AxisAlignedCubeGeometry<Scalar, dim-1, dimWorld>; }; /*! @@ -115,7 +85,6 @@ class FreeFlowStaggeredSubControlVolumeFace using Geometry = typename T::Geometry; using GridIndexType = typename IndexTraits<GV>::GridIndex; using LocalIndexType = typename IndexTraits<GV>::LocalIndex; - using CornerStorage = typename T::CornerStorage; using PairData = typename T::PairData; using AxisData = typename T::AxisData; @@ -146,7 +115,6 @@ public: const std::vector<GridIndexType>& scvIndices, const typename T::GeometryHelper& geometryHelper) : ParentType(), - geomType_(isGeometry.type()), area_(isGeometry.volume()), center_(isGeometry.center()), unitOuterNormal_(is.centerUnitOuterNormal()), @@ -160,11 +128,9 @@ public: outerNormalSign_(sign(unitOuterNormal_[directionIndex()])), isGhostFace_(false) { - if constexpr (Detail::hasResize<CornerStorage>()) - corners_.resize(isGeometry.corners()); - - for (int i = 0; i < isGeometry.corners(); ++i) - corners_[i] = isGeometry.corner(i); + dimensions[0] = (isGeometry.corner(1) - isGeometry.corner(0)).two_norm(); + if constexpr (dim == 3) + dimensions[1] = (isGeometry.corner(2) - isGeometry.corner(0)).two_norm(); } //! The center of the sub control volume face @@ -222,13 +188,6 @@ public: return scvfIndex_; } - //! The geometry of the sub control volume face - [[deprecated("Will be removed after 3.7. Use fvGeometry.geometry(scvf).")]] - const Geometry geometry() const - { - return Geometry(geomType_, corners_); - } - //! The local index of this sub control volume face LocalIndexType localFaceIdx() const { @@ -280,15 +239,10 @@ public: //! Returns the length of the face in a certain direction (adaptation of area() for 3d) Scalar faceLength(const int localSubFaceIdx) const { - if (dim == 3) - { - if (localSubFaceIdx < 2) - return (corners_[1] - corners_[0]).two_norm(); - else - return (corners_[2] - corners_[0]).two_norm(); - } + if (dim == 3 && localSubFaceIdx > 1) + return dimensions[1]; else - return (corners_[1] - corners_[0]).two_norm(); + return dimensions[0]; } /*! @@ -442,8 +396,7 @@ public: { isGhostFace_ = isGhostFaceFlag; } private: - Dune::GeometryType geomType_; - CornerStorage corners_; + std::array<Scalar, dim-1> dimensions; Scalar area_; GlobalPosition center_; GlobalPosition unitOuterNormal_; diff --git a/dumux/discretization/staggered/fvelementgeometry.hh b/dumux/discretization/staggered/fvelementgeometry.hh index ee9ec9747ea74296c8a387ec142085998a89acff..8279145c0944034c3c14a5dc7530e914c200c0cc 100644 --- a/dumux/discretization/staggered/fvelementgeometry.hh +++ b/dumux/discretization/staggered/fvelementgeometry.hh @@ -15,6 +15,7 @@ #include <optional> #include <dumux/common/indextraits.hh> #include <dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh> +#include <dumux/discretization/facecentered/staggered/normalaxis.hh> namespace Dumux { @@ -207,20 +208,32 @@ public: bool hasBoundaryScvf() const { return hasBoundaryScvf_; } - // suppress warnings due to current implementation - // these interfaces should be used! - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wdeprecated-declarations" - //! Create the geometry of a given sub control volume typename SubControlVolume::Traits::Geometry geometry(const SubControlVolume& scv) const - { return scv.geometry(); } + { return gridGeometryPtr_->element(scv.dofIndex()).geometry(); } //! Create the geometry of a given sub control volume face typename SubControlVolumeFace::Traits::Geometry geometry(const SubControlVolumeFace& scvf) const - { return scvf.geometry(); } + { + const auto insideElementIndex = scvf.insideScvIdx(); + const auto elementGeometry = (insideElementIndex != scvIndices_[0]) ? + element_->geometry() : + gridGeometryPtr_->element(insideElementIndex).geometry(); + const auto center = elementGeometry.center(); + const auto normalAxis = Dumux::normalAxis(scvf.unitOuterNormal()); + + auto lowerLeft = elementGeometry.corner(0); + auto upperRight = elementGeometry.corner(elementGeometry.corners()-1); - #pragma GCC diagnostic pop + // shift corners to scvf plane and halve lateral faces + lowerLeft[normalAxis] = center[normalAxis]; + upperRight[normalAxis] = center[normalAxis]; + + auto inPlaneAxes = std::move(std::bitset<SubControlVolumeFace::Traits::dimWorld>{}.set()); + inPlaneAxes.set(normalAxis, false); + + return {lowerLeft, upperRight, inPlaneAxes}; + } private: //! Binding of an element preparing the geometries only inside the element diff --git a/dumux/discretization/staggered/subcontrolvolumeface.hh b/dumux/discretization/staggered/subcontrolvolumeface.hh index 6adf5ef48044914edb3a56eea382d3f08ec799e9..1a6b43d1f0a9289acbcd8709f9f3ffc2dadf3cad 100644 --- a/dumux/discretization/staggered/subcontrolvolumeface.hh +++ b/dumux/discretization/staggered/subcontrolvolumeface.hh @@ -85,11 +85,15 @@ private: template<class GridView> struct StaggeredDefaultScvfGeometryTraits { - using Geometry = typename GridView::template Codim<1>::Geometry; using GridIndexType = typename IndexTraits<GridView>::GridIndex; using LocalIndexType = typename IndexTraits<GridView>::LocalIndex; using Scalar = typename GridView::ctype; - using GlobalPosition = Dune::FieldVector<Scalar, GridView::dimensionworld>; + using Element = typename GridView::template Codim<0>::Entity; + using GlobalPosition = typename Element::Geometry::GlobalCoordinate; + + static constexpr int dim = GridView::Grid::dimension; + static constexpr int dimWorld = GridView::Grid::dimensionworld; + using Geometry = Dune::AxisAlignedCubeGeometry<Scalar, dim-1, dimWorld>; }; /*! @@ -129,7 +133,6 @@ public: const std::vector<GridIndexType>& scvIndices, const GeometryHelper& geometryHelper) : ParentType() - , geomType_(isGeometry.type()) , area_(isGeometry.volume()) , center_(isGeometry.center()) , unitOuterNormal_(is.centerUnitOuterNormal()) @@ -137,10 +140,6 @@ public: , scvIndices_(scvIndices) , boundary_(is.boundary()) { - corners_.resize(isGeometry.corners()); - for (int i = 0; i < isGeometry.corners(); ++i) - corners_[i] = isGeometry.corner(i); - dofIdx_ = geometryHelper.dofIndex(); localFaceIdx_ = geometryHelper.localFaceIndex(); } @@ -200,13 +199,6 @@ public: return scvfIndex_; } - //! The geometry of the sub control volume face - [[deprecated("Will be removed after 3.7. Use fvGeometry.geometry(scvf).")]] - const Geometry geometry() const - { - return Geometry(geomType_, corners_); - } - //! The global index of the dof living on this face GridIndexType dofIndex() const { @@ -220,8 +212,6 @@ public: } private: - Dune::GeometryType geomType_; - std::vector<GlobalPosition> corners_; Scalar area_; GlobalPosition center_; GlobalPosition unitOuterNormal_; diff --git a/dumux/multidomain/facet/cellcentered/mpfa/couplingmapper.hh b/dumux/multidomain/facet/cellcentered/mpfa/couplingmapper.hh index 9c9d612d1d8d7c129572e0c0ab5d189429b96be2..54fc7ca8de8c1f034105b3e6784e69302b768e2b 100644 --- a/dumux/multidomain/facet/cellcentered/mpfa/couplingmapper.hh +++ b/dumux/multidomain/facet/cellcentered/mpfa/couplingmapper.hh @@ -127,7 +127,7 @@ public: else { const auto eps = lowDimGeometry.volume()*1e-8; - const auto diffVec = lowDimGeometry.center()-scvf.facetCorner(); + const auto diffVec = lowDimGeometry.center()-fvGeometry.facetCorner(scvf); if ( Dune::FloatCmp::eq<GlobalPosition, Dune::FloatCmp::CmpStyle::absolute>(diffVec, GlobalPosition(0.0), eps) ) embeddedScvfIndices.push_back(scvf.index()); diff --git a/test/discretization/cellcentered/CMakeLists.txt b/test/discretization/cellcentered/CMakeLists.txt index 6e2ca56bcc4d2c3b41ebf2b4c1dd7e3aa68ec146..3e84f26153d4fbe8c2dfd6ad914fe975c85baf76 100644 --- a/test/discretization/cellcentered/CMakeLists.txt +++ b/test/discretization/cellcentered/CMakeLists.txt @@ -1,4 +1,5 @@ # SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder # SPDX-License-Identifier: GPL-3.0-or-later -add_subdirectory("tpfa") +add_subdirectory(tpfa) +add_subdirectory(mpfa) diff --git a/test/discretization/cellcentered/mpfa/CMakeLists.txt b/test/discretization/cellcentered/mpfa/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..606c9160b7d29553f1074f2ae16f0ee262aeb9dc --- /dev/null +++ b/test/discretization/cellcentered/mpfa/CMakeLists.txt @@ -0,0 +1,11 @@ +# SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder +# SPDX-License-Identifier: GPL-3.0-or-later + +dumux_add_test(NAME test_mpfafvgeometry + SOURCES test_mpfafvgeometry.cc + LABELS unit discretization) + +dumux_add_test(NAME test_mpfafvgeometry_caching + SOURCES test_mpfafvgeometry.cc + LABELS unit discretization + COMPILE_DEFINITIONS ENABLECACHING=1) diff --git a/test/discretization/cellcentered/mpfa/test_mpfafvgeometry.cc b/test/discretization/cellcentered/mpfa/test_mpfafvgeometry.cc new file mode 100644 index 0000000000000000000000000000000000000000..447e260792a1e9ccbf0113b33e83d91b93a270e0 --- /dev/null +++ b/test/discretization/cellcentered/mpfa/test_mpfafvgeometry.cc @@ -0,0 +1,159 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +// +// SPDX-FileCopyrightInfo: Copyright © DuMux Project contributors, see AUTHORS.md in root folder +// SPDX-License-Identifier: GPL-3.0-or-later +// +/*! + * \file + * \brief Test for the mpfa finite volume element geometry. + */ +#include <config.h> + +#include <iostream> +#include <vector> +#include <utility> +#include <algorithm> + +#include <dune/common/fvector.hh> +#include <dune/common/float_cmp.hh> +#include <dune/grid/yaspgrid.hh> + +#include <dumux/common/initialize.hh> +#include <dumux/common/properties.hh> +#include <dumux/common/parameters.hh> +#include <dumux/discretization/ccmpfa.hh> + +#ifndef ENABLECACHING +#define ENABLECACHING 0 +#endif + +namespace Dumux::Properties { +namespace TTag { struct TestTag { using InheritsFrom = std::tuple<CCMpfaModel>; }; } + +template<typename TypeTag> +struct Grid<TypeTag, TTag::TestTag> { using type = Dune::YaspGrid<2>; }; + +template<typename TypeTag> +struct Scalar<TypeTag, TTag::TestTag> { using type = double; }; + +template<typename TypeTag> +struct EnableGridGeometryCache<TypeTag, TTag::TestTag> { + static constexpr bool value = ENABLECACHING; +}; + +} // namespace Dumux::Properties + +template<class Range> +auto size(const Range& r) +{ return std::distance(std::begin(r), std::end(r)); } + +template<class FVElementGeometry> +auto numBoundaryScvfs(const FVElementGeometry& fvGeometry) +{ + unsigned int count = 0; + for (const auto& scvf : scvfs(fvGeometry)) + if (scvf.boundary()) + count++; + return count; +} + +template<typename Geometry> +auto popped(std::vector<typename Geometry::GlobalCoordinate> expected, const Geometry& geo) +{ + using T = std::vector<typename Geometry::GlobalCoordinate>; + for (int c = 0; c < geo.corners(); ++c) + { + auto it = std::find_if( + expected.begin(), + expected.end(), + [corner=geo.corner(c)] (const auto& exp) { + return Dune::FloatCmp::eq(corner, exp); + }); + if (it == expected.end()) + { + std::cout << "Could not find corner " << geo.corner(c) << std::endl; + return std::optional<T>{}; + } + expected.erase(it); + } + return std::optional<T>{std::move(expected)}; +} + +int main (int argc, char *argv[]) +{ + using namespace Dumux; + + initialize(argc, argv); + Parameters::init(argc, argv); + + std::cout << "Checking the FVGeometries, SCVs and SCV faces" << std::endl; + + using TypeTag = Properties::TTag::TestTag; + using GridGeometry = GetPropType<TypeTag, Properties::GridGeometry>; + using FVElementGeometry = typename GridGeometry::LocalView; + using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; + + GetPropType<TypeTag, Properties::Grid> grid{{1.0, 1.0}, {1, 1}}; + auto leafGridView = grid.leafGridView(); + GridGeometry gridGeometry(leafGridView); + + for (const auto& element : elements(leafGridView)) + { + auto fvGeometry = localView(gridGeometry); + + if (fvGeometry.isBound()) + DUNE_THROW(Dune::Exception, "Local view should not be bound at this point"); + + fvGeometry.bind(element); + if (!fvGeometry.isBound()) + DUNE_THROW(Dune::Exception, "Local view should be bound at this point"); + + const auto eIdx = gridGeometry.elementMapper().index(element); + const auto eIdxBound = gridGeometry.elementMapper().index(fvGeometry.element()); + if (eIdx != eIdxBound) + DUNE_THROW(Dune::Exception, "Bound element index does not match"); + + if (size(scvs(fvGeometry)) != 1) DUNE_THROW(Dune::InvalidStateException, "Unexpected number of scvs"); + if (size(scvfs(fvGeometry)) != 8) DUNE_THROW(Dune::InvalidStateException, "Unexpected number of scvfs"); + if (numBoundaryScvfs(fvGeometry) != 8) DUNE_THROW(Dune::InvalidStateException, "Unexpected number of boundary scvfs"); + + for (const auto& scv : scvs(fvGeometry)) + { + const auto geo = fvGeometry.geometry(scv); + if (!Dune::FloatCmp::eq(geo.volume(), 1.0)) + DUNE_THROW(Dune::InvalidStateException, "Unexpected scv volume"); + const auto result = popped({ + {0.0, 0.0}, + {1.0, 0.0}, + {1.0, 1.0}, + {0.0, 1.0} + }, geo); + if (!result.has_value() || !result.value().empty()) + DUNE_THROW(Dune::InvalidStateException, "Unexpected scv corners"); + } + + std::vector<typename SubControlVolumeFace::GlobalPosition> expected{ + {0.0, 0.0}, {0.5, 0.0}, + {0.5, 0.0}, {1.0, 0.0}, + {1.0, 0.0}, {1.0, 0.5}, + {1.0, 0.5}, {1.0, 1.0}, + {1.0, 1.0}, {0.5, 1.0}, + {0.5, 1.0}, {0.0, 1.0}, + {0.0, 1.0}, {0.0, 0.5}, + {0.0, 0.5}, {0.0, 0.0} + }; + for (const auto& scvf : scvfs(fvGeometry)) + { + const auto geo = fvGeometry.geometry(scvf); + if (!Dune::FloatCmp::eq(geo.volume(), 0.5)) + DUNE_THROW(Dune::InvalidStateException, "Unexpected scvf area " << geo.volume()); + const auto shrunk = popped(expected, geo); + if (!shrunk.has_value()) + DUNE_THROW(Dune::InvalidStateException, "Unexpected scvf corners"); + expected = shrunk.value(); + } + if (!expected.empty()) + DUNE_THROW(Dune::InvalidStateException, "Could not find all expected scvf corners"); + } +}