diff --git a/dumux/common/pointsource.hh b/dumux/common/pointsource.hh index 426567da3aad66fd288a8c3c081a2d00d9acca78..f636d72f91729867286bf38f2947596da833e234 100644 --- a/dumux/common/pointsource.hh +++ b/dumux/common/pointsource.hh @@ -314,14 +314,16 @@ public: // check in which subcontrolvolume(s) we are // TODO mapper/problem in bboxtree would allow to make this much better const auto element = boundingBoxTree.entity(eIdx); - auto fvGeometry = problem.model().fvGeometries(element); + auto fvGeometry = localView(problem.model().globalFvGeometry()); + fvGeometry.bindElement(element); + const auto globalPos = source.position(); // loop over all sub control volumes and check if the point source is inside std::vector<unsigned int> scvIndices; - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { if (BoundingBoxTreeHelper<dimworld>::pointInGeometry(scv.geometry(), globalPos)) - scvIndices.push_back(scv.indexInElement()); + scvIndices.push_back(scv.index()); } // for all scvs that where tested positiv add the point sources // to the element/scv to point source map diff --git a/dumux/discretization/box/boxgeometryhelper.hh b/dumux/discretization/box/boxgeometryhelper.hh new file mode 100644 index 0000000000000000000000000000000000000000..75e879c259df597e64b19c50d52f96cc1773c0ac --- /dev/null +++ b/dumux/discretization/box/boxgeometryhelper.hh @@ -0,0 +1,444 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \brief Helper class constructing the dual grid finite volume geometries + * for the box discretizazion method + */ +#ifndef DUMUX_DISCRETIZATION_BOX_GEOMETRY_HELPER_HH +#define DUMUX_DISCRETIZATION_BOX_GEOMETRY_HELPER_HH + +#include <dune/geometry/multilineargeometry.hh> +#include <dune/geometry/referenceelements.hh> + +#include <dumux/implicit/box/properties.hh> +#include <dumux/common/math.hh> + +namespace Dumux +{ + +//! Create sub control volumes and sub control volume face geometries +template<class GridView, int dim> +class BoxGeometryHelper; + +//! A class to create sub control volume and sub control volume face geometries per element +template <class GridView> +class BoxGeometryHelper<GridView, 1> +{ +private: + using Scalar = typename GridView::ctype; + static const int dim = GridView::dimension; + static const int dimWorld = GridView::dimensionworld; + using ScvGeometry = Dune::MultiLinearGeometry<Scalar, dim, dimWorld>; + using ScvfGeometry = Dune::MultiLinearGeometry<Scalar, dim-1, dimWorld>; + + using GlobalPosition = typename ScvGeometry::GlobalCoordinate; + using CornerList = std::vector<GlobalPosition>; + using Element = typename GridView::template Codim<0>::Entity; + using Intersection = typename GridView::Intersection; + + using ReferenceElements = typename Dune::ReferenceElements<Scalar, dim>; + +public: + using ScvGeometryVector = std::vector<ScvGeometry>; + using ScvfGeometryVector = std::vector<ScvfGeometry>; + + //! get sub control volume geometries from element + void getScvAndScvfGeometries(const typename Element::Geometry& geometry, + ScvGeometryVector& scvGeometries, + ScvfGeometryVector& scvfGeometries) + { + scvGeometries.reserve(2); + scvfGeometries.reserve(1); + + // the sub control volumes + scvGeometries.emplace_back(Dune::GeometryType(1), std::vector<GlobalPosition>({geometry.corner(0), geometry.center()})); + scvGeometries.emplace_back(Dune::GeometryType(1), std::vector<GlobalPosition>({geometry.center(), geometry.corner(1)})); + + // the sub control volume faces + scvfGeometries.emplace_back(Dune::GeometryType(0), std::vector<GlobalPosition>({geometry.center()})); + } + + //! get sub control volume geometries from element of dimension 1 + ScvfGeometryVector getBoundaryScvfGeometries(const typename Intersection::Geometry& geometry) + { + return {ScvfGeometry(Dune::GeometryType(0), std::vector<GlobalPosition>({geometry.center()}))}; + } + + //! get scvf normal vector + static GlobalPosition normal(const typename Element::Geometry& geometry, + const ScvfGeometry& scvfGeometry) + { + GlobalPosition normal = geometry.corner(1) - geometry.corner(0); + normal /= normal.two_norm(); + return normal; + } +}; + +//! A class to create sub control volume and sub control volume face geometries per element +template <class GridView> +class BoxGeometryHelper<GridView, 2> +{ +private: + using Scalar = typename GridView::ctype; + static const int dim = GridView::dimension; + static const int dimWorld = GridView::dimensionworld; + + using ScvGeometry = Dune::MultiLinearGeometry<Scalar, dim, dimWorld>; + using ScvfGeometry = Dune::MultiLinearGeometry<Scalar, dim-1, dimWorld>; + + using GlobalPosition = typename ScvGeometry::GlobalCoordinate; + using Element = typename GridView::template Codim<0>::Entity; + using Intersection = typename GridView::Intersection; + + using ReferenceElements = typename Dune::ReferenceElements<Scalar, dim>; + +public: + + BoxGeometryHelper(const typename Element::Geometry& geometry) + { + // extract the corners of the sub control volumes + const auto& referenceElement = ReferenceElements::general(geometry.type()); + + // vertices + for (int i = 0; i < geometry.corners(); ++i) + v.emplace_back(geometry.corner(i)); + + // face midpoints + for (int i = 0; i < referenceElement.size(1); ++i) + f.emplace_back(geometry.global(referenceElement.position(i, 1))); + + c = geometry.center(); + + corners = geometry.corners(); + } + + //! Create the sub control volume geometries + std::vector<ScvGeometry> createScvGeometries() + { + std::vector<ScvGeometry> scvGeometries; + + // sub control volume geometries in 2D are always quadrilaterals + Dune::GeometryType scvGeometryType; + scvGeometryType.makeQuadrilateral(); + + // proceed according to number of corners + switch (corners) + { + case 3: // triangle + { + scvGeometries.reserve(3); + + // the sub control volumes + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({v[0], f[0], f[1], c})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({f[0], v[1], c, f[2]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({f[1], c, v[2], f[2]})); + + break; + } + case 4: // quadrilateral + { + scvGeometries.reserve(4); + + // the sub control volumes + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({v[0], f[2], f[0], c})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({f[2], v[1], c, f[1]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({f[0], c, v[2], f[3]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({c, f[1], f[3], v[3]})); + + break; + } + default: + DUNE_THROW(Dune::NotImplemented, "Box scv geometries for dim=" << dim + << " dimWorld=" << dimWorld + << " corners=" << corners); + } + + return scvGeometries; + } + + + //! Create the sub control volume face geometries + std::vector<ScvfGeometry> createScvfGeometries() + { + std::vector<ScvfGeometry> scvfGeometries; + + // sub control volume face geometries in 2D are always lines + Dune::GeometryType scvfGeometryType; + scvfGeometryType.makeLine(); + + // proceed according to number of corners + switch (corners) + { + case 3: // triangle + { + scvfGeometries.reserve(3); + + // the sub control volume faces + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[0], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[1], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[2], c})); + + break; + } + case 4: // quadrilateral + { + scvfGeometries.reserve(4); + + // the sub control volume faces + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[0], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[1], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[2], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[3], c})); + + break; + } + default: + DUNE_THROW(Dune::NotImplemented, "Box scv geometries for dim=" << dim + << " dimWorld=" << dimWorld + << " corners=" << corners); + } + + return scvfGeometries; + } + + //! Create the sub control volume face geometries on the boundary + static std::vector<ScvfGeometry> createBoundaryScvfGeometries(const typename Intersection::Geometry& geometry) + { + return {ScvfGeometry(Dune::GeometryType(1), std::vector<GlobalPosition>({geometry.corner(0), geometry.center()})), + ScvfGeometry(Dune::GeometryType(1), std::vector<GlobalPosition>({geometry.center(), geometry.corner(1)}))}; + } + + //! get scvf normal vector for dim == 2, dimworld == 3 + template <int w = dimWorld> + static typename std::enable_if<w == 3, GlobalPosition>::type + normal(const typename Element::Geometry& geometry, + const ScvfGeometry& scvfGeometry) + { + const auto v1 = geometry.corner(1) - geometry.corner(0); + const auto v2 = geometry.corner(2) - geometry.corner(0); + const auto v3 = Dumux::crossProduct(v1, v2); + const auto t = scvfGeometry.corner(1) - scvfGeometry.corner(0); + GlobalPosition normal = Dumux::crossProduct(v3, t); + normal /= normal.two_norm(); + return normal; + } + + //! get scvf normal vector for dim == 2, dimworld == 2 + template <int w = dimWorld> + static typename std::enable_if<w == 2, GlobalPosition>::type + normal(const typename Element::Geometry& geometry, + const ScvfGeometry& scvfGeometry) + { + const auto t = scvfGeometry.corner(1) - scvfGeometry.corner(0); + GlobalPosition normal({-t[1], t[0]}); + normal /= normal.two_norm(); + return normal; + } +private: + std::vector<GlobalPosition> v; // vertices + std::vector<GlobalPosition> f; // face midpoints + GlobalPosition c; // element center + std::size_t corners; // number of element corners +}; + +//! A class to create sub control volume and sub control volume face geometries per element +template <class GridView> +class BoxGeometryHelper<GridView, 3> +{ +private: + using Scalar = typename GridView::ctype; + static const int dim = GridView::dimension; + static const int dimWorld = GridView::dimensionworld; + using ScvGeometry = Dune::MultiLinearGeometry<Scalar, dim, dimWorld>; + using ScvfGeometry = Dune::MultiLinearGeometry<Scalar, dim-1, dimWorld>; + + using GlobalPosition = typename ScvGeometry::GlobalCoordinate; + using CornerList = std::vector<GlobalPosition>; + using Element = typename GridView::template Codim<0>::Entity; + using Intersection = typename GridView::Intersection; + + using ReferenceElements = typename Dune::ReferenceElements<Scalar, dim>; + using FaceReferenceElements = typename Dune::ReferenceElements<Scalar, dim-1>; + +public: + using ScvGeometryVector = std::vector<ScvGeometry>; + using ScvfGeometryVector = std::vector<ScvfGeometry>; + + //! get sub control volume geometries from element + void getScvAndScvfGeometries(const typename Element::Geometry& geometry, + ScvGeometryVector& scvGeometries, + ScvfGeometryVector& scvfGeometries) + { + // sub control volume geometries in 3D are always hexahedrons + Dune::GeometryType scvGeometryType; scvGeometryType.makeHexahedron(); + // sub control volume face geometries in 3D are always quadrilaterals + Dune::GeometryType scvfGeometryType; scvfGeometryType.makeQuadrilateral(); + + // extract the corners of the sub control volumes + const auto& referenceElement = ReferenceElements::general(geometry.type()); + + // vertices + CornerList v; + for (int i = 0; i < geometry.corners(); ++i) + v.emplace_back(geometry.corner(i)); + + // edge midpoints + CornerList e; + for (int i = 0; i < referenceElement.size(dim-1); ++i) + e.emplace_back(geometry.global(referenceElement.position(i, dim-1))); + + // face midpoints + CornerList f; + for (int i = 0; i < referenceElement.size(1); ++i) + f.emplace_back(geometry.global(referenceElement.position(i, 1))); + + auto c = geometry.center(); + + // procees according to number of corners + // \todo prisms (corners == 6) and pyramids (corners == 5) + switch (geometry.corners()) + { + case 4: // tetrahedron + { + scvGeometries.reserve(4); + scvfGeometries.reserve(6); + + // sub control volumes + ScvGeometryVector scvGeometries(4); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({v[0], e[0], e[1], f[0], e[3], f[1], f[2], c})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({v[1], e[2], e[0], f[0], f[3], e[4], c, f[1]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({v[2], e[1], e[2], f[0], e[5], f[2], f[3], c})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({v[3], e[3], e[5], f[2], e[4], f[1], f[3], c})); + + // sub control volume faces + ScvfGeometryVector scvfGeometries(6); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[0], f[0], f[1], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[0], e[1], c, f[2]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[2], f[0], f[3], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[2], e[3], c, f[1]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[3], c, e[4], f[1]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[5], f[2], f[3], c})); + + break; + } + case 8: // hexahedron + { + scvGeometries.reserve(8); + scvfGeometries.reserve(12); + + // sub control volumes + ScvGeometryVector scvGeometries(8); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({v[0], e[6], e[4], f[4], e[0], f[2], f[0], c})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({e[6], v[1], f[4], e[5], f[2], e[1], c, f[1]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({e[4], f[4], v[2], e[7], f[0], c, e[2], f[3]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({f[4], e[5], e[7], v[3], c, f[1], f[3], e[3]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({e[0], f[2], f[0], c, v[4], e[10], e[8], f[5]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({f[2], e[1], c, f[1], e[10], v[5], f[5], e[9]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({f[0], c, e[2], f[3], e[8], f[5], v[6], e[11]})); + scvGeometries.emplace_back(scvGeometryType, std::vector<GlobalPosition>({c, f[1], f[3], e[3], f[5], e[9], e[11], v[7]})); + + // sub control volume faces + ScvfGeometryVector scvfGeometries(12); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[0], e[0], c, f[2]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[1], c, e[1], f[2]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[3], e[2], c, f[0]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[3], f[3], f[1], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[4], e[4], c, f[0]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[5], f[4], f[1], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[6], f[4], f[2], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({f[4], e[7], c, f[3]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({c, f[0], f[5], e[8]})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[9], f[1], f[5], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[10], f[2], f[5], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({e[11], f[5], f[3], c})); + + break; + } + default: + DUNE_THROW(Dune::NotImplemented, "Box scv geometries for " << geometry.type()); + } + } + + //! get sub control volume geometries from element + ScvfGeometryVector getBoundaryScvfGeometries(const typename Intersection::Geometry& geometry) + { + ScvfGeometryVector scvfGeometries; + + // sub control volume face geometries in 3D are always quadrilaterals + Dune::GeometryType scvfGeometryType; scvfGeometryType.makeQuadrilateral(); + + // extract the corners of the sub control volumes + const auto& referenceElement = FaceReferenceElements::general(geometry.type()); + + // vertices + CornerList v; + for (int i = 0; i < geometry.corners(); ++i) + v.emplace_back(geometry.corner(i)); + + // edge midpoints + CornerList e; + for (int i = 0; i < referenceElement.size(1); ++i) + e.emplace_back(geometry.global(referenceElement.position(i, 1))); + + // face midpoint + auto c = geometry.center(); + + // procees according to number of corners + switch (geometry.corners()) + { + case 3: // triangle + { + scvfGeometries.reserve(3); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({v[0], e[0], e[1], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({v[1], e[2], e[0], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({v[2], e[1], e[2], c})); + + return scvfGeometries; + } + case 4: // quadrilateral + { + scvfGeometries.reserve(4); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({v[0], e[2], e[0], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({v[1], e[1], e[2], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({v[2], e[0], e[3], c})); + scvfGeometries.emplace_back(scvfGeometryType, std::vector<GlobalPosition>({v[3], e[3], e[1], c})); + + return scvfGeometries; + } + default: + DUNE_THROW(Dune::NotImplemented, "Box scvf boundary geometries for " << geometry.type()); + } + } + + //! get scvf normal vector + static GlobalPosition normal(const typename Element::Geometry& geometry, + const ScvfGeometry& scvfGeometry) + { + const auto t1 = scvfGeometry.corner(1) - scvfGeometry.corner(0); + const auto t2 = scvfGeometry.corner(2) - scvfGeometry.corner(0); + GlobalPosition normal = Dumux::crossProduct(t1, t2); + normal /= normal.two_norm(); + return normal; + } +}; + +} // end namespace Dumux + +#endif diff --git a/dumux/discretization/box/darcyslaw.hh b/dumux/discretization/box/darcyslaw.hh index 61152459b052397766e1553f714a50909a84083a..093ba8ddf22089cf01be6049b584545d82a3fb2e 100644 --- a/dumux/discretization/box/darcyslaw.hh +++ b/dumux/discretization/box/darcyslaw.hh @@ -52,50 +52,47 @@ NEW_PROP_TAG(ProblemEnableGravity); template <class TypeTag> class DarcysLaw<TypeTag, typename std::enable_if<GET_PROP_VALUE(TypeTag, DiscretizationMethod) == GET_PROP(TypeTag, DiscretizationMethods)::Box>::type > { - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace) SubControlVolumeFace; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariablesCache) FluxVariablesCache; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GridView::IndexSet::IndexType IndexType; - typedef typename GridView::ctype CoordScalar; - typedef std::vector<IndexType> Stencil; - - enum { dim = GridView::dimension} ; - enum { dimWorld = GridView::dimensionworld} ; - - typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> DimWorldMatrix; - typedef Dune::FieldVector<Scalar, dimWorld> DimVector; - - typedef Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1> FeCache; - typedef typename FeCache::FiniteElementType::Traits::LocalBasisType FeLocalBasis; - typedef typename FluxVariablesCache::FaceData FaceData; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using CoordScalar = typename GridView::ctype; + using Stencil = std::vector<IndexType>; + + enum { dim = GridView::dimension}; + enum { dimWorld = GridView::dimensionworld}; + + using DimWorldMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>; + using DimVector = Dune::FieldVector<Scalar, dimWorld>; + using FaceData = typename FluxVariablesCache::FaceData; public: static Scalar flux(const Problem& problem, const Element& element, - const SubControlVolumeFace& scvFace, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvf, const IndexType phaseIdx) { // get the precalculated local jacobian and shape values at the integration point - const auto& faceData = problem.model().fluxVarsCache()[scvFace].faceData(); + const auto& faceData = problem.model().fluxVarsCache()[scvf].faceData(); - const auto& fvGeometry = problem.model().fvGeometries(element); - const auto& insideScv = problem.model().fvGeometries().subControlVolume(scvFace.insideScvIdx()); + const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx()); const auto extrusionFactor = problem.model().curVolVars(insideScv).extrusionFactor(); const auto K = problem.spatialParams().intrinsicPermeability(insideScv); // evaluate gradP - rho*g at integration point DimVector gradP(0.0); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { // the global shape function gradient DimVector gradI; - faceData.jacInvT.mv(faceData.localJacobian[scv.indexInElement()][0], gradI); + faceData.jacInvT.mv(faceData.shapeJacobian[scv.index()][0], gradI); gradI *= problem.model().curVolVars(scv).pressure(phaseIdx); gradP += gradI; @@ -103,11 +100,11 @@ public: if (GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity)) { // gravitational acceleration - DimVector g(problem.gravityAtPos(scvFace.center())); + DimVector g(problem.gravityAtPos(scvf.center())); // interpolate the density at the IP const auto& insideVolVars = problem.model().curVolVars(insideScv); - const auto& outsideScv = problem.model().fvGeometries().subControlVolume(scvFace.outsideScvIdx()); + const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx()); const auto& outsideVolVars = problem.model().curVolVars(outsideScv); Scalar rho = 0.5*(insideVolVars.density(phaseIdx) + outsideVolVars.density(phaseIdx)); @@ -120,7 +117,7 @@ public: // apply the permeability and return the flux auto KGradP = applyPermeability(K, gradP); - return -1.0*(KGradP*scvFace.unitOuterNormal())*scvFace.area()*extrusionFactor; + return -1.0*(KGradP*scvf.unitOuterNormal())*scvf.area()*extrusionFactor; } static DimVector applyPermeability(const DimWorldMatrix& K, const DimVector& gradI) @@ -139,22 +136,30 @@ public: } // This is for compatibility with the cc methods. The flux stencil info is obsolete for the box method. - static Stencil stencil(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace) + static Stencil stencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvf) { return Stencil(0); } - static FaceData calculateFaceData(const Problem& problem, const Element& element, const typename Element::Geometry& geometry, const FeLocalBasis& localBasis, const SubControlVolumeFace& scvFace) + static FaceData calculateFaceData(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvf) { FaceData faceData; + const auto geometry = element.geometry(); + const auto& localBasis = fvGeometry.feLocalBasis(); // evaluate shape functions and gradients at the integration point - const auto ipLocal = geometry.local(scvFace.center()); + const auto ipLocal = geometry.local(scvf.center()); faceData.jacInvT = geometry.jacobianInverseTransposed(ipLocal); - localBasis.evaluateJacobian(ipLocal, faceData.localJacobian); - localBasis.evaluateFunction(ipLocal, faceData.shapeValues); + localBasis.evaluateJacobian(ipLocal, faceData.shapeJacobian); + localBasis.evaluateFunction(ipLocal, faceData.shapeValue); - return std::move(faceData); + return faceData; } }; diff --git a/dumux/discretization/box/fluxvariablescachevector.hh b/dumux/discretization/box/fluxvariablescachevector.hh index b62bc5e92c7d9e5a3357f8d780c61f725a0e5768..65168271c8c028e959d5067752d3bfd9ae067673 100644 --- a/dumux/discretization/box/fluxvariablescachevector.hh +++ b/dumux/discretization/box/fluxvariablescachevector.hh @@ -28,12 +28,22 @@ namespace Dumux { +/*! + * \ingroup ImplicitModel + * \brief Base class for the finite volume geometry vector for box models + * This builds up the sub control volumes and sub control volume faces + * for each element. + */ +template<class TypeTag, bool EnableGlobalFluxVariablesCache> +class BoxFluxVariablesCacheVector +{}; + /*! * \ingroup ImplicitModel * \brief Base class for the flux variables cache vector, we store one cache per face */ template<class TypeTag> -class BoxFluxVariablesCacheVector +class BoxFluxVariablesCacheVector<TypeTag, true> { using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); @@ -41,87 +51,107 @@ class BoxFluxVariablesCacheVector using Element = typename GridView::template Codim<0>::Entity; using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); public: - template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type update(Problem& problem) + void update(Problem& problem) { problemPtr_ = &problem; - fluxVarsCache_.resize(problem.model().fvGeometries().numScvf()); + fluxVarsCache_.resize(problem.gridView.size(0)); for (const auto& element : elements(problem.gridView())) { + eIdx_ = problem.elementMapper().index(element); // bind the geometries and volume variables to the element (all the elements in stencil) - problem.model().fvGeometries_().bind(element); + auto fvGeometry = localView(problem.model().globalFvGeometries()); + fvGeometry.bind(element); - const auto& elementGeometry = element.geometry(); - const auto& localBasis = problem.model().fvGeometries().feLocalBasis(elementGeometry.type()); - const auto& fvGeometry = problem.model().fvGeometries(element); - for (const auto& scvf : scvfs(fvGeometry)) + const auto& localBasis = fvGeometry.feLocalBasis(); + fluxVarsCache_[eIdx_].resize(fvGeometry.numScvf()); + for (auto&& scvf : scvfs(fvGeometry)) { - (*this)[scvf].update(problem, element, elementGeometry, localBasis, scvf); + (*this)[scvf].update(problem, element, localBasis, scvf); } } } - template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type update(Problem& problem) + // Function is called by the BoxLocalJacobian prior to flux calculations on the element. + // We assume the FVGeometries to be bound at this point + void bind(const Element& element, const FVElementGeometry& fvGeometry) + { + bindElement(element, fvGeometry); + } + + void bindElement(const Element& element, const FVElementGeometry& fvGeometry) + { eIdx_ = problem_().elementMapper().index(element); } + + // access operator + const FluxVariablesCache& operator [](const SubControlVolumeFace& scvf) const + { return fluxVarsCache_[eIdx_][scvf.index()]; } + + // access operator + FluxVariablesCache& operator [](const SubControlVolumeFace& scvf) + { return fluxVarsCache_[eIdx_][scvf.index()]; } + +private: + const Problem& problem_() const + { return *problemPtr_; } + + // currently bound element + IndexType eIdx_; + const Problem* problemPtr_; + std::vector<std::vector<FluxVariablesCache>> fluxVarsCache_; +}; + +/*! + * \ingroup ImplicitModel + * \brief Base class for the flux variables cache vector, we store one cache per face + */ +template<class TypeTag> +class BoxFluxVariablesCacheVector<TypeTag, false> +{ + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using IndexType = typename GridView::IndexSet::IndexType; + using Element = typename GridView::template Codim<0>::Entity; + using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + +public: + + void update(Problem& problem) { problemPtr_ = &problem; } // Function is called by the BoxLocalJacobian prior to flux calculations on the element. // We assume the FVGeometries to be bound at this point - void bind(const Element& element) + void bind(const Element& element, const FVElementGeometry& fvGeometry) { - bindElement(element); + bindElement(element, fvGeometry); } - template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type - bindElement(const Element& element) + void bindElement(const Element& element, const FVElementGeometry& fvGeometry) { - const auto& fvGeometry = problem_().model().fvGeometries(element); - const auto& elementGeometry = element.geometry(); - const auto& localBasis = problem_().model().fvGeometries().feLocalBasis(elementGeometry.type()); - // temporary resizing of the cache - const auto numScvf = fvGeometry.numScvf(); - fluxVarsCache_.resize(numScvf); - IndexType localScvfIdx = 0; - for (const auto& scvf : scvfs(fvGeometry)) - fluxVarsCache_[localScvfIdx++].update(problem_(), element, elementGeometry, localBasis, scvf); + fluxVarsCache_.resize(fvGeometry.numScvf()); + for (auto&& scvf : scvfs(fvGeometry)) + (*this)[scvf].update(problem_(), element, fvGeometry, scvf); } - template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type - bindElement(const Element& element) {} - - // access operators in the case of caching - template <typename T = TypeTag> - const typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache), FluxVariablesCache>::type& - operator [](const SubControlVolumeFace& scvf) const + // access operator + const FluxVariablesCache& operator [](const SubControlVolumeFace& scvf) const { return fluxVarsCache_[scvf.index()]; } - template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache), FluxVariablesCache>::type& - operator [](const SubControlVolumeFace& scvf) + // access operator + FluxVariablesCache& operator [](const SubControlVolumeFace& scvf) { return fluxVarsCache_[scvf.index()]; } - // access operators in the case of no caching - template <typename T = TypeTag> - const typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache), FluxVariablesCache>::type& - operator [](const SubControlVolumeFace& scvf) const - { return fluxVarsCache_[scvf.indexInElement()]; } - - template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache), FluxVariablesCache>::type& - operator [](const SubControlVolumeFace& scvf) - { return fluxVarsCache_[scvf.indexInElement()]; } - private: const Problem& problem_() const { return *problemPtr_; } + // currently bound element const Problem* problemPtr_; std::vector<FluxVariablesCache> fluxVarsCache_; }; diff --git a/dumux/discretization/box/fvelementgeometry.hh b/dumux/discretization/box/fvelementgeometry.hh new file mode 100644 index 0000000000000000000000000000000000000000..5d843b48095c63553331fb9bcc3bfc235760d2d3 --- /dev/null +++ b/dumux/discretization/box/fvelementgeometry.hh @@ -0,0 +1,373 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \brief Base class for the local finite volume geometry for box models + * This builds up the sub control volumes and sub control volume faces + * for an element. + */ +#ifndef DUMUX_DISCRETIZATION_BOX_FV_ELEMENT_GEOMETRY_HH +#define DUMUX_DISCRETIZATION_BOX_FV_ELEMENT_GEOMETRY_HH + +#include <dune/geometry/referenceelements.hh> +#include <dune/localfunctions/lagrange/pqkfactory.hh> + +#include <dumux/discretization/scvandscvfiterators.hh> +#include <dumux/discretization/box/boxgeometryhelper.hh> +#include <dumux/implicit/box/properties.hh> + +namespace Dumux +{ + +//! forward declaration of the global finite volume geometry +template<class TypeTag, bool EnableGlobalFVGeometryCache> +class BoxGlobalFVGeometry; + +/*! + * \ingroup ImplicitModel + * \brief Base class for the finite volume geometry vector for box models + * This builds up the sub control volumes and sub control volume faces + * for each element. + */ +template<class TypeTag, bool EnableGlobalFVGeometryCache> +class BoxFVElementGeometry +{}; + +//! specialization in case the FVElementGeometries are stored +template<class TypeTag> +class BoxFVElementGeometry<TypeTag, true> +{ + using ThisType = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using IndexType = typename GridView::IndexSet::IndexType; + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using Element = typename GridView::template Codim<0>::Entity; + using GlobalFVGeometry = typename GET_PROP_TYPE(TypeTag, GlobalFVGeometry); + + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using CoordScalar = typename GridView::ctype; + + static const int dim = GridView::dimension; + static const int dimWorld = GridView::dimensionworld; + + using FeCache = Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; + using FeLocalBasis = typename FeCache::FiniteElementType::Traits::LocalBasisType; + using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>; + + using ScvIterator = ScvIterator<SubControlVolume, std::vector<IndexType>, ThisType>; + using ScvfIterator = ScvfIterator<SubControlVolumeFace, std::vector<IndexType>, ThisType>; + +public: + //! Constructor + BoxFVElementGeometry(const GlobalFVGeometry& globalFvGeometry) + : globalFvGeometryPtr_(&globalFvGeometry) {} + + //! Get a sub control volume with a local scv index + const SubControlVolume& scv(IndexType scvIdx) const + { + return globalFvGeometry().scv(scvIdx, eIdx_); + } + + //! Get a sub control volume face with a local scvf index + const SubControlVolumeFace& scvf(IndexType scvfIdx) const + { + return globalFvGeometry().scvf(scvfIdx, eIdx_); + } + + //! iterator range for sub control volumes. Iterates over + //! all scvs of the bound element. + //! This is a free function found by means of ADL + //! To iterate over all sub control volumes of this FVElementGeometry use + //! for (auto&& scv : scvs(fvGeometry)) + friend inline Dune::IteratorRange<typename std::vector<SubControlVolume>::const_iterator> + scvs(const BoxFVElementGeometry& fvGeometry) + { + const auto& g = fvGeometry.globalFvGeometry(); + using Iter = typename std::vector<SubControlVolume>::const_iterator; + return Dune::IteratorRange<Iter>(g.scvs(fvGeometry.eIdx_).begin(), g.scvs(fvGeometry.eIdx_).end()); + } + + //! iterator range for sub control volumes faces. Iterates over + //! all scvfs of the bound element. + //! This is a free function found by means of ADL + //! To iterate over all sub control volume faces of this FVElementGeometry use + //! for (auto&& scvf : scvfs(fvGeometry)) + friend inline Dune::IteratorRange<typename std::vector<SubControlVolumeFace>::const_iterator> + scvfs(const BoxFVElementGeometry& fvGeometry) + { + const auto& g = fvGeometry.globalFvGeometry(); + using Iter = typename std::vector<SubControlVolumeFace>::const_iterator; + return Dune::IteratorRange<Iter>(g.scvfs(fvGeometry.eIdx_).begin(), g.scvfs(fvGeometry.eIdx_).end()); + } + + //! Get a local finite element basis + const FeLocalBasis& feLocalBasis() const + { + return globalFvGeometry().feCache().get(elementPtr_->geometry().type()).localBasis(); + } + + //! The total number of sub control volumes + std::size_t numScv() const + { + return globalFvGeometry().scvs(eIdx_).size(); + } + + //! The total number of sub control volume faces + std::size_t numScvf() const + { + return globalFvGeometry().scvfs(eIdx_).size(); + } + + //! this function is for compatibility reasons with cc methods + //! The box stencil is always element-local so bind and bindElement + //! are identical. + void bind(const Element& element) + { + this->bindElement(element); + } + + //! Binding of an element, has to be called before using the fvgeometries + //! Prepares all the volume variables within the element + //! For compatibility reasons with the FVGeometry cache being disabled + void bindElement(const Element& element) + { + elementPtr_ = &element; + eIdx_ = globalFvGeometry().problem_().elementMapper().index(element); + } + + //! The global finite volume geometry we are a restriction of + const GlobalFVGeometry& globalFvGeometry() const + { return *globalFvGeometryPtr_; } + +private: + const Element* elementPtr_; + const GlobalFVGeometry* globalFvGeometryPtr_; + + IndexType eIdx_; +}; + +//! specialization in case the FVElementGeometries are not stored +template<class TypeTag> +class BoxFVElementGeometry<TypeTag, false> +{ + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using IndexType = typename GridView::IndexSet::IndexType; + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using GlobalFVGeometry = typename GET_PROP_TYPE(TypeTag, GlobalFVGeometry); + + static const int dim = GridView::dimension; + static const int dimWorld = GridView::dimensionworld; + + using Element = typename GridView::template Codim<0>::Entity; + + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using CoordScalar = typename GridView::ctype; + + using FeCache = Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; + using FeLocalBasis = typename FeCache::FiniteElementType::Traits::LocalBasisType; + using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>; + + using GeometryHelper = BoxGeometryHelper<GridView, dim>; + +public: + //! Constructor + BoxFVElementGeometry(const GlobalFVGeometry& globalFvGeometry) + : globalFvGeometryPtr_(&globalFvGeometry) {} + + //! Get a sub control volume with a local scv index + const SubControlVolume& scv(IndexType scvIdx) const + { + return scvs_[scvIdx]; + } + + //! Get a sub control volume face with a local scvf index + const SubControlVolumeFace& scvf(IndexType scvfIdx) const + { + return scvfs_[scvfIdx]; + } + + //! iterator range for sub control volumes. Iterates over + //! all scvs of the bound element. + //! This is a free function found by means of ADL + //! To iterate over all sub control volumes of this FVElementGeometry use + //! for (auto&& scv : scvs(fvGeometry)) + friend inline Dune::IteratorRange<typename std::vector<SubControlVolume>::const_iterator> + scvs(const BoxFVElementGeometry& fvGeometry) + { + using Iter = typename std::vector<SubControlVolume>::const_iterator; + return Dune::IteratorRange<Iter>(fvGeometry.scvs_.begin(), fvGeometry.scvs_.end()); + } + + //! iterator range for sub control volumes faces. Iterates over + //! all scvfs of the bound element. + //! This is a free function found by means of ADL + //! To iterate over all sub control volume faces of this FVElementGeometry use + //! for (auto&& scvf : scvfs(fvGeometry)) + friend inline Dune::IteratorRange<typename std::vector<SubControlVolumeFace>::const_iterator> + scvfs(const BoxFVElementGeometry& fvGeometry) + { + using Iter = typename std::vector<SubControlVolumeFace>::const_iterator; + return Dune::IteratorRange<Iter>(fvGeometry.scvfs_.begin(), fvGeometry.scvfs_.end()); + } + + //! Get a local finite element basis + const FeLocalBasis& feLocalBasis() const + { + return globalFvGeometry().feCache().get(elementPtr_->geometry().type()).localBasis(); + } + + //! The total number of sub control volumes + std::size_t numScv() const + { + return scvs_.size(); + } + + //! The total number of sub control volume faces + std::size_t numScvf() const + { + return scvfs_.size(); + } + + //! this function is for compatibility reasons with cc methods + //! The box stencil is always element-local so bind and bindElement + //! are identical. + void bind(const Element& element) + { + this->bindElement(element); + } + + //! Binding of an element, has to be called before using the fvgeometries + //! Prepares all the volume variables within the element + //! For compatibility reasons with the FVGeometry cache being disabled + void bindElement(const Element& element) + { + elementPtr_ = &element; + eIdx_ = globalFvGeometry().problem_().elementMapper().index(element); + makeElementGeometries(element); + } + + //! The global finite volume geometry we are a restriction of + const GlobalFVGeometry& globalFvGeometry() const + { return *globalFvGeometryPtr_; } + +private: + + void makeElementGeometries(const Element& element) + { + auto eIdx = globalFvGeometry().problem_().elementMapper().index(element); + + // get the element geometry + auto elementGeometry = element.geometry(); + const auto& referenceElement = ReferenceElements::general(elementGeometry.type()); + + // get the sub control volume geometries of this element + GeometryHelper geometryHelper(elementGeometry); + auto scvGeometries = geometryHelper.createScvGeometries(); + auto scvfGeometries = geometryHelper.createScvfGeometries(); + + // construct the sub control volumes + IndexType scvLocalIdx = 0; + for (auto&& scvGeometry : scvGeometries) + { + // get asssociated dof index + auto dofIdxGlobal = globalFvGeometry().problem_().vertexMapper().subIndex(element, scvLocalIdx, dim); + + // add scv to the local container + scvs_.emplace_back(std::move(scvGeometry), + scvLocalIdx, + eIdx, + dofIdxGlobal); + // increment local counter + scvLocalIdx++; + } + + // construct the sub control volume faces + IndexType scvfLocalIdx = 0; + for (auto&& scvfGeometry : scvfGeometries) + { + // find the local scv indices this scvf is connsected to + std::vector<IndexType> localScvIndices({static_cast<IndexType>(referenceElement.subEntity(scvfLocalIdx, dim-1, 0, dim)), + static_cast<IndexType>(referenceElement.subEntity(scvfLocalIdx, dim-1, 1, dim))}); + + // compute the scvf normal unit outer normal + auto normal = geometryHelper.normal(elementGeometry, scvfGeometry); + const auto v = elementGeometry.corner(localScvIndices[1]) - elementGeometry.corner(localScvIndices[0]); + const auto s = v*normal; + if (std::signbit(s)) + normal *= -1; + + scvfs_.emplace_back(std::move(scvfGeometry), + normal, + scvfLocalIdx, + localScvIndices, + false); + + // increment local counter + scvfLocalIdx++; + } + + // construct the sub control volume faces on the domain boundary + for (const auto& intersection : intersections(globalFvGeometry().gridView(), element)) + { + if (intersection.boundary()) + { + auto isGeometry = intersection.geometry(); + auto boundaryScvfGeometries = geometryHelper.createBoundaryScvfGeometries(isGeometry); + + IndexType boundaryFaceLocalIdx = 0; + for (auto&& scvfGeometry : boundaryScvfGeometries) + { + // find the scv this scvf is connected to + std::vector<IndexType> localScvIndices = + {static_cast<IndexType>(referenceElement.subEntity(intersection.indexInInside(), 1, + boundaryFaceLocalIdx++, dim))}; + + scvfs_.emplace_back(std::move(scvfGeometry), + intersection.centerUnitOuterNormal(), + scvfLocalIdx, + localScvIndices, + true); + + // increment local counter + scvfLocalIdx++; + } + } + } + } + + //! The bound element + const Element* elementPtr_; + IndexType eIdx_; + + //! The global geometry this is a restriction of + const GlobalFVGeometry* globalFvGeometryPtr_; + + //! vectors to store the geometries locally after binding an element + std::vector<SubControlVolume> scvs_; + std::vector<SubControlVolumeFace> scvfs_; +}; + +} // end namespace + +#endif diff --git a/dumux/discretization/box/fvelementgeometryvector.hh b/dumux/discretization/box/fvelementgeometryvector.hh deleted file mode 100644 index 48c11d229f87c976f351d25437dc735b2ae6de00..0000000000000000000000000000000000000000 --- a/dumux/discretization/box/fvelementgeometryvector.hh +++ /dev/null @@ -1,919 +0,0 @@ -// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// vi: set et ts=4 sw=4 sts=4: -/***************************************************************************** - * See the file COPYING for full copying permissions. * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -/*! - * \file - * \brief Base class for the finite volume geometry vector for box models - * This builds up the sub control volumes and sub control volume faces - * for each element. - */ -#ifndef DUMUX_DISCRETIZATION_BOX_FV_GEOMETRY_VECTOR_HH -#define DUMUX_DISCRETIZATION_BOX_FV_GEOMETRY_VECTOR_HH - -#include <dune/geometry/multilineargeometry.hh> -#include <dune/geometry/referenceelements.hh> -#include <dune/localfunctions/lagrange/pqkfactory.hh> - -#include <dumux/implicit/box/properties.hh> -#include <dumux/common/elementmap.hh> -#include <dumux/common/math.hh> - -namespace Dumux -{ - -//! A class to create sub control volume and sub control volume face geometries per element -template <class GridView> -class BoxGeometryHelper -{ -private: - using Scalar = typename GridView::ctype; - static const int dim = GridView::dimension; - static const int dimWorld = GridView::dimensionworld; - using ScvGeometry = Dune::MultiLinearGeometry<Scalar, dim, dimWorld>; - using ScvfGeometry = Dune::MultiLinearGeometry<Scalar, dim-1, dimWorld>; - - using ScvGeometryVector = std::vector<std::shared_ptr<ScvGeometry>>; - using ScvfGeometryVector = std::vector<std::shared_ptr<ScvfGeometry>>; - using GeometryPair = std::pair<ScvGeometryVector, ScvfGeometryVector>; - - using GlobalPosition = typename ScvGeometry::GlobalCoordinate; - using CornerList = std::vector<GlobalPosition>; - using Element = typename GridView::template Codim<0>::Entity; - using Intersection = typename GridView::Intersection; - - using ReferenceElements = typename Dune::ReferenceElements<Scalar, dim>; - using FaceReferenceElements = typename Dune::ReferenceElements<Scalar, dim-1>; - -public: - //! get sub control volume geometries from element of dimension 1 - template <int d = dim> - static typename std::enable_if<d == 1, GeometryPair>::type - getScvAndScvfGeometries(const typename Element::Geometry& geometry) - { - // the sub control volumes - ScvGeometryVector scvGeometries(2); - scvGeometries[0] = std::make_shared<ScvGeometry>(Dune::GeometryType(1), std::vector<GlobalPosition>({geometry.corner(0), geometry.center()})); - scvGeometries[1] = std::make_shared<ScvGeometry>(Dune::GeometryType(1), std::vector<GlobalPosition>({geometry.center(), geometry.corner(1)})); - - // the sub control volume faces - ScvfGeometryVector scvfGeometries(1); - scvfGeometries[0] = std::make_shared<ScvfGeometry>(Dune::GeometryType(0), std::vector<GlobalPosition>({geometry.center()})); - - return std::make_pair(scvGeometries, scvfGeometries); - } - - //! get sub control volume geometries from element of dimension 2 - template <int d = dim> - static typename std::enable_if<d == 2, GeometryPair>::type - getScvAndScvfGeometries(const typename Element::Geometry& geometry) - { - // sub control volume geometries in 2D are always quadrilaterals - Dune::GeometryType scvGeometryType; scvGeometryType.makeQuadrilateral(); - // sub control volume face geometries in 2D are always lines - Dune::GeometryType scvfGeometryType; scvfGeometryType.makeLine(); - - // extract the corners of the sub control volumes - const auto& referenceElement = ReferenceElements::general(geometry.type()); - - // vertices - CornerList v; - for (int i = 0; i < geometry.corners(); ++i) - v.emplace_back(geometry.corner(i)); - - // face midpoints - CornerList f; - for (int i = 0; i < referenceElement.size(1); ++i) - f.emplace_back(geometry.global(referenceElement.position(i, 1))); - - auto c = geometry.center(); - - // proceed according to number of corners - switch (geometry.corners()) - { - case 3: // triangle - { - // the sub control volumes - ScvGeometryVector scvGeometries(3); - scvGeometries[0] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({v[0], f[0], f[1], c})); - scvGeometries[1] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({f[0], v[1], c, f[2]})); - scvGeometries[2] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({f[1], c, v[2], f[2]})); - - // the sub control volume faces - ScvfGeometryVector scvfGeometries(3); - scvfGeometries[0] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[0], c})); - scvfGeometries[1] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[1], c})); - scvfGeometries[2] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[2], c})); - - return std::make_pair(scvGeometries, scvfGeometries); - } - case 4: // quadrilateral - { - // the sub control volumes - ScvGeometryVector scvGeometries(4); - scvGeometries[0] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({v[0], f[2], f[0], c})); - scvGeometries[1] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({f[2], v[1], c, f[1]})); - scvGeometries[2] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({f[0], c, v[2], f[3]})); - scvGeometries[3] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({c, f[1], f[3], v[3]})); - - // the sub control volume faces - ScvfGeometryVector scvfGeometries(4); - scvfGeometries[0] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[0], c})); - scvfGeometries[1] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[1], c})); - scvfGeometries[2] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[2], c})); - scvfGeometries[3] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[3], c})); - - return std::make_pair(scvGeometries, scvfGeometries); - } - default: - DUNE_THROW(Dune::NotImplemented, "Box scv geometries for " << geometry.type()); - } - } - - //! get sub control volume geometries from element of dimension 3 - template <int d = dim> - static typename std::enable_if<d == 3, GeometryPair>::type - getScvAndScvfGeometries(const typename Element::Geometry& geometry) - { - // sub control volume geometries in 3D are always hexahedrons - Dune::GeometryType scvGeometryType; scvGeometryType.makeHexahedron(); - // sub control volume face geometries in 3D are always quadrilaterals - Dune::GeometryType scvfGeometryType; scvfGeometryType.makeQuadrilateral(); - - // extract the corners of the sub control volumes - const auto& referenceElement = ReferenceElements::general(geometry.type()); - - // vertices - CornerList v; - for (int i = 0; i < geometry.corners(); ++i) - v.emplace_back(geometry.corner(i)); - - // edge midpoints - CornerList e; - for (int i = 0; i < referenceElement.size(dim-1); ++i) - e.emplace_back(geometry.global(referenceElement.position(i, dim-1))); - - // face midpoints - CornerList f; - for (int i = 0; i < referenceElement.size(1); ++i) - f.emplace_back(geometry.global(referenceElement.position(i, 1))); - - auto c = geometry.center(); - - // procees according to number of corners - // \todo prisms (corners == 6) and pyramids (corners == 5) - switch (geometry.corners()) - { - case 4: // tetrahedron - { - // sub control volumes - ScvGeometryVector scvGeometries(4); - scvGeometries[0] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({v[0], e[0], e[1], f[0], e[3], f[1], f[2], c})); - scvGeometries[1] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({v[1], e[2], e[0], f[0], f[3], e[4], c, f[1]})); - scvGeometries[2] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({v[2], e[1], e[2], f[0], e[5], f[2], f[3], c})); - scvGeometries[3] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({v[3], e[3], e[5], f[2], e[4], f[1], f[3], c})); - - // sub control volume faces - ScvfGeometryVector scvfGeometries(6); - scvfGeometries[0] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[0], f[0], f[1], c})); - scvfGeometries[1] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[0], e[1], c, f[2]})); - scvfGeometries[2] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[2], f[0], f[3], c})); - scvfGeometries[3] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[2], e[3], c, f[1]})); - scvfGeometries[4] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[3], c, e[4], f[1]})); - scvfGeometries[5] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[5], f[2], f[3], c})); - - return std::make_pair(scvGeometries, scvfGeometries); - } - case 8: // hexahedron - { - // sub control volumes - ScvGeometryVector scvGeometries(8); - scvGeometries[0] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({v[0], e[6], e[4], f[4], e[0], f[2], f[0], c})); - scvGeometries[1] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({e[6], v[1], f[4], e[5], f[2], e[1], c, f[1]})); - scvGeometries[2] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({e[4], f[4], v[2], e[7], f[0], c, e[2], f[3]})); - scvGeometries[3] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({f[4], e[5], e[7], v[3], c, f[1], f[3], e[3]})); - scvGeometries[4] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({e[0], f[2], f[0], c, v[4], e[10], e[8], f[5]})); - scvGeometries[5] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({f[2], e[1], c, f[1], e[10], v[5], f[5], e[9]})); - scvGeometries[6] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({f[0], c, e[2], f[3], e[8], f[5], v[6], e[11]})); - scvGeometries[7] = std::make_shared<ScvGeometry>(scvGeometryType, std::vector<GlobalPosition>({c, f[1], f[3], e[3], f[5], e[9], e[11], v[7]})); - - // sub control volume faces - ScvfGeometryVector scvfGeometries(12); - scvfGeometries[0] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[0], e[0], c, f[2]})); - scvfGeometries[1] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[1], c, e[1], f[2]})); - scvfGeometries[2] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[3], e[2], c, f[0]})); - scvfGeometries[3] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[3], f[3], f[1], c})); - scvfGeometries[4] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[4], e[4], c, f[0]})); - scvfGeometries[5] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[5], f[4], f[1], c})); - scvfGeometries[6] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[6], f[4], f[2], c})); - scvfGeometries[7] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({f[4], e[7], c, f[3]})); - scvfGeometries[8] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({c, f[0], f[5], e[8]})); - scvfGeometries[9] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[9], f[1], f[5], c})); - scvfGeometries[10] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[10], f[2], f[5], c})); - scvfGeometries[11] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({e[11], f[5], f[3], c})); - - return std::make_pair(scvGeometries, scvfGeometries); - } - default: - DUNE_THROW(Dune::NotImplemented, "Box scv geometries for " << geometry.type()); - } - } - - //! get sub control volume geometries from element of dimension 1 - template <int d = dim> - static typename std::enable_if<d == 1, ScvfGeometryVector>::type - getBoundaryScvfGeometries(const typename Intersection::Geometry& geometry) - { - return {std::make_shared<ScvfGeometry>(ScvfGeometry(Dune::GeometryType(0), std::vector<GlobalPosition>({geometry.center()})))}; - } - - //! get sub control volume geometries from element of dimension 2 - template <int d = dim> - static typename std::enable_if<d == 2, ScvfGeometryVector>::type - getBoundaryScvfGeometries(const typename Intersection::Geometry& geometry) - { - return {std::make_shared<ScvfGeometry>(ScvfGeometry(Dune::GeometryType(1), std::vector<GlobalPosition>({geometry.corner(0), geometry.center()}))), - std::make_shared<ScvfGeometry>(ScvfGeometry(Dune::GeometryType(1), std::vector<GlobalPosition>({geometry.center(), geometry.corner(1)})))}; - } - - //! get sub control volume geometries from element of dimension 3 - template <int d = dim> - static typename std::enable_if<d == 3, ScvfGeometryVector>::type - getBoundaryScvfGeometries(const typename Intersection::Geometry& geometry) - { - // sub control volume face geometries in 3D are always quadrilaterals - Dune::GeometryType scvfGeometryType; scvfGeometryType.makeQuadrilateral(); - - // extract the corners of the sub control volumes - const auto& referenceElement = FaceReferenceElements::general(geometry.type()); - - // vertices - CornerList v; - for (int i = 0; i < geometry.corners(); ++i) - v.emplace_back(geometry.corner(i)); - - // edge midpoints - CornerList e; - for (int i = 0; i < referenceElement.size(1); ++i) - e.emplace_back(geometry.global(referenceElement.position(i, 1))); - - // face midpoint - auto c = geometry.center(); - - // procees according to number of corners - switch (geometry.corners()) - { - case 3: // triangle - { - ScvfGeometryVector scvfGeometries(3); - scvfGeometries[0] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({v[0], e[0], e[1], c})); - scvfGeometries[1] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({v[1], e[2], e[0], c})); - scvfGeometries[2] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({v[2], e[1], e[2], c})); - - return scvfGeometries; - } - case 4: // quadrilateral - { - ScvfGeometryVector scvfGeometries(4); - scvfGeometries[0] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({v[0], e[2], e[0], c})); - scvfGeometries[1] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({v[1], e[1], e[2], c})); - scvfGeometries[2] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({v[2], e[0], e[3], c})); - scvfGeometries[3] = std::make_shared<ScvfGeometry>(scvfGeometryType, std::vector<GlobalPosition>({v[3], e[3], e[1], c})); - - return scvfGeometries; - } - default: - DUNE_THROW(Dune::NotImplemented, "Box scvf boundary geometries for " << geometry.type()); - } - } - - //! get scvf normal vector for dim == 3, dimworld == 3 - template <int d = dim, int w = dimWorld> - static typename std::enable_if<d == 3 && w == 3, GlobalPosition>::type - normal(const typename Element::Geometry& geometry, const ScvfGeometry& scvfGeometry) - { - const auto t1 = scvfGeometry.corner(1) - scvfGeometry.corner(0); - const auto t2 = scvfGeometry.corner(2) - scvfGeometry.corner(0); - GlobalPosition normal = Dumux::crossProduct(t1, t2); - normal /= normal.two_norm(); - return normal; - } - - //! get scvf normal vector for dim == 2, dimworld == 3 - template <int d = dim, int w = dimWorld> - static typename std::enable_if<d == 2 && w == 3, GlobalPosition>::type - normal(const typename Element::Geometry& geometry, const ScvfGeometry& scvfGeometry) - { - const auto v1 = geometry.corner(1) - geometry.corner(0); - const auto v2 = geometry.corner(2) - geometry.corner(0); - const auto v3 = Dumux::crossProduct(v1, v2); - const auto t = scvfGeometry.corner(1) - scvfGeometry.corner(0); - GlobalPosition normal = Dumux::crossProduct(v3, t); - normal /= normal.two_norm(); - return normal; - } - - //! get scvf normal vector for dim == 2, dimworld == 2 - template <int d = dim, int w = dimWorld> - static typename std::enable_if<d == 2 && w == 2, GlobalPosition>::type - normal(const typename Element::Geometry& geometry, const ScvfGeometry& scvfGeometry) - { - const auto t = scvfGeometry.corner(1) - scvfGeometry.corner(0); - GlobalPosition normal({-t[1], t[0]}); - normal /= normal.two_norm(); - return normal; - } - - //! get scvf normal vector for dim == 2, dimworld == 2 - template <int d = dim> - static typename std::enable_if<d == 1, GlobalPosition>::type - normal(const typename Element::Geometry& geometry, const ScvfGeometry& scvfGeometry) - { - GlobalPosition normal = geometry.corner(1) - geometry.corner(0); - normal /= normal.two_norm(); - return normal; - } -}; - -/*! - * \ingroup ImplicitModel - * \brief Base class for the finite volume geometry vector for box models - * This builds up the sub control volumes and sub control volume faces - * for each element. - */ -template<class TypeTag, bool EnableFVElementGeometryCache> -class BoxFVElementGeometryVector -{}; - -// specialization in case the FVElementGeometries are stored -template<class TypeTag> -class BoxFVElementGeometryVector<TypeTag, true> -{ - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using IndexType = typename GridView::IndexSet::IndexType; - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - using Element = typename GridView::template Codim<0>::Entity; - - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using CoordScalar = typename GridView::ctype; - - static const int dim = GridView::dimension; - static const int dimWorld = GridView::dimensionworld; - - using FeCache = Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; - using FeLocalBasis = typename FeCache::FiniteElementType::Traits::LocalBasisType; - using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>; - -public: - //! Constructor - BoxFVElementGeometryVector(const GridView gridView) - : gridView_(gridView), elementMap_(gridView) {} - - /* \brief Get the finite volume geometry of an element - * \note The finite volume geometry offers iterators over the sub control volumes - * and the sub control volume faces of an element. - */ - const FVElementGeometry& fvGeometry(const Element& element) const - { - return fvGeometries_[problem_().elementMapper().index(element)]; - } - - //! Get a sub control volume with a global scv index - const SubControlVolume& subControlVolume(IndexType scvIdx) const - { - return *scvs_[globalScvIndices_[eIdxBound_][scvIdx]]; - } - - //! Get a sub control volume face with a global scvf index - const SubControlVolumeFace& subControlVolumeFace(IndexType scvfIdx) const - { - return *scvfs_[globalScvfIndices_[eIdxBound_][scvfIdx]]; - } - - //! Get a local finite element basis - const FeLocalBasis& feLocalBasis(const Dune::GeometryType& type) const - { - return feCache_.get(type).localBasis(); - } - - //! The total number of sub control volumes - std::size_t numScv() const - { - return scvs_.size(); - } - - //! The total number of sun control volume faces - std::size_t numScvf() const - { - return scvfs_.size(); - } - - //! The total number of boundary sub control volume faces - //! For compatibility reasons with cc methods - std::size_t numBoundaryScvf() const - { - return 0; - } - - // Get an element from a sub control volume contained in it - Element element(const SubControlVolume& scv) const - { return elementMap_.element(scv.elementIndex()); } - - // Get an element from a global element index - Element element(IndexType eIdx) const - { return elementMap_.element(eIdx); } - - //! update all fvElementGeometries (do this again after grid adaption) - void update(const Problem& problem) - { - problemPtr_ = &problem; - - scvs_.clear(); - scvfs_.clear(); - fvGeometries_.clear(); - elementMap_.clear(); - - IndexType numElements = gridView_.size(0); - IndexType numScvs = 0; - IndexType numScvfs = 0; - for (const auto& element : elements(gridView_)) - { - numScvs += element.subEntities(dim); - numScvfs += element.subEntities(dim-1); - - // add number of boundary faces - for (const auto& is : intersections(gridView_, element)) - { - if (is.boundary()) - numScvfs += is.geometry().corners(); - } - } - - scvs_.reserve(numScvs); - scvfs_.reserve(numScvfs); - globalScvIndices_.resize(numElements); - globalScvfIndices_.resize(numElements); - elementMap_.resize(numElements); - - // Build the SCV and SCV faces - IndexType scvIdx = 0; - IndexType scvfIdx = 0; - for (const auto& element : elements(gridView_)) - { - // the element-wise index sets for finite volume geometry - std::vector<IndexType> scvLocalIndexSet; - std::vector<IndexType> scvfLocalIndexSet; - - // fill the element map with seeds - auto eIdx = problem.elementMapper().index(element); - elementMap_[eIdx] = element.seed(); - - // get the element geometry - auto elementGeometry = element.geometry(); - const auto& referenceElement = ReferenceElements::general(elementGeometry.type()); - - // get the sub control volume geometries of this element - auto boxGeometries = std::move(BoxGeometryHelper<GridView>::getScvAndScvfGeometries(elementGeometry)); - // define some aliases - auto& scvGeometries = boxGeometries.first; - auto& scvfGeometries = boxGeometries.second; - - // construct the sub control volumes - globalScvIndices_[eIdx].resize(scvGeometries.size()); - scvLocalIndexSet.reserve(scvGeometries.size()); - IndexType scvLocalIdx = 0; - for (auto&& scvGeometry : scvGeometries) - { - scvLocalIndexSet.push_back(scvLocalIdx); - auto dofIdxGlobal = problem.vertexMapper().subIndex(element, scvLocalIdx, dim); - scvs_.emplace_back(std::make_shared<SubControlVolume>(*scvGeometry, - scvIdx, - eIdx, - scvLocalIdx, - dofIdxGlobal)); - - globalScvIndices_[eIdx][scvLocalIdx] = scvIdx; - - // increment local counters - scvIdx++; scvLocalIdx++; - } - - // construct the sub control volume faces - globalScvfIndices_[eIdx].resize(scvfGeometries.size()); - scvfLocalIndexSet.reserve(scvfGeometries.size()); - IndexType scvfLocalIdx = 0; - for (auto&& scvfGeometry : scvfGeometries) - { - // add this scvf to the element's scvf list - scvfLocalIndexSet.push_back(scvfLocalIdx); - - // find the global and local scv indices this scvf is belonging to - std::vector<IndexType> localScvIndices(2); - localScvIndices[0] = referenceElement.subEntity(scvfLocalIdx, dim-1, 0, dim); - localScvIndices[1] = referenceElement.subEntity(scvfLocalIdx, dim-1, 1, dim); - - // compute the scvf normal unit outer normal - auto normal = std::move(BoxGeometryHelper<GridView>::normal(elementGeometry, *scvfGeometry)); - const auto v = elementGeometry.corner(localScvIndices[1]) - elementGeometry.corner(localScvIndices[0]); - const auto s = v*normal; - if (std::signbit(s)) - normal *= -1; - - scvfs_.emplace_back(std::make_shared<SubControlVolumeFace>(*scvfGeometry, - scvfGeometry->center(), - normal, - scvfIdx, - scvfLocalIdx, - localScvIndices, - false)); - - globalScvfIndices_[eIdx][scvfLocalIdx] = scvfIdx; - - // increment local counters - scvfIdx++; scvfLocalIdx++; - } - - // construct the sub control volume faces on the domain boundary - for (const auto& intersection : intersections(gridView_, element)) - { - if (intersection.boundary()) - { - auto isGeometry = intersection.geometry(); - auto boundaryScvfGeometries = std::move(BoxGeometryHelper<GridView>::getBoundaryScvfGeometries(isGeometry)); - - IndexType isScvfLocalIdx = 0; - for (auto&& scvfGeometry : boundaryScvfGeometries) - { - // add this scvf to the element's scvf list - scvfLocalIndexSet.push_back(scvfLocalIdx); - - // find the scvs this scvf is belonging to - std::vector<IndexType> localScvIndices = {static_cast<IndexType>(referenceElement.subEntity(intersection.indexInInside(), 1, isScvfLocalIdx, dim))}; - - // get the unit outer normal through the intersection - auto normal = intersection.unitOuterNormal(isGeometry.local(scvfGeometry->center())); - - scvfs_.emplace_back(std::make_shared<SubControlVolumeFace>(*scvfGeometry, - scvfGeometry->center(), - normal, - scvfIdx, - scvfLocalIdx++, - localScvIndices, - true)); - - globalScvfIndices_[eIdx].push_back(scvfIdx++); - } - } - } - - // Compute the finite volume element geometries - fvGeometries_.push_back(FVElementGeometry(*this, scvLocalIndexSet, scvfLocalIndexSet)); - } - } - - // Binding of an element, has to be called before using the fvgeometries - // Prepares all the volume variables within the element - // For compatibility reasons with the FVGeometry cache being disabled - void bindElement(const Element& element) - { - eIdxBound_ = problem_().elementMapper().index(element); - } - // this function is for compatibility reasons with cc methods - void bind(const Element& element) - { - bindElement(element); - } - -private: - const Problem& problem_() const - { return *problemPtr_; } - - const Problem* problemPtr_; - - IndexType eIdxBound_; - GridView gridView_; - Dumux::ElementMap<GridView> elementMap_; - std::vector<std::shared_ptr<SubControlVolume>> scvs_; - std::vector<std::shared_ptr<SubControlVolumeFace>> scvfs_; - std::vector<FVElementGeometry> fvGeometries_; - - std::vector<std::vector<IndexType>> globalScvIndices_; - std::vector<std::vector<IndexType>> globalScvfIndices_; - const FeCache feCache_; -}; - -// specialization in case the FVElementGeometries are not stored -template<class TypeTag> -class BoxFVElementGeometryVector<TypeTag, false> -{ - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using IndexType = typename GridView::IndexSet::IndexType; - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - - static const int dim = GridView::dimension; - static const int dimWorld = GridView::dimensionworld; - - using Element = typename GridView::template Codim<0>::Entity; - using Vertex = typename GridView::template Codim<dim>::Entity; - - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using CoordScalar = typename GridView::ctype; - - using FeCache = Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; - using FeLocalBasis = typename FeCache::FiniteElementType::Traits::LocalBasisType; - using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>; - -public: - //! Constructor - BoxFVElementGeometryVector(const GridView gridView) - : gridView_(gridView), elementMap_(gridView), eIdxBound_(-1) {} - - /* \brief Get the finite volume geometry of an element - * \note The finite volume geometry offers iterators over the sub control volumes - * and the sub control volume faces of an element. - */ - const FVElementGeometry& fvGeometry(const Element& element) const - { - auto eIdx = problem_().elementMapper().index(element); - if (eIdx != eIdxBound_) - DUNE_THROW(Dune::InvalidStateException, "Trying to get FVElementGeometry for element with index " << eIdx - << ", but bound is element " << eIdxBound_ << ". Please call bindElement() before using the fvGeometry."); - return fvGeometry_[0]; - } - - //! Get a sub control volume with a global scv index - const SubControlVolume& subControlVolume(IndexType scvIdx) const - { - return stencilScvs_[scvIdx]; - } - - //! Get a sub control volume face with a global scvf index - const SubControlVolumeFace& subControlVolumeFace(IndexType scvfIdx) const - { - return stencilScvfs_[scvfIdx]; - } - - //! Get a local finite element basis - const FeLocalBasis& feLocalBasis(const Dune::GeometryType& type) const - { - return feCache_.get(type).localBasis(); - } - - //! The total number of sub control volumes - std::size_t numScv() const - { - return numScvs_; - } - - //! The total number of sun control volume faces - std::size_t numScvf() const - { - return numScvf_; - } - - //! The total number of boundary sub control volume faces - //! For compatibility reasons with cc methods - std::size_t numBoundaryScvf() const - { - return 0; - } - - // Get an element from a sub control volume contained in it - Element element(const SubControlVolume& scv) const - { return elementMap_.element(scv.elementIndex()); } - - // Get an element from a global element index - Element element(IndexType eIdx) const - { return elementMap_.element(eIdx); } - - //! update all fvElementGeometries (do this again after grid adaption) - void update(const Problem& problem) - { - problemPtr_ = &problem; - elementMap_.clear(); - release_(); - eIdxBound_ = -1; - - auto numElems = gridView_.size(0); - elementMap_.resize(numElems); - scvIndices_.resize(numElems); - scvFaceIndices_.resize(numElems); - - // save data on the grid's scvs and scvfs - IndexType scvIdx = 0; - IndexType scvfIdx = 0; - for (const auto& element : elements(gridView_)) - { - // the element-wise index sets for finite volume geometry - std::vector<IndexType> scvIndexSet; - std::vector<IndexType> scvfIndexSet; - - // fill the element map with seeds - auto eIdx = problem.elementMapper().index(element); - elementMap_[eIdx] = element.seed(); - - // store scv indices of the element - for (int scvLocalIdx = 0; scvLocalIdx < element.subEntities(dim); ++scvLocalIdx) - scvIndexSet.push_back(scvIdx++); - - // store scv face indices of the element - for (int scvfLocalIdx = 0; scvfLocalIdx < element.subEntities(dim-1); ++scvfLocalIdx) - scvfIndexSet.push_back(scvfIdx++); - - // store the sub control volume face indices on the domain boundary - for (const auto& intersection : intersections(gridView_, element)) - { - if (intersection.boundary()) - { - for (int localNodeIdx = 0; localNodeIdx < intersection.geometry().corners(); ++localNodeIdx) - { - // add this scvf to the element's scvf list - scvfIndexSet.push_back(scvfIdx++); - } - } - } - - // store the sets of indices in the data containers - scvIndices_[eIdx] = scvIndexSet; - scvFaceIndices_[eIdx] = scvfIndexSet; - } - - numScvs_ = scvIdx; - numScvf_ = scvfIdx; - } - - // build the geometries inside an element - void bindElement(const Element& element) - { - eIdxBound_ = problem_().elementMapper().index(element); - release_(); - makeElementGeometries_(element); - } - - // for cc methods, this method binds all the elements in the stencil. - // Here, we simply forward to the bindElement() routine. - void bind(const Element& element) - { - bindElement(element); - } - -private: - void release_() - { - stencilScvs_.clear(); - stencilScvfs_.clear(); - fvGeometry_.clear(); - } - - void makeElementGeometries_(const Element& element) - { - const auto eIdx = problem_().elementMapper().index(element); - - // the element-wise index sets for finite volume geometry - auto scvIndexSet = scvIndices_[eIdx]; - auto scvfIndexSet = scvFaceIndices_[eIdx]; - std::vector<IndexType> localScvIndexSet; - std::vector<IndexType> localScvfIndexSet; - localScvIndexSet.reserve(scvIndexSet.size()); - localScvfIndexSet.reserve(scvfIndexSet.size()); - - // get the element geometry - auto elementGeometry = element.geometry(); - const auto& referenceElement = ReferenceElements::general(elementGeometry.type()); - - // get the sub control volume geometries of this element - auto boxGeometries = std::move(BoxGeometryHelper<GridView>::getScvAndScvfGeometries(elementGeometry)); - // define some aliases - auto& scvGeometries = boxGeometries.first; - auto& scvfGeometries = boxGeometries.second; - - // construct the sub control volumes - IndexType scvLocalIdx = 0; - for (auto&& scvGeometry : scvGeometries) - { - localScvIndexSet.push_back(scvLocalIdx); - auto dofIdxGlobal = problem_().vertexMapper().subIndex(element, scvLocalIdx, dim); - - // add scv to the local container - stencilScvs_.emplace_back(SubControlVolume(*scvGeometry, - scvIndexSet[scvLocalIdx], - eIdx, - scvLocalIdx, - dofIdxGlobal)); - // increment local counter - scvLocalIdx++; - } - - // construct the sub control volume faces - IndexType scvfLocalIdx = 0; - for (auto&& scvfGeometry : scvfGeometries) - { - localScvfIndexSet.push_back(scvfLocalIdx); - - // find the local scv indices this scvf is connsected to - std::vector<IndexType> localScvIndices(2); - localScvIndices[0] = referenceElement.subEntity(scvfLocalIdx, dim-1, 0, dim); - localScvIndices[1] = referenceElement.subEntity(scvfLocalIdx, dim-1, 1, dim); - - // compute the scvf normal unit outer normal - auto normal = std::move(BoxGeometryHelper<GridView>::normal(elementGeometry, *scvfGeometry)); - const auto v = elementGeometry.corner(localScvIndices[1]) - elementGeometry.corner(localScvIndices[0]); - const auto s = v*normal; - if (std::signbit(s)) - normal *= -1; - - stencilScvfs_.emplace_back(SubControlVolumeFace(*scvfGeometry, - scvfGeometry->center(), - normal, - scvfIndexSet[scvfLocalIdx], - scvfLocalIdx, - localScvIndices, - false)); - - // increment local counter - scvfLocalIdx++; - } - - // construct the sub control volume faces on the domain boundary - for (const auto& intersection : intersections(gridView_, element)) - { - if (intersection.boundary()) - { - auto isGeometry = intersection.geometry(); - auto boundaryScvfGeometries = std::move(BoxGeometryHelper<GridView>::getBoundaryScvfGeometries(isGeometry)); - - IndexType boundaryFaceLocalIdx = 0; - for (auto&& scvfGeometry : boundaryScvfGeometries) - { - localScvfIndexSet.push_back(scvfLocalIdx); - - // find the scv this scvf is connected to - std::vector<IndexType> localScvIndices = {static_cast<IndexType>(referenceElement.subEntity(intersection.indexInInside(), 1, boundaryFaceLocalIdx++, dim))}; - - // get the unit outer normal through the intersection - auto normal = intersection.unitOuterNormal(isGeometry.local(scvfGeometry->center())); - - stencilScvfs_.emplace_back(SubControlVolumeFace(*scvfGeometry, - scvfGeometry->center(), - normal, - scvfIndexSet[scvfLocalIdx], - scvfLocalIdx, - localScvIndices, - true)); - - // increment local counter - scvfLocalIdx++; - } - } - } - - // Compute the finite volume element geometries - fvGeometry_.push_back(FVElementGeometry(*this, localScvIndexSet, localScvfIndexSet)); - } - - const Problem& problem_() const - { return *problemPtr_; } - - GridView gridView_; - const Problem* problemPtr_; - const FeCache feCache_; - - // Information on the global number of geometries - IndexType numScvs_; - IndexType numScvf_; - - // vectors that store the global data - Dumux::ElementMap<GridView> elementMap_; - std::vector<std::vector<IndexType>> scvIndices_; - std::vector<std::vector<IndexType>> scvFaceIndices_; - - // vectors to store the geometries temporarily after binding an element - IndexType eIdxBound_; - std::vector<SubControlVolume> stencilScvs_; - std::vector<SubControlVolumeFace> stencilScvfs_; - std::vector<FVElementGeometry> fvGeometry_; -}; - -} // end namespace - -#endif diff --git a/dumux/discretization/box/globalfvgeometry.hh b/dumux/discretization/box/globalfvgeometry.hh new file mode 100644 index 0000000000000000000000000000000000000000..e1efe5803a13509de9a0f488bd71439f290ae88b --- /dev/null +++ b/dumux/discretization/box/globalfvgeometry.hh @@ -0,0 +1,383 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \brief Base class for the finite volume geometry vector for box models + * This builds up the sub control volumes and sub control volume faces + * for each element of the grid partition. + */ +#ifndef DUMUX_DISCRETIZATION_BOX_GLOBAL_FVGEOMETRY_HH +#define DUMUX_DISCRETIZATION_BOX_GLOBAL_FVGEOMETRY_HH + +#include <dune/geometry/referenceelements.hh> +#include <dune/localfunctions/lagrange/pqkfactory.hh> + +#include <dumux/discretization/box/boxgeometryhelper.hh> +#include <dumux/discretization/box/fvelementgeometry.hh> +#include <dumux/implicit/box/properties.hh> +#include <dumux/common/elementmap.hh> + +namespace Dumux +{ + +/*! + * \ingroup ImplicitModel + * \brief Base class for the finite volume geometry vector for box models + * This builds up the sub control volumes and sub control volume faces + * for each element. + */ +template<class TypeTag, bool EnableGlobalFVGeometryCache> +class BoxGlobalFVGeometry +{}; + +// specialization in case the FVElementGeometries are stored +template<class TypeTag> +class BoxGlobalFVGeometry<TypeTag, true> +{ + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using IndexType = typename GridView::IndexSet::IndexType; + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using Element = typename GridView::template Codim<0>::Entity; + //! The local class needs access to the scv, scvfs + //! as they are globally cached + friend typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using CoordScalar = typename GridView::ctype; + + static const int dim = GridView::dimension; + static const int dimWorld = GridView::dimensionworld; + + using FeCache = Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; + using FeLocalBasis = typename FeCache::FiniteElementType::Traits::LocalBasisType; + using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>; + + using GeometryHelper = BoxGeometryHelper<GridView, dim>; + +public: + //! Constructor + BoxGlobalFVGeometry(const GridView gridView) + : gridView_(gridView), elementMap_(gridView) {} + + //! The total number of sub control volumes + std::size_t numScv() const + { return numScv_; } + + //! The total number of sun control volume faces + std::size_t numScvf() const + { return numScvf_; } + + //! The total number of boundary sub control volume faces + //! For compatibility reasons with cc methods + std::size_t numBoundaryScvf() const + { return numBoundaryScvf_; } + + // Get an element from a sub control volume contained in it + Element element(const SubControlVolume& scv) const + { return elementMap_.element(scv.index()); } + + // Get an element from a global element index + Element element(IndexType eIdx) const + { return elementMap_.element(eIdx); } + + //! Return the gridView this global object lives on + const GridView& gridView() const + { return gridView_; } + + //! update all fvElementGeometries (do this again after grid adaption) + void update(const Problem& problem) + { + problemPtr_ = &problem; + + scvs_.clear(); + scvfs_.clear(); + elementMap_.clear(); + + auto numElements = gridView_.size(0); + scvs_.resize(numElements); + scvfs_.resize(numElements); + elementMap_.resize(numElements); + + numScv_ = 0; + numScvf_ = 0; + numBoundaryScvf_ = 0; + // Build the SCV and SCV faces + for (const auto& element : elements(gridView_)) + { + // fill the element map with seeds + auto eIdx = problem.elementMapper().index(element); + elementMap_[eIdx] = element.seed(); + + // count + numScv_ += element.subEntities(dim); + numScvf_ += element.subEntities(dim-1); + + // get the element geometry + auto elementGeometry = element.geometry(); + const auto& referenceElement = ReferenceElements::general(elementGeometry.type()); + + // get the sub control volume geometries of this element + GeometryHelper geometryHelper(elementGeometry); + auto scvGeometries = geometryHelper.createScvGeometries(); + auto scvfGeometries = geometryHelper.createScvfGeometries(); + + // construct the sub control volumes + IndexType scvLocalIdx = 0; + scvs_[eIdx].reserve(scvGeometries.size()); + for (auto&& scvGeometry : scvGeometries) + { + auto dofIdxGlobal = problem.vertexMapper().subIndex(element, scvLocalIdx, dim); + scvs_[eIdx].emplace_back(std::move(scvGeometry), + scvLocalIdx, + eIdx, + dofIdxGlobal); + // increment local counter + scvLocalIdx++; + } + + // construct the sub control volume faces + IndexType scvfLocalIdx = 0; + scvfs_[eIdx].reserve(scvfGeometries.size()); + for (auto&& scvfGeometry : scvfGeometries) + { + // find the global and local scv indices this scvf is belonging to + std::vector<IndexType> localScvIndices({static_cast<IndexType>(referenceElement.subEntity(scvfLocalIdx, dim-1, 0, dim)), + static_cast<IndexType>(referenceElement.subEntity(scvfLocalIdx, dim-1, 1, dim))}); + + // compute the scvf normal unit outer normal + auto normal = geometryHelper.normal(elementGeometry, *scvfGeometry); + const auto v = elementGeometry.corner(localScvIndices[1]) - elementGeometry.corner(localScvIndices[0]); + const auto s = v*normal; + if (std::signbit(s)) + normal *= -1; + + scvfs_.emplace_back(std::move(scvfGeometry), + normal, + scvfLocalIdx, + localScvIndices, + false); + + // increment local counter + scvfLocalIdx++; + } + + // construct the sub control volume faces on the domain boundary + for (const auto& intersection : intersections(gridView_, element)) + { + if (intersection.boundary()) + { + auto isGeometry = intersection.geometry(); + // count + numScvf_ += isGeometry.corners(); + numBoundaryScvf_ += isGeometry.corners(); + auto boundaryScvfGeometries = geometryHelper.createBoundaryScvfGeometries(isGeometry); + + IndexType isScvfLocalIdx = 0; + for (auto&& scvfGeometry : boundaryScvfGeometries) + { + // find the scvs this scvf is belonging to + std::vector<IndexType> localScvIndices = + {static_cast<IndexType>(referenceElement.subEntity(intersection.indexInInside(), 1, + isScvfLocalIdx++, dim))}; + + scvfs_.emplace_back(std::move(scvfGeometry), + intersection.centerUnitOuterNormal(), + scvfLocalIdx, + localScvIndices, + true); + + // increment local counter + scvfLocalIdx++; + } + } + } + } + } + + /*! + * \brief Return a local restriction of this global object + * The local object is only functional after calling its bind/bindElement method + * This is a free function that will be found by means of ADL + */ + friend FVElementGeometry localView(const BoxGlobalFVGeometry& global) + { + return FVElementGeometry(global); + } + + //! The finite element cache for creating local FE bases + const FeCache& feCache() const + { return feCache_; } + +private: + + //! Get the local scvs for an element + const std::vector<SubControlVolume>& scvs(IndexType eIdx) + { return scvs_[eIdx]; } + + //! Get the local scvfs for an element + const std::vector<SubControlVolume>& scvfs(IndexType eIdx) + { return scvfs_[eIdx]; } + + const Problem& problem_() const + { return *problemPtr_; } + + const Problem* problemPtr_; + const FeCache feCache_; + + GridView gridView_; + Dumux::ElementMap<GridView> elementMap_; + std::vector<std::vector<SubControlVolume>> scvs_; + std::vector<std::vector<SubControlVolumeFace>> scvfs_; + // TODO do we need those? + std::size_t numScv_; + std::size_t numScvf_; + std::size_t numBoundaryScvf_; +}; + +// specialization in case the FVElementGeometries are not stored +template<class TypeTag> +class BoxGlobalFVGeometry<TypeTag, false> +{ + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using IndexType = typename GridView::IndexSet::IndexType; + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + + //! The local class needs access to the problem + friend typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + + static const int dim = GridView::dimension; + static const int dimWorld = GridView::dimensionworld; + + using Element = typename GridView::template Codim<0>::Entity; + using Vertex = typename GridView::template Codim<dim>::Entity; + + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using CoordScalar = typename GridView::ctype; + + using FeCache = Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; + using FeLocalBasis = typename FeCache::FiniteElementType::Traits::LocalBasisType; + using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>; + +public: + //! Constructor + BoxGlobalFVGeometry(const GridView gridView) + : gridView_(gridView), elementMap_(gridView) {} + + //! The total number of sub control volumes + std::size_t numScv() const + { return numScv_; } + + //! The total number of sun control volume faces + std::size_t numScvf() const + { return numScvf_; } + + //! The total number of boundary sub control volume faces + //! For compatibility reasons with cc methods + std::size_t numBoundaryScvf() const + { return numBoundaryScvf_; } + + // Get an element from a sub control volume contained in it + Element element(const SubControlVolume& scv) const + { return elementMap_.element(scv.index()); } + + // Get an element from a global element index + Element element(IndexType eIdx) const + { return elementMap_.element(eIdx); } + + //! Return the gridView this global object lives on + const GridView& gridView() const + { return gridView_; } + + //! update all fvElementGeometries (do this again after grid adaption) + void update(const Problem& problem) + { + problemPtr_ = &problem; + elementMap_.clear(); + + auto numElems = gridView_.size(0); + elementMap_.resize(numElems); + + // save global data on the grid's scvs and scvfs + numScv_ = 0; + numScvf_ = 0; + numBoundaryScvf_ = 0; + for (const auto& element : elements(gridView_)) + { + // fill the element map with seeds + auto eIdx = problem.elementMapper().index(element); + elementMap_[eIdx] = element.seed(); + + numScv_ += element.subEntities(dim); + numScvf_ += element.subEntities(dim-1); + + // store the sub control volume face indices on the domain boundary + for (const auto& intersection : intersections(gridView_, element)) + { + if (intersection.boundary()) + { + auto isGeometry = intersection.geometry(); + numScvf_ += isGeometry.corners(); + numBoundaryScvf_ += isGeometry.corners(); + } + } + } + } + + /*! + * \brief Return a local restriction of this global object + * The local object is only functional after calling its bind/bindElement method + * This is a free function that will be found by means of ADL + */ + friend FVElementGeometry localView(const BoxGlobalFVGeometry& global) + { + return FVElementGeometry(global); + } + + //! The finite element cache for creating local FE bases + const FeCache& feCache() const + { return feCache_; } + +private: + + const Problem& problem_() const + { return *problemPtr_; } + + GridView gridView_; + const Problem* problemPtr_; + const FeCache feCache_; + + // Information on the global number of geometries + // TODO do we need those information? + std::size_t numScv_; + std::size_t numScvf_; + std::size_t numBoundaryScvf_; + + // vectors that store the global data + Dumux::ElementMap<GridView> elementMap_; +}; + +} // end namespace + +#endif diff --git a/dumux/discretization/box/stencils.hh b/dumux/discretization/box/stencils.hh index afe38dc3f8b2023eeef0069bbec5c06d3d2618fe..489dead98995b32bdfed9bcdd1c301b77874896c 100644 --- a/dumux/discretization/box/stencils.hh +++ b/dumux/discretization/box/stencils.hh @@ -141,16 +141,16 @@ public: elementStencils_[eIdx].update(problem, element); // bind the FvGeometry to the element before using it - problem.model().fvGeometries_().bindElement(element); - const auto& fvGeometry = problem.model().fvGeometries(element); + auto fvGeometry = localView(problem.model().globalFvGeometry()); + fvGeometry.bindElement(element); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { auto vIdxGlobal = scv.dofIndex(); vertexStencils_[vIdxGlobal].vertexScvs().push_back(scv.index()); vertexStencils_[vIdxGlobal].elementIndices().push_back(eIdx); - for (const auto& scvJ : scvs(fvGeometry)) + for (auto&& scvJ : scvs(fvGeometry)) { auto vIdxGlobalJ = scvJ.dofIndex(); diff --git a/dumux/discretization/box/subcontrolvolume.hh b/dumux/discretization/box/subcontrolvolume.hh index df886d74d351a46a4a3e58b029edd245d67efbda..410a2f272a57d5638a107be1e03ae09324df7c26 100644 --- a/dumux/discretization/box/subcontrolvolume.hh +++ b/dumux/discretization/box/subcontrolvolume.hh @@ -43,21 +43,15 @@ private: public: // the contructor in the box case - BoxSubControlVolume(Geometry geometry, - IndexType scvIdx, - IndexType elementIndex, - IndexType indexInElement, - IndexType dofIndex) + BoxSubControlVolume(Geometry&& geometry, + IndexType scvIdx, + IndexType elementIndex, + IndexType dofIndex) : SubControlVolumeBase<G, I>(std::move(geometry), std::move(elementIndex)), - scvIdx_(scvIdx), indexInElement_(std::move(indexInElement)), + scvIdx_(std::move(scvIdx)), dofIndex_(std::move(dofIndex)) {} - IndexType indexInElement() const - { - return indexInElement_; - } - - //! The global index of this scv + //! The local index of this scv IndexType index() const { return scvIdx_; @@ -70,12 +64,11 @@ public: GlobalPosition dofPosition() const { - return this->geometry().corner(indexInElement_); + return this->geometry().corner(scvIdx_); } private: IndexType scvIdx_; - IndexType indexInElement_; IndexType dofIndex_; }; diff --git a/dumux/discretization/box/subcontrolvolumeface.hh b/dumux/discretization/box/subcontrolvolumeface.hh index b96d5085c58f0d20dbcac3e393b966cbb64aeb77..1f297a77e203c8aed3fb21421b304540454dfeb9 100644 --- a/dumux/discretization/box/subcontrolvolumeface.hh +++ b/dumux/discretization/box/subcontrolvolumeface.hh @@ -46,14 +46,12 @@ class BoxSubControlVolumeFace : public SubControlVolumeFaceBase<Geometry, IndexT using LocalPosition = Dune::FieldVector<Scalar, dim>; public: - BoxSubControlVolumeFace(const Geometry& geometry, - const GlobalPosition& ipGlobal, - const GlobalPosition& unitOuterNormal, - IndexType scvfIndex, - IndexType indexInElement, - const std::vector<IndexType>& scvIndices, - bool boundary = false) - : SubControlVolumeFaceBase<Geometry, IndexType>(geometry, ipGlobal, unitOuterNormal, scvfIndex, indexInElement, scvIndices, boundary) {} + BoxSubControlVolumeFace(Geometry&& geometry, + const GlobalPosition& unitOuterNormal, + IndexType scvfIndex, + const std::vector<IndexType>& scvIndices, + bool boundary = false) + : SubControlVolumeFaceBase<Geometry, IndexType>(std::move(geometry), geometry.center(), unitOuterNormal, scvfIndex, scvIndices, boundary) {} }; } // end namespace diff --git a/dumux/discretization/box/volumevariablesvector.hh b/dumux/discretization/box/volumevariablesvector.hh index 313f39f796eee3fc2b9541c676baf366f2def39b..31e88237bf17c0e26d5841a4ad0588e3f2e8a48b 100644 --- a/dumux/discretization/box/volumevariablesvector.hh +++ b/dumux/discretization/box/volumevariablesvector.hh @@ -38,7 +38,7 @@ class BoxVolumeVariablesVector // specialization in case of storing the volume variables template<class TypeTag, bool useOldSol> -class BoxVolumeVariablesVector<TypeTag, useOldSol,/*enableVolVarCaching*/true> : public std::vector<typename GET_PROP_TYPE(TypeTag, VolumeVariables)> +class BoxVolumeVariablesVector<TypeTag, useOldSol,/*enableVolVarCaching*/true> { friend BoxVolumeVariablesVector<TypeTag, !useOldSol, true>; friend ImplicitModel<TypeTag>; @@ -48,10 +48,10 @@ class BoxVolumeVariablesVector<TypeTag, useOldSol,/*enableVolVarCaching*/true> : using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); using IndexType = typename GridView::IndexSet::IndexType; + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); static const int dim = GridView::dimension; using Element = typename GridView::template Codim<0>::Entity; - using Vertex = typename GridView::template Codim<dim>::Entity; enum{ isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) }; @@ -59,11 +59,8 @@ class BoxVolumeVariablesVector<TypeTag, useOldSol,/*enableVolVarCaching*/true> : BoxVolumeVariablesVector<TypeTag, useOldSol, true>& operator= (const BoxVolumeVariablesVector<TypeTag, !useOldSol, true>& other) { - // do the copy - numScvs_ = other.numScvs_; - volumeVariables_ = other.volumeVariables_; - - // return the existing object + volVars_ = other.volVars_; + eIdx_ = other.eIdx_; return *this; }; @@ -72,52 +69,49 @@ public: { problemPtr_ = &problem; - numScvs_ = problem.model().fvGeometries().numScv(); - volumeVariables_.resize(numScvs_); + volVars_.resize(problem.gridView().size(0)); for (const auto& element : elements(problem.gridView())) { - problem.model().fvGeometries_().bindElement(element); - const auto& fvGeometry = problem.model().fvGeometries(element); + auto fvGeometry = localView(problem.model().globalFvGeometry()); + fvGeometry.bindElement(element); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { (*this)[scv].update(sol[scv.dofIndex()], - problem, - element, - scv); + problem, + element, + scv); } } } const VolumeVariables& operator [](IndexType scvIdx) const { - const auto& scv = problem_().model().fvGeometries().subControlVolume(scvIdx); - return (*this)[scv]; + return volVars_[eIdx_][scvIdx]; } VolumeVariables& operator [](IndexType scvIdx) { - const auto& scv = problem_().model().fvGeometries().subControlVolume(scvIdx); - return (*this)[scv]; + return volVars_[eIdx_][scvIdx]; } const VolumeVariables& operator [](const SubControlVolume& scv) const { - return volumeVariables_[scv.index()]; + return volVars_[eIdx_][scv.index()]; } VolumeVariables& operator [](const SubControlVolume& scv) { - return volumeVariables_[scv.index()]; + return volVars_[eIdx_][scv.index()]; } // For compatibility reasons with the case of not storing the vol vars. // function to be called before assembling an element, preparing the vol vars within the stencil - void bind(const Element& element) {} - // In the box method, the vol vars within the elements adjacent to a vertex need to be bound - void bind(const Vertex& vertex) {} + void bind(const Element& element) + { bindElement(element); } // function to prepare the vol vars within the element - void bindElement(const Element& element) {} + void bindElement(const Element& element) + { eIdx_ = problem_().elementMapper().index(element); } private: const Problem& problem_() const @@ -125,9 +119,8 @@ private: const Problem* problemPtr_; - IndexType eIdxBound_; - IndexType numScvs_; - std::vector<VolumeVariables> volumeVariables_; + IndexType eIdx_; + std::vector<std::vector<VolumeVariables>> volVars_; }; @@ -144,21 +137,16 @@ class BoxVolumeVariablesVector<TypeTag, /*isOldSol*/false, /*enableVolVarCaching using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); using IndexType = typename GridView::IndexSet::IndexType; + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); static const int dim = GridView::dimension; using Element = typename GridView::template Codim<0>::Entity; - using Vertex = typename GridView::template Codim<dim>::Entity; - BoxVolumeVariablesVector& operator= (const BoxVolumeVariablesVector<TypeTag, /*isOldSol*/false, /*enableVolVarCaching*/false>& other) = default; + BoxVolumeVariablesVector& operator= (const BoxVolumeVariablesVector<TypeTag, false, false>& other) = default; // operator curVolVars = prevVolVars - void operator= (const BoxVolumeVariablesVector<TypeTag, /*isOldSol*/true, /*enableVolVarCaching*/false>& other) - { - eIdxBound_ = -1; - } - - BoxVolumeVariablesVector() : problemPtr_(nullptr), eIdxBound_(-1) {} - + void operator= (const BoxVolumeVariablesVector<TypeTag, true, false>& other) + {} public: @@ -167,205 +155,54 @@ public: problemPtr_ = &problem; } - - // Binding of an element, prepares the volume variables within the element stencil - // called by the local jacobian to prepare element assembly - // specialization for cc models - template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, ImplicitIsBox)>::type - bind(const Element& element) - { - const auto eIdx = problem_().elementMapper().index(element); - if (eIdx == eIdxBound_ && volVarIndices_.size() > 1) - return; - - eIdxBound_ = eIdx; - - // make sure the FVElementGeometry is bound to the element - problem_().model().fvGeometries_().bind(element); - const auto& fvGeometry = problem_().model().fvGeometries(eIdx); - - // stencil information - const auto& elementStencil = problem_().model().stencils(element).elementStencil(); - const auto& neighborStencil = problem_().model().stencils(element).neighborStencil(); - - // maximum number of possible vol vars to be created - const auto numDofs = elementStencil.size();;// + fvGeometry.numScvf(); - - // resize local containers to the required size - volumeVariables_.resize(numDofs); - volVarIndices_.resize(numDofs); - int localIdx = 0; - - // update the volume variables of the element at hand - const auto& scvI = problem_().model().fvGeometries().subControlVolume(eIdx); - const auto& solI = problem_().model().curSol()[eIdx]; - // VolumeVariables tmp; - // tmp.update(solI, problem_(), element, scvI); - volumeVariables_[localIdx].update(solI, problem_(), element, scvI); - volVarIndices_[localIdx] = scvI.index(); - // volumeVariables_.push_back(tmp); - // volVarIndices_.push_back(scvI.index()); - localIdx++; - - // Update the volume variables of the neighboring elements - for (auto globalJ : neighborStencil) - { - const auto& elementJ = problem_().model().fvGeometries().element(globalJ); - const auto& scvJ = problem_().model().fvGeometries().subControlVolume(globalJ); - const auto& solJ = problem_().model().curSol()[globalJ]; - // tmp.update(solJ, problem_(), elementJ, scvJ); - // volumeVariables_.push_back(tmp); - // volVarIndices_.push_back(scvJ.index()); - volumeVariables_[localIdx].update(solJ, problem_(), elementJ, scvJ); - volVarIndices_[localIdx] = scvJ.index(); - localIdx++; - } - - // Update boundary volume variables - for (const auto& scvFace : scvfs(fvGeometry)) - { - // if we are not on a boundary, skip the rest - if (!scvFace.boundary()) - continue; - - // When complex boundary handling is inactive, we only use BC vol vars on pure Dirichlet boundaries - const auto bcTypes = problem_().boundaryTypes(element, scvFace); - if (/*TODO !GET_PROP_VALUE(TypeTag, BoundaryReconstruction) && */bcTypes.hasNeumann() || bcTypes.hasOutflow()) - continue; - - const auto dirichletPriVars = problem_().dirichlet(element, scvFace); - // tmp.update(dirichletPriVars, problem_(), element, scvI); - // volumeVariables_.push_back(tmp); - // volVarIndices_.push_back(scvI.index()); - volumeVariables_.resize(localIdx+1); - volVarIndices_.resize(localIdx+1); - volumeVariables_[localIdx].update(dirichletPriVars, problem_(), element, scvI); - volVarIndices_[localIdx] = scvFace.outsideScvIdx(); - localIdx++; - } - } - // specialization for box models, simply forwards to the bindElement method - template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type - bind(const Element& element) + void bind(const Element& element, const FVElementGeometry& fvGeometry) { - bindElement(element); + bindElement(element, fvGeometry); } - // Binding of an element, prepares only the volume variables of the element - // specialization for cc models - template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, ImplicitIsBox)>::type - bindElement(const Element& element) - { - const auto eIdx = problem_().elementMapper().index(element); - if (eIdx == eIdxBound_ || std::find(volVarIndices_.begin(), volVarIndices_.end(), eIdx) != volVarIndices_.end()) - return; - - volumeVariables_.resize(1); - volVarIndices_.resize(1); - eIdxBound_ = eIdx; - - // make sure the FVElementGeometry is bound to the element - problem_().model().fvGeometries_().bindElement(element); - - // update the volume variables of the element at hand - const auto& scv = problem_().model().fvGeometries().subControlVolume(eIdx); - const auto& sol = problem_().model().curSol()[eIdx]; - volumeVariables_[0].update(sol, problem_(), element, scv); - volVarIndices_[0] = scv.index(); - } - - // In the box method, the vol vars within the elements adjacent to a vertex need to be bound (TODO: IMPLEMENT) - template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type - bind(const Vertex& vertex) const {} - // specialization for box models - template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type - bindElement(const Element& element) + void bindElement(const Element& element, const FVElementGeometry& fvGeometry) { - const auto eIdx = problem_().elementMapper().index(element); - if (eIdx == eIdxBound_) - return; - - eIdxBound_ = eIdx; - - // make sure the FVElementGeometry is bound to the element - problem_().model().fvGeometries_().bind(element); - const auto& fvGeometry = problem_().model().fvGeometries(element); - - // get stencil information - const auto numDofs = element.subEntities(dim); - // resize volume variables to the required size - volumeVariables_.resize(numDofs); - // volVarIndices_.resize(numDofs); + volVars_.resize(fvGeometry.numScv()); - int localIdx = 0; - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { - // std::cout << "scv index: " << scv.index() << ", dofIdx: " << scv.dofIndex() << ", localIdx: " << scv.indexInElement() << std::endl; const auto& sol = problem_().model().curSol()[scv.dofIndex()]; - // let the interface solver update the volvars - // volVarIndices_[localIdx] = scv.index(); // TODO: INTERFACE SOLVER // problem_().model().boxInterfaceConditionSolver().updateScvVolVars(element, scv, sol); - volumeVariables_[scv.indexInElement()].update(sol, problem_(), element, scv); - localIdx++; + volVars_[scv.index()].update(sol, problem_(), element, scv); } - // std::cout << "finished\n"; } const VolumeVariables& operator [](IndexType scvIdx) const { - return volumeVariables_[scvIdx]; + return volVars_[scvIdx]; } VolumeVariables& operator [](IndexType scvIdx) { - return volumeVariables_[scvIdx]; + return volVars_[scvIdx]; } const VolumeVariables& operator [](const SubControlVolume& scv) const { - return volumeVariables_[scv.indexInElement()]; + return volVars_[scv.index()]; } VolumeVariables& operator [](const SubControlVolume& scv) { - return volumeVariables_[scv.indexInElement()]; + return volVars_[scv.index()]; } private: - void release_() - { - volumeVariables_.clear(); - volVarIndices_.clear(); - } - - const int getLocalIdx_(const int volVarIdx) const - { - auto it = std::find(volVarIndices_.begin(), volVarIndices_.end(), volVarIdx); - - if (it != volVarIndices_.end()) - return std::distance(volVarIndices_.begin(), it); - else - DUNE_THROW(Dune::InvalidStateException, "Could not find the current volume variables for volVarIdx = " << volVarIdx << - ", make sure to properly bind the volume variables to the element before using them"); - } - Problem& problem_() const { return *problemPtr_;} Problem* problemPtr_; - IndexType eIdxBound_; - std::vector<IndexType> volVarIndices_; - std::vector<VolumeVariables> volumeVariables_; + std::vector<VolumeVariables> volVars_; }; // Specialization when the previous volume variables are not stored @@ -381,22 +218,18 @@ class BoxVolumeVariablesVector<TypeTag, /*isOldSol*/true, /*enableVolVarCaching* using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); using IndexType = typename GridView::IndexSet::IndexType; + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); static const int dim = GridView::dimension; using Element = typename GridView::template Codim<0>::Entity; - using Vertex = typename GridView::template Codim<dim>::Entity; BoxVolumeVariablesVector& operator= (const BoxVolumeVariablesVector<TypeTag, /*isOldSol*/false, /*enableVolVarCaching*/false>& other) { - release_(); + volVars_.clear(); problemPtr_ = other.problemPtr_; - eIdxBound_ = -1; return *this; } - BoxVolumeVariablesVector() : problemPtr_(nullptr), eIdxBound_(-1) {} - - public: void update(const Problem& problem, const SolutionVector& sol) @@ -404,116 +237,49 @@ public: problemPtr_ = &problem; } - // Binding of an element, prepares the volume variables of only the element - // specialization for cc models - template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, ImplicitIsBox)>::type - bindElement(const Element& element) - { - const auto eIdx = problem_().elementMapper().index(element); - if (eIdx == eIdxBound_) - return; - - volumeVariables_.resize(1); - volVarIndices_.resize(1); - eIdxBound_ = eIdx; - - // make sure FVElementGeometry is bound to the element - problem_().model().fvGeometries_().bindElement(element); - - // update the volume variables of the element at hand - const auto& scv = problem_().model().fvGeometries().subControlVolume(eIdx); - const auto& sol = problem_().model().prevSol()[eIdx]; - volumeVariables_[0].update(sol, problem_(), element, scv); - volVarIndices_[0] = scv.index(); - } - - // specialization for box models - template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type - bindElement(const Element& element) + // bind an element + void bindElement(const Element& element, const FVElementGeometry& fvGeometry) { - const auto eIdx = problem_().elementMapper().index(element); - if (eIdx == eIdxBound_) - return; - - eIdxBound_ = eIdx; - - // make sure the FVElementGeometry is bound to the element - problem_().model().fvGeometries_().bind(element); - const auto& fvGeometry = problem_().model().fvGeometries(element); - - // get stencil information - const auto numDofs = element.subEntities(dim); - // resize volume variables to the required size - volumeVariables_.resize(numDofs); - // volVarIndices_.resize(numDofs); + volVars_.resize(fvGeometry.numScv()); - int localIdx = 0; - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { const auto& sol = problem_().model().prevSol()[scv.dofIndex()]; - // let the interface solver update the volvars - // volVarIndices_[localIdx] = scv.index(); //TODO: INTERFACE SOLVER? // problem_().model().boxInterfaceConditionSolver().updateScvVolVars(element, scv, sol); - volumeVariables_[localIdx].update(sol, problem_(), element, scv); - localIdx++; + volVars_[scv.index()].update(sol, problem_(), element, scv); } } - // In the box method, the vol vars within the elements adjacent to a vertex need to be bound (TODO: IMPLEMENT) - template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, ImplicitIsBox)>::type - bind(const Vertex& vertex) const {} - - // const VolumeVariables& operator [](IndexType scvIdx) const - // { - // return volumeVariables_[getLocalIdx_(scvIdx)]; - // } - - // VolumeVariables& operator [](IndexType scvIdx) - // { - // return volumeVariables_[getLocalIdx_(scvIdx)]; - // } - - const VolumeVariables& operator [](const SubControlVolume& scv) const + const VolumeVariables& operator [](IndexType scvIdx) const { - return volumeVariables_[scv.indexInElement()]; + return volVars_[scvIdx]; } - VolumeVariables& operator [](const SubControlVolume& scv) + VolumeVariables& operator [](IndexType scvIdx) { - return volumeVariables_[scv.indexInElement()]; + return volVars_[scvIdx]; } -private: - - void release_() + const VolumeVariables& operator [](const SubControlVolume& scv) const { - volumeVariables_.clear(); - volVarIndices_.clear(); + return volVars_[scv.index()]; } - const int getLocalIdx_(const int volVarIdx) const + VolumeVariables& operator [](const SubControlVolume& scv) { - auto it = std::find(volVarIndices_.begin(), volVarIndices_.end(), volVarIdx); - - if (it != volVarIndices_.end()) - return std::distance(volVarIndices_.begin(), it); - else - DUNE_THROW(Dune::InvalidStateException, "Could not find the previous volume variables for volVarIdx = " << volVarIdx << - ", make sure to properly bind the volume variables to the element before using them"); + return volVars_[scv.index()]; } +private: + Problem& problem_() const { return *problemPtr_;} Problem* problemPtr_; - IndexType eIdxBound_; - std::vector<IndexType> volVarIndices_; - std::vector<VolumeVariables> volumeVariables_; + + std::vector<VolumeVariables> volVars_; }; } // end namespace diff --git a/dumux/discretization/cellcentered/fluxvariablescachevector.hh b/dumux/discretization/cellcentered/fluxvariablescachevector.hh index 859f16d12f3ceea8bbf5262fb210f4891ac7c24c..a44c8084f4a6b04cbf442ed3aa3875f183721656 100644 --- a/dumux/discretization/cellcentered/fluxvariablescachevector.hh +++ b/dumux/discretization/cellcentered/fluxvariablescachevector.hh @@ -39,24 +39,26 @@ class CCFluxVariablesCacheVector using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using IndexType = typename GridView::IndexSet::IndexType; using Element = typename GridView::template Codim<0>::Entity; + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); public: // When global caching is enabled, precompute transmissibilities and stencils for all the scv faces template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type update(Problem& problem) + typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type + update(Problem& problem) { problemPtr_ = &problem; - - fluxVarsCache_.resize(problem.model().fvGeometries().numScvf()); + const auto& globalFvGeometry = problem.model().globalFvGeometry(); + fluxVarsCache_.resize(globalFvGeometry.numScvf()); for (const auto& element : elements(problem.gridView())) { // Prepare the geometries within the elements of the stencil - problem.model().fvGeometries_().bind(element); + auto fvGeometry = localView(globalFvGeometry); + fvGeometry.bind(element); - const auto& fvGeometry = problem.model().fvGeometries(element); - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { (*this)[scvf].update(problem, element, scvf); } @@ -65,7 +67,8 @@ public: // When global flux variables caching is disabled, we don't need to update the cache template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type update(Problem& problem) + typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type + update(Problem& problem) { problemPtr_ = &problem; } @@ -73,10 +76,9 @@ public: // This function has to be called prior to flux calculations on the element. // Prepares the transmissibilities of the scv faces in an element. The FvGeometry is assumed to be bound. template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type bindElement(const Element& element) + typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type + bindElement(const Element& element, const FVElementGeometry& fvGeometry) { - const auto& fvGeometry = problem_().model().fvGeometries(element); - // resizing of the cache const auto numScvf = fvGeometry.numScvf(); fluxVarsCache_.resize(numScvf); @@ -84,9 +86,9 @@ public: IndexType localScvfIdx = 0; // fill the containers - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { - fluxVarsCache_[localScvfIdx].update(problem_(), element, scvf); + fluxVarsCache_[localScvfIdx].update(problem_(), element, fvGeometry, scvf); globalScvfIndices_[localScvfIdx] = scvf.index(); localScvfIdx++; } @@ -94,20 +96,22 @@ public: // Specialization for the global caching being enabled - do nothing here template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type bindElement(const Element& element) {} + typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type + bindElement(const Element& element, const FVElementGeometry& fvGeometry) + {} // This function is called by the CCLocalResidual before flux calculations during assembly. // Prepares the transmissibilities of the scv faces in the stencil. The FvGeometries are assumed to be bound. template <typename T = TypeTag> - typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type bind(const Element& element) + typename std::enable_if<!GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type + bind(const Element& element, const FVElementGeometry& fvGeometry) { const auto globalI = problem_().elementMapper().index(element); - const auto& fvGeometry = problem_().model().fvGeometries(element); const auto& neighborStencil = problem_().model().stencils(element).neighborStencil(); const auto numNeighbors = neighborStencil.size(); // find the number of scv faces that need to be prepared - IndexType numScvf = fvGeometry.numScvf(); + auto numScvf = fvGeometry.numScvf(); for (IndexType localIdxJ = 0; localIdxJ < numNeighbors; ++localIdxJ) { const auto& fluxVarIndicesJ = problem_().model().localJacobian().assemblyMap()[globalI][localIdxJ]; @@ -118,9 +122,9 @@ public: fluxVarsCache_.resize(numScvf); globalScvfIndices_.resize(numScvf); IndexType localScvfIdx = 0; - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { - fluxVarsCache_[localScvfIdx].update(problem_(), element, scvf); + fluxVarsCache_[localScvfIdx].update(problem_(), element, fvGeometry, scvf); globalScvfIndices_[localScvfIdx] = scvf.index(); localScvfIdx++; } @@ -129,11 +133,12 @@ public: for (IndexType localIdxJ = 0; localIdxJ < numNeighbors; ++localIdxJ) { const auto& fluxVarIndicesJ = problem_().model().localJacobian().assemblyMap()[globalI][localIdxJ]; - const auto elementJ = problem_().model().fvGeometries().element(neighborStencil[localIdxJ]); + const auto elementJ = fvGeometry.globalFvGeometry().element(neighborStencil[localIdxJ]); + for (auto fluxVarIdx : fluxVarIndicesJ) { - const auto& scvfJ = problem_().model().fvGeometries().subControlVolumeFace(fluxVarIdx); - fluxVarsCache_[localScvfIdx].update(problem_(), elementJ, scvfJ); + auto&& scvfJ = fvGeometry.scvf(fluxVarIdx); + fluxVarsCache_[localScvfIdx].update(problem_(), elementJ, fvGeometry, scvfJ); globalScvfIndices_[localScvfIdx] = scvfJ.index(); localScvfIdx++; } @@ -142,7 +147,8 @@ public: // Specialization for the global caching being enabled - do nothing here template <typename T = TypeTag> - typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type bind(const Element& element) {} + typename std::enable_if<GET_PROP_VALUE(T, EnableGlobalFluxVariablesCache)>::type + bind(const Element& element, const FVElementGeometry& fvGeometry) {} // access operators in the case of caching template <typename T = TypeTag> @@ -173,11 +179,8 @@ private: getLocalScvfIdx_(const int scvfIdx) const { auto it = std::find(globalScvfIndices_.begin(), globalScvfIndices_.end(), scvfIdx); - - if (it != globalScvfIndices_.end()) - return std::distance(globalScvfIndices_.begin(), it); - else - DUNE_THROW(Dune::InvalidStateException, "Could not find the flux vars cache for scvfIdx = " << scvfIdx); + assert(it != globalScvfIndices_.end() && "Could not find the flux vars cache for scvfIdx"); + return std::distance(globalScvfIndices_.begin(), it); } const Problem& problem_() const diff --git a/dumux/discretization/cellcentered/stencils.hh b/dumux/discretization/cellcentered/stencils.hh index 98c0a346d8b9048508884a9963131ddf5cacec57..ef2b34e86caea8e681e1d48b82563c982d3f0fbc 100644 --- a/dumux/discretization/cellcentered/stencils.hh +++ b/dumux/discretization/cellcentered/stencils.hh @@ -38,22 +38,24 @@ class CCElementStencils using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using IndexType = typename GridView::IndexSet::IndexType; using Element = typename GridView::template Codim<0>::Entity; // TODO a separate stencil class all stencils can derive from? using Stencil = std::vector<IndexType>; public: - void update(const Problem& problem, const Element& element) + //! Update the stencil. We expect a bound fvGeometry + void update(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry) { elementStencil_.clear(); - const auto& fvGeometry = problem.model().fvGeometries(element); // loop over sub control faces - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { FluxVariables fluxVars; - const auto& stencil = fluxVars.computeStencil(problem, element, scvf); - + const auto& stencil = fluxVars.computeStencil(problem, element, fvGeometry, scvf); elementStencil_.insert(elementStencil_.end(), stencil.begin(), stencil.end()); } // make values in elementstencil unique @@ -64,15 +66,16 @@ public: neighborStencil_ = elementStencil_; // remove the element itself and possible ghost neighbors from the neighbor stencil - auto pred = [&problem, globalI](const int i) -> bool + auto pred = [&fvGeometry, globalI](const int i) -> bool { if (i == globalI) return true; - if (problem.model().fvGeometries().element(i).partitionType() == Dune::GhostEntity) + if (fvGeometry.globalFvGeometry().element(i).partitionType() == Dune::GhostEntity) return true; return false; }; - neighborStencil_.erase(std::remove_if(neighborStencil_.begin(), neighborStencil_.end(), pred), neighborStencil_.end()); + neighborStencil_.erase(std::remove_if(neighborStencil_.begin(), neighborStencil_.end(), pred), + neighborStencil_.end()); } //! The full element stencil (all element this element is interacting with) @@ -110,11 +113,12 @@ public: elementStencils_.resize(problem.gridView().size(0)); for (const auto& element : elements(problem.gridView())) { - // bind the FvGeometry to the element before using it - problem.model().fvGeometries_().bind(element); + // restrict the FvGeometry locally and bind to the element + auto fvGeometry = localView(problem.model().globalFvGeometry()); + fvGeometry.bind(element); auto eIdx = problem.elementMapper().index(element); - elementStencils_[eIdx].update(problem, element); + elementStencils_[eIdx].update(problem, element, fvGeometry); } } diff --git a/dumux/discretization/cellcentered/tpfa/CMakeLists.txt b/dumux/discretization/cellcentered/tpfa/CMakeLists.txt index ff7ebeb2ba8ab4c57db241f4588d5f05ef4d7663..9bb40dd86338a59dfac0202c5efd7bbc3b3e9443 100644 --- a/dumux/discretization/cellcentered/tpfa/CMakeLists.txt +++ b/dumux/discretization/cellcentered/tpfa/CMakeLists.txt @@ -1,5 +1,6 @@ install(FILES -fvelementgeometryvector.hh +globalfvgeometry.hh +fvelementgeometry.hh subcontrolvolumeface.hh subcontrolvolume.hh DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/dumux/discretization/cellcentered/tpfa) \ No newline at end of file diff --git a/dumux/discretization/cellcentered/tpfa/darcyslaw.hh b/dumux/discretization/cellcentered/tpfa/darcyslaw.hh index c24d224618ad2a754c52a16ac3c651c5ae1d71c0..345e94d58c6ca6c28d08201b567c52643ea1bfee 100644 --- a/dumux/discretization/cellcentered/tpfa/darcyslaw.hh +++ b/dumux/discretization/cellcentered/tpfa/darcyslaw.hh @@ -52,33 +52,35 @@ NEW_PROP_TAG(ProblemEnableGravity); template <class TypeTag> class DarcysLaw<TypeTag, typename std::enable_if<GET_PROP_VALUE(TypeTag, DiscretizationMethod) == GET_PROP(TypeTag, DiscretizationMethods)::CCTpfa>::type > { - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace) SubControlVolumeFace; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GridView::IndexSet::IndexType IndexType; - typedef std::vector<IndexType> Stencil; + using Element = typename GridView::template Codim<0>::Entity; + using IndexType = typename GridView::IndexSet::IndexType; + using Stencil = std::vector<IndexType>; enum { dim = GridView::dimension} ; enum { dimWorld = GridView::dimensionworld} ; - typedef Dune::FieldMatrix<Scalar, dimWorld, dimWorld> DimWorldMatrix; - typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition; + using DimWorldMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>; + using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>; public: static Scalar flux(const Problem& problem, const Element& element, + const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvFace, const IndexType phaseIdx) { const auto& tij = problem.model().fluxVarsCache(scvFace).tij(); // Get the inside and outside volume variables - const auto& insideScv = problem.model().fvGeometries().subControlVolume(scvFace.insideScvIdx()); + const auto& insideScv = fvGeometry.scv(scvFace.insideScvIdx()); const auto& insideVolVars = problem.model().curVolVars(insideScv); const auto& outsideVolVars = problem.model().curVolVars(scvFace.outsideScvIdx()); @@ -108,7 +110,9 @@ public: else { const auto outsideScvIdx = scvFace.outsideScvIdx(); - const auto& outsideScv = problem.model().fvGeometries().subControlVolume(outsideScvIdx); + // as we assemble fluxes from the neighbor to our element the outside index + // refers to the scv of our element, so we use the scv method + const auto& outsideScv = fvGeometry.scv(outsideScvIdx); const auto xOutside = outsideScv.center(); const auto gOutside = problem.gravityAtPos(xOutside); hOutside -= rho*(gOutside*xOutside); @@ -118,7 +122,10 @@ public: return tij*(hInside - hOutside); } - static Stencil stencil(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace) + static Stencil stencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) { Stencil stencil; if (!scvFace.boundary()) @@ -134,20 +141,25 @@ public: // The flux variables cache has to be bound to an element prior to flux calculations // During the binding, the transmissibilities will be computed and stored using the method below. - static Scalar calculateTransmissibilities(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace) + static Scalar calculateTransmissibilities(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) { Scalar tij; const auto insideScvIdx = scvFace.insideScvIdx(); - const auto& insideScv = problem.model().fvGeometries().subControlVolume(insideScvIdx); + const auto& insideScv = fvGeometry.scv(insideScvIdx); const auto insideK = problem.spatialParams().intrinsicPermeability(insideScv); Scalar ti = calculateOmega_(problem, scvFace, insideK, element, insideScv); if (!scvFace.boundary()) { const auto outsideScvIdx = scvFace.outsideScvIdx(); - const auto& outsideScv = problem.model().fvGeometries().subControlVolume(outsideScvIdx); - const auto outsideElement = problem.model().fvGeometries().element(outsideScvIdx); + // as we assemble fluxes from the neighbor to our element the outside index + // refers to the scv of our element, so we use the scv method + const auto& outsideScv = fvGeometry.scv(outsideScvIdx); + const auto outsideElement = fvGeometry.globalFvGeometry().element(outsideScvIdx); const auto outsideK = problem.spatialParams().intrinsicPermeability(outsideScv); Scalar tj = -1.0*calculateOmega_(problem, scvFace, outsideK, outsideElement, outsideScv); @@ -163,7 +175,11 @@ public: private: - static Scalar calculateOmega_(const Problem& problem, const SubControlVolumeFace& scvFace, const DimWorldMatrix &K, const Element& element, const SubControlVolume &scv) + static Scalar calculateOmega_(const Problem& problem, + const SubControlVolumeFace& scvFace, + const DimWorldMatrix &K, + const Element& element, + const SubControlVolume &scv) { GlobalPosition Knormal; K.mv(scvFace.unitOuterNormal(), Knormal); @@ -178,7 +194,11 @@ private: return omega; } - static Scalar calculateOmega_(const Problem& problem, const SubControlVolumeFace& scvFace, const Scalar K, const Element& element, const SubControlVolume &scv) + static Scalar calculateOmega_(const Problem& problem, + const SubControlVolumeFace& scvFace, + const Scalar K, + const Element& element, + const SubControlVolume &scv) { auto distanceVector = scvFace.center(); distanceVector -= scv.center(); diff --git a/dumux/discretization/cellcentered/tpfa/fickslaw.hh b/dumux/discretization/cellcentered/tpfa/fickslaw.hh index cddca62731be7c0ca1fb190a13b38dd7a785f4ed..6f6d5cc37b4debe234faa92ba53c4516d2e41056 100644 --- a/dumux/discretization/cellcentered/tpfa/fickslaw.hh +++ b/dumux/discretization/cellcentered/tpfa/fickslaw.hh @@ -59,6 +59,7 @@ class FicksLaw<TypeTag, typename std::enable_if<GET_PROP_VALUE(TypeTag, Discreti typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; typedef typename GridView::IndexSet::IndexType IndexType; typedef typename std::vector<IndexType> Stencil; + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using Element = typename GridView::template Codim<0>::Entity; @@ -73,16 +74,16 @@ public: static Scalar flux(const Problem& problem, const Element& element, + const FVElementGeometry& fvGeometry, const SubControlVolumeFace& scvFace, const int phaseIdx, const int compIdx) { // diffusion tensors are always solution dependent - Scalar tij = calculateTransmissibility_(problem, element, scvFace, phaseIdx, compIdx); + Scalar tij = calculateTransmissibility_(problem, element, fvGeometry, scvFace, phaseIdx, compIdx); // Get the inside volume variables - const auto insideScvIdx = scvFace.insideScvIdx(); - const auto& insideScv = problem.model().fvGeometries().subControlVolume(insideScvIdx); + const auto& insideScv = fvGeometry.scv(scvFace.insideScvIdx()); const auto& insideVolVars = problem.model().curVolVars(insideScv); // and the outside volume variables @@ -96,7 +97,10 @@ public: return rho*tij*(xInside - xOutside); } - static Stencil stencil(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace) + static Stencil stencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) { std::vector<IndexType> stencil; stencil.clear(); @@ -114,12 +118,16 @@ public: private: - static Scalar calculateTransmissibility_(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace, const int phaseIdx, const int compIdx) + static Scalar calculateTransmissibility_(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace, + const int phaseIdx, const int compIdx) { Scalar tij; const auto insideScvIdx = scvFace.insideScvIdx(); - const auto& insideScv = problem.model().fvGeometries().subControlVolume(insideScvIdx); + const auto& insideScv = fvGeometry.scv(insideScvIdx); const auto& insideVolVars = problem.model().curVolVars(insideScvIdx); auto insideD = insideVolVars.diffusionCoefficient(phaseIdx, compIdx); @@ -129,7 +137,7 @@ private: if (!scvFace.boundary()) { const auto outsideScvIdx = scvFace.outsideScvIdx(); - const auto& outsideScv = problem.model().fvGeometries().subControlVolume(outsideScvIdx); + const auto& outsideScv = fvGeometry.scv(outsideScvIdx); const auto& outsideVolVars = problem.model().curVolVars(outsideScvIdx); auto outsideD = outsideVolVars.diffusionCoefficient(phaseIdx, compIdx); diff --git a/dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh b/dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh new file mode 100644 index 0000000000000000000000000000000000000000..9acef62f15faa0e654d11da4237d68b541a964d9 --- /dev/null +++ b/dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh @@ -0,0 +1,360 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \brief Base class for a local finite volume geometry for cell-centered TPFA models + * This builds up the sub control volumes and sub control volume faces + * for each element in the local scope we are restricting to, e.g. stencil or element. + */ +#ifndef DUMUX_DISCRETIZATION_CCTPFA_FV_ELEMENT_GEOMETRY_HH +#define DUMUX_DISCRETIZATION_CCTPFA_FV_ELEMENT_GEOMETRY_HH + +#include <dune/common/iteratorrange.hh> + +#include <dumux/discretization/scvandscvfiterators.hh> +#include <dumux/implicit/cellcentered/tpfa/properties.hh> + +namespace Dumux +{ + +//! forward declaration of the global finite volume geometry +template<class TypeTag, bool EnableGlobalFVGeometryCache> +class CCTpfaGlobalFVGeometry; + +/*! + * \ingroup ImplicitModel + * \brief Base class for the finite volume geometry vector for cell-centered TPFA models + * This builds up the sub control volumes and sub control volume faces + * for each element. + */ +template<class TypeTag, bool EnableGlobalFVGeometryCache> +class CCTpfaFVElementGeometry +{}; + +//! specialization in case the FVElementGeometries are stored globally +//! In this case we just forward internally to the global object +template<class TypeTag> +class CCTpfaFVElementGeometry<TypeTag, true> +{ + using ThisType = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using IndexType = typename GridView::IndexSet::IndexType; + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using Element = typename GridView::template Codim<0>::Entity; + using GlobalFVGeometry = typename GET_PROP_TYPE(TypeTag, GlobalFVGeometry); + + using ScvIterator = ScvIterator<SubControlVolume, std::vector<IndexType>, ThisType>; + using ScvfIterator = ScvfIterator<SubControlVolumeFace, std::vector<IndexType>, ThisType>; + +public: + //! Constructor + CCTpfaFVElementGeometry(const GlobalFVGeometry& globalFvGeometry) + : globalFvGeometryPtr_(&globalFvGeometry) {} + + //! Get an elment sub control volume with a global scv index + //! We separate element and neighbor scvs to speed up mapping + const SubControlVolume& scv(IndexType scvIdx) const + { + return globalFvGeometry().scv(scvIdx); + } + + //! Get an element sub control volume face with a global scvf index + //! We separate element and neighbor scvfs to speed up mapping + const SubControlVolumeFace& scvf(IndexType scvfIdx) const + { + return globalFvGeometry().scvf(scvfIdx); + } + + //! iterator range for sub control volumes. Iterates over + //! all scvs of the bound element (not including neighbor scvs) + //! This is a free function found by means of ADL + //! To iterate over all sub control volumes of this FVElementGeometry use + //! for (auto&& scv : scvs(fvGeometry)) + friend inline Dune::IteratorRange<ScvIterator> + scvs(const CCTpfaFVElementGeometry& fvGeometry) + { + return Dune::IteratorRange<ScvIterator>(ScvIterator(fvGeometry.scvIndices_.begin(), fvGeometry), + ScvIterator(fvGeometry.scvIndices_.end(), fvGeometry)); + } + + //! iterator range for sub control volumes faces. Iterates over + //! all scvfs of the bound element (not including neighbor scvfs) + //! This is a free function found by means of ADL + //! To iterate over all sub control volume faces of this FVElementGeometry use + //! for (auto&& scvf : scvfs(fvGeometry)) + friend inline Dune::IteratorRange<ScvfIterator> + scvfs(const CCTpfaFVElementGeometry& fvGeometry) + { + const auto& g = fvGeometry.globalFvGeometry(); + const auto scvIdx = fvGeometry.scvIndices()[0]; + return Dune::IteratorRange<ScvfIterator>(ScvfIterator(g.scvfIndicesOfScv(scvIdx).begin(), fvGeometry), + ScvfIterator(g.scvfIndicesOfScv(scvIdx).end(), fvGeometry)); + } + + //! number of sub control volumes in this fv element geometry + std::size_t numScv() const + { + return scvIndices_.size(); + } + + //! number of sub control volumes in this fv element geometry + std::size_t numScvf() const + { + return globalFvGeometry().scvfIndicesOfScv(scvIndices_[0]).size(); + } + + //! Binding of an element, called by the local jacobian to prepare element assembly + void bind(const Element& element) + { + this->bindElement(element); + } + + //! Bind only element-local + void bindElement(const Element& element) + { + elementPtr_ = &element; + scvIndices_ = std::vector<IndexType>({globalFvGeometry().problem_().elementMapper().index(*elementPtr_)}); + } + + //! The global finite volume geometry we are a restriction of + const GlobalFVGeometry& globalFvGeometry() const + { return *globalFvGeometryPtr_; } + +private: + + const Element* elementPtr_; + std::vector<IndexType> scvIndices_; + const GlobalFVGeometry* globalFvGeometryPtr_; +}; + +//! specialization in case the FVElementGeometries are not stored +template<class TypeTag> +class CCTpfaFVElementGeometry<TypeTag, false> +{ + using ThisType = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using IndexType = typename GridView::IndexSet::IndexType; + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using Element = typename GridView::template Codim<0>::Entity; + using GlobalFVGeometry = typename GET_PROP_TYPE(TypeTag, GlobalFVGeometry); + + using ScvIterator = ScvIterator<SubControlVolume, std::vector<IndexType>, ThisType>; + using ScvfIterator = ScvfIterator<SubControlVolumeFace, std::vector<IndexType>, ThisType>; + +public: + //! Constructor + CCTpfaFVElementGeometry(const GlobalFVGeometry& globalFvGeometry) + : globalFvGeometryPtr_(&globalFvGeometry) {} + + //! Get an elment sub control volume with a global scv index + //! We separate element and neighbor scvs to speed up mapping + const SubControlVolume& scv(IndexType scvIdx) const + { + if (scvIdx == scvIndices_[0]) + return scvs_[0]; + else + return neighborScvs_[findLocalIndex(scvIdx, neighborScvIndices_)]; + } + + //! Get an element sub control volume face with a global scvf index + //! We separate element and neighbor scvfs to speed up mapping + const SubControlVolumeFace& scvf(IndexType scvfIdx) const + { + auto it = std::find(scvfIndices_.begin(), scvfIndices_.end(), scvfIdx); + if (it != scvfIndices_.end()) + return scvfs_[std::distance(scvfIndices_.begin(), it)]; + else + return neighborScvfs_[findLocalIndex(scvfIdx, neighborScvfIndices_)]; + } + + //! iterator range for sub control volumes. Iterates over + //! all scvs of the bound element (not including neighbor scvs) + //! This is a free function found by means of ADL + //! To iterate over all sub control volumes of this FVElementGeometry use + //! for (auto&& scv : scvs(fvGeometry)) + friend inline Dune::IteratorRange<typename std::vector<SubControlVolume>::const_iterator> + scvs(const ThisType& g) + { + using Iter = typename std::vector<SubControlVolume>::const_iterator; + return Dune::IteratorRange<Iter>(g.scvs_.begin(), g.scvs_.end()); + } + + //! iterator range for sub control volumes faces. Iterates over + //! all scvfs of the bound element (not including neighbor scvfs) + //! This is a free function found by means of ADL + //! To iterate over all sub control volume faces of this FVElementGeometry use + //! for (auto&& scvf : scvfs(fvGeometry)) + friend inline Dune::IteratorRange<typename std::vector<SubControlVolumeFace>::const_iterator> + scvfs(const ThisType& g) + { + using Iter = typename std::vector<SubControlVolumeFace>::const_iterator; + return Dune::IteratorRange<Iter>(g.scvfs_.begin(), g.scvfs_.end()); + } + + //! number of sub control volumes in this fv element geometry + std::size_t numScv() const + { + return scvs_.size(); + } + + //! number of sub control volumes in this fv element geometry + std::size_t numScvf() const + { + return scvfs_.size(); + } + + //! Binding of an element preparing the geometries of the whole stencil + //! called by the local jacobian to prepare element assembly + void bind(const Element& element) + { + bindElement(element); + for (const auto& intersection : intersections(globalFvGeometry().gridView(), element)) + { + if (intersection.neighbor()) + makeNeighborGeometries(intersection.outside()); + } + } + + //! Binding of an element preparing the geometries only inside the element + void bindElement(const Element& element) + { + clear(); + elementPtr_ = &element; + makeElementGeometries(element); + } + + //! The global finite volume geometry we are a restriction of + const GlobalFVGeometry& globalFvGeometry() const + { return *globalFvGeometryPtr_; } + +private: + + //! create scvs and scvfs of the bound element + void makeElementGeometries(const Element& element) + { + auto eIdx = globalFvGeometry().problem_().elementMapper().index(element); + scvs_.emplace_back(element.geometry(), eIdx); + scvIndices_.emplace_back(eIdx); + + const auto& scvFaceIndices = globalFvGeometry().scvfIndicesOfScv(eIdx); + const auto& neighborVolVarIndices = globalFvGeometry().neighborVolVarIndices(eIdx); + + int scvfCounter = 0; + for (const auto& intersection : intersections(globalFvGeometry().gridView(), element)) + { + if (intersection.neighbor() || intersection.boundary()) + { + scvfs_.emplace_back(intersection, + scvFaceIndices[scvfCounter], + std::vector<IndexType>({eIdx, neighborVolVarIndices[scvfCounter]}) + ); + + scvfIndices_.push_back(scvFaceIndices[scvfCounter]); + scvfCounter++; + } + } + } + + //! create the necessary scvs and scvfs of the neighbor elements to the bound elements + void makeNeighborGeometries(const Element& element) + { + // create the neighbor scv + auto eIdx = globalFvGeometry().problem_().elementMapper().index(element); + neighborScvs_.emplace_back(element.geometry(), eIdx); + neighborScvIndices_.push_back(eIdx); + + const auto& scvFaceIndices = globalFvGeometry().scvfIndicesOfScv(eIdx); + const auto& neighborVolVarIndices = globalFvGeometry().neighborVolVarIndices(eIdx); + + int scvfCounter = 0; + for (const auto& intersection : intersections(globalFvGeometry().gridView(), element)) + { + if (intersection.neighbor()) + { + // only create subcontrol faces where the outside element is the bound element + if (intersection.outside() == *elementPtr_) + { + neighborScvfs_.emplace_back(intersection, + scvFaceIndices[scvfCounter], + std::vector<IndexType>({eIdx, neighborVolVarIndices[scvfCounter]}) + ); + + neighborScvfIndices_.push_back(scvFaceIndices[scvfCounter]); + } + // always increase local counter + scvfCounter++; + } + else if (intersection.boundary()) + { + neighborScvfs_.emplace_back(intersection, + scvFaceIndices[scvfCounter], + std::vector<IndexType>({eIdx, neighborVolVarIndices[scvfCounter]}) + ); + + neighborScvfIndices_.push_back(scvFaceIndices[scvfCounter]); + scvfCounter++; + } + } + } + + const IndexType findLocalIndex(const IndexType idx, + const std::vector<IndexType>& indices) const + { + auto it = std::find(indices.begin(), indices.end(), idx); + assert(it != indices.end() && "Could not find the scv/scvf! Make sure to properly bind this class!"); + return std::distance(indices.begin(), it); + + } + + void clear() + { + scvIndices_.clear(); + scvfIndices_.clear(); + scvs_.clear(); + scvfs_.clear(); + + neighborScvIndices_.clear(); + neighborScvfIndices_.clear(); + neighborScvs_.clear(); + neighborScvfs_.clear(); + } + + // the bound element + const Element* elementPtr_; + + const GlobalFVGeometry* globalFvGeometryPtr_; + + // local storage after binding an element + std::vector<IndexType> scvIndices_; + std::vector<IndexType> scvfIndices_; + std::vector<SubControlVolume> scvs_; + std::vector<SubControlVolumeFace> scvfs_; + + std::vector<IndexType> neighborScvIndices_; + std::vector<IndexType> neighborScvfIndices_; + std::vector<SubControlVolume> neighborScvs_; + std::vector<SubControlVolumeFace> neighborScvfs_; +}; + +} // end namespace + +#endif diff --git a/dumux/discretization/cellcentered/tpfa/fvelementgeometryvector.hh b/dumux/discretization/cellcentered/tpfa/globalfvgeometry.hh similarity index 59% rename from dumux/discretization/cellcentered/tpfa/fvelementgeometryvector.hh rename to dumux/discretization/cellcentered/tpfa/globalfvgeometry.hh index 1a239b4e38eee895288e0a3940b2ba40aac6250f..35e3e1f15dd1056cf95757105513a4287dd55455 100644 --- a/dumux/discretization/cellcentered/tpfa/fvelementgeometryvector.hh +++ b/dumux/discretization/cellcentered/tpfa/globalfvgeometry.hh @@ -20,13 +20,14 @@ * \file * \brief Base class for the finite volume geometry vector for cell-centered TPFA models * This builds up the sub control volumes and sub control volume faces - * for each element. + * for each element of the grid partition. */ -#ifndef DUMUX_DISCRETIZATION_CCTPFA_FV_GEOMETRY_VECTOR_HH -#define DUMUX_DISCRETIZATION_CCTPFA_FV_GEOMETRY_VECTOR_HH +#ifndef DUMUX_DISCRETIZATION_CCTPFA_GLOBAL_FVGEOMETRY_HH +#define DUMUX_DISCRETIZATION_CCTPFA_GLOBAL_FVGEOMETRY_HH -#include <dumux/implicit/cellcentered/tpfa/properties.hh> #include <dumux/common/elementmap.hh> +#include <dumux/implicit/cellcentered/tpfa/properties.hh> +#include <dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh> namespace Dumux { @@ -37,13 +38,13 @@ namespace Dumux * This builds up the sub control volumes and sub control volume faces * for each element. */ -template<class TypeTag, bool EnableFVElementGeometryCache> -class CCTpfaFVElementGeometryVector +template<class TypeTag, bool EnableGlobalFVGeometryCache> +class CCTpfaGlobalFVGeometry {}; -// specialization in case the FVElementGeometries are stored +// specialization in case the FVElementGeometries are stored globally template<class TypeTag> -class CCTpfaFVElementGeometryVector<TypeTag, true> +class CCTpfaGlobalFVGeometry<TypeTag, true> { using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); @@ -52,33 +53,15 @@ class CCTpfaFVElementGeometryVector<TypeTag, true> using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using Element = typename GridView::template Codim<0>::Entity; + //! The local class needs access to the scv, scvfs and the fv element geometry + //! as they are globally cached + friend typename GET_PROP_TYPE(TypeTag, FVElementGeometry); public: //! Constructor - CCTpfaFVElementGeometryVector(const GridView gridView) + CCTpfaGlobalFVGeometry(const GridView gridView) : gridView_(gridView), elementMap_(gridView) {} - /* \brief Get the finite volume geometry of an element - * \note The finite volume geometry offers iterators over the sub control volumes - * and the sub control volume faces of an element. - */ - const FVElementGeometry& fvGeometry(const Element& element) const - { - return fvGeometries_[problem_().elementMapper().index(element)]; - } - - //! Get a sub control volume with a global scv index - const SubControlVolume& subControlVolume(IndexType scvIdx) const - { - return *scvs_[scvIdx]; - } - - //! Get a sub control volume face with a global scvf index - const SubControlVolumeFace& subControlVolumeFace(IndexType scvfIdx) const - { - return scvfs_[scvfIdx]; - } - //! The total number of sub control volumes std::size_t numScv() const { @@ -105,6 +88,10 @@ public: Element element(IndexType eIdx) const { return elementMap_.element(eIdx); } + //! Return the gridView this global object lives on + const GridView& gridView() const + { return gridView_; } + //! update all fvElementGeometries (do this again after grid adaption) void update(const Problem& problem) { @@ -113,7 +100,7 @@ public: // clear containers (necessary after grid refinement) scvs_.clear(); scvfs_.clear(); - fvGeometries_.clear(); + scvfIndicesOfScv_.clear(); elementMap_.clear(); // determine size of containers @@ -124,8 +111,9 @@ public: // reserve memory elementMap_.resize(numScvs); - scvs_.resize(numScvs); + scvs_.reserve(numScvs); scvfs_.reserve(numScvf); + scvfIndicesOfScv_.resize(numScvs); // Build the scvs and scv faces IndexType scvfIdx = 0; @@ -133,7 +121,7 @@ public: for (const auto& element : elements(gridView_)) { auto eIdx = problem.elementMapper().index(element); - scvs_[eIdx] = std::make_shared<SubControlVolume>(element.geometry(), eIdx); + scvs_.emplace_back(element.geometry(), eIdx); // fill the element map with seeds elementMap_[eIdx] = element.seed(); @@ -169,17 +157,41 @@ public: } } - // Compute the finite volume element geometries - fvGeometries_.push_back(FVElementGeometry(*this, {eIdx}, scvfsIndexSet)); + // Save the scvf indices belonging to this scv to build up fv element geometries fast + scvfIndicesOfScv_[eIdx] = scvfsIndexSet; } } - // Binding of an element, called by the local jacobian to prepare element assembly - // For compatibility reasons with the FVGeometry cache disabled - void bind(const Element& element) {} - void bindElement(const Element& element) {} + /*! + * \brief Return a local restriction of this global object + * The local object is only functional after calling its bind/bindElement method + * This is a free function that will be found by means of ADL + */ + friend FVElementGeometry localView(const CCTpfaGlobalFVGeometry& global) + { + return FVElementGeometry(global); + } private: + + //! Get a sub control volume with a global scv index + const SubControlVolume& scv(IndexType scvIdx) const + { + return scvs_[scvIdx]; + } + + //! Get a sub control volume face with a global scvf index + const SubControlVolumeFace& scvf(IndexType scvfIdx) const + { + return scvfs_[scvfIdx]; + } + + //! Get the sub control volume face indices of an scv by global index + const std::vector<IndexType>& scvfIndicesOfScv(IndexType scvIdx) const + { + return scvfIndicesOfScv_[scvIdx]; + } + const Problem& problem_() const { return *problemPtr_; } @@ -187,15 +199,15 @@ private: GridView gridView_; Dumux::ElementMap<GridView> elementMap_; - std::vector<std::shared_ptr<SubControlVolume>> scvs_; + std::vector<SubControlVolume> scvs_; std::vector<SubControlVolumeFace> scvfs_; - std::vector<FVElementGeometry> fvGeometries_; + std::vector<std::vector<IndexType>> scvfIndicesOfScv_; IndexType numBoundaryScvf_; }; // specialization in case the FVElementGeometries are not stored template<class TypeTag> -class CCTpfaFVElementGeometryVector<TypeTag, false> +class CCTpfaGlobalFVGeometry<TypeTag, false> { using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); @@ -204,32 +216,13 @@ class CCTpfaFVElementGeometryVector<TypeTag, false> using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using Element = typename GridView::template Codim<0>::Entity; + //! The local fvGeometry needs access to the problem + friend typename GET_PROP_TYPE(TypeTag, FVElementGeometry); public: //! Constructor - CCTpfaFVElementGeometryVector(const GridView gridView) - : gridView_(gridView), elementMap_(gridView), eIdxBound_(-1) {} - - /* \brief Get the finite volume geometry of an element - * \note The finite volume geometry offers iterators over the sub control volumes - * and the sub control volume faces of an element. - */ - const FVElementGeometry& fvGeometry(const Element& element) const - { - return fvGeometries_[getLocalScvIdx_(problem_().elementMapper().index(element), true)]; - } - - //! Get a sub control volume with a global scv index - const SubControlVolume& subControlVolume(IndexType scvIdx) const - { - return localSvs_[getLocalScvIdx_(scvIdx)]; - } - - //! Get a sub control volume face with a global scvf index - const SubControlVolumeFace& subControlVolumeFace(IndexType scvfIdx) const - { - return localScvfs_[getLocalScvFaceIdx_(scvfIdx)]; - } + CCTpfaGlobalFVGeometry(const GridView gridView) + : gridView_(gridView), elementMap_(gridView) {} //! The total number of sub control volumes std::size_t numScv() const @@ -257,19 +250,22 @@ public: Element element(IndexType eIdx) const { return elementMap_.element(eIdx); } + //! Return the gridView this global object lives on + const GridView& gridView() const + { return gridView_; } + //! update all fvElementGeometries (do this again after grid adaption) void update(const Problem& problem) { problemPtr_ = &problem; elementMap_.clear(); - eIdxBound_ = -1; // reserve memory or resize the containers numScvs_ = gridView_.size(0); numScvf_ = 0; numBoundaryScvf_ = 0; elementMap_.resize(numScvs_); - scvFaceIndices_.resize(numScvs_); + scvfIndicesOfScv_.resize(numScvs_); neighborVolVarIndices_.resize(numScvs_); // Build the SCV and SCV face @@ -303,113 +299,33 @@ public: } // store the sets of indices in the data container - scvFaceIndices_[eIdx] = scvfsIndexSet; + scvfIndicesOfScv_[eIdx] = scvfsIndexSet; neighborVolVarIndices_[eIdx] = neighborVolVarIndexSet; } } - // Binding of an element preparing the geometries of the whole stencil - // called by the local jacobian to prepare element assembly - void bind(const Element& element) - { - eIdxBound_ = problem_().elementMapper().index(element); - release_(); - makeElementGeometries_(element); - for (const auto& intersection : intersections(gridView_, element)) - { - if (intersection.neighbor()) - makeElementGeometries_(intersection.outside()); - } - } - - // Binding of an element preparing the geometries only inside the element - void bindElement(const Element& element) - { - eIdxBound_ = problem_().elementMapper().index(element); - release_(); - makeElementGeometries_(element); - } - - -private: - - void release_() - { - localSvs_.clear(); - localScvIndices_.clear(); - localScvfs_.clear(); - localScvfIndices_.clear(); - fvGeometries_.clear(); - } - - void makeElementGeometries_(const Element& element) - { - const auto eIdx = problem_().elementMapper().index(element); - - SubControlVolume scv(element.geometry(), eIdx); - localSvs_.push_back(scv); - localScvIndices_.push_back(eIdx); - - const auto& scvFaceIndices = scvFaceIndices_[eIdx]; - const auto& neighborVolVarIndices = neighborVolVarIndices_[eIdx]; - - int scvfCounter = 0; - for (const auto& intersection : intersections(gridView_, element)) - { - if (intersection.neighbor() || intersection.boundary()) - { - localScvfs_.push_back(SubControlVolumeFace(intersection.geometry(), - intersection.geometry().center(), - intersection.centerUnitOuterNormal(), - scvFaceIndices[scvfCounter], - intersection.indexInInside(), - std::vector<IndexType>({eIdx, neighborVolVarIndices[scvfCounter]}), - intersection.boundary())); - - localScvfIndices_.push_back(scvFaceIndices[scvfCounter]); - scvfCounter++; - } - } - - // Compute the finite volume element geometries - fvGeometries_.push_back(FVElementGeometry(*this, {eIdx}, scvFaceIndices)); - } - - const int getLocalScvIdx_(const int scvIdx, bool isElement = false) const - { - auto it = std::find(localScvIndices_.begin(), localScvIndices_.end(), scvIdx); + const std::vector<IndexType>& scvfIndicesOfScv(IndexType scvIdx) const + { return scvfIndicesOfScv_[scvIdx]; } - if (it != localScvIndices_.end()) - return std::distance(localScvIndices_.begin(), it); - else - { - if (!isElement) - DUNE_THROW(Dune::InvalidStateException, - "Could not find the sub control volume for scvIdx = " << scvIdx << - ", make sure to properly bind the FVGeometries to the element before using them."); - else - DUNE_THROW(Dune::InvalidStateException, - "You are trying to get the fvgeometry of element with index " << scvIdx << - ", but bound is the element " << eIdxBound_ << ". Please bind element before using the fvgeometry."); - } - } + const std::vector<IndexType>& neighborVolVarIndices(IndexType scvIdx) const + { return neighborVolVarIndices_[scvIdx]; } - const int getLocalScvFaceIdx_(const int scvfIdx) const + /*! + * \brief Return a local restriction of this global object + * The local object is only functional after calling its bind/bindElement method + * This is a free function that will be found by means of ADL + */ + friend FVElementGeometry localView(const CCTpfaGlobalFVGeometry& global) { - auto it = std::find(localScvfIndices_.begin(), localScvfIndices_.end(), scvfIdx); - - if (it != localScvfIndices_.end()) - return std::distance(localScvfIndices_.begin(), it); - else - DUNE_THROW(Dune::InvalidStateException, - "Could not find the sub control volume face for scvfIdx = " << scvfIdx << - ", make sure to properly bind the FVGeometries to the to the element before using them."); + return FVElementGeometry(global); } +private: const Problem& problem_() const { return *problemPtr_; } const Problem* problemPtr_; + GridView gridView_; // Information on the global number of geometries @@ -419,16 +335,8 @@ private: // vectors that store the global data Dumux::ElementMap<GridView> elementMap_; - std::vector<std::vector<IndexType>> scvFaceIndices_; + std::vector<std::vector<IndexType>> scvfIndicesOfScv_; std::vector<std::vector<IndexType>> neighborVolVarIndices_; - - // vectors to store the geometries temporarily after binding an element - IndexType eIdxBound_; - std::vector<SubControlVolume> localSvs_; - std::vector<IndexType> localScvIndices_; - std::vector<SubControlVolumeFace> localScvfs_; - std::vector<IndexType> localScvfIndices_; - std::vector<FVElementGeometry> fvGeometries_; }; } // end namespace diff --git a/dumux/discretization/cellcentered/tpfa/subcontrolvolume.hh b/dumux/discretization/cellcentered/tpfa/subcontrolvolume.hh index aaba6ee555717cba8bf670ebffc7a45bb9bc9222..40d78cfaee6a1fba9e7b0d3d9d338bfbdc28fc19 100644 --- a/dumux/discretization/cellcentered/tpfa/subcontrolvolume.hh +++ b/dumux/discretization/cellcentered/tpfa/subcontrolvolume.hh @@ -43,9 +43,14 @@ private: public: // the contructor in the cc case - CCTpfaSubControlVolume(Geometry geometry, - IndexType elementIndex) - : SubControlVolumeBase<G, I>(std::move(geometry), std::move(elementIndex)) {} + CCTpfaSubControlVolume(Geometry&& geometry, + IndexType elementIndex) + : SubControlVolumeBase<G, I>(std::move(geometry), elementIndex) {} + + // the contructor in the cc case + CCTpfaSubControlVolume(const Geometry& geometry, + IndexType elementIndex) + : SubControlVolumeBase<G, I>(geometry, elementIndex) {} IndexType indexInElement() const { diff --git a/dumux/discretization/cellcentered/tpfa/subcontrolvolumeface.hh b/dumux/discretization/cellcentered/tpfa/subcontrolvolumeface.hh index 9a3d763c5c3d3cca5de94071ee97353608e2d30d..6c43bc501528d90359867f85857cc17ba500dba4 100644 --- a/dumux/discretization/cellcentered/tpfa/subcontrolvolumeface.hh +++ b/dumux/discretization/cellcentered/tpfa/subcontrolvolumeface.hh @@ -38,6 +38,7 @@ namespace Dumux template<class Geometry, typename IndexType> class CCTpfaSubControlVolumeFace : public SubControlVolumeFaceBase<Geometry, IndexType> { + using ParentType = SubControlVolumeFaceBase<Geometry, IndexType>; using Scalar = typename Geometry::ctype; static const int dim = Geometry::mydimension; static const int dimworld = Geometry::coorddimension; @@ -46,14 +47,27 @@ class CCTpfaSubControlVolumeFace : public SubControlVolumeFaceBase<Geometry, Ind using LocalPosition = Dune::FieldVector<Scalar, dim>; public: + //! Constructor with all arguments CCTpfaSubControlVolumeFace(const Geometry& geometry, const GlobalPosition& ipGlobal, const GlobalPosition& unitOuterNormal, IndexType scvfIndex, - IndexType indexInElement, const std::vector<IndexType>& scvIndices, bool boundary = false) - : SubControlVolumeFaceBase<Geometry, IndexType>(geometry, ipGlobal, unitOuterNormal, scvfIndex, indexInElement, scvIndices, boundary) + : ParentType(geometry, ipGlobal, unitOuterNormal, scvfIndex, scvIndices, boundary) + {} + + //! Constructor with intersection + template <class Intersection> + CCTpfaSubControlVolumeFace(const Intersection& is, + IndexType scvfIndex, + const std::vector<IndexType>& scvIndices) + : ParentType(is.geometry(), + is.geometry().center(), + is.centerUnitOuterNormal(), + scvfIndex, + scvIndices, + is.boundary()) {} }; diff --git a/dumux/discretization/cellcentered/volumevariablesvector.hh b/dumux/discretization/cellcentered/volumevariablesvector.hh index 39b62356521f3c019af01fc8675799e21a315880..1fcc38cf146981f41c2e35a7a3a681ecdecea2d7 100644 --- a/dumux/discretization/cellcentered/volumevariablesvector.hh +++ b/dumux/discretization/cellcentered/volumevariablesvector.hh @@ -78,7 +78,7 @@ public: { problem.model().fvGeometries_().bindElement(element); const auto& fvGeometry = problem.model().fvGeometries(element); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { (*this)[scv].update(sol[scv.dofIndex()], problem, @@ -87,7 +87,7 @@ public: } // handle the boundary volume variables - for (const auto& scvFace : scvfs(fvGeometry)) + for (auto&& scvFace : scvfs(fvGeometry)) { // if we are not on a boundary, skip the rest if (!scvFace.boundary()) @@ -161,6 +161,7 @@ class CCVolumeVariablesVector<TypeTag, /*isOldSol*/false, /*enableVolVarCaching* using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector); using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using IndexType = typename GridView::IndexSet::IndexType; static const int dim = GridView::dimension; @@ -187,7 +188,8 @@ public: // Binding of an element, prepares the volume variables within the element stencil // called by the local jacobian to prepare element assembly - void bind(const Element& element) + void bind(const Element& element, + const FVElementGeometry& fvGeometry) { eIdxBound_ = problem_().elementMapper().index(element); @@ -202,7 +204,7 @@ public: int localIdx = 0; // update the volume variables of the element at hand - const auto& scvI = problem_().model().fvGeometries().subControlVolume(eIdxBound_); + auto&& scvI = fvGeometry.scv(eIdxBound_); const auto& solI = problem_().model().curSol()[eIdxBound_]; volumeVariables_[localIdx].update(solI, problem_(), element, scvI); volVarIndices_[localIdx] = scvI.index(); @@ -211,8 +213,8 @@ public: // Update the volume variables of the neighboring elements for (auto globalJ : neighborStencil) { - const auto& elementJ = problem_().model().fvGeometries().element(globalJ); - const auto& scvJ = problem_().model().fvGeometries().subControlVolume(globalJ); + const auto& elementJ = fvGeometry.globalFvGeometry().element(globalJ); + auto&& scvJ = fvGeometry.scv(globalJ); const auto& solJ = problem_().model().curSol()[globalJ]; volumeVariables_[localIdx].update(solJ, problem_(), elementJ, scvJ); volVarIndices_[localIdx] = scvJ.index(); @@ -220,8 +222,7 @@ public: } // Update boundary volume variables - const auto& fvGeometry = problem_().model().fvGeometries(element); - for (const auto& scvFace : scvfs(fvGeometry)) + for (auto&& scvFace : scvfs(fvGeometry)) { // if we are not on a boundary, skip the rest if (!scvFace.boundary()) @@ -243,14 +244,15 @@ public: // Binding of an element, prepares only the volume variables of the element // specialization for cc models - void bindElement(const Element& element) + void bindElement(const Element& element, + const FVElementGeometry& fvGeometry) { eIdxBound_ = problem_().elementMapper().index(element); volumeVariables_.resize(1); volVarIndices_.resize(1); // update the volume variables of the element at hand - const auto& scv = problem_().model().fvGeometries().subControlVolume(eIdxBound_); + auto&& scv = fvGeometry.scv(eIdxBound_); const auto& sol = problem_().model().curSol()[eIdxBound_]; volumeVariables_[0].update(sol, problem_(), element, scv); volVarIndices_[0] = scv.index(); @@ -283,12 +285,8 @@ private: const int getLocalIdx_(const int volVarIdx) const { auto it = std::find(volVarIndices_.begin(), volVarIndices_.end(), volVarIdx); - - if (it != volVarIndices_.end()) - return std::distance(volVarIndices_.begin(), it); - else - DUNE_THROW(Dune::InvalidStateException, "Could not find the current volume variables for volVarIdx = " << volVarIdx << - ", make sure to properly bind the volume variables to the element before using them"); + assert(it != volVarIndices_.end() && "Could not find the current volume variables for volVarIdx!"); + return std::distance(volVarIndices_.begin(), it); } Problem& problem_() const @@ -312,6 +310,7 @@ class CCVolumeVariablesVector<TypeTag, /*isOldSol*/true, /*enableVolVarCaching*/ using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector); using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using IndexType = typename GridView::IndexSet::IndexType; static const int dim = GridView::dimension; @@ -337,14 +336,15 @@ public: } // Binding of an element, prepares the volume variables of only the element - void bindElement(const Element& element) + void bindElement(const Element& element, + const FVElementGeometry& fvGeometry) { eIdxBound_ = problem_().elementMapper().index(element); volumeVariables_.resize(1); volVarIndices_.resize(1); // update the volume variables of the element at hand - const auto& scv = problem_().model().fvGeometries().subControlVolume(eIdxBound_); + auto&& scv = fvGeometry.scv(eIdxBound_); const auto& sol = problem_().model().prevSol()[eIdxBound_]; volumeVariables_[0].update(sol, problem_(), element, scv); volVarIndices_[0] = scv.index(); @@ -377,12 +377,8 @@ private: const int getLocalIdx_(const int volVarIdx) const { auto it = std::find(volVarIndices_.begin(), volVarIndices_.end(), volVarIdx); - - if (it != volVarIndices_.end()) - return std::distance(volVarIndices_.begin(), it); - else - DUNE_THROW(Dune::InvalidStateException, "Could not find the previous volume variables for volVarIdx = " << volVarIdx << - ", make sure to properly bind the volume variables to the element before using them"); + assert(it != volVarIndices_.end() && "Could not find the current volume variables for volVarIdx!"); + return std::distance(volVarIndices_.begin(), it); } Problem& problem_() const diff --git a/dumux/discretization/fluxvariablesbase.hh b/dumux/discretization/fluxvariablesbase.hh index de8061254d48ce12d473e717c04a6ee5430b64b1..52eb6dfd7204cf0337a5cbb09d605ba8e744884f 100644 --- a/dumux/discretization/fluxvariablesbase.hh +++ b/dumux/discretization/fluxvariablesbase.hh @@ -42,6 +42,7 @@ class FluxVariablesBase using IndexType = typename GridView::IndexSet::IndexType; using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); using Stencil = std::vector<IndexType>; + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); enum{ enableFluxVarsCache = GET_PROP_VALUE(TypeTag, EnableGlobalFluxVariablesCache) }; @@ -53,15 +54,17 @@ public: void init(const Problem& problem, const Element& element, + const FVElementGeometry& fvGeometry, const SubControlVolumeFace &scvFace) { problemPtr_ = &problem; elementPtr_ = &element; scvFacePtr_ = &scvFace; + fvGeometryPtr_ = &fvGeometry; // update the stencil if needed if (!enableFluxVarsCache) - stencil_ = asImp_().computeStencil(problem, element, scvFace); + stencil_ = asImp_().computeStencil(problem, element, fvGeometry, scvFace); } // when caching is enabled, get the stencil from the cache class @@ -83,6 +86,9 @@ public: const SubControlVolumeFace& scvFace() const { return *scvFacePtr_; } + const FVElementGeometry& fvGeometry() const + { return *fvGeometryPtr_; } + Stencil computeStencil(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace) { DUNE_THROW(Dune::InvalidStateException, "computeStencil() routine is not provided by the implementation."); } @@ -101,7 +107,8 @@ private: } const Problem* problemPtr_; //! Pointer to the problem - const Element* elementPtr_; //! Pointer to the element at hand + const Element* elementPtr_; //! Pointer to the element at hand + const FVElementGeometry* fvGeometryPtr_; const SubControlVolumeFace* scvFacePtr_; //! Pointer to the sub control volume face for which the flux variables are created Stencil stencil_; //! The flux stencil }; diff --git a/dumux/discretization/fvelementgeometry.hh b/dumux/discretization/fvelementgeometry.hh deleted file mode 100644 index 7640c0be3f4d01570134921b1e5649be370fcb9b..0000000000000000000000000000000000000000 --- a/dumux/discretization/fvelementgeometry.hh +++ /dev/null @@ -1,207 +0,0 @@ -// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- -// vi: set et ts=4 sw=4 sts=4: -/***************************************************************************** - * See the file COPYING for full copying permissions. * - * * - * This program is free software: you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation, either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * GNU General Public License for more details. * - * * - * You should have received a copy of the GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -/*! - * \file - * \brief Class providing iterators over sub control volumes and sub control - * volume faces of an element. - */ -#ifndef DUMUX_DISCRETIZATION_FV_ELEMENTGEOMETRY_HH -#define DUMUX_DISCRETIZATION_FV_ELEMENTGEOMETRY_HH - -#include <dune/common/iteratorrange.hh> -#include <dune/common/iteratorfacades.hh> - -namespace Dumux -{ -namespace Properties -{ -NEW_PROP_TAG(SubControlVolume); -NEW_PROP_TAG(SubControlVolumeFace); -NEW_PROP_TAG(FVElementGeometry); -NEW_PROP_TAG(FVElementGeometryVector); -} - -/*! - * \ingroup Discretization - * \brief An iterator over sub control volumes - */ -template<class SubControlVolume, class Vector, class FVElementGeometryVector> -class ScvIterator : public Dune::ForwardIteratorFacade<ScvIterator<SubControlVolume, - Vector, - FVElementGeometryVector>, - const SubControlVolume> -{ - using ThisType = ScvIterator<SubControlVolume, Vector, FVElementGeometryVector>; - using Iterator = typename Vector::const_iterator; -public: - ScvIterator(const Iterator& it, const FVElementGeometryVector& fvGeometryVector) - : it_(it), fvGeometryVector_(&fvGeometryVector) {} - - //! default constructor - ScvIterator() : it_(Iterator()), fvGeometryVector_(nullptr) {} - - const SubControlVolume& dereference() const - { - return fvGeometryVector_->subControlVolume(*it_); - } - - bool equals(const ThisType& other) const - { - return it_ == other.it_; - } - - void increment() - { - ++it_; - } - -private: - Iterator it_; - const FVElementGeometryVector* fvGeometryVector_; -}; - -/*! - * \ingroup ImplcititModel - * \brief An iterator over sub control volume faces - */ -template<class SubControlVolumeFace, class Vector, class FVElementGeometryVector> -class ScvfIterator : public Dune::ForwardIteratorFacade<ScvfIterator<SubControlVolumeFace, - Vector, - FVElementGeometryVector>, - const SubControlVolumeFace> -{ - using ThisType = ScvfIterator<SubControlVolumeFace, Vector, FVElementGeometryVector>; - using Iterator = typename Vector::const_iterator; -public: - ScvfIterator(const Iterator& it, const FVElementGeometryVector& fvGeometryVector) - : it_(it), fvGeometryVector_(&fvGeometryVector) {} - - //! default constructor - ScvfIterator() : it_(Iterator()), fvGeometryVector_(nullptr) {} - - const SubControlVolumeFace& dereference() const - { - return fvGeometryVector_->subControlVolumeFace(*it_); - } - - bool equals(const ThisType& other) const - { - return it_ == other.it_; - } - - void increment() - { - it_++; - } - -private: - Iterator it_; - const FVElementGeometryVector* fvGeometryVector_; -}; - -/*! - * \ingroup ImplcititModel - * \brief Provide iterators over sub control volumes and sub control - * volume faces of an element.. - */ -template<class TypeTag> -class FVElementGeometry -{ - using ThisType = Dumux::FVElementGeometry<TypeTag>; - using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); - using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); - using FVElementGeometryVector = typename GET_PROP_TYPE(TypeTag, FVElementGeometryVector); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using IndexType = typename GridView::IndexSet::IndexType; - using ScvIterator = Dumux::ScvIterator<SubControlVolume, std::vector<IndexType>, FVElementGeometryVector>; - using ScvfIterator = Dumux::ScvfIterator<SubControlVolumeFace, std::vector<IndexType>, FVElementGeometryVector>; - -public: - // This class in not default-constructible - FVElementGeometry() = delete; - - // Constructor with vectors - FVElementGeometry(const FVElementGeometryVector& localFvGeometry, - const std::vector<IndexType>& scvIndices, - const std::vector<IndexType>& scvfIndices) - : localFvGeometry_(localFvGeometry), - scvIndices_(scvIndices), - scvfIndices_(scvfIndices) - {} - - //! iterator range for sub control volumes - //! This is a free function found by means of ADL - //! To iterate over all sub control volumes of this FVElementGeometry use - //! for (const auto& scv : scvs(fvGeometry)) - friend inline Dune::IteratorRange<ScvIterator> - scvs(const FVElementGeometry& g) - { - return Dune::IteratorRange<ScvIterator>(ScvIterator(g.scvIndices().begin(), g.localFvGeometry()), - ScvIterator(g.scvIndices().end(), g.localFvGeometry())); - } - - //! iterator range for sub control volume faces - //! This is a free function found by means of ADL - //! To iterate over all sub control volume faces of this FVElementGeometry use - //! for (const auto& scvf : scvfs(fvGeometry)) - friend inline Dune::IteratorRange<ScvfIterator> - scvfs(const FVElementGeometry& g) - { - return Dune::IteratorRange<ScvfIterator>(ScvfIterator(g.scvfIndices().begin(), g.localFvGeometry()), - ScvfIterator(g.scvfIndices().end(), g.localFvGeometry())); - } - - //! number of sub control volumes in this fv element geometry - std::size_t numScv() const - { - return scvIndices_.size(); - } - - //! number of sub control volumes in this fv element geometry - std::size_t numScvf() const - { - return scvfIndices_.size(); - } - -private: - - //! The sub control volume indices - //! Depending on the type of discretization and caching - //! these may be local or global indices - const std::vector<IndexType>& scvIndices() const - { return scvIndices_; } - - //! The sub control volume face indices - //! Depending on the type of discretization and caching - //! these may be local or global indices - const std::vector<IndexType>& scvfIndices() const - { return scvfIndices_; } - - //! The LocalFvGeometry object this FvElementGeometry belongs to - const FVElementGeometryVector& localFvGeometry() const - { return localFvGeometry_; } - - const FVElementGeometryVector& localFvGeometry_; - std::vector<IndexType> scvIndices_; - std::vector<IndexType> scvfIndices_; -}; - -} - -#endif diff --git a/dumux/discretization/scvandscvfiterators.hh b/dumux/discretization/scvandscvfiterators.hh new file mode 100644 index 0000000000000000000000000000000000000000..81c01a1ab86a613a978a8e83fff03b821a322b00 --- /dev/null +++ b/dumux/discretization/scvandscvfiterators.hh @@ -0,0 +1,112 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * See the file COPYING for full copying permissions. * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see <http://www.gnu.org/licenses/>. * + *****************************************************************************/ +/*! + * \file + * \brief Class providing iterators over sub control volumes and sub control + * volume faces of an element. + */ +#ifndef DUMUX_SCV_AND_SCVF_ITERATORS_HH +#define DUMUX_SCV_AND_SCVF_ITERATORS_HH + +#include <dune/common/iteratorfacades.hh> + +namespace Dumux +{ + +/*! + * \ingroup Discretization + * \brief An iterator over sub control volumes + */ +template<class SubControlVolume, class Vector, class FVElementGeometry> +class ScvIterator : public Dune::ForwardIteratorFacade<ScvIterator<SubControlVolume, + Vector, + FVElementGeometry>, + const SubControlVolume> +{ + using ThisType = ScvIterator<SubControlVolume, Vector, FVElementGeometry>; + using Iterator = typename Vector::const_iterator; +public: + ScvIterator(const Iterator& it, const FVElementGeometry& fvGeometry) + : it_(it), fvGeometryPtr_(&fvGeometry) {} + + //! default constructor + ScvIterator() : it_(Iterator()), fvGeometryPtr_(nullptr) {} + + const SubControlVolume& dereference() const + { + return fvGeometryPtr_->scv(*it_); + } + + bool equals(const ThisType& other) const + { + return it_ == other.it_; + } + + void increment() + { + ++it_; + } + +private: + Iterator it_; + const FVElementGeometry* fvGeometryPtr_; +}; + +/*! + * \ingroup ImplcititModel + * \brief An iterator over sub control volume faces + */ +template<class SubControlVolumeFace, class Vector, class FVElementGeometry> +class ScvfIterator : public Dune::ForwardIteratorFacade<ScvfIterator<SubControlVolumeFace, + Vector, + FVElementGeometry>, + const SubControlVolumeFace> +{ + using ThisType = ScvfIterator<SubControlVolumeFace, Vector, FVElementGeometry>; + using Iterator = typename Vector::const_iterator; +public: + ScvfIterator(const Iterator& it, const FVElementGeometry& fvGeometry) + : it_(it), fvGeometryPtr_(&fvGeometry) {} + + //! default constructor + ScvfIterator() : it_(Iterator()), fvGeometryPtr_(nullptr) {} + + const SubControlVolumeFace& dereference() const + { + return fvGeometryPtr_->scvf(*it_); + } + + bool equals(const ThisType& other) const + { + return it_ == other.it_; + } + + void increment() + { + it_++; + } + +private: + Iterator it_; + const FVElementGeometry* fvGeometryPtr_; +}; + +} // end namespace Dumux + +#endif diff --git a/dumux/discretization/subcontrolvolumebase.hh b/dumux/discretization/subcontrolvolumebase.hh index 56f141514ad036325286abb7708a21c676888f62..15722ac3e3912547cad7071f3fe1f84b7c80740e 100644 --- a/dumux/discretization/subcontrolvolumebase.hh +++ b/dumux/discretization/subcontrolvolumebase.hh @@ -32,9 +32,12 @@ namespace Dumux * \brief Base class for a sub control volume, i.e a part of the control * volume we are making the balance for. */ -template<class Geometry, typename IndexType> +template<class G, typename I> class SubControlVolumeBase { + using IndexType = I; + using Geometry = typename std::decay<G>::type; + using Scalar = typename Geometry::ctype; enum { dimworld = Geometry::coorddimension }; using GlobalPosition = Dune::FieldVector<Scalar, dimworld>; @@ -43,24 +46,54 @@ public: /*\brief The constructor * \param geometry The geometry of the sub control volume * \param elementIndex The index of the element the scv is part of - * \param indexInElement The local index of the scv in the element */ - SubControlVolumeBase(Geometry geometry, + SubControlVolumeBase(Geometry&& geometry, IndexType elementIndex) : geometry_(std::move(geometry)), elementIndex_(std::move(elementIndex)) {} + /*\brief The constructor + * \param geometry The geometry of the sub control volume + * \param elementIndex The index of the element the scv is part of + */ + SubControlVolumeBase(const Geometry& geometry, + IndexType elementIndex) + : geometry_(geometry), + elementIndex_(elementIndex) + {} + + //! The copy constrcutor + SubControlVolumeBase(const SubControlVolumeBase& other) = delete; + + //! The move constrcutor + SubControlVolumeBase(SubControlVolumeBase&& other) = default; + + //! The copy assignment operator + SubControlVolumeBase& operator=(const SubControlVolumeBase& other) = delete; + + //! The move assignment operator + SubControlVolumeBase& operator=(SubControlVolumeBase&& other) + { + // We want to use the default copy/move assignment operators. + // But since geometry is not assignable :( we + // have to dirty reconstruct it + geometry_.~Geometry(); + new(&geometry_) Geometry(std::move(other.geometry_)); + elementIndex_ = std::move(other.elementIndex_); + return *this; + } + //! The center of the sub control volume GlobalPosition center() const { - return geometry_.center(); + return geometry().center(); } //! The volume of the sub control volume Scalar volume() const { - return geometry_.volume(); + return geometry().volume(); } //! The geometry of the sub control volume @@ -81,104 +114,6 @@ private: IndexType elementIndex_; }; -// This class is set as the property -template<class G, typename I, bool isBox> -class SubControlVolume {}; - -// Specialization for cc models -template<class G, typename I> -class SubControlVolume<G, I, false> : public SubControlVolumeBase<G, I> -{ -public: - // exported types - using Geometry = G; - using IndexType = I; - -private: - using Scalar = typename Geometry::ctype; - enum { dimworld = Geometry::coorddimension }; - using GlobalPosition = Dune::FieldVector<Scalar, dimworld>; - -public: - // the contructor in the cc case - SubControlVolume(Geometry geometry, - IndexType elementIndex) - : SubControlVolumeBase<G, I>(std::move(geometry), std::move(elementIndex)) {} - - IndexType indexInElement() const - { - return IndexType(0); - } - - //! The global index of this scv - IndexType index() const - { - return this->elementIndex(); - } - - IndexType dofIndex() const - { - return this->elementIndex(); - } - - GlobalPosition dofPosition() const - { - return this->geometry().center(); - } -}; - -// Specialization for box models -template<class G, typename I> -class SubControlVolume<G, I, true> : public SubControlVolumeBase<G, I> -{ -public: - // exported types - using Geometry = G; - using IndexType = I; - -private: - using Scalar = typename Geometry::ctype; - enum { dimworld = Geometry::coorddimension }; - using GlobalPosition = Dune::FieldVector<Scalar, dimworld>; - -public: - // the contructor in the box case - SubControlVolume(Geometry geometry, - IndexType scvIdx, - IndexType elementIndex, - IndexType indexInElement, - IndexType dofIndex) - : SubControlVolumeBase<G, I>(std::move(geometry), std::move(elementIndex)), - scvIdx_(scvIdx), indexInElement_(std::move(indexInElement)), - dofIndex_(std::move(dofIndex)) {} - - IndexType indexInElement() const - { - return indexInElement_; - } - - //! The global index of this scv - IndexType index() const - { - return scvIdx_; - } - - IndexType dofIndex() const - { - return dofIndex_; - } - - GlobalPosition dofPosition() const - { - return this->geometry().corner(indexInElement_); - } - -private: - IndexType scvIdx_; - IndexType indexInElement_; - IndexType dofIndex_; -}; - } // end namespace #endif diff --git a/dumux/discretization/subcontrolvolumefacebase.hh b/dumux/discretization/subcontrolvolumefacebase.hh index ab732275d7e7c33d073146635603ee9b5d627879..01e962c3153a477a82e017823449532c9869603f 100644 --- a/dumux/discretization/subcontrolvolumefacebase.hh +++ b/dumux/discretization/subcontrolvolumefacebase.hh @@ -49,7 +49,6 @@ public: const GlobalPosition& ipGlobal, const GlobalPosition& unitOuterNormal, IndexType scvfIndex, - IndexType indexInElement, const std::vector<IndexType>& scvIndices, bool boundary = false) : geometry_(geometry), @@ -57,7 +56,20 @@ public: ipLocal_(geometry.local(ipGlobal)), unitOuterNormal_(unitOuterNormal), scvfIndex_(scvfIndex), - indexInElement_(indexInElement), + scvIndices_(scvIndices), + boundary_(boundary) {} + + SubControlVolumeFaceBase(Geometry&& geometry, + const GlobalPosition& ipGlobal, + const GlobalPosition& unitOuterNormal, + IndexType scvfIndex, + const std::vector<IndexType>& scvIndices, + bool boundary = false) + : geometry_(std::move(geometry)), + ipGlobal_(ipGlobal), + ipLocal_(geometry_.local(ipGlobal)), + unitOuterNormal_(unitOuterNormal), + scvfIndex_(scvfIndex), scvIndices_(scvIndices), boundary_(boundary) {} @@ -123,19 +135,12 @@ public: return scvfIndex_; } - //! The global index of this sub control volume face - IndexType indexInElement() const - { - return indexInElement_; - } - private: Geometry geometry_; GlobalPosition ipGlobal_; LocalPosition ipLocal_; GlobalPosition unitOuterNormal_; IndexType scvfIndex_; - IndexType indexInElement_; std::vector<IndexType> scvIndices_; bool boundary_; }; diff --git a/dumux/geomechanics/elastic/model.hh b/dumux/geomechanics/elastic/model.hh index 809b59ffc4de898c014384c13b2443791a01eafa..b2c5c13b1bbe0cccaabc0ddc28e61919dfcb6152 100644 --- a/dumux/geomechanics/elastic/model.hh +++ b/dumux/geomechanics/elastic/model.hh @@ -166,6 +166,7 @@ public: sigmay[eIdx] += stress[1]; if (dim == 3) sigmaz[eIdx] += stress[2]; + } } writer.attachDofData(ux, "ux", isBox); diff --git a/dumux/implicit/assembler.hh b/dumux/implicit/assembler.hh index 09e16ae56f1ea0a3541e104ac21b831cf252ef5f..e824559e463b2648791675fba78c8fffee1a2601 100644 --- a/dumux/implicit/assembler.hh +++ b/dumux/implicit/assembler.hh @@ -24,6 +24,7 @@ #define DUMUX_IMPLICIT_ASSEMBLER_HH #include "properties.hh" +#include <dune/istl/io.hh> namespace Dumux { @@ -115,6 +116,8 @@ public: DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system"); } + // printmatrix(std::cout, matrix(), "", ""); + } /*! diff --git a/dumux/implicit/box/elementboundarytypes.hh b/dumux/implicit/box/elementboundarytypes.hh index 69ec63c1c01fbee0a66ef3db3cf9b689c4f2e15d..1a8e24d07213544a52c16c9ebd89c98cc9b65db9 100644 --- a/dumux/implicit/box/elementboundarytypes.hh +++ b/dumux/implicit/box/elementboundarytypes.hh @@ -89,9 +89,9 @@ public: hasNeumann_ = false; hasOutflow_ = false; - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { - int scvIdxLocal = scv.indexInElement(); + int scvIdxLocal = scv.index(); (*this)[scvIdxLocal].reset(); if (problem.model().onBoundary(scv)) diff --git a/dumux/implicit/box/localjacobian.hh b/dumux/implicit/box/localjacobian.hh index bd1b8af5bcab8ef30229aae3959d50926903642f..38ef7f2044779171b49a98b01f9741cf454ba947 100644 --- a/dumux/implicit/box/localjacobian.hh +++ b/dumux/implicit/box/localjacobian.hh @@ -68,30 +68,30 @@ namespace Dumux template<class TypeTag> class BoxLocalJacobian : public ImplicitLocalJacobian<TypeTag> { - typedef ImplicitLocalJacobian<TypeTag> ParentType; - typedef typename GET_PROP_TYPE(TypeTag, LocalJacobian) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) LocalResidual; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, Model) Model; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, JacobianAssembler) JacobianAssembler; + using ParentType = ImplicitLocalJacobian<TypeTag>; + using Implementation = typename GET_PROP_TYPE(TypeTag, LocalJacobian); + using LocalResidual = typename GET_PROP_TYPE(TypeTag, LocalResidual); + using Problem = typename GET_PROP_TYPE(TypeTag, Problem); + using Model = typename GET_PROP_TYPE(TypeTag, Model); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Element = typename GridView::template Codim<0>::Entity; + using JacobianAssembler = typename GET_PROP_TYPE(TypeTag, JacobianAssembler); enum { numEq = GET_PROP_VALUE(TypeTag, NumEq), dim = GridView::dimension, }; - typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; - typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper; - typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + using JacobianMatrix = typename GET_PROP_TYPE(TypeTag, JacobianMatrix); + using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using VertexMapper = typename GET_PROP_TYPE(TypeTag, VertexMapper); + using ElementSolutionVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector); + using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables); + using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); + using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes); + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); public: BoxLocalJacobian() @@ -105,41 +105,41 @@ public: * * \param element The DUNE Codim<0> entity which we look at. */ - void assemble(const Element& element, JacobianMatrix& matrix, SolutionVector& residual) + void assemble(const Element& element, + JacobianMatrix& matrix, + SolutionVector& residual) { // prepare the volvars/fvGeometries for the case when caching is disabled - this->model_().fvGeometries_().bind(element); - this->model_().curVolVars_().bind(element); - this->model_().prevVolVars_().bindElement(element); - this->model_().fluxVariablesCache_().bind(element); - - // the finite volume element geometry - const auto& fvGeometry = this->model_().fvGeometries(element); + auto fvGeometry = localView(this->problem_().model().globalFvGeometry()); + fvGeometry.bind(element); + this->model_().curVolVars_().bind(element, fvGeometry); + this->model_().prevVolVars_().bindElement(element, fvGeometry); + this->model_().fluxVariablesCache_().bind(element, fvGeometry); // the element boundary types - bcTypes_.update(this->problem_(), element, fvGeometry); + ElementBoundaryTypes bcTypes; + bcTypes.update(this->problem_(), element, fvGeometry); // calculate the actual element residual - this->localResidual().eval(element, bcTypes_); + this->localResidual().eval(element, bcTypes, fvGeometry); this->residual_ = this->localResidual().residual(); this->model_().updatePVWeights(fvGeometry); // calculation of the derivatives - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { // dof index and corresponding actual pri vars const auto dofIdx = scv.dofIndex(); - const auto localScvIdx = scv.indexInElement(); VolumeVariables origVolVars(this->model_().curVolVars(scv)); // add precalculated residual for this scv into the global container - residual[dofIdx] += this->residual_[localScvIdx]; + residual[dofIdx] += this->residual_[scv.index()]; // calculate derivatives w.r.t to the privars at the dof at hand for (int pvIdx = 0; pvIdx < numEq; pvIdx++) { - evalPartialDerivative_(matrix, element, scv, pvIdx); + evalPartialDerivative_(matrix, element, fvGeometry, scv, bcTypes, pvIdx); // restore the original state of the scv's volume variables this->model_().curVolVars_(scv) = origVolVars; @@ -195,10 +195,12 @@ protected: */ void evalPartialDerivative_(JacobianMatrix& matrix, const Element& element, + const FVElementGeometry& fvGeometry, const SubControlVolume& scv, + const ElementBoundaryTypes& bcTypes, const int pvIdx) { - auto dofIdx = scv.dofIndex(); + const auto dofIdx = scv.dofIndex(); ElementSolutionVector partialDeriv(element.subEntities(dim)); PrimaryVariables priVars(this->model_().curSol()[dofIdx]); @@ -219,7 +221,7 @@ protected: this->model_().curVolVars_(scv).update(priVars, this->problem_(), element, scv); // calculate the deflected residual - this->localResidual().eval(element, bcTypes_); + this->localResidual().eval(element, bcTypes, fvGeometry); // store the residual partialDeriv = this->localResidual().residual(); @@ -245,7 +247,7 @@ protected: this->model_().curVolVars_(scv).update(priVars, this->problem_(), element, scv); // calculate the deflected residual - this->localResidual().eval(element, bcTypes_); + this->localResidual().eval(element, bcTypes, fvGeometry); // subtract the residual from the derivative storage partialDeriv -= this->localResidual().residual(); @@ -263,17 +265,14 @@ protected: partialDeriv /= delta; // update the global stiffness matrix with the current partial derivatives - const auto& fvGeometry = this->model_().fvGeometries(element); - for (const auto& scvJ : scvs(fvGeometry)) - this->updateGlobalJacobian_(matrix, scvJ.dofIndex(), dofIdx, pvIdx, partialDeriv[scvJ.indexInElement()]); + for (auto&& scvJ : scvs(fvGeometry)) + this->updateGlobalJacobian_(matrix, scvJ.dofIndex(), dofIdx, pvIdx, partialDeriv[scvJ.index()]); } private: - int numericDifferenceMethod_; - - ElementBoundaryTypes bcTypes_; }; + } #endif diff --git a/dumux/implicit/box/localresidual.hh b/dumux/implicit/box/localresidual.hh index 0f20ee7e1c45e71d9f0da2ef414ec1c91b9e22e7..d8ff00658203fa5c2a11a6e5f0169f4006484578 100644 --- a/dumux/implicit/box/localresidual.hh +++ b/dumux/implicit/box/localresidual.hh @@ -44,45 +44,78 @@ namespace Dumux template<class TypeTag> class BoxLocalResidual : public ImplicitLocalResidual<TypeTag> { - typedef ImplicitLocalResidual<TypeTag> ParentType; + using ParentType = ImplicitLocalResidual<TypeTag>; friend class ImplicitLocalResidual<TypeTag>; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); enum { numEq = GET_PROP_VALUE(TypeTag, NumEq), dim = GridView::dimension }; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace) SubControlVolumeFace; + using Element = typename GridView::template Codim<0>::Entity; + using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables); + using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes); + using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); +public: // copying the local residual class is not a good idea - BoxLocalResidual(const BoxLocalResidual &); + BoxLocalResidual(const BoxLocalResidual &) = delete; -public: - BoxLocalResidual() : ParentType() - { } + BoxLocalResidual() : ParentType() {} protected: - void evalFluxes_() + void evalFluxes_(const Element& element, + const ElementBoundaryTypes& bcTypes, + const FVElementGeometry& fvGeometry) { // calculate the mass flux over the scv faces and subtract - const auto& fvGeometry = this->fvGeometry_(); - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { if (!scvf.boundary()) { - auto flux = this->asImp_().computeFlux(scvf); - const auto& insideScv = this->model_().fvGeometries().subControlVolume(scvf.insideScvIdx()); - const auto& outsideScv = this->model_().fvGeometries().subControlVolume(scvf.outsideScvIdx()); + const auto& insideScv = fvGeometry.scv(scvf.insideScvIdx()); + const auto& outsideScv = fvGeometry.scv(scvf.outsideScvIdx()); + + auto flux = this->asImp_().computeFlux(element, fvGeometry, scvf, bcTypes[insideScv.index()]); - this->residual_[insideScv.indexInElement()] += flux; - this->residual_[outsideScv.indexInElement()] -= flux; + this->residual_[insideScv.index()] += flux; + this->residual_[outsideScv.index()] -= flux; + } + } + } + + void evalBoundary_(const Element &element, + const ElementBoundaryTypes& bcTypes, + const FVElementGeometry& fvGeometry) + { + if (bcTypes.hasNeumann() || bcTypes.hasOutflow()) + { + for (auto&& scvf : scvfs(fvGeometry)) + { + if (scvf.boundary()) + { + auto&& scv = fvGeometry.scv(scvf.insideScvIdx()); + this->asImp_().evalBoundaryFluxes_(element, scvf, scv, bcTypes[scv.index()]); + } + } + } + + // additionally treat mixed D/N conditions in a strong sense + if (bcTypes.hasDirichlet()) + { + for (auto&& scv : scvs(fvGeometry)) + { + auto scvBcTypes = bcTypes[scv.index()]; + if (!scvBcTypes.hasDirichlet()) + continue; + + this->asImp_().evalDirichlet_(element, scv, scvBcTypes); } } } @@ -91,9 +124,11 @@ protected: * \brief Set the values of the Dirichlet boundary control volumes * of the current element. */ - void evalDirichlet_(const SubControlVolume& scv, const BoundaryTypes& bcTypes) + void evalDirichlet_(const Element& element, + const SubControlVolume &scv, + const BoundaryTypes& bcTypes) { - PrimaryVariables dirichletValues = this->asImp_().problem_().dirichlet(this->element_(), scv); + PrimaryVariables dirichletValues = this->problem().dirichlet(element, scv); // set the dirichlet conditions for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) @@ -105,9 +140,9 @@ protected: Valgrind::CheckDefined(dirichletValues[pvIdx]); // get the primary variables - const auto& priVars = this->model_().curVolVars(scv).priVars(); + const auto& priVars = this->problem().model().curVolVars(scv).priVars(); - this->residual_[scv.indexInElement()][eqIdx] = priVars[pvIdx] - dirichletValues[pvIdx]; + this->residual_[scv.index()][eqIdx] = priVars[pvIdx] - dirichletValues[pvIdx]; } } } @@ -115,12 +150,15 @@ protected: /*! * \brief Add all fluxes resulting from Neumann and outflow boundary conditions to the local residual. */ - void evalBoundaryFluxes_(const SubControlVolumeFace &scvf, const SubControlVolume& insideScv, const BoundaryTypes& bcTypes) + void evalBoundaryFluxes_(const Element& element, + const SubControlVolumeFace &scvf, + const SubControlVolume& insideScv, + const BoundaryTypes& bcTypes) { // evaluate the Neumann conditions at the boundary face if (bcTypes.hasNeumann()) - this->residual_[insideScv.indexInElement()] += this->asImp_().evalNeumannSegment_(scvf, insideScv, bcTypes); + this->residual_[insideScv.index()] += this->asImp_().evalNeumannSegment_(element, scvf, insideScv, bcTypes); // TODO: evaluate the outflow conditions at the boundary face //if (bcTypes.hasOutflow()) @@ -130,17 +168,18 @@ protected: /*! * \brief Add Neumann boundary conditions for a single scv face */ - PrimaryVariables evalNeumannSegment_(const SubControlVolumeFace &scvf, + PrimaryVariables evalNeumannSegment_(const Element& element, + const SubControlVolumeFace &scvf, const SubControlVolume& insideScv, const BoundaryTypes &bcTypes) { // temporary vector to store the neumann boundary fluxes PrimaryVariables flux(0); - auto neumannFluxes = this->problem_().neumann(this->element_(), scvf); + auto neumannFluxes = this->problem().neumann(element, scvf); // multiply neumann fluxes with the area and the extrusion factor - neumannFluxes *= scvf.area()*this->problem_().model().curVolVars(insideScv).extrusionFactor(); + neumannFluxes *= scvf.area()*this->problem().model().curVolVars(insideScv).extrusionFactor(); // add fluxes to the temporary vector for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) @@ -181,35 +220,6 @@ protected: // } // } // } - - void evalBoundary_() - { - const auto& fvGeometry = this->fvGeometry_(); - if (this->bcTypes_().hasNeumann() || this->bcTypes_().hasOutflow()) - { - for (const auto& scvf : scvfs(fvGeometry)) - { - if (scvf.boundary()) - { - const auto& scv = this->problem_().model().fvGeometries().subControlVolume(scvf.insideScvIdx()); - this->asImp_().evalBoundaryFluxes_(scvf, scv, this->bcTypes_(scv.indexInElement())); - } - } - } - - // additionally treat mixed D/N conditions in a strong sense - if (this->bcTypes_().hasDirichlet()) - { - for (const auto& scv : scvs(fvGeometry)) - { - BoundaryTypes bcTypes = this->bcTypes_(scv.indexInElement()); - if (!bcTypes.hasDirichlet()) - continue; - - this->asImp_().evalDirichlet_(scv, bcTypes); - } - } - } }; } diff --git a/dumux/implicit/box/propertydefaults.hh b/dumux/implicit/box/propertydefaults.hh index 3681ef036c5559759336bcbc84057b2c62819ed6..71d919fcea438ad0debbdb6e8e070dd8200b2b8f 100644 --- a/dumux/implicit/box/propertydefaults.hh +++ b/dumux/implicit/box/propertydefaults.hh @@ -27,12 +27,12 @@ #define DUMUX_BOX_PROPERTY_DEFAULTS_HH #include <dumux/implicit/propertydefaults.hh> -#include <dumux/discretization/fvelementgeometry.hh> #include <dumux/discretization/box/subcontrolvolume.hh> #include <dumux/discretization/box/subcontrolvolumeface.hh> #include <dumux/discretization/box/fluxvariablescachevector.hh> #include <dumux/discretization/box/volumevariablesvector.hh> -#include <dumux/discretization/box/fvelementgeometryvector.hh> +#include <dumux/discretization/box/globalfvgeometry.hh> +#include <dumux/discretization/box/fvelementgeometry.hh> #include <dumux/discretization/box/stencils.hh> #include <dumux/porousmediumflow/implicit/fluxvariablescache.hh> @@ -58,7 +58,10 @@ namespace Properties { SET_INT_PROP(BoxModel, DiscretizationMethod, GET_PROP(TypeTag, DiscretizationMethods)::Box); //! Set the default for the FVElementGeometry vector -SET_TYPE_PROP(BoxModel, FVElementGeometryVector, BoxFVElementGeometryVector<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFVElementGeometryCache)>); +SET_TYPE_PROP(BoxModel, GlobalFVGeometry, BoxGlobalFVGeometry<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFVGeometryCache)>); + +//! Set the default for the FVElementGeometry vector +SET_TYPE_PROP(BoxModel, FVElementGeometry, BoxFVElementGeometry<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFVGeometryCache)>); //! The sub control volume SET_PROP(BoxModel, SubControlVolume) @@ -71,7 +74,7 @@ private: using ScvGeometry = Dune::MultiLinearGeometry<Scalar, dim, dimWorld>; using IndexType = typename GridView::IndexSet::IndexType; public: - using type = BoxSubControlVolume<ScvGeometry, IndexType, /*isBox=*/true>; + using type = BoxSubControlVolume<ScvGeometry, IndexType>; }; SET_PROP(BoxModel, SubControlVolumeFace) @@ -103,7 +106,7 @@ SET_TYPE_PROP(BoxModel, CurrentVolumeVariablesVector, BoxVolumeVariablesVector<T SET_TYPE_PROP(BoxModel, PreviousVolumeVariablesVector, BoxVolumeVariablesVector<TypeTag, true, GET_PROP_VALUE(TypeTag, EnableGlobalVolumeVariablesCache)>); //! The global flux variables cache vector class -SET_TYPE_PROP(BoxModel, FluxVariablesCacheVector, BoxFluxVariablesCacheVector<TypeTag>); +SET_TYPE_PROP(BoxModel, FluxVariablesCacheVector, BoxFluxVariablesCacheVector<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFluxVariablesCache)>); //! Set the BaseLocalResidual to BoxLocalResidual SET_TYPE_PROP(BoxModel, BaseLocalResidual, BoxLocalResidual<TypeTag>); diff --git a/dumux/implicit/cellcentered/elementboundarytypes.hh b/dumux/implicit/cellcentered/elementboundarytypes.hh index a11630ed96275895801ba84daf099c7f445402c6..addff4924c4379d128d9294ae79b5a4ace7f7e60 100644 --- a/dumux/implicit/cellcentered/elementboundarytypes.hh +++ b/dumux/implicit/cellcentered/elementboundarytypes.hh @@ -87,12 +87,12 @@ public: (*this)[0].reset(); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { if (!problem.model().onBoundary(scv)) return; - for (const auto& scvFace : scvfs(fvGeometry)) + for (auto&& scvFace : scvfs(fvGeometry)) { if (!scvFace.boundary()) continue; diff --git a/dumux/implicit/cellcentered/localjacobian.hh b/dumux/implicit/cellcentered/localjacobian.hh index a38fe2d64063fd7eb54d27509a5209cdf0805941..3ddce0a1cbefeb8e6d1e263e6933c629cafb9603 100644 --- a/dumux/implicit/cellcentered/localjacobian.hh +++ b/dumux/implicit/cellcentered/localjacobian.hh @@ -75,7 +75,7 @@ class CCLocalJacobian : public ImplicitLocalJacobian<TypeTag> typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; @@ -114,8 +114,8 @@ public: assemblyMap_.resize(problem.gridView().size(0)); for (const auto& element : elements(problem.gridView())) { - // bind FVGeometry to the element to prepare all the geometries of the stencil - problem.model().fvGeometries_().bind(element); + // get a local finite volume geometry object that is bindable + auto fvGeometryJ = localView(problem.model().globalFvGeometry()); auto globalI = problem.elementMapper().index(element); const auto& neighborStencil = this->model_().stencils(element).neighborStencil(); @@ -123,18 +123,19 @@ public: assemblyMap_[globalI].reserve(neighborStencil.size()); for (auto globalJ : neighborStencil) { - const auto& elementJ = this->model_().fvGeometries().element(globalJ); - const auto& fvGeometry = this->model_().fvGeometries(elementJ); + const auto& elementJ = fvGeometryJ.globalFvGeometry().element(globalJ); + fvGeometryJ.bind(elementJ); // find the flux vars needed for the calculation of the flux into element std::vector<IndexType> fluxVarIndices; - for (const auto& scvFaceJ : scvfs(fvGeometry)) + for (auto&& scvFaceJ : scvfs(fvGeometryJ)) { auto fluxVarsIdx = scvFaceJ.index(); // if globalI is in flux var stencil, add to list FluxVariables fluxVars; - const auto fluxStencil = fluxVars.computeStencil(problem, elementJ, scvFaceJ); + const auto fluxStencil = fluxVars.computeStencil(problem, elementJ, fvGeometryJ, scvFaceJ); + for (auto globalIdx : fluxStencil) if (globalIdx == globalI) fluxVarIndices.push_back(fluxVarsIdx); @@ -156,15 +157,16 @@ public: const bool isGhost = (element.partitionType() == Dune::GhostEntity); // prepare the volvars/fvGeometries in case caching is disabled - this->model_().fvGeometries_().bind(element); - this->model_().curVolVars_().bind(element); - this->model_().prevVolVars_().bindElement(element); - this->model_().fluxVariablesCache_().bind(element); + auto fvGeometry = localView(this->model_().globalFvGeometry()); + fvGeometry.bind(element); + + this->model_().curVolVars_().bind(element, fvGeometry); + this->model_().prevVolVars_().bindElement(element, fvGeometry); + this->model_().fluxVariablesCache_().bind(element, fvGeometry); // set the actual dof index globalI_ = this->problem_().elementMapper().index(element); - const auto& fvGeometry = this->model_().fvGeometries(element); bcTypes_.update(this->problem_(), element, fvGeometry); // calculate the local residual @@ -175,7 +177,7 @@ public: } else { - this->localResidual().eval(element, bcTypes_); + this->localResidual().eval(element, bcTypes_, fvGeometry); this->residual_ = this->localResidual().residual(); // store residual in global container as well residual[globalI_] = this->localResidual().residual(0); @@ -184,7 +186,7 @@ public: this->model_().updatePVWeights(fvGeometry); // calculate derivatives of all dofs in stencil with respect to the dofs in the element - evalPartialDerivatives_(element, matrix, residual, isGhost); + evalPartialDerivatives_(element, fvGeometry, matrix, residual, isGhost); // TODO: calculate derivatives in the case of an extended source stencil // const auto& extendedSourceStencil = model_().stencils(element).extendedSourceStencil(); @@ -205,7 +207,11 @@ public: { return assemblyMap_; } private: - void evalPartialDerivatives_(const Element& element, JacobianMatrix& matrix, SolutionVector& residual, const bool isGhost) + void evalPartialDerivatives_(const Element& element, + const FVElementGeometry& fvGeometry, + JacobianMatrix& matrix, + SolutionVector& residual, + const bool isGhost) { // get stencil informations const auto& neighborStencil = this->model_().stencils(element).neighborStencil(); @@ -230,16 +236,19 @@ private: unsigned int j = 0; for (auto globalJ : neighborStencil) { - auto elementJ = this->problem_().model().fvGeometries().element(globalJ); + auto elementJ = fvGeometry.globalFvGeometry().element(globalJ); neighborElements.push_back(elementJ); for (auto fluxVarIdx : assemblyMap_[globalI_][j]) - origFlux[j] += localRes.evalFlux_(elementJ, fluxVarIdx); + { + auto&& scvf = fvGeometry.scvf(fluxVarIdx); + origFlux[j] += localRes.evalFlux_(elementJ, fvGeometry, scvf); + } ++j; } - const auto& scv = this->model_().fvGeometries().subControlVolume(globalI_); + auto&& scv = fvGeometry.scv(globalI_); VolumeVariables origVolVars(this->model_().curVolVars(scv)); for (int pvIdx = 0; pvIdx < numEq; pvIdx++) @@ -261,12 +270,12 @@ private: // update the volume variables and bind the flux var cache again this->model_().curVolVars_(scv).update(priVars, this->problem_(), element, scv); - this->model_().fluxVariablesCache_().bind(element); + this->model_().fluxVariablesCache_().bind(element, fvGeometry); if (!isGhost) { // calculate the residual with the deflected primary variables - this->localResidual().eval(element, bcTypes_); + this->localResidual().eval(element, bcTypes_, fvGeometry); // store the residual and the storage term partialDeriv = this->localResidual().residual(0); @@ -276,7 +285,10 @@ private: for (std::size_t k = 0; k < numNeighbors; ++k) { for (auto fluxVarIdx : assemblyMap_[globalI_][k]) - neighborDeriv[k] += localRes.evalFlux_(neighborElements[k], fluxVarIdx); + { + auto&& scvf = fvGeometry.scvf(fluxVarIdx); + neighborDeriv[k] += localRes.evalFlux_(neighborElements[k], fvGeometry, scvf); + } } } else @@ -300,12 +312,12 @@ private: // update the volume variables and bind the flux var cache again this->model_().curVolVars_(scv).update(priVars, this->problem_(), element, scv); - this->model_().fluxVariablesCache_().bind(element); + this->model_().fluxVariablesCache_().bind(element, fvGeometry); if (!isGhost) { // calculate the residual with the deflected primary variables - this->localResidual().eval(element, bcTypes_); + this->localResidual().eval(element, bcTypes_, fvGeometry); // subtract the residual from the derivative storage partialDeriv -= this->localResidual().residual(0); @@ -315,7 +327,10 @@ private: for (std::size_t k = 0; k < numNeighbors; ++k) { for (auto fluxVarIdx : assemblyMap_[globalI_][k]) - neighborDeriv[k] -= localRes.evalFlux_(neighborElements[k], fluxVarIdx); + { + auto&& scvf = fvGeometry.scvf(fluxVarIdx); + neighborDeriv[k] -= localRes.evalFlux_(neighborElements[k], fvGeometry, scvf); + } } } else diff --git a/dumux/implicit/cellcentered/localresidual.hh b/dumux/implicit/cellcentered/localresidual.hh index 4766debb5ff239e8b5de58517485275aac1c8627..2882022e1db9af03bb91e7869f5816a8538cddca 100644 --- a/dumux/implicit/cellcentered/localresidual.hh +++ b/dumux/implicit/cellcentered/localresidual.hh @@ -43,24 +43,21 @@ namespace Dumux template<class TypeTag> class CCLocalResidual : public ImplicitLocalResidual<TypeTag> { - typedef ImplicitLocalResidual<TypeTag> ParentType; + using ParentType = ImplicitLocalResidual<TypeTag>; friend class ImplicitLocalResidual<TypeTag>; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - - enum { - numEq = GET_PROP_VALUE(TypeTag, NumEq) - }; + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; enum { constantBC = GET_PROP_VALUE(TypeTag, ConstantBoundaryConditions) }; - enum { enableVolVarsCache = GET_PROP_VALUE(TypeTag, EnableGlobalVolumeVariablesCache) }; - typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace) SubControlVolumeFace; + using Element = typename GridView::template Codim<0>::Entity; + using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables); + using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes); + using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); public: // copying the local residual class is not a good idea @@ -70,42 +67,46 @@ public: protected: - void evalFluxes_() + void evalFluxes_(const Element& element, + const ElementBoundaryTypes& bcTypes, + const FVElementGeometry& fvGeometry) { // calculate the mass flux over the scv faces - const auto& fvGeometry = this->fvGeometry_(); - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { - this->residual_[0] += this->asImp_().computeFlux_(scvf); + this->residual_[0] += this->asImp_().computeFlux_(element, fvGeometry, scvf, bcTypes); } } - PrimaryVariables computeFlux_(const SubControlVolumeFace &scvf) + PrimaryVariables computeFlux_(const Element &element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace &scvf, + const ElementBoundaryTypes& bcTypes) { if (!scvf.boundary() /*TODO: || GET_PROP_VALUE(TypeTag, BoundaryReconstruction)*/) - return this->asImp_().computeFlux(scvf); + return this->asImp_().computeFlux(element, fvGeometry, scvf, bcTypes[0]); else return PrimaryVariables(0.0); } - void evalBoundary_() + void evalBoundary_(const Element &element, + const ElementBoundaryTypes& bcTypes, + const FVElementGeometry& fvGeometry) { - const auto& fvGeometry = this->fvGeometry_(); - - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { if (scvf.boundary()) - this->residual_[0] += evalBoundaryFluxes_(scvf); + this->residual_[0] += evalBoundaryFluxes_(element, scvf, fvGeometry, bcTypes[0]); } // additionally treat mixed D/N conditions in a strong sense - if (this->bcTypes_().hasDirichlet()) + if (bcTypes.hasDirichlet()) { - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { if (scvf.boundary()) - this->asImp_().evalDirichlet_(scvf); + this->asImp_().evalDirichlet_(element, scvf, fvGeometry); } } } @@ -114,14 +115,15 @@ protected: * \brief Add all fluxes resulting from Neumann, outflow and pure Dirichlet * boundary conditions to the local residual. */ - PrimaryVariables evalBoundaryFluxes_(const SubControlVolumeFace &scvf) + PrimaryVariables evalBoundaryFluxes_(const Element &element, + const SubControlVolumeFace &scvf, + const FVElementGeometry& fvGeometry, + const BoundaryTypes& bcTypes) { - BoundaryTypes bcTypes = this->problem_().boundaryTypes(this->element_(), scvf); - // evaluate the Neumann conditions at the boundary face PrimaryVariables flux(0); if (bcTypes.hasNeumann() /*TODO: && !GET_PROP_VALUE(TypeTag, BoundaryReconstruction)*/) - flux += this->asImp_().evalNeumannSegment_(scvf, bcTypes); + flux += this->asImp_().evalNeumannSegment_(element, scvf, fvGeometry, bcTypes); // TODO: evaluate the outflow conditions at the boundary face //if (bcTypes.hasOutflow() /*TODO: && !GET_PROP_VALUE(TypeTag, BoundaryReconstruction)*/) @@ -129,37 +131,42 @@ protected: // evaluate the pure Dirichlet conditions at the boundary face if (bcTypes.hasDirichlet() && !bcTypes.hasNeumann()) - flux += this->asImp_().evalDirichletSegment_(scvf, bcTypes); + flux += this->asImp_().evalDirichletSegment_(element, scvf, fvGeometry, bcTypes); return flux; } + /*! * \brief Evaluate Dirichlet conditions on faces that have mixed * Dirichlet/Neumann boundary conditions. */ - void evalDirichlet_(const SubControlVolumeFace &scvf) + void evalDirichlet_(const Element& element, + const SubControlVolumeFace &scvf, + const FVElementGeometry& fvGeometry) { - BoundaryTypes bcTypes = this->problem_().boundaryTypes(this->element_(), scvf); + BoundaryTypes bcTypes = this->problem().boundaryTypes(element, scvf); if (bcTypes.hasDirichlet() && bcTypes.hasNeumann()) - this->asImp_().evalDirichletSegmentMixed_(scvf, bcTypes); + this->asImp_().evalDirichletSegmentMixed_(element, scvf, fvGeometry, bcTypes); } /*! * \brief Add Neumann boundary conditions for a single scv face */ - PrimaryVariables evalNeumannSegment_(const SubControlVolumeFace &scvf, + PrimaryVariables evalNeumannSegment_(const Element& element, + const SubControlVolumeFace &scvf, + const FVElementGeometry& fvGeometry, const BoundaryTypes &bcTypes) { // temporary vector to store the neumann boundary fluxes PrimaryVariables flux(0); - auto neumannFluxes = this->problem_().neumann(this->element_(), scvf); + auto neumannFluxes = this->problem().neumann(element, scvf); // multiply neumann fluxes with the area and the extrusion factor - const auto& scv = this->problem_().model().fvGeometries().subControlVolume(scvf.insideScvIdx()); - neumannFluxes *= scvf.area()*this->problem_().model().curVolVars(scv).extrusionFactor(); + auto&& scv = fvGeometry.scv(scvf.insideScvIdx()); + neumannFluxes *= scvf.area()*this->problem().model().curVolVars(scv).extrusionFactor(); // add fluxes to the residual for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) @@ -169,6 +176,66 @@ protected: return flux; } + /*! + * \brief Treat Dirichlet boundary conditions in a weak sense for a single + * intersection that only has Dirichlet boundary conditions + */ + PrimaryVariables evalDirichletSegment_(const Element& element, + const SubControlVolumeFace &scvf, + const FVElementGeometry& fvGeometry, + const BoundaryTypes &bcTypes) + { + // temporary vector to store the Dirichlet boundary fluxes + PrimaryVariables flux(0); + + if (!constantBC || !enableVolVarsCache) + { + // update corresponding boundary volume variables before flux calculation + const auto insideScvIdx = scvf.insideScvIdx(); + const auto& insideScv = fvGeometry.scv(insideScvIdx); + const auto dirichletPriVars = this->problem().dirichlet(element, scvf); + this->problem().model().curVolVars_(scvf.outsideScvIdx()).update(dirichletPriVars, + this->problem(), + element, + insideScv); + } + + auto dirichletFlux = this->asImp_().computeFlux(element, fvGeometry, scvf, bcTypes); + + // add fluxes to the residual + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) + if (bcTypes.isDirichlet(eqIdx)) + flux[eqIdx] += dirichletFlux[eqIdx]; + + return flux; + } + + /*! + * \brief Treat Dirichlet boundary conditions in a strong sense for a + * single intersection that has mixed D/N boundary conditions + */ + void evalDirichletSegmentMixed_(const Element& element, + const SubControlVolumeFace &scvf, + const FVElementGeometry& fvGeometry, + const BoundaryTypes &bcTypes) + { + // temporary vector to store the Dirichlet values + PrimaryVariables dirichletValues = this->problem().dirichlet(element, scvf); + + // get the primary variables + const auto& priVars = this->problem().model().curVolVars(scvf.insideScvIdx()).priVars(); + + // set Dirichlet conditions in a strong sense + for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) + { + if (bcTypes.isDirichlet(eqIdx)) + { + auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx); + this->residual_[0][eqIdx] = priVars[pvIdx] - dirichletValues[pvIdx]; + } + } + } + /*! * \brief Add outflow boundary conditions for a single intersection */ @@ -227,59 +294,6 @@ protected: // restore the pointer to the FVElementGeometry this->fvElemGeomPtr_ = oldFVGeometryPtr; }*/ - - /*! - * \brief Treat Dirichlet boundary conditions in a weak sense for a single - * intersection that only has Dirichlet boundary conditions - */ - PrimaryVariables evalDirichletSegment_(const SubControlVolumeFace &scvf, - const BoundaryTypes &bcTypes) - { - // temporary vector to store the Dirichlet boundary fluxes - PrimaryVariables flux(0); - - if (!constantBC || !enableVolVarsCache) - { - // update corresponding boundary volume variables before flux calculation - const auto insideScvIdx = scvf.insideScvIdx(); - const auto& insideScv = this->model_().fvGeometries().subControlVolume(insideScvIdx); - const auto dirichletPriVars = this->problem_().dirichlet(this->element_(), scvf); - this->model_().curVolVars_(scvf.outsideScvIdx()).update(dirichletPriVars, this->problem_(), this->element_(), insideScv); - } - - auto dirichletFlux = this->asImp_().computeFlux(scvf); - - // add fluxes to the residual - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) - if (bcTypes.isDirichlet(eqIdx)) - flux[eqIdx] += dirichletFlux[eqIdx]; - - return flux; - } - - /*! - * \brief Treat Dirichlet boundary conditions in a strong sense for a - * single intersection that has mixed D/N boundary conditions - */ - void evalDirichletSegmentMixed_(const SubControlVolumeFace &scvf, - const BoundaryTypes &bcTypes) - { - // temporary vector to store the Dirichlet values - PrimaryVariables dirichletValues = this->problem_().dirichlet(this->element_(), scvf); - - // get the primary variables - const auto& priVars = this->model_().curVolVars(scvf.insideScvIdx()).priVars(); - - // set Dirichlet conditions in a strong sense - for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) - { - if (bcTypes.isDirichlet(eqIdx)) - { - auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx); - this->residual_[0][eqIdx] = priVars[pvIdx] - dirichletValues[pvIdx]; - } - } - } }; } diff --git a/dumux/implicit/cellcentered/tpfa/propertydefaults.hh b/dumux/implicit/cellcentered/tpfa/propertydefaults.hh index cc904e2b56783dc6a1d67589904e457e8811a284..5ce873a384f1fe92c5ec7c18afba04016c6416df 100644 --- a/dumux/implicit/cellcentered/tpfa/propertydefaults.hh +++ b/dumux/implicit/cellcentered/tpfa/propertydefaults.hh @@ -29,7 +29,8 @@ #include <dumux/implicit/propertydefaults.hh> #include <dumux/porousmediumflow/implicit/fluxvariablescache.hh> -#include <dumux/discretization/cellcentered/tpfa/fvelementgeometryvector.hh> +#include <dumux/discretization/cellcentered/tpfa/globalfvgeometry.hh> +#include <dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh> #include <dumux/discretization/cellcentered/tpfa/subcontrolvolume.hh> #include <dumux/discretization/cellcentered/tpfa/subcontrolvolumeface.hh> #include <dumux/implicit/cellcentered/properties.hh> @@ -43,8 +44,11 @@ namespace Properties { //! Set the corresponding discretization method property SET_INT_PROP(CCTpfaModel, DiscretizationMethod, GET_PROP(TypeTag, DiscretizationMethods)::CCTpfa); -//! Set the default for the FVElementGeometry vector -SET_TYPE_PROP(CCTpfaModel, FVElementGeometryVector, CCTpfaFVElementGeometryVector<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFVElementGeometryCache)>); +//! Set the default for the global finite volume geometry +SET_TYPE_PROP(CCTpfaModel, GlobalFVGeometry, CCTpfaGlobalFVGeometry<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFVGeometryCache)>); + +//! Set the default for the local finite volume geometry +SET_TYPE_PROP(CCTpfaModel, FVElementGeometry, CCTpfaFVElementGeometry<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFVGeometryCache)>); //! The sub control volume SET_PROP(CCTpfaModel, SubControlVolume) diff --git a/dumux/implicit/localresidual.hh b/dumux/implicit/localresidual.hh index 96c8ee5cc3df1a31bc9c2def71f3be70cede90e0..2396859acdb509a28008976e8220800f28f70e3e 100644 --- a/dumux/implicit/localresidual.hh +++ b/dumux/implicit/localresidual.hh @@ -51,7 +51,7 @@ private: typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; typedef typename GridView::template Codim<0>::Entity Element; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; typedef typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace) SubControlVolumeFace; typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector; @@ -82,6 +82,14 @@ public: void init(Problem &problem) { problemPtr_ = &problem; } + + /*! + * \name User interface + * \note The following methods are usually expensive to evaluate + * They are useful for outputting residual information. + */ + // \{ + /*! * \brief Compute the local residual, i.e. the deviation of the * equations from zero. @@ -92,15 +100,17 @@ public: void eval(const Element &element) { // make sure FVElementGeometry and volume variables are bound to the element - model_().fvGeometries_().bind(element); - model_().curVolVars_().bind(element); - model_().prevVolVars_().bindElement(element); - model_().fluxVariablesCache_().bindElement(element); + auto fvGeometry = localView(problem().model().globalFvGeometry()); + fvGeometry.bind(element); + + problem().model().curVolVars_().bind(element, fvGeometry); + problem().model().prevVolVars_().bindElement(element, fvGeometry); + problem().model().fluxVariablesCache_().bindElement(element, fvGeometry); ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); + bcTypes.update(problem(), element, fvGeometry); - asImp_().eval(element, bcTypes); + asImp_().eval(element, bcTypes, fvGeometry); } /*! @@ -114,47 +124,53 @@ public: */ void evalStorage(const Element &element) { - elemPtr_ = &element; - // make sure FVElementGeometry and volume variables are bound to the element - model_().fvGeometries_().bindElement(element); - model_().curVolVars_().bindElement(element); - model_().prevVolVars_().bindElement(element); + auto fvGeometry = localView(problem().model().globalFvGeometry()); + fvGeometry.bind(element); - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); - bcTypesPtr_ = &bcTypes; + // make sure FVElementGeometry and volume variables are bound to the element + problem().model().curVolVars_().bindElement(element, fvGeometry); + problem().model().prevVolVars_().bindElement(element, fvGeometry); - asImp_().evalStorage_(); + asImp_().evalStorage_(fvGeometry); } - /*! - * \brief Compute the flux term for the current solution. - * - * \param element The DUNE Codim<0> entity for which the residual - * ought to be calculated - * \param curVolVars The volume averaged variables for all - * sub-contol volumes of the element - */ - void evalFluxes(const Element &element) - { - elemPtr_ = &element; + // ! + // * \brief Compute the flux term for the current solution. + // * + // * \param element The DUNE Codim<0> entity for which the residual + // * ought to be calculated + // * \param curVolVars The volume averaged variables for all + // * sub-contol volumes of the element - // make sure FVElementGeometry and volume variables are bound to the element - model_().fvGeometries_().bind(element); - model_().curVolVars_().bind(element); - model_().prevVolVars_().bindElement(element); - model_().fluxVariablesCache_().bindElement(element); + // void evalFluxes(const Element &element) + // { + // elemPtr_ = &element; - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); + // // make sure FVElementGeometry and volume variables are bound to the element + // problem().model().fvGeometries_().bind(element); + // problem().model().curVolVars_().bind(element); + // problem().model().prevVolVars_().bindElement(element); + // problem().model().fluxVariablesCache_().bindElement(element); - residual_.resize(fvGeometry_().numScv); - residual_ = 0; + // ElementBoundaryTypes bcTypes; + // bcTypes.update(problem(), element, fvGeometry_()); + + // residual_.resize(fvGeometry_().numScv); + // residual_ = 0; + + // bcTypesPtr_ = &bcTypes; + // asImp_().evalFluxes_(); + // } + + // \} - bcTypesPtr_ = &bcTypes; - asImp_().evalFluxes_(); - } + + /*! + * \name Main interface + * \note Methods used by the assembler to compute derivatives and residual + */ + // \{ /*! * \brief Compute the local residual, i.e. the deviation of the @@ -173,40 +189,38 @@ public: * vertices of the element */ void eval(const Element &element, - const ElementBoundaryTypes &bcTypes) + const ElementBoundaryTypes &bcTypes, + const FVElementGeometry& fvGeometry) { - // At this point the fv geometry has to be bound already - elemPtr_ = &element; - bcTypesPtr_ = &bcTypes; - // resize the vectors for all terms - int numScv = fvGeometry_().numScv(); + auto numScv = fvGeometry.numScv(); residual_.resize(numScv); storageTerm_.resize(numScv); residual_ = 0.0; storageTerm_ = 0.0; - asImp_().evalFluxes_(); - asImp_().evalVolumeTerms_(); - asImp_().evalBoundary_(); + asImp_().evalFluxes_(element, bcTypes, fvGeometry); + asImp_().evalVolumeTerms_(element, bcTypes, fvGeometry); + asImp_().evalBoundary_(element, bcTypes, fvGeometry); } /*! * \brief Calculate the source term of the equation * - * \param source The source/sink in the sub-control volume for each phase - * \param scvIdx The index of the sub-control volume + * \param scv The sub-control volume over which we integrate the source term * */ - PrimaryVariables computeSource(const SubControlVolume &scv) + PrimaryVariables computeSource(const Element& element, + const SubControlVolume &scv) { PrimaryVariables source(0); - source += this->problem_().source(element_(), scv); + // add contributions from volume flux sources + source += this->problem().source(element, scv); // add contribution from possible point sources - source += this->problem_().scvPointSources(element_(), scv); + source += this->problem().scvPointSources(element, scv); return source; } @@ -241,80 +255,75 @@ public: const PrimaryVariables &storageTerm(const int scvIdx) const { return storageTerm_[scvIdx]; } + /*! + * \brief Return the problem we are solving. Only call this after init()! + */ + const Problem& problem() const + { return *problemPtr_; } + + /*! + * \brief Return the problem we are solving. Only call this after init()! + */ + Problem& problem() + { return *problemPtr_; } + + // \} + protected: Implementation &asImp_() - { - assert(static_cast<Implementation*>(this) != 0); - return *static_cast<Implementation*>(this); - } + { return *static_cast<Implementation*>(this); } const Implementation &asImp_() const - { - assert(static_cast<const Implementation*>(this) != 0); - return *static_cast<const Implementation*>(this); - } + { return *static_cast<const Implementation*>(this); } - PrimaryVariables evalFlux_(const Element &element, const int scvfIdx) + PrimaryVariables evalFlux_(const Element &element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace scvf) { - const auto& scvf = model_().fvGeometries().subControlVolumeFace(scvfIdx); - elemPtr_ = &element; - ElementBoundaryTypes bcTypes; - bcTypes.update(problem_(), element, fvGeometry_()); - bcTypesPtr_ = &bcTypes; + bcTypes.update(problem(), element, fvGeometry); - residual_.resize(fvGeometry_().numScv()); + residual_.resize(fvGeometry.numScv()); residual_ = 0; - return evalFlux_(scvf); - } - - PrimaryVariables evalFlux_(const int scvfIdx) - { - auto&& scvf = model_().fvGeometries().subControlVolumeFace(scvfIdx); - return evalFlux_(scvf); - } - - PrimaryVariables evalFlux_(const SubControlVolumeFace &scvf) - { - return asImp_().computeFlux_(scvf); + return asImp_().computeFlux_(element, fvGeometry, scvf, bcTypes); } /*! * \brief Set the local residual to the storage terms of all * sub-control volumes of the current element. */ - void evalStorage_() + void evalStorage_(const FVElementGeometry& fvGeometry) { - storageTerm_.resize(fvGeometry_().numScv()); + storageTerm_.resize(fvGeometry.numScv()); storageTerm_ = 0; // calculate the amount of conservation each quantity inside // all sub control volumes - const auto& fvGeometry = fvGeometry_(); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { - auto scvIdx = scv.indexInElement(); + auto scvIdx = isBox ? scv.index() : 0; - storageTerm_[scvIdx] = asImp_().computeStorage(scv, model_().curVolVars(scv)); - storageTerm_[scvIdx] *= scv.volume() * model_().curVolVars(scv).extrusionFactor(); + storageTerm_[scvIdx] = asImp_().computeStorage(scv, problem().model().curVolVars(scv)); + storageTerm_[scvIdx] *= scv.volume() * problem().model().curVolVars(scv).extrusionFactor(); } } - PrimaryVariables evalSource_() - { - PrimaryVariables source(0); - const auto& fvGeometry = fvGeometry_(); - for (const auto& scv : scvs(fvGeometry)) - { - source += this->problem_().source(element_(), scv); + // PrimaryVariables evalSource_(const Element& element, + // const FVElementGeometry& fvGeometry) + // { + // PrimaryVariables source(0); + // const auto& fvGeometry = fvGeometry.fvElementGeometry(); + // for (auto&& scv : scvs(fvGeometry)) + // { + // source += this->problem().source(element, scv); - // add contribution from possible point sources - source += this->problem_().scvPointSources(element_(), scv); - } + // // add contribution from possible point sources + // source += this->problem().scvPointSources(element, scv); + // } - return source; - } + // return source; + // } /*! * \brief Add the change the source term for stationary problems @@ -323,17 +332,18 @@ protected: */ template<class P = Problem> typename std::enable_if<Dumux::Capabilities::isStationary<P>::value, void>::type - evalVolumeTerms_() + evalVolumeTerms_(const Element &element, + const ElementBoundaryTypes &bcTypes, + const FVElementGeometry& fvGeometry) { // evaluate the volume terms (storage + source terms) - const auto& fvGeometry = fvGeometry_(); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { - auto scvIdx = scv.indexInElement(); - auto curExtrusionFactor = model_().curVolVars(scv).extrusionFactor(); + auto scvIdx = isBox ? scv.index() : 0; + auto curExtrusionFactor = problem().model().curVolVars(scv).extrusionFactor(); // subtract the source term from the local rate - PrimaryVariables source = asImp_().computeSource(scv); + PrimaryVariables source = asImp_().computeSource(element, scv); source *= scv.volume()*curExtrusionFactor; residual_[scvIdx] -= source; @@ -347,15 +357,16 @@ protected: */ template<class P = Problem> typename std::enable_if<!Dumux::Capabilities::isStationary<P>::value, void>::type - evalVolumeTerms_() + evalVolumeTerms_(const Element &element, + const ElementBoundaryTypes &bcTypes, + const FVElementGeometry& fvGeometry) { // evaluate the volume terms (storage + source terms) - const auto& fvGeometry = fvGeometry_(); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { - auto scvIdx = scv.indexInElement(); - auto prevExtrusionFactor = model_().prevVolVars(scv).extrusionFactor(); - auto curExtrusionFactor = model_().curVolVars(scv).extrusionFactor(); + auto scvIdx = isBox ? scv.index() : 0; + auto prevExtrusionFactor = problem().model().prevVolVars(scv).extrusionFactor(); + auto curExtrusionFactor = problem().model().curVolVars(scv).extrusionFactor(); // mass balance within the element. this is the // \f$\frac{m}{\partial t}\f$ term if using implicit @@ -363,8 +374,8 @@ protected: // // We might need a more explicit way for // doing the time discretization... - PrimaryVariables prevStorage = asImp_().computeStorage(scv, model_().prevVolVars(scv)); - PrimaryVariables curStorage = asImp_().computeStorage(scv, model_().curVolVars(scv)); + PrimaryVariables prevStorage = asImp_().computeStorage(scv, problem().model().prevVolVars(scv)); + PrimaryVariables curStorage = asImp_().computeStorage(scv, problem().model().curVolVars(scv)); prevStorage *= prevExtrusionFactor; curStorage *= curExtrusionFactor; @@ -372,96 +383,25 @@ protected: storageTerm_[scvIdx] = std::move(curStorage); storageTerm_[scvIdx] -= std::move(prevStorage); storageTerm_[scvIdx] *= scv.volume(); - storageTerm_[scvIdx] /= problem_().timeManager().timeStepSize(); + storageTerm_[scvIdx] /= problem().timeManager().timeStepSize(); // add the storage term to the residual residual_[scvIdx] += storageTerm_[scvIdx]; // subtract the source term from the local rate - PrimaryVariables source = asImp_().computeSource(scv); + PrimaryVariables source = asImp_().computeSource(element, scv); source *= scv.volume()*curExtrusionFactor; residual_[scvIdx] -= source; } } - /*! - * \brief Returns a reference to the problem. - */ - const Problem &problem_() const - { return *problemPtr_; } - - /*! - * \brief Returns a reference to the problem. - */ - Problem &problem_() - { return *problemPtr_; } - - /*! - * \brief Returns a reference to the model. - */ - const Model &model_() const - { return problem_().model(); } - - /*! - * \brief Returns a reference to the model. - */ - Model &model_() - { return problem_().model(); } - - /*! - * \brief Returns a reference to the grid view. - */ - const GridView &gridView_() const - { return problem_().gridView(); } - - /*! - * \brief Returns a reference to the current element. - */ - const Element &element_() const - { - Valgrind::CheckDefined(elemPtr_); - return *elemPtr_; - } - - /*! - * \brief Returns a reference to the current element's finite - * volume geometry. - */ - const FVElementGeometry& fvGeometry_() const - { - return model_().fvGeometries(element_()); - } - - /*! - * \brief Returns a reference to the boundary types of all - * sub-control volumes of the current element. - */ - const ElementBoundaryTypes &bcTypes_() const - { - Valgrind::CheckDefined(bcTypesPtr_); - return *bcTypesPtr_; - } - - /*! - * \brief Returns a reference to the boundary types of the i-th - * sub-control volume of the current element. - */ - const BoundaryTypes &bcTypes_(const int i) const - { - return bcTypes_()[i]; - } - protected: ElementSolutionVector storageTerm_; ElementSolutionVector residual_; - // The problem we would like to solve - Problem *problemPtr_; - - const Element *elemPtr_; - - const ElementBoundaryTypes *bcTypesPtr_; +private: + Problem* problemPtr_; }; } diff --git a/dumux/implicit/model.hh b/dumux/implicit/model.hh index 8a76072f7185cf7a1e1350ef066b23f792a3fcb7..4088bf1cc96857682707a7adcaadb523044012ab 100644 --- a/dumux/implicit/model.hh +++ b/dumux/implicit/model.hh @@ -82,7 +82,7 @@ class ImplicitModel dim = GridView::dimension }; - typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometryVector) FVElementGeometryVector; + using GlobalFVGeometry = typename GET_PROP_TYPE(TypeTag, GlobalFVGeometry); typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry; typedef typename GET_PROP_TYPE(TypeTag, LocalJacobian) LocalJacobian; typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) LocalResidual; @@ -119,8 +119,8 @@ public: updateBoundaryIndices_(); - fvGeometryVector_ = std::make_shared<FVElementGeometryVector>(gridView_()); - fvGeometryVector_->update(problem_()); + globalFvGeometryPtr_ = std::make_shared<GlobalFVGeometry>(gridView_()); + globalFvGeometryPtr_->update(problem); int numDofs = asImp_().numDofs(); uCur_.resize(numDofs); @@ -132,18 +132,18 @@ public: asImp_().applyInitialSolution_(); // resize and update the volVars with the initial solution - curVolVarsVector_.update(problem_(), curSol()); + curVolVarsVector_.update(problem, curSol()); // update stencils - stencilsVector_.update(problem_()); + stencilsVector_.update(problem); // update the flux variables caches - fluxVarsCacheVector_.update(problem_()); + fluxVarsCacheVector_.update(problem); // initialize assembler and create matrix - localJacobian_.init(problem_()); + localJacobian_.init(problem); jacAsm_ = std::make_shared<JacobianAssembler>(); - jacAsm_->init(problem_()); + jacAsm_->init(problem); // also set the solution of the "previous" time step to the // initial solution. @@ -786,11 +786,8 @@ public: const VolumeVariables& curVolVars(const unsigned int scvIdx) const { return curVolVarsVector_[scvIdx]; } - const FVElementGeometryVector& fvGeometries() const - { return *fvGeometryVector_; } - - const FVElementGeometry& fvGeometries(const Element& element) const - { return fvGeometryVector_->fvGeometry(element); } + const GlobalFVGeometry& globalFvGeometry() const + { return *globalFvGeometryPtr_; } protected: @@ -815,8 +812,8 @@ protected: FluxVariablesCache& fluxVarsCache_(const SubControlVolumeFace& scvf) { return fluxVarsCacheVector_[scvf]; } - FVElementGeometryVector& fvGeometries_() - { return *fvGeometryVector_; } + GlobalFVGeometry& globalFvGeometry_() + { return *globalFvGeometryPtr_; } /*! * \brief A reference to the problem on which the model is applied. @@ -858,11 +855,11 @@ protected: for (const auto& element : elements(gridView_())) { // deal with the current element, bind FVGeometry to it - fvGeometries_().bindElement(element); - const auto& fvGeometry = fvGeometries(element); + auto fvGeometry = localView(globalFvGeometry()); + fvGeometry.bindElement(element); // loop over sub control volumes - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { // let the problem do the dirty work of nailing down // the initial solution. @@ -980,7 +977,7 @@ protected: StencilsVector stencilsVector_; // the finite volume element geometries - std::shared_ptr<FVElementGeometryVector> fvGeometryVector_; + std::shared_ptr<GlobalFVGeometry> globalFvGeometryPtr_; // container to store the box volumes Dune::BlockVector<Dune::FieldVector<Scalar, 1> > boxVolume_; diff --git a/dumux/implicit/problem.hh b/dumux/implicit/problem.hh index 77c9cd298748e878be0b4a5c12cf4de12bcfa66d..916cb385dd3cdf2fea61a9108cb78679a5a61bb2 100644 --- a/dumux/implicit/problem.hh +++ b/dumux/implicit/problem.hh @@ -973,8 +973,8 @@ public: PrimaryVariables scvPointSources(const Element &element, const SubControlVolume &scv) const { PrimaryVariables source(0); - - auto key = std::make_pair(this->gridView().indexSet().index(element), scv.indexInElement()); + auto scvIdx = isBox ? scv.index() : 0; + auto key = std::make_pair(this->gridView().indexSet().index(element), scvIdx); if (pointSourceMap_.count(key)) { // call the solDependent function. Herein the user might fill/add values to the point sources diff --git a/dumux/implicit/properties.hh b/dumux/implicit/properties.hh index c4effc39f902f57720a44bba9ea537cd1dd40817..cff3fdf63c97ca79a8bcde659272416b4fb40e2c 100644 --- a/dumux/implicit/properties.hh +++ b/dumux/implicit/properties.hh @@ -59,9 +59,9 @@ NEW_PROP_TAG(LocalJacobian); //!< The type of the local jacobian operator NEW_PROP_TAG(SubControlVolume);//!< The type of the sub control volume NEW_PROP_TAG(SubControlVolumeFace); //!< The type of the sub control volume face -NEW_PROP_TAG(FVElementGeometry); //!< The type of the finite volume geometry (iterators over scvs, scvfs) -NEW_PROP_TAG(FVElementGeometryVector); //!< The type of the finite volume geometry vector -NEW_PROP_TAG(EnableGlobalFVElementGeometryCache); //! specifies if geometric data is be saved (faster, but more memory consuming) +NEW_PROP_TAG(FVElementGeometry); //!< The type of the local finite volume geometry (iterators over scvs, scvfs) +NEW_PROP_TAG(GlobalFVGeometry); //!< The type of the global finite volume geometry +NEW_PROP_TAG(EnableGlobalFVGeometryCache); //! specifies if geometric data is be saved (faster, but more memory consuming) NEW_PROP_TAG(JacobianAssembler); //!< Assembles the global jacobian matrix NEW_PROP_TAG(JacobianMatrix); //!< Type of the global jacobian matrix diff --git a/dumux/implicit/propertydefaults.hh b/dumux/implicit/propertydefaults.hh index 2d4219e401879e44f97545bcfb3f40e5e81f5644..864a2b02027ed141261ac6b0a6b5534ec64411e2 100644 --- a/dumux/implicit/propertydefaults.hh +++ b/dumux/implicit/propertydefaults.hh @@ -39,7 +39,6 @@ #include <dumux/porousmediumflow/implicit/fluxvariablescache.hh> #include <dumux/discretization/volumevariables.hh> -#include <dumux/discretization/fvelementgeometry.hh> #include <dumux/discretization/darcyslaw.hh> #include <dumux/discretization/fickslaw.hh> @@ -106,9 +105,6 @@ SET_TYPE_PROP(ImplicitBase, //! Set the BaseModel to ImplicitModel SET_TYPE_PROP(ImplicitBase, BaseModel, ImplicitModel<TypeTag>); -//! The finite volume element geometry providing iterators over scvs and scv faces -SET_TYPE_PROP(ImplicitBase, FVElementGeometry, Dumux::FVElementGeometry<TypeTag>); - //! The volume variable class, to be overloaded by the model SET_TYPE_PROP(ImplicitBase, VolumeVariables, ImplicitVolumeVariables<TypeTag>); @@ -167,7 +163,7 @@ SET_BOOL_PROP(ImplicitBase, ImplicitEnableJacobianRecycling, false); SET_BOOL_PROP(ImplicitBase, ImplicitEnablePartialReassemble, false); //! We do not store the FVGeometry by default -SET_BOOL_PROP(ImplicitBase, EnableGlobalFVElementGeometryCache, false); +SET_BOOL_PROP(ImplicitBase, EnableGlobalFVGeometryCache, false); //! We do not store the volume variables by default SET_BOOL_PROP(ImplicitBase, EnableGlobalVolumeVariablesCache, false); diff --git a/dumux/porousmediumflow/1p/implicit/model.hh b/dumux/porousmediumflow/1p/implicit/model.hh index 32cbdb2ebe75673526392457b0b631d65888a8e1..f0431f462395e00304d0dbb2a7e490b70ffbd436 100644 --- a/dumux/porousmediumflow/1p/implicit/model.hh +++ b/dumux/porousmediumflow/1p/implicit/model.hh @@ -93,18 +93,21 @@ public: int eIdx = this->elementMapper().index(element); (*rank)[eIdx] = this->gridView_().comm().rank(); - // make sure FVElementGeometry and the volume variables are bound to the element - this->fvGeometries_().bindElement(element); - this->curVolVars_().bindElement(element); + // get the local fv geometry + auto fvGeometry = localView(this->globalFvGeometry()); + fvGeometry.bindElement(element); + this->curVolVars_().bindElement(element, fvGeometry); - const auto& fvGeometry = this->fvGeometries(element); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { const auto& spatialParams = this->problem_().spatialParams(); auto dofIdxGlobal = scv.dofIndex(); (*p)[dofIdxGlobal] = this->curVolVars(scv).pressure(); } + + // velocity output + //velocityOutput.calculateVelocity(*velocity, elemVolVars, fvGeometry, element, /*phaseIdx=*/0); } writer.attachDofData(*p, "p", isBox); diff --git a/dumux/porousmediumflow/2p/implicit/model.hh b/dumux/porousmediumflow/2p/implicit/model.hh index f463222bf0cad0922a09b0e3a919ea0c524a3d2f..068d2bc2df15f8f12efac6a5b1f9d5742b8a0ede 100644 --- a/dumux/porousmediumflow/2p/implicit/model.hh +++ b/dumux/porousmediumflow/2p/implicit/model.hh @@ -158,11 +158,12 @@ public: (*rank)[eIdx] = this->gridView_().comm().rank(); // make sure FVElementGeometry & vol vars are bound to the element - this->fvGeometries_().bindElement(element); - this->curVolVars_().bindElement(element); + auto fvGeometry = localView(this->globalFvGeometry()); + fvGeometry.bind(element); - const auto& fvGeometry = this->fvGeometries(element); - for (const auto& scv : scvs(fvGeometry)) + this->curVolVars_().bindElement(element, fvGeometry); + + for (auto&& scv : scvs(fvGeometry)) { auto dofIdxGlobal = scv.dofIndex(); const auto& volVars = this->curVolVars(scv); diff --git a/dumux/porousmediumflow/3p/implicit/model.hh b/dumux/porousmediumflow/3p/implicit/model.hh index 90bbff0c6c86d8f9ed0312317efb4b5b367f70e9..1e42005229172d25294a326fd8bb5cbca8ad94f6 100644 --- a/dumux/porousmediumflow/3p/implicit/model.hh +++ b/dumux/porousmediumflow/3p/implicit/model.hh @@ -144,11 +144,12 @@ public: for (const auto& scv : fvGeometry.scvs()) { // make sure FVElementGeometry & vol vars are bound to the element - this->fvGeometries_().bindElement(element); - this->curVolVars_().bindElement(element); + auto fvGeometry = localView(this->globalFvGeometry()); + fvGeometry.bindElement(element); - const auto& fvGeometry = this->fvGeometries(element); - for (const auto& scv : scvs(fvGeometry)) + this->curVolVars_().bindElement(element, fvGeometry); + + for (auto&& scv : scvs(fvGeometry)) { auto eIdx = scv.elementIndex(); auto dofIdxGlobal = scv.dofIndex(); diff --git a/dumux/porousmediumflow/3p3c/implicit/localresidual.hh b/dumux/porousmediumflow/3p3c/implicit/localresidual.hh index 9f6c94b9c208d590cf3497fd0379a8386d965e47..2a726cdc787503bc8c40db21ba7fe637d9249664 100644 --- a/dumux/porousmediumflow/3p3c/implicit/localresidual.hh +++ b/dumux/porousmediumflow/3p3c/implicit/localresidual.hh @@ -49,6 +49,10 @@ class ThreePThreeCLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Element = typename GridView::template Codim<0>::Entity; enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases), @@ -116,10 +120,13 @@ public: * \param onBoundary A boolean variable to specify whether the flux variables * are calculated for interior SCV faces or boundary faces, default=false */ - PrimaryVariables computeFlux(const SubControlVolumeFace& scvFace) + PrimaryVariables computeFlux(const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvf, + const BoundaryTypes& bcTypes) { FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(asImp_()->problem_(), this->element_(), scvFace); + fluxVars.initAndComputeFluxes(this->problem(), element, fvGeometry, scvf); // get upwind weights into local scope auto massWeight = massWeight_; diff --git a/dumux/porousmediumflow/3p3c/implicit/model.hh b/dumux/porousmediumflow/3p3c/implicit/model.hh index 514460534e83557f5f4a4b221ba64dc0f065af3f..1f6a00d18b568ceb971dfdddde8de0c7d0bcdb8a 100644 --- a/dumux/porousmediumflow/3p3c/implicit/model.hh +++ b/dumux/porousmediumflow/3p3c/implicit/model.hh @@ -160,11 +160,12 @@ public: for (const auto& element : elements(this->problem_().gridView())) { // make sure FVElementGeometry & vol vars are bound to the element - this->fvGeometries_().bindElement(element); - this->curVolVars_().bindElement(element); + auto fvGeometry = localView(this->globalFvGeometry()); + fvGeometry.bindElement(element); - const auto& fvGeometry = this->fvGeometries(element); - for (const auto& scv : scvs(fvGeometry)) + this->curVolVars_().bindElement(element, fvGeometry); + + for (auto&& scv : scvs(fvGeometry)) { auto dofIdxGlobal = scv.dofIndex(); if (priVarSwitch_().wasSwitched(dofIdxGlobal)) @@ -302,11 +303,12 @@ public: (*rank)[eIdx] = this->gridView_().comm().rank(); // make sure FVElementGeometry & vol vars are bound to the element - this->fvGeometries_().bindElement(element); - this->curVolVars_().bindElement(element); + auto fvGeometry = localView(this->globalFvGeometry()); + fvGeometry.bindElement(element); + + this->curVolVars_().bindElement(element, fvGeometry); - const auto& fvGeometry = this->fvGeometries(element); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { const auto& volVars = this->curVolVars(scv); int dofIdxGlobal = scv.dofIndex(); diff --git a/dumux/porousmediumflow/compositional/primaryvariableswitch.hh b/dumux/porousmediumflow/compositional/primaryvariableswitch.hh index 2ddd9534c0b89e50e1358bfc910ea1d60bc6b9b8..941e76309767c242df990ccb20911af703c60f93 100644 --- a/dumux/porousmediumflow/compositional/primaryvariableswitch.hh +++ b/dumux/porousmediumflow/compositional/primaryvariableswitch.hh @@ -58,10 +58,10 @@ public: for (const auto& element : elements(problem.gridView())) { // make sure FVElementGeometry is bound to the element - problem.model().fvGeometries_().bindElement(element); + auto fvGeometry = localView(problem.model().globalFvGeometry()); + fvGeometry.bindElement(element); - const auto& fvGeometry = problem.model().fvGeometries(element); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { auto dofIdxGlobal = scv.dofIndex(); phasePresence_[dofIdxGlobal] = problem.initialPhasePresence(scv); @@ -124,11 +124,12 @@ public: for (const auto& element : elements(problem.gridView())) { // make sure FVElementGeometry is bound to the element - problem.model().fvGeometries_().bindElement(element); - volVarsVector.bindElement(element); + auto fvGeometry = localView(problem.model().globalFvGeometry()); + fvGeometry.bindElement(element); - const auto& fvGeometry = problem.model().fvGeometries(element); - for (const auto& scv : scvs(fvGeometry)) + volVarsVector.bindElement(element, fvGeometry); + + for (auto&& scv : scvs(fvGeometry)) { auto dofIdxGlobal = scv.dofIndex(); if (!visited_[dofIdxGlobal]) diff --git a/dumux/porousmediumflow/immiscible/localresidual.hh b/dumux/porousmediumflow/immiscible/localresidual.hh index ee999d5aaedbaf090add9ff343cde9738be2a992..c2fdf8a451fa7691c82fcf57d9891ee97536c7d1 100644 --- a/dumux/porousmediumflow/immiscible/localresidual.hh +++ b/dumux/porousmediumflow/immiscible/localresidual.hh @@ -38,14 +38,18 @@ class ImmiscibleLocalResidual : public GET_PROP_TYPE(TypeTag, BaseLocalResidual) { typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables; - typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume; - typedef typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace) SubControlVolumeFace; - - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables); + using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); + using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume); + using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); + using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes); + using GridView = typename GET_PROP_TYPE(TypeTag, GridView); + using Element = typename GridView::template Codim<0>::Entity; + + using Indices = typename GET_PROP_TYPE(TypeTag, Indices); // first index for the mass balance enum { conti0EqIdx = Indices::conti0EqIdx }; @@ -95,10 +99,16 @@ public: * \brief Evaluate the mass flux over a face of a sub control volume * \param scvf The sub control volume face to compute the flux on */ - PrimaryVariables computeFlux(const SubControlVolumeFace& scvf) + PrimaryVariables computeFlux(const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvf, + const BoundaryTypes& bcTypes) { FluxVariables fluxVars; - fluxVars.initAndComputeFluxes(asImp_()->problem_(), this->element_(), scvf); + fluxVars.initAndComputeFluxes(this->problem(), + element, + fvGeometry, + scvf); // copy weight to local scope for use in lambda expression auto w = upwindWeight_; @@ -114,7 +124,6 @@ public: auto eqIdx = conti0EqIdx + phaseIdx; flux[eqIdx] = fluxVars.advectiveFlux(phaseIdx, upwindRule); } - return flux; } diff --git a/dumux/porousmediumflow/implicit/fluxvariables.hh b/dumux/porousmediumflow/implicit/fluxvariables.hh index a528cd9872120c7b479e97c192de8befafdb2fbd..4eb29b8ad8f7f237152c150fd037ff296cb8d96a 100644 --- a/dumux/porousmediumflow/implicit/fluxvariables.hh +++ b/dumux/porousmediumflow/implicit/fluxvariables.hh @@ -56,6 +56,7 @@ class PorousMediumFluxVariables<TypeTag, true, false, false> : public FluxVariab using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); using Stencil = std::vector<IndexType>; using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables); @@ -69,17 +70,22 @@ public: void initAndComputeFluxes(const Problem& problem, const Element& element, + const FVElementGeometry& fvGeometry, const SubControlVolumeFace &scvFace) { - ParentType::init(problem, element, scvFace); + ParentType::init(problem, element, fvGeometry, scvFace); } template<typename FunctionType> - Scalar advectiveFlux(const int phaseIdx, const FunctionType upwindFunction) + Scalar advectiveFlux(const int phaseIdx, const FunctionType& upwindFunction) { - Scalar flux = AdvectionType::flux(this->problem(), this->element(), this->scvFace(), phaseIdx); + Scalar flux = AdvectionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->scvFace(), + phaseIdx); - const auto& insideScv = this->problem().model().fvGeometries().subControlVolume(this->scvFace().insideScvIdx()); + const auto& insideScv = this->fvGeometry().scv(this->scvFace().insideScvIdx()); const auto& insideVolVars = this->problem().model().curVolVars(insideScv); const auto& outsideVolVars = this->problem().model().curVolVars(this->scvFace().outsideScvIdx()); @@ -89,8 +95,11 @@ public: return flux*upwindFunction(insideVolVars, outsideVolVars); } - Stencil computeStencil(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace) - { return AdvectionType::stencil(problem, element, scvFace); } + Stencil computeStencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) + { return AdvectionType::stencil(problem, element, fvGeometry, scvFace); } }; @@ -109,6 +118,7 @@ class PorousMediumFluxVariables<TypeTag, true, true, false> : public FluxVariabl using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); using MolecularDiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); enum { @@ -120,19 +130,23 @@ public: void initAndComputeFluxes(const Problem& problem, const Element& element, + const FVElementGeometry& fvGeometry, const SubControlVolumeFace &scvFace) { - ParentType::init(problem, element, scvFace); + ParentType::init(problem, element, fvGeometry, scvFace); for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - advectiveFluxes_[phaseIdx] = AdvectionType::flux(problem, element, scvFace, phaseIdx); + advectiveFluxes_[phaseIdx] = AdvectionType::flux(problem, element, fvGeometry, scvFace, phaseIdx); } - Stencil computeStencil(const Problem& problem, const Element& element, const SubControlVolumeFace& scvFace) + Stencil computeStencil(const Problem& problem, + const Element& element, + const FVElementGeometry& fvGeometry, + const SubControlVolumeFace& scvFace) { // unifiy advective and diffusive stencil - Stencil stencil = AdvectionType::stencil(problem, element, scvFace); - Stencil diffusionStencil = MolecularDiffusionType::stencil(problem, element, scvFace); + Stencil stencil = AdvectionType::stencil(problem, element, fvGeometry, scvFace); + Stencil diffusionStencil = MolecularDiffusionType::stencil(problem, element, fvGeometry, scvFace); stencil.insert(stencil.end(), diffusionStencil.begin(), diffusionStencil.end()); std::sort(stencil.begin(), stencil.end()); @@ -142,7 +156,7 @@ public: } template<typename FunctionType> - Scalar advectiveFlux(const int phaseIdx, const FunctionType upwindFunction) + Scalar advectiveFlux(const int phaseIdx, const FunctionType& upwindFunction) { const auto& insideVolVars = this->problem().model().curVolVars(this->scvFace().insideScvIdx()); const auto& outsideVolVars = this->problem().model().curVolVars(this->scvFace().outsideScvIdx()); @@ -155,7 +169,11 @@ public: Scalar molecularDiffusionFlux(const int phaseIdx, const int compIdx) { - Scalar flux = MolecularDiffusionType::flux(this->problem(), this->element(), this->scvFace(), phaseIdx, compIdx); + Scalar flux = MolecularDiffusionType::flux(this->problem(), + this->element(), + this->fvGeometry(), + this->scvFace(), + phaseIdx, compIdx); return flux; } diff --git a/dumux/porousmediumflow/implicit/fluxvariablescache.hh b/dumux/porousmediumflow/implicit/fluxvariablescache.hh index 3bf64405eed1b750f9d905c1a3a7d5b22146db50..73c307b3915d86a3e6004320bb9fc969128d90db 100644 --- a/dumux/porousmediumflow/implicit/fluxvariablescache.hh +++ b/dumux/porousmediumflow/implicit/fluxvariablescache.hh @@ -45,6 +45,7 @@ class PorousMediumFluxVariablesCache<TypeTag, typename std::enable_if<GET_PROP_V using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); using Element = typename GridView::template Codim<0>::Entity; @@ -52,30 +53,30 @@ class PorousMediumFluxVariablesCache<TypeTag, typename std::enable_if<GET_PROP_V using Stencil = std::vector<IndexType>; using TransmissibilityVector = std::vector<IndexType>; - typedef typename GridView::ctype CoordScalar; + using CoordScalar = typename GridView::ctype; static const int dim = GridView::dimension; - typedef Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1> FeCache; - typedef typename FeCache::FiniteElementType::Traits::LocalBasisType FeLocalBasis; - typedef typename FeLocalBasis::Traits::JacobianType ShapeJacobian; - typedef typename Dune::FieldVector<Scalar, 1> ShapeValue; - typedef typename Element::Geometry::JacobianInverseTransposed JacobianInverseTransposed; + + using FeCache = Dune::PQkLocalFiniteElementCache<CoordScalar, Scalar, dim, 1>; + using FeLocalBasis = typename FeCache::FiniteElementType::Traits::LocalBasisType; + using ShapeJacobian = typename FeLocalBasis::Traits::JacobianType; + using ShapeValue = typename Dune::FieldVector<Scalar, 1>; + using JacobianInverseTransposed = typename Element::Geometry::JacobianInverseTransposed; public: // stores required data for the flux calculation struct FaceData { - std::vector<ShapeJacobian> localJacobian; - std::vector<ShapeValue> shapeValues; + std::vector<ShapeJacobian> shapeJacobian; + std::vector<ShapeValue> shapeValue; JacobianInverseTransposed jacInvT; }; void update(const Problem& problem, const Element& element, - const typename Element::Geometry& geometry, - const FeLocalBasis& localBasis, + const FVElementGeometry& fvGeometry, const SubControlVolumeFace &scvFace) { - faceData_ = AdvectionType::calculateFaceData(problem, element, geometry, localBasis, scvFace); + faceData_ = AdvectionType::calculateFaceData(problem, element, fvGeometry, scvFace); // The stencil info is obsolete for the box method. // It is here for compatibility with cc methods @@ -103,6 +104,7 @@ class PorousMediumFluxVariablesCache<TypeTag, typename std::enable_if<GET_PROP_V using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables); + using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry); using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace); using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); using Element = typename GridView::template Codim<0>::Entity; @@ -112,11 +114,12 @@ class PorousMediumFluxVariablesCache<TypeTag, typename std::enable_if<GET_PROP_V public: void update(const Problem& problem, const Element& element, + const FVElementGeometry& fvGeometry, const SubControlVolumeFace &scvFace) { FluxVariables fluxVars; - stencil_ = fluxVars.computeStencil(problem, element, scvFace); - tij_ = AdvectionType::calculateTransmissibilities(problem, element, scvFace); + stencil_ = fluxVars.computeStencil(problem, element, fvGeometry, scvFace); + tij_ = AdvectionType::calculateTransmissibilities(problem, element, fvGeometry, scvFace); } const Stencil& stencil() const diff --git a/test/geomechanics/elastic/elasticmatrixproblem.hh b/test/geomechanics/elastic/elasticmatrixproblem.hh index f980d9646670e541b23e682f830207e74d07c7ff..612599adacde51b4c874ba96f5e7101975854405 100644 --- a/test/geomechanics/elastic/elasticmatrixproblem.hh +++ b/test/geomechanics/elastic/elasticmatrixproblem.hh @@ -189,7 +189,7 @@ public: PrimaryVariables values(0.0); // inside scv - const auto& scv = this->model().fvGeometries().subControlVolume(scvFace.insideScvIdx()); + auto&& scv = this->model().fvGeometries().subControlVolume(scvFace.insideScvIdx()); // get Lame parameters Scalar lambda = this->spatialParams().lameParams(element, scv)[0]; diff --git a/test/implicit/test_fvelementgeometry.cc b/test/implicit/test_fvelementgeometry.cc index d3e35162c3e4532378b9e3386a819132d2750aff..ab4e30f4e0367c66b979db651a5c104b6fc1accb 100644 --- a/test/implicit/test_fvelementgeometry.cc +++ b/test/implicit/test_fvelementgeometry.cc @@ -32,7 +32,7 @@ #include <dune/grid/common/mcmgmapper.hh> #include <dumux/implicit/cellcentered/tpfa/properties.hh> -#include <dumux/implicit/cellcentered/tpfa/fvelementgeometryvector.hh> +#include <dumux/implicit/cellcentered/tpfa/globalfvgeometry.hh> #include <dumux/implicit/fvelementgeometry.hh> #include <dumux/implicit/subcontrolvolume.hh> #include <dumux/implicit/subcontrolvolumeface.hh> @@ -119,7 +119,7 @@ int main (int argc, char *argv[]) try if(0 != testForwardIterator(range.begin(), range.end(), op)) DUNE_THROW(Dune::Exception, "Iterator does not fulfill the forward iterator concept"); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { std::cout << "-- scv center at: " << scv.center() << std::endl; } @@ -129,7 +129,7 @@ int main (int argc, char *argv[]) try if(0 != testForwardIterator(range2.begin(), range2.end(), op2)) DUNE_THROW(Dune::Exception, "Iterator does not fulfill the forward iterator concept"); - for (const auto& scvf : scvfs(fvGeometry)) + for (auto&& scvf : scvfs(fvGeometry)) { std::cout << "-- scvf center at: " << scvf.center(); if (scvf.boundary()) std::cout << " (on boundary)."; diff --git a/test/porousmediumflow/3p3c/implicit/infiltrationproblem.hh b/test/porousmediumflow/3p3c/implicit/infiltrationproblem.hh index c0773b0b9146de9b2860c918a158bfd11fae851c..92fb753e7ed91ba28f68be7bd365ad49beafe081 100644 --- a/test/porousmediumflow/3p3c/implicit/infiltrationproblem.hh +++ b/test/porousmediumflow/3p3c/implicit/infiltrationproblem.hh @@ -344,10 +344,10 @@ public: for (const auto& element : elements(this->gridView())) { // make sure the FVElementGeometry is bound to the element - this->model().fvGeometries_().bindElement(element); - const auto& fvGeometry = this->model().fvGeometries(element); + auto fvGeometry = localView(this->model().globalFvGeometry()); + fvGeometry.bindElement(element); - for (const auto& scv : scvs(fvGeometry)) + for (auto&& scv : scvs(fvGeometry)) { auto dofIdxGlobal = scv.dofIndex(); (*Kxx)[dofIdxGlobal] = this->spatialParams().intrinsicPermeability(scv);