diff --git a/dumux/common/properties.hh b/dumux/common/properties.hh index a0ccd5ffdf1d92ddba88b6463f44cc068ed68ed0..3ac71613f4bcfec3db3bc0f8000e45c5ddbb5482 100644 --- a/dumux/common/properties.hh +++ b/dumux/common/properties.hh @@ -91,12 +91,10 @@ NEW_PROP_TAG(ElementFluxVariablesCache); //!< A local vector of flux v NEW_PROP_TAG(GridFluxVariablesCache); //!< The global vector of flux variable containers NEW_PROP_TAG(EnableGridFluxVariablesCache); //!< specifies if data on flux vars should be saved (faster, but more memory consuming) NEW_PROP_TAG(GridVariables); //!< The grid variables object managing variable data on the grid (volvars/fluxvars cache) -NEW_PROP_TAG(MaxNumNeighborsPerScvf); //!< The maximum number of neighboring elements allowed per scvf (for static memory allocation) ///////////////////////////////////////////////////////////////// // Additional properties used by the cell-centered mpfa schemes: ///////////////////////////////////////////////////////////////// -NEW_PROP_TAG(MpfaHelper); //!< A Helper class depending on the mpfa method and grid dimension NEW_PROP_TAG(PrimaryInteractionVolume); //!< The primary interaction volume type NEW_PROP_TAG(SecondaryInteractionVolume); //!< The secondary interaction volume type used e.g. on the boundaries NEW_PROP_TAG(DualGridNodalIndexSet); //!< The type used for the nodal index sets of the dual grid diff --git a/dumux/discretization/cellcentered/mpfa/darcyslaw.hh b/dumux/discretization/cellcentered/mpfa/darcyslaw.hh index 60e525c13d9666bbc8ed05fc5c1e43ace2a653ac..86e2e5502fbe5f558d3c765216e2c3ed6f28b015 100644 --- a/dumux/discretization/cellcentered/mpfa/darcyslaw.hh +++ b/dumux/discretization/cellcentered/mpfa/darcyslaw.hh @@ -32,8 +32,6 @@ #include <dumux/common/parameters.hh> #include <dumux/discretization/methods.hh> -#include <dumux/discretization/methods.hh> - namespace Dumux { //! forward declaration of the method-specific implementation @@ -52,7 +50,8 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using Element = typename GridView::template Codim<0>::Entity; - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView; + using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry); + using FVElementGeometry = typename FVGridGeometry::LocalView; using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); @@ -95,30 +94,22 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); using DualGridNodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet); - using Stencil = typename DualGridNodalIndexSet::GridStencilType; + using Stencil = typename DualGridNodalIndexSet::NodalGridStencilType; - using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); + using MpfaHelper = typename FVGridGeometry::MpfaHelper; static constexpr bool considerSecondaryIVs = MpfaHelper::considerSecondaryIVs(); - // In the current implementation of the flux variables cache we cannot make a - // disctinction between dynamic (e.g. mpfa-o unstructured) and static (e.g.mpfa-l) - // matrix and vector types, as currently the cache class can only be templated - // by a type tag (and there can only be one). Currently, pointers to both the - // primary and secondary iv data is stored. Before accessing it has to be checked - // whether or not the scvf is embedded in a secondary interaction volume. using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); using PrimaryIvLocalFaceData = typename PrimaryInteractionVolume::Traits::LocalFaceData; - using PrimaryIvDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle; - using PrimaryIvVector = typename PrimaryInteractionVolume::Traits::Vector; - using PrimaryIvMatrix = typename PrimaryInteractionVolume::Traits::Matrix; - using PrimaryIvTij = typename PrimaryIvMatrix::row_type; + using PrimaryIvDataHandle = typename ElementFluxVariablesCache::PrimaryIvDataHandle; + using PrimaryIvCellVector = typename PrimaryInteractionVolume::Traits::MatVecTraits::CellVector; + using PrimaryIvTij = typename PrimaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type; using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); using SecondaryIvLocalFaceData = typename SecondaryInteractionVolume::Traits::LocalFaceData; - using SecondaryIvDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle; - using SecondaryIvVector = typename SecondaryInteractionVolume::Traits::Vector; - using SecondaryIvMatrix = typename SecondaryInteractionVolume::Traits::Matrix; - using SecondaryIvTij = typename SecondaryIvMatrix::row_type; + using SecondaryIvDataHandle = typename ElementFluxVariablesCache::SecondaryIvDataHandle; + using SecondaryIvCellVector = typename SecondaryInteractionVolume::Traits::MatVecTraits::CellVector; + using SecondaryIvTij = typename SecondaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type; public: // export the filler type @@ -238,11 +229,11 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> //! Coefficients for the cell (& Dirichlet) unknowns in flux expressions (secondary type) const SecondaryIvTij& advectionTijSecondaryIv() const { return *secondaryTij_; } - //! The cell (& Dirichlet) pressures within this interaction volume (primary type) - const PrimaryIvVector& pressuresPrimaryIv(unsigned int phaseIdx) const { return *primaryPj_[phaseIdx]; } + //! The cell (& maybe Dirichlet) pressures within this interaction volume (primary type) + const PrimaryIvCellVector& pressuresPrimaryIv(unsigned int phaseIdx) const { return *primaryPj_[phaseIdx]; } - //! The cell (& Dirichlet) pressures within this interaction volume (secondary type) - const SecondaryIvVector& pressuresSecondaryIv(unsigned int phaseIdx) const { return *secondaryPj_[phaseIdx]; } + //! The cell (& maybe Dirichlet) pressures within this interaction volume (secondary type) + const SecondaryIvCellVector& pressuresSecondaryIv(unsigned int phaseIdx) const { return *secondaryPj_[phaseIdx]; } //! The gravitational acceleration for a phase on this scvf Scalar gravity(unsigned int phaseIdx) const { return g_[phaseIdx]; } @@ -264,8 +255,8 @@ class DarcysLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> const SecondaryIvTij* secondaryTij_; //! The interaction-volume wide phase pressures pj - std::array<const PrimaryIvVector*, numPhases> primaryPj_; - std::array<const SecondaryIvVector*, numPhases> secondaryPj_; + std::array<const PrimaryIvCellVector*, numPhases> primaryPj_; + std::array<const SecondaryIvCellVector*, numPhases> secondaryPj_; //! Gravitational flux contribution on this face std::array< Scalar, numPhases > g_; diff --git a/dumux/discretization/cellcentered/mpfa/dualgridindexset.hh b/dumux/discretization/cellcentered/mpfa/dualgridindexset.hh index 2288f3b49d00aa2d83089d6d30224ae23928162d..59680aded654242d794f817ba0afad5c9138db51 100644 --- a/dumux/discretization/cellcentered/mpfa/dualgridindexset.hh +++ b/dumux/discretization/cellcentered/mpfa/dualgridindexset.hh @@ -38,40 +38,32 @@ namespace Dumux * \brief Nodal index set for mpfa schemes, constructed * around grid vertices. * - * \tparam GI The type used for indices on the grid - * \tparam LI The type used for indexing in interaction volumes - * \tparam dim The dimension of the grid - * \tparam maxE The maximum admissible number of elements around vertices. - * \tparam maxB The maximum admissible number of branches on intersections. - * This is only to be specified for network grids and defaults to 1 - * for normal grids. + * \tparam T The traits class to be used */ -template< class GI, class LI, int dim, int maxE, int maxB = 2 > +template< class T > class CCMpfaDualGridNodalIndexSet { - using DimIndexVector = Dune::ReservedVector<GI, dim>; + using LI = typename T::LocalIndexType; + using GI = typename T::GridIndexType; + + using DimLocalIndexVector = Dune::ReservedVector<LI, T::GridView::dimension>; + using ScvfIndicesInScvStorage = typename T::template NodalScvDataStorage< DimLocalIndexVector >; public: - //! Export the used index types - using GridIndexType = GI; - using LocalIndexType = LI; + //! Export the traits type + using Traits = T; - //! Export the specified maximum admissible sizes - static constexpr int dimension = dim; - static constexpr int maxBranches = maxB; - static constexpr int maxNumElementsAtNode = maxE*(maxBranches-1); - static constexpr int maxNumScvfsAtNode = maxNumElementsAtNode*dim; + //! Export the index types used + using LocalIndexType = LI; + using GridIndexType = GI; //! Export the stencil types used - using GridStencilType = Dune::ReservedVector<GridIndexType, maxNumElementsAtNode>; - using LocalStencilType = Dune::ReservedVector<LocalIndexType, maxNumElementsAtNode>; - - //! Export the type used for storing the global scvf indices at this node - using GridScvfStencilType = Dune::ReservedVector<GridIndexType, maxNumScvfsAtNode>; + using NodalGridStencilType = typename T::template NodalScvDataStorage< GI >; + using NodalLocalStencilType = typename T::template NodalScvDataStorage< LI >; + using NodalGridScvfStencilType = typename T::template NodalScvfDataStorage< GI >; //! Data structure to store the neighboring scv indices of an scvf (grid/local indices) - using ScvfNeighborIndexSet = Dune::ReservedVector<GridIndexType, maxBranches>; - using ScvfNeighborLocalIndexSet = Dune::ReservedVector<LocalIndexType, maxBranches>; + using ScvfNeighborLocalIndexSet = typename T::template ScvfNeighborDataStorage< LI >; //! Constructor CCMpfaDualGridNodalIndexSet() : numBoundaryScvfs_(0) {} @@ -80,49 +72,41 @@ public: template<typename SubControlVolumeFace> void insert(const SubControlVolumeFace& scvf) { - insert(scvf.boundary(), - scvf.index(), + insert(scvf.index(), scvf.insideScvIdx(), - scvf.outsideScvIndices()); + scvf.boundary()); } //! Inserts scvf data - template<typename OutsideGridIndexStorage> - void insert(const bool boundary, - const GridIndexType scvfIdx, + void insert(const GridIndexType scvfIdx, const GridIndexType insideScvIdx, - const OutsideGridIndexStorage& outsideScvIndices) + const bool boundary) { // this should always be called only once per scvf - assert(std::find(scvfIndices_.begin(), scvfIndices_.end(), scvfIdx ) == scvfIndices_.end() - && "scvf has already been inserted!"); + assert(std::count(scvfIndices_.begin(), scvfIndices_.end(), scvfIdx ) == 0 && "scvf already inserted!"); // the local index of the scvf data about to be inserted const LocalIndexType curScvfLocalIdx = scvfIndices_.size(); - // add grid scvf data - ScvfNeighborIndexSet scvIndices; - scvIndices.push_back(insideScvIdx); - for (const auto& outsideIdx : outsideScvIndices) - scvIndices.push_back(outsideIdx); - // if scvf is on boundary, increase counter - if (boundary) - numBoundaryScvfs_++; + if (boundary) numBoundaryScvfs_++; // insert data on the new scv scvfIndices_.push_back(scvfIdx); scvfIsOnBoundary_.push_back(boundary); - scvfNeighborScvIndices_.push_back(scvIndices); - // if entry for the inside scv exists, append scvf local index, create otherwise + // if entry for the inside scv exists append data, create otherwise auto it = std::find( scvIndices_.begin(), scvIndices_.end(), insideScvIdx ); if (it != scvIndices_.end()) - localScvfIndicesInScv_[ std::distance(scvIndices_.begin(), it) ].push_back(curScvfLocalIdx); + { + const auto scvIdxLocal = std::distance(scvIndices_.begin(), it); + scvfInsideScvIndices_.push_back(scvIdxLocal); + localScvfIndicesInScv_[scvIdxLocal].push_back(curScvfLocalIdx); + } else { - localScvfIndicesInScv_.push_back({}); - localScvfIndicesInScv_.back().push_back(curScvfLocalIdx); + scvfInsideScvIndices_.push_back(scvIndices_.size()); + localScvfIndicesInScv_.push_back({curScvfLocalIdx}); scvIndices_.push_back(insideScvIdx); } } @@ -136,49 +120,64 @@ public: //! returns the number of boundary scvfs around the node std::size_t numBoundaryScvfs() const { return numBoundaryScvfs_; } - //! returns the global scv indices connected to this dual grid node - const GridStencilType& globalScvIndices() const { return scvIndices_; } + //! returns the grid scv indices connected to this dual grid node + const NodalGridStencilType& globalScvIndices() const { return scvIndices_; } - //! returns the global scvf indices connected to this dual grid node - const GridScvfStencilType& globalScvfIndices() const { return scvfIndices_; } + //! returns the grid scvf indices connected to this dual grid node + const NodalGridScvfStencilType& globalScvfIndices() const { return scvfIndices_; } //! returns whether or not the i-th scvf is on a domain boundary - bool scvfIsOnBoundary(unsigned int i) const { return scvfIsOnBoundary_[i]; } + bool scvfIsOnBoundary(unsigned int i) const + { + assert(i < numScvfs()); + return scvfIsOnBoundary_[i]; + } - //! returns the global scv idx of the i-th scv - GridIndexType scvIdxGlobal(unsigned int i) const { return scvIndices_[i]; } + //! returns the grid scv idx of the i-th scv + GridIndexType scvIdxGlobal(unsigned int i) const + { + assert(i < numScvs()); + return scvIndices_[i]; + } //! returns the index of the i-th scvf - GridIndexType scvfIdxGlobal(unsigned int i) const { return scvfIndices_[i]; } + GridIndexType scvfIdxGlobal(unsigned int i) const + { + assert(i < numScvfs()); + return scvfIndices_[i]; + } - //! returns the global index of the j-th scvf embedded in the i-th scv + //! returns the grid index of the j-th scvf embedded in the i-th scv GridIndexType scvfIdxGlobal(unsigned int i, unsigned int j) const { - assert(j < dim); // only dim faces can be embedded in an scv + assert(i < numScvs()); + assert(j < localScvfIndicesInScv_[i].size()); return scvfIndices_[ localScvfIndicesInScv_[i][j] ]; } //! returns the node-local index of the j-th scvf embedded in the i-th scv LocalIndexType scvfIdxLocal(unsigned int i, unsigned int j) const { - assert(j < dim); // only dim faces can be embedded in an scv + assert(i < numScvs()); + assert(j < localScvfIndicesInScv_[i].size()); return localScvfIndicesInScv_[i][j]; } - //! returns the indices of the neighboring scvs of the i-th scvf - const ScvfNeighborIndexSet& neighboringScvIndices(unsigned int i) const - { return scvfNeighborScvIndices_[i]; } + //! returns the node-local index of the inside scv of the i-th scvf + LocalIndexType insideScvIdxLocal(unsigned int i) const + { + assert(i < numScvfs()); + return scvfInsideScvIndices_[i]; + } private: - GridStencilType scvIndices_; //!< The indices of the scvs around a dual grid node - Dune::ReservedVector<DimIndexVector, maxNumElementsAtNode> localScvfIndicesInScv_; //!< Maps to each scv a list of scvf indices embedded in it - - GridScvfStencilType scvfIndices_; //!< the indices of the scvfs around a dual grid node - std::size_t numBoundaryScvfs_; //!< stores how many boundary scvfs are embedded in this dual grid node - Dune::ReservedVector<bool, maxNumScvfsAtNode> scvfIsOnBoundary_; //!< Maps to each scvf a boolean to indicate if it is on the boundary + NodalGridStencilType scvIndices_; //!< The indices of the scvs around a dual grid node + ScvfIndicesInScvStorage localScvfIndicesInScv_; //!< Maps to each scv a list of scvf indices embedded in it - //! The neighboring scvs for the scvfs (order: 0 - inside, 1..n - outside) - Dune::ReservedVector<ScvfNeighborIndexSet, maxNumScvfsAtNode> scvfNeighborScvIndices_; + std::size_t numBoundaryScvfs_; //!< stores how many boundary scvfs are embedded in this dual grid node + NodalGridScvfStencilType scvfIndices_; //!< the indices of the scvfs around a dual grid node + typename T::template NodalScvfDataStorage< bool > scvfIsOnBoundary_; //!< Maps to each scvf a boolean to indicate if it is on the boundary + typename T::template NodalScvfDataStorage< LI > scvfInsideScvIndices_; //!< The inside local scv index for each scvf }; /*! @@ -199,7 +198,7 @@ public: //! Constructor taking a grid view template< class GridView > - CCMpfaDualGridIndexSet(const GridView& gridView) : nodalIndexSets_(gridView.size(NodalIndexSet::dimension)) {} + CCMpfaDualGridIndexSet(const GridView& gridView) : nodalIndexSets_(gridView.size(GridView::dimension)) {} //! Access with an scvf template< class SubControlVolumeFace > diff --git a/dumux/discretization/cellcentered/mpfa/elementfluxvariablescache.hh b/dumux/discretization/cellcentered/mpfa/elementfluxvariablescache.hh index f7709fe7878e8e776b4cf20f3649e6b26d786864..f1b766a4f995a507c42a19ebc27b1b7fdb5327e6 100644 --- a/dumux/discretization/cellcentered/mpfa/elementfluxvariablescache.hh +++ b/dumux/discretization/cellcentered/mpfa/elementfluxvariablescache.hh @@ -29,6 +29,8 @@ #include <dumux/common/properties.hh> #include <dumux/common/parameters.hh> +#include <dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh> + #include "fluxvariablescachefiller.hh" #include "methods.hh" @@ -63,8 +65,11 @@ class CCMpfaElementFluxVariablesCache<TypeTag, true> using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using GridFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, GridFluxVariablesCache); - public: + //! export the data handle types used by the grid-wide cache + using PrimaryIvDataHandle = typename GridFluxVariablesCache::PrimaryIvDataHandle; + using SecondaryIvDataHandle = typename GridFluxVariablesCache::SecondaryIvDataHandle; + //! The constructor CCMpfaElementFluxVariablesCache(const GridFluxVariablesCache& global) : gridFluxVarsCachePtr_(&global) {} @@ -121,11 +126,26 @@ class CCMpfaElementFluxVariablesCache<TypeTag, false> using FluxVariablesCacheFiller = CCMpfaFluxVariablesCacheFiller<TypeTag>; using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); - using PrimaryIvDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle; + using PrimaryMatVecTraits = typename PrimaryInteractionVolume::Traits::MatVecTraits; using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); - using SecondaryIvDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle; + using SecondaryMatVecTraits = typename SecondaryInteractionVolume::Traits::MatVecTraits; + + //! physics traits class to define the data handles + struct PhysicsTraits + { + static constexpr bool enableAdvection = GET_PROP_VALUE(TypeTag, EnableAdvection); + static constexpr bool enableMolecularDiffusion = GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion); + static constexpr bool enableHeatConduction = GET_PROP_VALUE(TypeTag, EnableEnergyBalance); + + static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); + static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); + }; public: + //! export the data handle types used + using PrimaryIvDataHandle = InteractionVolumeDataHandle< PrimaryMatVecTraits, PhysicsTraits >; + using SecondaryIvDataHandle = InteractionVolumeDataHandle< SecondaryMatVecTraits, PhysicsTraits >; + CCMpfaElementFluxVariablesCache(const GridFluxVariablesCache& global) : gridFluxVarsCachePtr_(&global) {} diff --git a/dumux/discretization/cellcentered/mpfa/fickslaw.hh b/dumux/discretization/cellcentered/mpfa/fickslaw.hh index ae3979d58deb66b2702ce536db2a6ae3cda9d59a..de03c053c1c5fa5bd584bc56afe2e7c71a5f74ce 100644 --- a/dumux/discretization/cellcentered/mpfa/fickslaw.hh +++ b/dumux/discretization/cellcentered/mpfa/fickslaw.hh @@ -46,7 +46,8 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using Element = typename GridView::template Codim<0>::Entity; - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView; + using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry); + using FVElementGeometry = typename FVGridGeometry::LocalView; using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem); using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); @@ -91,30 +92,22 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> class MpfaFicksLawCache { using DualGridNodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet); - using Stencil = typename DualGridNodalIndexSet::GridStencilType; + using Stencil = typename DualGridNodalIndexSet::NodalGridStencilType; - using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); + using MpfaHelper = typename FVGridGeometry::MpfaHelper; static constexpr bool considerSecondaryIVs = MpfaHelper::considerSecondaryIVs(); - // In the current implementation of the flux variables cache we cannot make a - // disctinction between dynamic (e.g. mpfa-o unstructured) and static (e.g.mpfa-l) - // matrix and vector types, as currently the cache class can only be templated - // by a type tag (and there can only be one). Currently, pointers to both the - // primary and secondary iv data is stored. Before accessing it has to be checked - // whether or not the scvf is embedded in a secondary interaction volume. using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); using PrimaryIvLocalFaceData = typename PrimaryInteractionVolume::Traits::LocalFaceData; - using PrimaryIvDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle; - using PrimaryIvVector = typename PrimaryInteractionVolume::Traits::Vector; - using PrimaryIvMatrix = typename PrimaryInteractionVolume::Traits::Matrix; - using PrimaryIvTij = typename PrimaryIvMatrix::row_type; + using PrimaryIvDataHandle = typename ElementFluxVariablesCache::PrimaryIvDataHandle; + using PrimaryIvCellVector = typename PrimaryInteractionVolume::Traits::MatVecTraits::CellVector; + using PrimaryIvTij = typename PrimaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type; using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); using SecondaryIvLocalFaceData = typename SecondaryInteractionVolume::Traits::LocalFaceData; - using SecondaryIvDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle; - using SecondaryIvVector = typename SecondaryInteractionVolume::Traits::Vector; - using SecondaryIvMatrix = typename SecondaryInteractionVolume::Traits::Matrix; - using SecondaryIvTij = typename SecondaryIvMatrix::row_type; + using SecondaryIvDataHandle = typename ElementFluxVariablesCache::SecondaryIvDataHandle; + using SecondaryIvCellVector = typename SecondaryInteractionVolume::Traits::MatVecTraits::CellVector; + using SecondaryIvTij = typename SecondaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type; static constexpr int dim = GridView::dimension; static constexpr int dimWorld = GridView::dimensionworld; @@ -198,12 +191,12 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> const SecondaryIvTij& diffusionTijSecondaryIv(unsigned int phaseIdx, unsigned int compIdx) const { return *secondaryTij_[phaseIdx][compIdx]; } - //! The cell (& Dirichlet) mole fractions within this interaction volume (primary type) - const PrimaryIvVector& moleFractionsPrimaryIv(unsigned int phaseIdx, unsigned int compIdx) const + //! The cell (& maybe Dirichlet) mole fractions within this interaction volume (primary type) + const PrimaryIvCellVector& moleFractionsPrimaryIv(unsigned int phaseIdx, unsigned int compIdx) const { return *primaryXj_[phaseIdx][compIdx]; } - //! The cell (& Dirichlet) mole fractions within this interaction volume (secondary type) - const SecondaryIvVector& moleFractionsSecondaryIv(unsigned int phaseIdx, unsigned int compIdx) const + //! The cell (& maybe Dirichlet) mole fractions within this interaction volume (secondary type) + const SecondaryIvCellVector& moleFractionsSecondaryIv(unsigned int phaseIdx, unsigned int compIdx) const { return *secondaryXj_[phaseIdx][compIdx]; } //! The stencils corresponding to the transmissibilities @@ -217,12 +210,12 @@ class FicksLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> std::array< std::array<const Stencil*, numComponents>, numPhases > stencil_; //! The transmissibilities such that f = Tij*xj - std::array< std::array<const PrimaryIvVector*, numComponents>, numPhases > primaryTij_; - std::array< std::array<const SecondaryIvVector*, numComponents>, numPhases > secondaryTij_; + std::array< std::array<const PrimaryIvCellVector*, numComponents>, numPhases > primaryTij_; + std::array< std::array<const SecondaryIvCellVector*, numComponents>, numPhases > secondaryTij_; //! The interaction-volume wide mole fractions xj - std::array< std::array<const PrimaryIvVector*, numComponents>, numPhases > primaryXj_; - std::array< std::array<const SecondaryIvVector*, numComponents>, numPhases > secondaryXj_; + std::array< std::array<const PrimaryIvCellVector*, numComponents>, numPhases > primaryXj_; + std::array< std::array<const SecondaryIvCellVector*, numComponents>, numPhases > secondaryXj_; }; public: diff --git a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh b/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh index 5a90cc053a209e2b0dd5f93f714733c626088d04..b2196d97c716c9657d12b30f28060eafc4d5ec85 100644 --- a/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh +++ b/dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh @@ -43,20 +43,22 @@ template<class TypeTag> class CCMpfaFluxVariablesCacheFiller { using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using Element = typename GridView::template Codim<0>::Entity; - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView; + using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry); + using FVElementGeometry = typename FVGridGeometry::LocalView; + using MpfaHelper = typename FVGridGeometry::MpfaHelper; using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); + using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); - using PrimaryDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle; + using PrimaryDataHandle = typename ElementFluxVariablesCache::PrimaryIvDataHandle; using PrimaryLocalFaceData = typename PrimaryInteractionVolume::Traits::LocalFaceData; using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); - using SecondaryDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle; + using SecondaryDataHandle = typename ElementFluxVariablesCache::SecondaryIvDataHandle; using SecondaryLocalFaceData = typename SecondaryInteractionVolume::Traits::LocalFaceData; static constexpr int dim = GridView::dimension; @@ -252,84 +254,8 @@ private: using AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType); using AdvectionFiller = typename AdvectionType::Cache::Filler; - static constexpr auto AdvectionMethod = AdvectionType::myDiscretizationMethod; - using LambdaFactory = TensorLambdaFactory<TypeTag, AdvectionMethod>; - - // skip the following if advection doesn't use mpfa - if (AdvectionMethod == DiscretizationMethods::CCMpfa) - { - // get instance of the interaction volume-local assembler - using IVTraits = typename InteractionVolume::Traits; - using IvLocalAssembler = InteractionVolumeAssembler< IVTraits, InteractionVolume::MpfaMethod >; - IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars()); - - // Use different assembly if gravity is enabled - static const bool enableGravity = getParamFromGroup<bool>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Problem.EnableGravity"); - - // Assemble T only if permeability is sol-dependent or if update is forced - if (forceUpdateAll || soldependentAdvection) - { - // distinguish between normal/surface grids (optimized away by compiler) - if (dim < dimWorld) - { - if (enableGravity) - localAssembler.assembleWithGravity( handle.advectionTout(), - handle.advectionT(), - handle.gravityOutside(), - handle.gravity(), - handle.advectionCA(), - handle.advectionA(), - iv, - LambdaFactory::getAdvectionLambda() ); - - else - localAssembler.assemble( handle.advectionTout(), - handle.advectionT(), - iv, - LambdaFactory::getAdvectionLambda() ); - } - - // normal grids - else - { - if (enableGravity) - localAssembler.assembleWithGravity( handle.advectionT(), - handle.gravity(), - handle.advectionCA(), - iv, - LambdaFactory::getAdvectionLambda() ); - else - localAssembler.assemble( handle.advectionT(), - iv, - LambdaFactory::getAdvectionLambda() ); - } - } - - // (maybe) only reassemble gravity vector - else if (enableGravity) - { - if (dim == dimWorld) - localAssembler.assembleGravity( handle.gravity(), - iv, - handle.advectionCA(), - LambdaFactory::getAdvectionLambda() ); - else - localAssembler.assembleGravity( handle.gravity(), - handle.gravityOutside(), - iv, - handle.advectionCA(), - handle.advectionA(), - LambdaFactory::getAdvectionLambda() ); - } - - // assemble pressure vectors - for (unsigned int pIdx = 0; pIdx < GET_PROP_VALUE(TypeTag, NumPhases); ++pIdx) - { - const auto& evv = &elemVolVars(); - auto getPressure = [&evv, pIdx] (auto volVarIdx) { return (evv->operator[](volVarIdx)).pressure(pIdx); }; - localAssembler.assemble(handle.pressures(pIdx), iv, getPressure); - } - } + // fill data in the handle + fillAdvectionHandle(iv, handle, forceUpdateAll); // fill advection caches for (unsigned int i = 0; i < iv.localFaceData().size(); ++i) @@ -384,51 +310,19 @@ private: using DiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType); using DiffusionFiller = typename DiffusionType::Cache::Filler; - static constexpr auto DiffusionMethod = DiffusionType::myDiscretizationMethod; - using LambdaFactory = TensorLambdaFactory<TypeTag, DiffusionMethod>; - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); - // get instance of the interaction volume-local assembler - using IVTraits = typename InteractionVolume::Traits; - using IvLocalAssembler = InteractionVolumeAssembler< IVTraits, InteractionVolume::MpfaMethod >; - IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars()); - for (unsigned int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { for (unsigned int compIdx = 0; compIdx < numComponents; ++compIdx) { - if (phaseIdx == compIdx) + using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem); + if (compIdx == FluidSystem::getMainComponent(phaseIdx)) continue; - // solve the local system subject to the diffusion tensor (if uses mpfa) - if (DiffusionMethod == DiscretizationMethods::CCMpfa) - { - // update the context in handle - handle.setPhaseIndex(phaseIdx); - handle.setComponentIndex(compIdx); - - // assemble T - if (forceUpdateAll || soldependentDiffusion) - { - if (dim < dimWorld) - localAssembler.assemble( handle.diffusionTout(), - handle.diffusionT(), - iv, - LambdaFactory::getDiffusionLambda(phaseIdx, compIdx) ); - else - localAssembler. assemble( handle.diffusionT(), - iv, - LambdaFactory::getDiffusionLambda(phaseIdx, compIdx) ); - } - - // assemble vector of mole fractions - const auto& evv = &elemVolVars(); - auto getMoleFraction = [&evv, phaseIdx, compIdx] (auto volVarIdx) - { return (evv->operator[](volVarIdx)).moleFraction(phaseIdx, compIdx); }; - localAssembler.assemble(handle.moleFractions(phaseIdx, compIdx), iv, getMoleFraction); - } + // fill data in the handle + fillDiffusionHandle(iv, handle, forceUpdateAll, phaseIdx, compIdx); // fill diffusion caches for (unsigned int i = 0; i < iv.localFaceData().size(); ++i) @@ -487,35 +381,8 @@ private: using HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType); using HeatConductionFiller = typename HeatConductionType::Cache::Filler; - static constexpr auto HeatConductionMethod = HeatConductionType::myDiscretizationMethod; - using LambdaFactory = TensorLambdaFactory<TypeTag, HeatConductionMethod>; - - // maybe solve the local system subject to fourier coefficient - if (HeatConductionMethod == DiscretizationMethods::CCMpfa) - { - // get instance of the interaction volume-local assembler - using IVTraits = typename InteractionVolume::Traits; - using IvLocalAssembler = InteractionVolumeAssembler< IVTraits, InteractionVolume::MpfaMethod >; - IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars()); - - if (forceUpdateAll || soldependentAdvection) - { - if (dim < dimWorld) - localAssembler.assemble( handle.heatConductionTout(), - handle.heatConductionT(), - iv, - LambdaFactory::getHeatConductionLambda() ); - else - localAssembler.assemble( handle.heatConductionT(), - iv, - LambdaFactory::getHeatConductionLambda() ); - } - - // assemble vector of temperatures - const auto& evv = &elemVolVars(); - auto getMoleFraction = [&evv] (auto volVarIdx) { return (evv->operator[](volVarIdx)).temperature(); }; - localAssembler.assemble(handle.temperatures(), iv, getMoleFraction); - } + // prepare data in handle + fillHeatConductionHandle(iv, handle, forceUpdateAll); // fill heat conduction caches for (unsigned int i = 0; i < iv.localFaceData().size(); ++i) @@ -556,6 +423,184 @@ private: bool forceUpdateAll = false) {} + //! prepares the quantities necessary for advective fluxes in the handle + template< class InteractionVolume, + class DataHandle, + class AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType), + typename std::enable_if_t<AdvectionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa, int> = 0 > + void fillAdvectionHandle(InteractionVolume& iv, DataHandle& handle, bool forceUpdateAll) + { + using LambdaFactory = TensorLambdaFactory<TypeTag, DiscretizationMethods::CCMpfa>; + + // get instance of the interaction volume-local assembler + static constexpr MpfaMethods M = InteractionVolume::MpfaMethod; + using IvLocalAssembler = InteractionVolumeAssembler< Problem, FVElementGeometry, ElementVolumeVariables, M >; + IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars()); + + // Use different assembly if gravity is enabled + static const bool enableGravity = getParamFromGroup<bool>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Problem.EnableGravity"); + + // Assemble T only if permeability is sol-dependent or if update is forced + if (forceUpdateAll || soldependentAdvection) + { + // distinguish between normal/surface grids (optimized away by compiler) + if (dim < dimWorld) + { + if (enableGravity) + localAssembler.assembleWithGravity( handle.advectionTout(), + handle.advectionT(), + handle.gravityOutside(), + handle.gravity(), + handle.advectionCA(), + handle.advectionA(), + iv, + LambdaFactory::getAdvectionLambda() ); + + else + localAssembler.assemble( handle.advectionTout(), + handle.advectionT(), + iv, + LambdaFactory::getAdvectionLambda() ); + } + + // normal grids + else + { + if (enableGravity) + localAssembler.assembleWithGravity( handle.advectionT(), + handle.gravity(), + handle.advectionCA(), + iv, + LambdaFactory::getAdvectionLambda() ); + else + localAssembler.assemble( handle.advectionT(), + iv, + LambdaFactory::getAdvectionLambda() ); + } + } + + // (maybe) only reassemble gravity vector + else if (enableGravity) + { + if (dim == dimWorld) + localAssembler.assembleGravity( handle.gravity(), + iv, + handle.advectionCA(), + LambdaFactory::getAdvectionLambda() ); + else + localAssembler.assembleGravity( handle.gravity(), + handle.gravityOutside(), + iv, + handle.advectionCA(), + handle.advectionA(), + LambdaFactory::getAdvectionLambda() ); + } + + // assemble pressure vectors + for (unsigned int pIdx = 0; pIdx < GET_PROP_VALUE(TypeTag, NumPhases); ++pIdx) + { + const auto& evv = &elemVolVars(); + auto getPressure = [&evv, pIdx] (auto volVarIdx) { return (evv->operator[](volVarIdx)).pressure(pIdx); }; + localAssembler.assemble(handle.pressures(pIdx), iv, getPressure); + } + } + + //! prepares the quantities necessary for diffusive fluxes in the handle + template< class InteractionVolume, + class DataHandle, + class DiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType), + typename std::enable_if_t<DiffusionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa, int> = 0 > + void fillDiffusionHandle(InteractionVolume& iv, + DataHandle& handle, + bool forceUpdateAll, + int phaseIdx, int compIdx) + { + using LambdaFactory = TensorLambdaFactory<TypeTag, DiscretizationMethods::CCMpfa>; + + // get instance of the interaction volume-local assembler + static constexpr MpfaMethods M = InteractionVolume::MpfaMethod; + using IvLocalAssembler = InteractionVolumeAssembler< Problem, FVElementGeometry, ElementVolumeVariables, M >; + IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars()); + + // solve the local system subject to the tensor and update the handle + handle.setPhaseIndex(phaseIdx); + handle.setComponentIndex(compIdx); + + // assemble T + if (forceUpdateAll || soldependentDiffusion) + { + if (dim < dimWorld) + localAssembler.assemble( handle.diffusionTout(), + handle.diffusionT(), + iv, + LambdaFactory::getDiffusionLambda(phaseIdx, compIdx) ); + else + localAssembler. assemble( handle.diffusionT(), + iv, + LambdaFactory::getDiffusionLambda(phaseIdx, compIdx) ); + } + + // assemble vector of mole fractions + const auto& evv = &elemVolVars(); + auto getMoleFraction = [&evv, phaseIdx, compIdx] (auto volVarIdx) + { return (evv->operator[](volVarIdx)).moleFraction(phaseIdx, compIdx); }; + localAssembler.assemble(handle.moleFractions(phaseIdx, compIdx), iv, getMoleFraction); + } + + //! prepares the quantities necessary for conductive fluxes in the handle + template< class InteractionVolume, + class DataHandle, + class HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType), + typename std::enable_if_t<HeatConductionType::myDiscretizationMethod == DiscretizationMethods::CCMpfa, int> = 0 > + void fillHeatConductionHandle(InteractionVolume& iv, DataHandle& handle, bool forceUpdateAll) + { + using LambdaFactory = TensorLambdaFactory<TypeTag, DiscretizationMethods::CCMpfa>; + + // get instance of the interaction volume-local assembler + static constexpr MpfaMethods M = InteractionVolume::MpfaMethod; + using IvLocalAssembler = InteractionVolumeAssembler< Problem, FVElementGeometry, ElementVolumeVariables, M >; + IvLocalAssembler localAssembler(problem(), fvGeometry(), elemVolVars()); + + if (forceUpdateAll || soldependentAdvection) + { + if (dim < dimWorld) + localAssembler.assemble( handle.heatConductionTout(), + handle.heatConductionT(), + iv, + LambdaFactory::getHeatConductionLambda() ); + else + localAssembler.assemble( handle.heatConductionT(), + iv, + LambdaFactory::getHeatConductionLambda() ); + } + + // assemble vector of temperatures + const auto& evv = &elemVolVars(); + auto getMoleFraction = [&evv] (auto volVarIdx) { return (evv->operator[](volVarIdx)).temperature(); }; + localAssembler.assemble(handle.temperatures(), iv, getMoleFraction); + } + + //! fill handle only when advection uses mpfa + template< class InteractionVolume, + class DataHandle, + class AdvectionType = typename GET_PROP_TYPE(TypeTag, AdvectionType), + typename std::enable_if_t<AdvectionType::myDiscretizationMethod != DiscretizationMethods::CCMpfa, int> = 0 > + void fillAdvectionHandle(InteractionVolume& iv, DataHandle& handle, bool forceUpdateAll) {} + + //! fill handle only when diffusion uses mpfa + template< class InteractionVolume, + class DataHandle, + class DiffusionType = typename GET_PROP_TYPE(TypeTag, MolecularDiffusionType), + typename std::enable_if_t<DiffusionType::myDiscretizationMethod != DiscretizationMethods::CCMpfa, int> = 0 > + void fillDiffusionHandle(InteractionVolume& iv, DataHandle& handle, bool forceUpdateAll, int phaseIdx, int compIdx) {} + + //! fill handle only when heat conduction uses mpfa + template< class InteractionVolume, + class DataHandle, + class HeatConductionType = typename GET_PROP_TYPE(TypeTag, HeatConductionType), + typename std::enable_if_t<HeatConductionType::myDiscretizationMethod != DiscretizationMethods::CCMpfa, int> = 0 > + void fillHeatConductionHandle(InteractionVolume& iv, DataHandle& handle, bool forceUpdateAll) {} + const Problem* problemPtr_; const Element* elementPtr_; const FVElementGeometry* fvGeometryPtr_; diff --git a/dumux/discretization/cellcentered/mpfa/fourierslaw.hh b/dumux/discretization/cellcentered/mpfa/fourierslaw.hh index 56e3af6da2d0625c0aca32d27c8afbec6f26cb41..aa153053a6447c327663794f6f982a052b5fdf90 100644 --- a/dumux/discretization/cellcentered/mpfa/fourierslaw.hh +++ b/dumux/discretization/cellcentered/mpfa/fourierslaw.hh @@ -49,7 +49,9 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> using Problem = typename GET_PROP_TYPE(TypeTag, Problem); using GridView = typename GET_PROP_TYPE(TypeTag, GridView); using Element = typename GridView::template Codim<0>::Entity; - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView; + + using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry); + using FVElementGeometry = typename FVGridGeometry::LocalView; using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); using ElementFluxVarsCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); @@ -89,30 +91,22 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> class MpfaFouriersLawCache { using DualGridNodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet); - using Stencil = typename DualGridNodalIndexSet::GridStencilType; + using Stencil = typename DualGridNodalIndexSet::NodalGridStencilType; - using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); + using MpfaHelper = typename FVGridGeometry::MpfaHelper; static constexpr bool considerSecondaryIVs = MpfaHelper::considerSecondaryIVs(); - // In the current implementation of the flux variables cache we cannot make a - // disctinction between dynamic (e.g. mpfa-o unstructured) and static (e.g.mpfa-l) - // matrix and vector types, as currently the cache class can only be templated - // by a type tag (and there can only be one). Currently, pointers to both the - // primary and secondary iv data is stored. Before accessing it has to be checked - // whether or not the scvf is embedded in a secondary interaction volume. using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); using PrimaryIvLocalFaceData = typename PrimaryInteractionVolume::Traits::LocalFaceData; - using PrimaryIvDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle; - using PrimaryIvVector = typename PrimaryInteractionVolume::Traits::Vector; - using PrimaryIvMatrix = typename PrimaryInteractionVolume::Traits::Matrix; - using PrimaryIvTij = typename PrimaryIvMatrix::row_type; + using PrimaryIvDataHandle = typename ElementFluxVarsCache::PrimaryIvDataHandle; + using PrimaryIvCellVector = typename PrimaryInteractionVolume::Traits::MatVecTraits::CellVector; + using PrimaryIvTij = typename PrimaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type; using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); using SecondaryIvLocalFaceData = typename SecondaryInteractionVolume::Traits::LocalFaceData; - using SecondaryIvDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle; - using SecondaryIvVector = typename SecondaryInteractionVolume::Traits::Vector; - using SecondaryIvMatrix = typename SecondaryInteractionVolume::Traits::Matrix; - using SecondaryIvTij = typename SecondaryIvMatrix::row_type; + using SecondaryIvDataHandle = typename ElementFluxVarsCache::SecondaryIvDataHandle; + using SecondaryIvCellVector = typename SecondaryInteractionVolume::Traits::MatVecTraits::CellVector; + using SecondaryIvTij = typename SecondaryInteractionVolume::Traits::MatVecTraits::TMatrix::row_type; static constexpr int dim = GridView::dimension; static constexpr int dimWorld = GridView::dimensionworld; @@ -188,10 +182,10 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> const Stencil& heatConductionStencil() const { return *stencil_; } //! The cell (& Dirichlet) temperatures within this interaction volume (primary type) - const PrimaryIvVector& temperaturesPrimaryIv() const { return *primaryTj_; } + const PrimaryIvCellVector& temperaturesPrimaryIv() const { return *primaryTj_; } //! The cell (& Dirichlet) temperatures within this interaction volume (secondary type) - const SecondaryIvVector& temperaturesSecondaryIv() const { return *secondaryTj_; } + const SecondaryIvCellVector& temperaturesSecondaryIv() const { return *secondaryTj_; } //! In the interaction volume-local system of eq we have one unknown per face. //! On scvfs on this face, but in "outside" (neighbor) elements of it, we have @@ -210,8 +204,8 @@ class FouriersLawImplementation<TypeTag, DiscretizationMethods::CCMpfa> const SecondaryIvTij* secondaryTij_; //! The interaction-volume wide temperature Tj - const PrimaryIvVector* primaryTj_; - const SecondaryIvVector* secondaryTj_; + const PrimaryIvCellVector* primaryTj_; + const SecondaryIvCellVector* secondaryTj_; }; public: diff --git a/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh b/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh index 557b70dad7da825c71ab7501130d3f6c60dec7b1..1d0a9f19c829b3a1243924fbaec1046e23561144 100644 --- a/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh +++ b/dumux/discretization/cellcentered/mpfa/fvelementgeometry.hh @@ -222,22 +222,7 @@ public: //! Note that e.g. the normals might be different in the case of surface grids const SubControlVolumeFace& flipScvf(GridIndexType scvfIdx, unsigned int outsideScvIdx = 0) const { - auto it = std::find(scvfIndices_.begin(), scvfIndices_.end(), scvfIdx); - if (it != scvfIndices_.end()) - { - const auto localScvfIdx = std::distance(scvfIndices_.begin(), it); - return neighborScvfs_[flipScvfIndices_[localScvfIdx][outsideScvIdx]]; - } - else - { - const auto neighborScvfIdxLocal = findLocalIndex(scvfIdx, neighborScvfIndices_); - const auto& scvf = neighborScvfs_[neighborScvfIdxLocal]; - - if (scvf.outsideScvIdx(outsideScvIdx) == scvIndices_[0]) - return scvfs_[neighborFlipScvfIndices_[neighborScvfIdxLocal][outsideScvIdx]]; - else - return neighborScvfs_[neighborFlipScvfIndices_[neighborScvfIdxLocal][outsideScvIdx]]; - } + return scvf( fvGridGeometry().flipScvfIdx(scvfIdx, outsideScvIdx) ); } //! iterator range for sub control volumes. Iterates over @@ -299,10 +284,6 @@ public: dataJ.scvfsJ, dataJ.additionalScvfs); - // set up the scvf flip indices for network grids - if (dim < dimWorld) - makeFlipIndexSet(); - // //! TODO Check if user added additional DOF dependencies, i.e. the residual of DOF globalI depends // //! on additional DOFs not included in the discretization schemes' occupation pattern // const auto& additionalDofDependencies = problem.getAdditionalDofDependencies(globalI); @@ -524,98 +505,6 @@ private: } } - //! find the "flip" indices for all scvfs - void makeFlipIndexSet() - { - const auto numInsideScvfs = scvfIndices_.size(); - const auto numNeighborScvfs = neighborScvfIndices_.size(); - - // first, handle the interior scvfs (flip scvf will be in outside scvfs) - flipScvfIndices_.resize(numInsideScvfs); - for (unsigned int insideFace = 0; insideFace < numInsideScvfs; ++insideFace) - { - const auto& scvf = scvfs_[insideFace]; - if (scvf.boundary()) - continue; - - const auto numOutsideScvs = scvf.numOutsideScvs(); - const auto vIdxGlobal = scvf.vertexIndex(); - const auto insideScvIdx = scvf.insideScvIdx(); - - flipScvfIndices_[insideFace].resize(numOutsideScvs); - for (unsigned int nIdx = 0; nIdx < numOutsideScvs; ++nIdx) - { - const auto outsideScvIdx = scvf.outsideScvIdx(nIdx); - for (unsigned int outsideFace = 0; outsideFace < numNeighborScvfs; ++outsideFace) - { - const auto& outsideScvf = neighborScvfs_[outsideFace]; - // check if outside face is the flip face - if (outsideScvf.insideScvIdx() == outsideScvIdx && - outsideScvf.vertexIndex() == vIdxGlobal && - MpfaHelper::vectorContainsValue(outsideScvf.outsideScvIndices(), insideScvIdx)) - { - flipScvfIndices_[insideFace][nIdx] = outsideFace; - // there is always only one flip face in an outside element - break; - } - } - } - } - - // Now we look for the flip indices of the outside faces - neighborFlipScvfIndices_.resize(numNeighborScvfs); - for (unsigned int outsideFace = 0; outsideFace < numNeighborScvfs; ++outsideFace) - { - const auto& scvf = neighborScvfs_[outsideFace]; - if (scvf.boundary()) - continue; - - const auto numOutsideScvs = scvf.numOutsideScvs(); - const auto vIdxGlobal = scvf.vertexIndex(); - const auto insideScvIdx = scvf.insideScvIdx(); - - neighborFlipScvfIndices_[outsideFace].resize(numOutsideScvs); - for (unsigned int nIdx = 0; nIdx < numOutsideScvs; ++nIdx) - { - const auto neighborScvIdx = scvf.outsideScvIdx(nIdx); - - // if the neighbor scv idx is the index of the bound element, - // then the flip scvf will be within the inside scvfs - if (neighborScvIdx == scvIndices_[0]) - { - for (unsigned int insideFace = 0; insideFace < numInsideScvfs; ++insideFace) - { - const auto& insideScvf = scvfs_[insideFace]; - // check if the face is the flip face - if (insideScvf.vertexIndex() == vIdxGlobal && - MpfaHelper::vectorContainsValue(insideScvf.outsideScvIndices(), insideScvIdx)) - { - neighborFlipScvfIndices_[outsideFace][nIdx] = insideFace; - // there is always only one flip face in an outside element - break; - } - } - } - else - { - for (unsigned int outsideFace2 = 0; outsideFace2 < numNeighborScvfs; ++outsideFace2) - { - const auto& outsideScvf = neighborScvfs_[outsideFace2]; - // check if outside face is the flip face - if (outsideScvf.insideScvIdx() == neighborScvIdx && - outsideScvf.vertexIndex() == vIdxGlobal && - MpfaHelper::vectorContainsValue(outsideScvf.outsideScvIndices(), insideScvIdx)) - { - neighborFlipScvfIndices_[outsideFace][nIdx] = outsideFace2; - // there is always only one flip face in an outside element - break; - } - } - } - } - } - } - //! map a global index to the local storage index const unsigned int findLocalIndex(const GridIndexType idx, const std::vector<GridIndexType>& indices) const @@ -635,9 +524,6 @@ private: neighborScvfIndices_.clear(); neighborScvs_.clear(); neighborScvfs_.clear(); - - flipScvfIndices_.clear(); - neighborFlipScvfIndices_.clear(); } const FVGridGeometry* fvGridGeometryPtr_; @@ -652,10 +538,6 @@ private: std::vector<GridIndexType> neighborScvfIndices_; std::vector<SubControlVolume> neighborScvs_; std::vector<SubControlVolumeFace> neighborScvfs_; - - // flip scvf index sets - std::vector< std::vector<GridIndexType> > flipScvfIndices_; - std::vector< std::vector<GridIndexType> > neighborFlipScvfIndices_; }; } // end namespace diff --git a/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh b/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh index 36a380d9002300402425a7e8887cde12ef95804e..6a6d7f40b5f2750067f629ac747e126c49debbfa 100644 --- a/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh +++ b/dumux/discretization/cellcentered/mpfa/fvgridgeometry.hh @@ -71,9 +71,13 @@ class CCMpfaFVGridGeometry<GV, Traits, true> using CoordScalar = typename GV::ctype; using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>; + using ScvfOutsideGridIndexStorage = typename Traits::SubControlVolumeFace::Traits::OutsideGridIndexStorage; + public: + //! export the flip scvf index set type + using FlipScvfIndexSet = std::vector<ScvfOutsideGridIndexStorage>; //! export the mpfa helper type - using MpfaHelper = typename Traits::MpfaHelper; + using MpfaHelper = typename Traits::template MpfaHelper<ThisType>; //! export the grid interaction volume index set type using GridIVIndexSets = typename Traits::template GridIvIndexSets<ThisType>; //! export the type to be used for indicators where to use the secondary ivs @@ -192,7 +196,6 @@ public: // for network grids there might be multiple intersection with the same geometryInInside // we indentify those by the indexInInside for now (assumes conforming grids at branching facets) - using ScvfOutsideGridIndexStorage = typename SubControlVolumeFace::Traits::OutsideGridIndexStorage; std::vector<ScvfOutsideGridIndexStorage> outsideIndices; if (dim < dimWorld) { @@ -301,34 +304,30 @@ public: } // Make the flip index set for network and surface grids - if (dim < dimWorld) + flipScvfIndices_.resize(scvfs_.size()); + for (const auto& scvf : scvfs_) { - flipScvfIndices_.resize(scvfs_.size()); - for (const auto& scvf : scvfs_) - { - if (scvf.boundary()) - continue; + if (scvf.boundary()) + continue; - const auto numOutsideScvs = scvf.numOutsideScvs(); - const auto vIdxGlobal = scvf.vertexIndex(); - const auto insideScvIdx = scvf.insideScvIdx(); + const auto numOutsideScvs = scvf.numOutsideScvs(); + const auto vIdxGlobal = scvf.vertexIndex(); + const auto insideScvIdx = scvf.insideScvIdx(); - flipScvfIndices_[scvf.index()].resize(numOutsideScvs); - for (std::size_t i = 0; i < numOutsideScvs; ++i) + flipScvfIndices_[scvf.index()].resize(numOutsideScvs); + for (std::size_t i = 0; i < numOutsideScvs; ++i) + { + const auto outsideScvIdx = scvf.outsideScvIdx(i); + for (auto outsideScvfIndex : scvfIndicesOfScv_[outsideScvIdx]) { - const auto outsideScvIdx = scvf.outsideScvIdx(i); - for (auto outsideScvfIndex : scvfIndicesOfScv_[outsideScvIdx]) + const auto& outsideScvf = this->scvf(outsideScvfIndex); + if (outsideScvf.vertexIndex() == vIdxGlobal && + MpfaHelper::vectorContainsValue(outsideScvf.outsideScvIndices(), insideScvIdx)) { - const auto& outsideScvf = this->scvf(outsideScvfIndex); - if (outsideScvf.vertexIndex() == vIdxGlobal && - MpfaHelper::vectorContainsValue(outsideScvf.outsideScvIndices(), insideScvIdx)) - { - flipScvfIndices_[scvf.index()][i] = outsideScvfIndex; - // there is always only one flip face in an outside element - break; - } + flipScvfIndices_[scvf.index()][i] = outsideScvfIndex; + // there is always only one flip face in an outside element + break; } - } } } @@ -347,6 +346,9 @@ public: std::cout << "Initializing of the connectivity map took " << timer.elapsed() << " seconds." << std::endl; } + //! Returns instance of the mpfa helper type + MpfaHelper mpfaHelper() const { return MpfaHelper(); } + //! Get a sub control volume with a global scv index const SubControlVolume& scv(GridIndexType scvIdx) const { return scvs_[scvIdx]; } @@ -360,15 +362,17 @@ public: //! Returns the grid interaction volume index set class. const GridIVIndexSets& gridInteractionVolumeIndexSets() const { return ivIndexSets_; } + //! Get the sub control volume face indices of an scv by global index + const std::vector<GridIndexType>& scvfIndicesOfScv(GridIndexType scvIdx) const { return scvfIndicesOfScv_[scvIdx]; } + + //! Returns the flip scvf index set + const FlipScvfIndexSet& flipScvfIndexSet() const { return flipScvfIndices_; } + //! Get the scvf on the same face but from the other side //! Note that e.g. the normals might be different in the case of surface grids const SubControlVolumeFace& flipScvf(GridIndexType scvfIdx, unsigned int outsideScvfIdx = 0) const { return scvfs_[flipScvfIndices_[scvfIdx][outsideScvfIdx]]; } - //! Get the sub control volume face indices of an scv by global index - const std::vector<GridIndexType>& scvfIndicesOfScv(GridIndexType scvIdx) const - { return scvfIndicesOfScv_[scvIdx]; } - private: // connectivity map for efficient assembly ConnectivityMap connectivityMap_; @@ -383,7 +387,7 @@ private: GridIndexType numBoundaryScvf_; // needed for embedded surface and network grids (dim < dimWorld) - std::vector<std::vector<GridIndexType>> flipScvfIndices_; + FlipScvfIndexSet flipScvfIndices_; // The grid interaction volume index set GridIVIndexSets ivIndexSets_; @@ -419,8 +423,10 @@ class CCMpfaFVGridGeometry<GV, Traits, false> using ScvfOutsideGridIndexStorage = typename Traits::SubControlVolumeFace::Traits::OutsideGridIndexStorage; public: + //! export the flip scvf index set type + using FlipScvfIndexSet = std::vector<ScvfOutsideGridIndexStorage>; //! export the mpfa helper type - using MpfaHelper = typename Traits::MpfaHelper; + using MpfaHelper = typename Traits::template MpfaHelper<ThisType>; //! export the grid interaction volume index set type using GridIVIndexSets = typename Traits::template GridIvIndexSets<ThisType>; //! export the type to be used for indicators where to use the secondary ivs @@ -523,6 +529,13 @@ public: // instantiate the dual grid index set (to be used for construction of interaction volumes) typename GridIVIndexSets::DualGridIndexSet dualIdSet(this->gridView()); + // keep track of boundary scvfs and scvf vertex indices in order to set up flip scvf index set + const auto maxNumScvfs = numScvs_*LocalView::maxNumElementScvfs; + std::vector<bool> scvfIsOnBoundary; + std::vector<GridIndexType> scvfVertexIndex; + scvfIsOnBoundary.reserve(maxNumScvfs); + scvfVertexIndex.reserve(maxNumScvfs); + // Build the SCVs and SCV faces numScvf_ = 0; numBoundaryScvf_ = 0; @@ -609,10 +622,12 @@ public: } (); // insert the scvf data into the dual grid index set - dualIdSet[vIdxGlobal].insert(boundary, numScvf_, eIdx, outsideScvIndices); + dualIdSet[vIdxGlobal].insert(numScvf_, eIdx, boundary); // store information on the scv face scvfsIndexSet.push_back(numScvf_++); + scvfIsOnBoundary.push_back(boundary); + scvfVertexIndex.push_back(vIdxGlobal); neighborVolVarIndexSet.emplace_back(std::move(outsideScvIndices)); } @@ -626,6 +641,43 @@ public: neighborVolVarIndices_[eIdx] = neighborVolVarIndexSet; } + // Make the flip scvf index set + flipScvfIndices_.resize(numScvf_); + for (std::size_t scvIdx = 0; scvIdx < numScvs_; ++scvIdx) + { + const auto& scvfIndices = scvfIndicesOfScv_[scvIdx]; + for (unsigned int i = 0; i < scvfIndices.size(); ++i) + { + // boundary scvf have no flip scvfs + if (scvfIsOnBoundary[ scvfIndices[i] ]) + continue; + + const auto scvfIdx = scvfIndices[i]; + const auto vIdxGlobal = scvfVertexIndex[scvfIdx]; + const auto numOutsideScvs = neighborVolVarIndices_[scvIdx][i].size(); + + flipScvfIndices_[scvfIdx].resize(numOutsideScvs); + for (unsigned int j = 0; j < numOutsideScvs; ++j) + { + const auto outsideScvIdx = neighborVolVarIndices_[scvIdx][i][j]; + const auto& outsideScvfIndices = scvfIndicesOfScv_[outsideScvIdx]; + for (unsigned int k = 0; k < outsideScvfIndices.size(); ++k) + { + const auto outsideScvfIndex = outsideScvfIndices[k]; + const auto outsideScvfVertexIndex = scvfVertexIndex[outsideScvfIndex]; + const auto& outsideScvfNeighborIndices = neighborVolVarIndices_[outsideScvIdx][k]; + if (outsideScvfVertexIndex == vIdxGlobal && + MpfaHelper::vectorContainsValue(outsideScvfNeighborIndices, scvIdx)) + { + flipScvfIndices_[scvfIdx][j] = outsideScvfIndex; + // there is always only one flip face in an outside element + break; + } + } + } + } + } + // building the geometries has finished std::cout << "Initializing of the grid finite volume geometry took " << timer.elapsed() << " seconds." << std::endl; @@ -640,6 +692,9 @@ public: std::cout << "Initializing of the connectivity map took " << timer.elapsed() << " seconds." << std::endl; } + //! Returns instance of the mpfa helper type + MpfaHelper mpfaHelper() const { return MpfaHelper(); } + //! Returns the sub control volume face indices of an scv by global index. const std::vector<GridIndexType>& scvfIndicesOfScv(GridIndexType scvIdx) const { return scvfIndicesOfScv_[scvIdx]; } @@ -648,6 +703,14 @@ public: const std::vector<ScvfOutsideGridIndexStorage>& neighborVolVarIndices(GridIndexType scvIdx) const { return neighborVolVarIndices_[scvIdx]; } + //! Get the index scvf on the same face but from the other side + //! Note that e.g. the normals might be different in the case of surface grids + const GridIndexType flipScvfIdx(GridIndexType scvfIdx, unsigned int outsideScvfIdx = 0) const + { return flipScvfIndices_[scvfIdx][outsideScvfIdx]; } + + //! Returns the flip scvf index set + const FlipScvfIndexSet& flipScvfIndexSet() const { return flipScvfIndices_; } + //! Returns the connectivity map of which dofs //! have derivatives with respect to a given dof. const ConnectivityMap& connectivityMap() const { return connectivityMap_; } @@ -668,6 +731,9 @@ private: GridIndexType numScvf_; GridIndexType numBoundaryScvf_; + // needed for embedded surface and network grids (dim < dimWorld) + FlipScvfIndexSet flipScvfIndices_; + // The grid interaction volume index set GridIVIndexSets ivIndexSets_; diff --git a/dumux/discretization/cellcentered/mpfa/gridfluxvariablescache.hh b/dumux/discretization/cellcentered/mpfa/gridfluxvariablescache.hh index 87392c2b4f71f4a911e799b90394a49f35bde083..a43048d8e8ad1db4874a1b7d0890c26d273ee8dc 100644 --- a/dumux/discretization/cellcentered/mpfa/gridfluxvariablescache.hh +++ b/dumux/discretization/cellcentered/mpfa/gridfluxvariablescache.hh @@ -25,6 +25,7 @@ #define DUMUX_DISCRETIZATION_CCMPFA_GRID_FLUXVARSCACHE_HH #include <dumux/common/properties.hh> +#include <dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh> #include <dumux/discretization/cellcentered/mpfa/fluxvariablescachefiller.hh> //! make the local view function available whenever we use this class @@ -61,13 +62,28 @@ class CCMpfaGridFluxVariablesCache<TypeTag, true> using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache); using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; + using FluxVariablesCacheFiller = CCMpfaFluxVariablesCacheFiller<TypeTag>; using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); - using PrimaryIvDataHandle = typename PrimaryInteractionVolume::Traits::DataHandle; + using PrimaryMatVecTraits = typename PrimaryInteractionVolume::Traits::MatVecTraits; using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); - using SecondaryIvDataHandle = typename SecondaryInteractionVolume::Traits::DataHandle; - using FluxVariablesCacheFiller = CCMpfaFluxVariablesCacheFiller<TypeTag>; + using SecondaryMatVecTraits = typename SecondaryInteractionVolume::Traits::MatVecTraits; + + //! physics traits class to define the data handles + struct PhysicsTraits + { + static constexpr bool enableAdvection = GET_PROP_VALUE(TypeTag, EnableAdvection); + static constexpr bool enableMolecularDiffusion = GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion); + static constexpr bool enableHeatConduction = GET_PROP_VALUE(TypeTag, EnableEnergyBalance); + + static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); + static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); + }; public: + // export the data handle types used + using PrimaryIvDataHandle = InteractionVolumeDataHandle< PrimaryMatVecTraits, PhysicsTraits >; + using SecondaryIvDataHandle = InteractionVolumeDataHandle< SecondaryMatVecTraits, PhysicsTraits >; + //! export the type of the local view using LocalView = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); @@ -254,6 +270,10 @@ public: //! export the type of the local view using LocalView = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache); + //! export the data handle types used by the local view + using PrimaryIvDataHandle = typename LocalView::PrimaryIvDataHandle; + using SecondaryIvDataHandle = typename LocalView::SecondaryIvDataHandle; + //! The constructor CCMpfaGridFluxVariablesCache(const Problem& problem) : problemPtr_(&problem) {} diff --git a/dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh b/dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh index 7a6875ca5c1720aaaec215710a02812c877a4982..3f7020bc6a4dae2334d2497283ebf1b960b3c081 100644 --- a/dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh +++ b/dumux/discretization/cellcentered/mpfa/gridinteractionvolumeindexsets.hh @@ -25,7 +25,6 @@ #define DUMUX_DISCRETIZATION_MPFA_O_GRIDINTERACTIONVOLUME_INDEXSETS_HH #include <memory> -#include <dumux/common/properties.hh> #include "dualgridindexset.hh" @@ -78,9 +77,9 @@ public: { const auto vIdxGlobal = fvGridGeometry.vertexMapper().index(vertex); if (!fvGridGeometry.vertexUsesSecondaryInteractionVolume(vIdxGlobal)) - numPrimaryIV_ += PrimaryInteractionVolume::numInteractionVolumesAtVertex((*dualGridIndexSet_)[vIdxGlobal]); + numPrimaryIV_ += PrimaryInteractionVolume::numIVAtVertex((*dualGridIndexSet_)[vIdxGlobal]); else - numSecondaryIV_ += SecondaryInteractionVolume::numInteractionVolumesAtVertex((*dualGridIndexSet_)[vIdxGlobal]); + numSecondaryIV_ += SecondaryInteractionVolume::numIVAtVertex((*dualGridIndexSet_)[vIdxGlobal]); } // reserve memory @@ -93,9 +92,15 @@ public: { const auto vIdxGlobal = fvGridGeometry.vertexMapper().index(vertex); if (!fvGridGeometry.vertexUsesSecondaryInteractionVolume(vIdxGlobal)) - PrimaryInteractionVolume::addInteractionVolumeIndexSets(primaryIVIndexSets_, scvfIndexMap_, (*dualGridIndexSet_)[vIdxGlobal]); + PrimaryInteractionVolume::addIVIndexSets(primaryIVIndexSets_, + scvfIndexMap_, + (*dualGridIndexSet_)[vIdxGlobal], + fvGridGeometry.flipScvfIndexSet()); else - SecondaryInteractionVolume::addInteractionVolumeIndexSets(secondaryIVIndexSets_, scvfIndexMap_, (*dualGridIndexSet_)[vIdxGlobal]); + SecondaryInteractionVolume::addIVIndexSets(secondaryIVIndexSets_, + scvfIndexMap_, + (*dualGridIndexSet_)[vIdxGlobal], + fvGridGeometry.flipScvfIndexSet()); } } diff --git a/dumux/discretization/cellcentered/mpfa/helper.hh b/dumux/discretization/cellcentered/mpfa/helper.hh index 71aa0263bae23999892d91bbc0cfdf94446df8f3..dac6e546245690ca97c9da50c658cfe2050b0581 100644 --- a/dumux/discretization/cellcentered/mpfa/helper.hh +++ b/dumux/discretization/cellcentered/mpfa/helper.hh @@ -32,7 +32,6 @@ #include <dune/geometry/type.hh> #include <dune/geometry/referenceelements.hh> -#include <dumux/common/properties.hh> #include <dumux/common/math.hh> namespace Dumux { @@ -41,34 +40,22 @@ namespace Dumux { * \ingroup CCMpfaDiscretization * \brief Dimension-specific helper class to get data required for mpfa scheme. */ -template<class TypeTag, int dim, int dimWorld> +template<class FVGridGeometry, int dim, int dimWorld> class MpfaDimensionHelper; /*! * \ingroup CCMpfaDiscretization - * \brief Dimension-specific helper class to get data required for mpfa scheme. - * Specialization for dim == 2 & dimWorld == 2 + * \brief Dimension-specific mpfa helper class for dim == 2 & dimWorld == 2 */ -template<class TypeTag> -class MpfaDimensionHelper<TypeTag, /*dim*/2, /*dimWorld*/2> +template<class FVGridGeometry> +class MpfaDimensionHelper<FVGridGeometry, /*dim*/2, /*dimWorld*/2> { - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView; - using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; + using GridView = typename FVGridGeometry::GridView; + using CoordScalar = typename GridView::ctype; + using GlobalPosition = Dune::FieldVector<CoordScalar, GridView::dimensionworld>; + + using SubControlVolumeFace = typename FVGridGeometry::SubControlVolumeFace; using ScvfCornerVector = typename SubControlVolumeFace::Traits::CornerStorage; - using InteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); - using LocalScvType = typename InteractionVolume::Traits::LocalScvType; - using ScvBasis = typename LocalScvType::LocalBasis; - - // We know that dim = 2 & dimworld = 2. However, the specialization for - // dim = 2 & dimWorld = 3 reuses some methods of this class, thus, we - // obtain the world dimension from the grid view here to get the - // GlobalPosition vector right. Be picky about the dimension though. - static_assert(GridView::dimension == 2, "The chosen mpfa helper expects a grid view with dim = 2"); - static const int dim = 2; - static const int dimWorld = GridView::dimensionworld; - using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>; // Container to store the positions of intersections required for scvf // corner computation. In 2d, these are the center plus the two corners @@ -80,9 +67,10 @@ public: * * \param scvBasis The basis of an scv */ + template< class ScvBasis > static ScvBasis calculateInnerNormals(const ScvBasis& scvBasis) { - static const Dune::FieldMatrix<Scalar, dim, dim> R = {{0.0, 1.0}, {-1.0, 0.0}}; + static const Dune::FieldMatrix<CoordScalar, 2, 2> R = {{0.0, 1.0}, {-1.0, 0.0}}; ScvBasis innerNormals; R.mv(scvBasis[1], innerNormals[0]); @@ -103,10 +91,11 @@ public: * * \param scvBasis The basis of an scv */ - static typename LocalScvType::ctype calculateDetX(const ScvBasis& scvBasis) + template< class ScvBasis > + static CoordScalar calculateDetX(const ScvBasis& scvBasis) { using std::abs; - return abs(crossProduct<Scalar>(scvBasis[0], scvBasis[1])); + return abs(crossProduct<CoordScalar>(scvBasis[0], scvBasis[1])); } /*! @@ -139,8 +128,9 @@ public: * * \param scvBasis The basis of an scv */ + template< class ScvBasis > static bool isRightHandSystem(const ScvBasis& scvBasis) - { return !std::signbit(crossProduct<Scalar>(scvBasis[0], scvBasis[1])); } + { return !std::signbit(crossProduct<CoordScalar>(scvBasis[0], scvBasis[1])); } /*! * \brief Returns a vector containing the positions on a given intersection @@ -164,7 +154,8 @@ public: p[0] = 0.0; for (unsigned int c = 0; c < numCorners; ++c) { - p[c+1] = eg.global(refElement.position(refElement.subEntity(indexInElement, 1, c, dim), dim)); + // codim = 1, dim = 2 + p[c+1] = eg.global(refElement.position(refElement.subEntity(indexInElement, 1, c, 2), 2)); p[0] += p[c+1]; } p[0] /= numCorners; @@ -199,7 +190,7 @@ public: * * \param scvfCorners Container with the corners of the scvf */ - static Scalar getScvfArea(const ScvfCornerVector& scvfCorners) + static CoordScalar getScvfArea(const ScvfCornerVector& scvfCorners) { return (scvfCorners[1]-scvfCorners[0]).two_norm(); } /*! @@ -229,19 +220,15 @@ public: /*! * \ingroup CCMpfaDiscretization - * \brief Dimension-specific helper class to get data required for mpfa scheme. - * Specialization for dim == 2 & dimWorld == 2. Reuses some functionality - * of the specialization for dim = dimWorld = 2 + * \brief Dimension-specific mpfa helper class for dim == 2 & dimWorld == 2. + * Reuses some functionality of the specialization for dim = dimWorld = 2 */ -template<class TypeTag> -class MpfaDimensionHelper<TypeTag, /*dim*/2, /*dimWorld*/3> - : public MpfaDimensionHelper<TypeTag, 2, 2> +template<class FVGridGeometry> +class MpfaDimensionHelper<FVGridGeometry, /*dim*/2, /*dimWorld*/3> + : public MpfaDimensionHelper<FVGridGeometry, 2, 2> { - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using InteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); - using LocalScvType = typename InteractionVolume::Traits::LocalScvType; - using ScvBasis = typename LocalScvType::LocalBasis; - + using GridView = typename FVGridGeometry::GridView; + using CoordScalar = typename GridView::ctype; public: /*! @@ -249,19 +236,20 @@ public: * * \param scvBasis The basis of an scv */ + template< class ScvBasis > static ScvBasis calculateInnerNormals(const ScvBasis& scvBasis) { // compute vector normal to the basis plane const auto normal = [&] () { - auto n = crossProduct<Scalar>(scvBasis[0], scvBasis[1]); + auto n = crossProduct<CoordScalar>(scvBasis[0], scvBasis[1]); n /= n.two_norm(); return n; } (); // compute inner normals using the normal vector ScvBasis innerNormals; - innerNormals[0] = crossProduct<Scalar>(scvBasis[1], normal); - innerNormals[1] = crossProduct<Scalar>(normal, scvBasis[0]); + innerNormals[0] = crossProduct<CoordScalar>(scvBasis[1], normal); + innerNormals[1] = crossProduct<CoordScalar>(normal, scvBasis[0]); return innerNormals; } @@ -274,10 +262,11 @@ public: * * \param scvBasis The basis of an scv */ - static typename LocalScvType::ctype calculateDetX(const ScvBasis& scvBasis) + template< class ScvBasis > + static CoordScalar calculateDetX(const ScvBasis& scvBasis) { using std::abs; - return abs(crossProduct<Scalar>(scvBasis[0], scvBasis[1]).two_norm()); + return abs(crossProduct<CoordScalar>(scvBasis[0], scvBasis[1]).two_norm()); } /*! @@ -287,32 +276,24 @@ public: * * \param scvBasis The basis of an scv */ - static bool isRightHandSystem(const ScvBasis& scvBasis) - { return true; } + template< class ScvBasis > + static constexpr bool isRightHandSystem(const ScvBasis& scvBasis) { return true; } }; /*! * \ingroup CCMpfaDiscretization - * \brief Dimension-specific helper class to get data required for mpfa scheme. - * Specialization for dim == 3 & dimWorld == 3. + * \brief Dimension-specific mpfa helper class for dim == 3 & dimWorld == 3. + * */ -template<class TypeTag> -class MpfaDimensionHelper<TypeTag, /*dim*/3, /*dimWorld*/3> +template<class FVGridGeometry> +class MpfaDimensionHelper<FVGridGeometry, /*dim*/3, /*dimWorld*/3> { - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView; - using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; + using SubControlVolumeFace = typename FVGridGeometry::SubControlVolumeFace; using ScvfCornerVector = typename SubControlVolumeFace::Traits::CornerStorage; - using InteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); - using LocalScvType = typename InteractionVolume::Traits::LocalScvType; - using ScvBasis = typename LocalScvType::LocalBasis; // Be picky about the dimensions - static_assert(GridView::dimension == 3 && GridView::dimensionworld == 3, - "The chosen mpfa helper expects a grid view with dim = 3 & dimWorld = 3"); - static const int dim = 3; - static const int dimWorld = 3; - using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>; + using GridView = typename FVGridGeometry::GridView; + using CoordScalar = typename GridView::ctype; + using GlobalPosition = Dune::FieldVector<CoordScalar, /*dimworld*/3>; // container to store the positions of intersections required for // scvf corner computation. Maximum number of points needed is 9 @@ -326,13 +307,14 @@ public: * * \param scvBasis The basis of an scv */ + template< class ScvBasis > static ScvBasis calculateInnerNormals(const ScvBasis& scvBasis) { ScvBasis innerNormals; - innerNormals[0] = crossProduct<Scalar>(scvBasis[1], scvBasis[2]); - innerNormals[1] = crossProduct<Scalar>(scvBasis[2], scvBasis[0]); - innerNormals[2] = crossProduct<Scalar>(scvBasis[0], scvBasis[1]); + innerNormals[0] = crossProduct<CoordScalar>(scvBasis[1], scvBasis[2]); + innerNormals[1] = crossProduct<CoordScalar>(scvBasis[2], scvBasis[0]); + innerNormals[2] = crossProduct<CoordScalar>(scvBasis[0], scvBasis[1]); if (!isRightHandSystem(scvBasis)) { @@ -350,10 +332,11 @@ public: * * \param scvBasis The basis of an scv */ - static typename LocalScvType::ctype calculateDetX(const ScvBasis& scvBasis) + template< class ScvBasis > + static CoordScalar calculateDetX(const ScvBasis& scvBasis) { using std::abs; - return abs(tripleProduct<Scalar>(scvBasis[0], scvBasis[1], scvBasis[2])); + return abs(tripleProduct<CoordScalar>(scvBasis[0], scvBasis[1], scvBasis[2])); } /*! @@ -396,8 +379,9 @@ public: * * \param scvBasis The basis of an scv */ + template< class ScvBasis > static bool isRightHandSystem(const ScvBasis& scvBasis) - { return !std::signbit(tripleProduct<Scalar>(scvBasis[0], scvBasis[1], scvBasis[2])); } + { return !std::signbit(tripleProduct<CoordScalar>(scvBasis[0], scvBasis[1], scvBasis[2])); } /*! * \brief Returns a vector containing the positions on a given intersection @@ -424,7 +408,8 @@ public: p[0] = 0.0; for (unsigned int c = 0; c < numCorners; ++c) { - p[c+1] = eg.global(refElement.position(refElement.subEntity(indexInElement, 1, c, dim), dim)); + // codim = 1, dim = 3 + p[c+1] = eg.global(refElement.position(refElement.subEntity(indexInElement, 1, c, 3), 3)); p[0] += p[c+1]; } p[0] /= numCorners; @@ -441,6 +426,7 @@ public: p[numCorners+2] /= 2; p[numCorners+3] = p[3] + p[2]; p[numCorners+3] /= 2; + return p; } case 4: // quadrilateral { @@ -453,14 +439,12 @@ public: p[numCorners+3] /= 2; p[numCorners+4] = p[4] + p[3]; p[numCorners+4] /= 2; + return p; } default: - DUNE_THROW(Dune::NotImplemented, "Mpfa scvf corners for dim = " << dim - << ", dimWorld = " << dimWorld - << ", corners = " << numCorners); + DUNE_THROW(Dune::NotImplemented, + "Mpfa scvf corners for dim = 3, dimWorld = 3, corners = " << numCorners); } - - return p; } /*! @@ -515,9 +499,8 @@ public: p[map[cornerIdx][3]]} ); } default: - DUNE_THROW(Dune::NotImplemented, "Mpfa scvf corners for dim = " << dim - << ", dimWorld = " << dimWorld - << ", corners = " << numIntersectionCorners); + DUNE_THROW(Dune::NotImplemented, + "Mpfa scvf corners for dim = 3, dimWorld = 3, corners = " << numIntersectionCorners); } } @@ -526,7 +509,7 @@ public: * * \param scvfCorners Container with the corners of the scvf */ - static Scalar getScvfArea(const ScvfCornerVector& scvfCorners) + static CoordScalar getScvfArea(const ScvfCornerVector& scvfCorners) { // after Wolfram alpha quadrilateral area return 0.5*Dumux::crossProduct(scvfCorners[3]-scvfCorners[0], scvfCorners[2]-scvfCorners[1]).two_norm(); @@ -566,26 +549,26 @@ public: /*! * \ingroup CCMpfaDiscretization * \brief Helper class to get the required information on an interaction volume. - * Specializations depending on the method and dimension are provided. + * + * \tparam FVGridGeometry The finite volume grid geometry */ -template<class TypeTag, int dim, int dimWorld> -class CCMpfaHelperImplementation : public MpfaDimensionHelper<TypeTag, dim, dimWorld> +template<class FVGridGeometry> +class CCMpfaHelper : public MpfaDimensionHelper<FVGridGeometry, + FVGridGeometry::GridView::dimension, + FVGridGeometry::GridView::dimensionworld> { - using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); - - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - using Element = typename GridView::template Codim<0>::Entity; - using IndexType = typename GridView::IndexSet::IndexType; - - using PrimaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); - using SecondaryInteractionVolume = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); + using PrimaryInteractionVolume = typename FVGridGeometry::GridIVIndexSets::PrimaryInteractionVolume; + using SecondaryInteractionVolume = typename FVGridGeometry::GridIVIndexSets::SecondaryInteractionVolume; - using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry); using VertexMapper = typename FVGridGeometry::VertexMapper; using FVElementGeometry = typename FVGridGeometry::LocalView; using SubControlVolumeFace = typename FVElementGeometry::SubControlVolumeFace; using ScvfCornerVector = typename SubControlVolumeFace::Traits::CornerStorage; + using GridView = typename FVGridGeometry::GridView; + static constexpr int dim = GridView::dimension; + static constexpr int dimWorld = GridView::dimensionworld; + using CoordScalar = typename GridView::ctype; using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>; using ReferenceElements = typename Dune::ReferenceElements<CoordScalar, dim>; @@ -597,14 +580,17 @@ public: * \param scvfCorners Container with the corners of the scvf * \param q Parameterization of the integration point on the scvf */ + template< class Scalar > static GlobalPosition getScvfIntegrationPoint(const ScvfCornerVector& scvfCorners, Scalar q) { - // scvfs in 3d are always quadrilaterals // ordering -> first corner: facet center, last corner: vertex if (q == 0.0) return scvfCorners[0]; - const auto d = [&] () { auto tmp = scvfCorners.back() - scvfCorners.front(); tmp *= q; return tmp; } (); - return scvfCorners[0] + d; + + auto ip = scvfCorners.back() - scvfCorners.front(); + ip *= q; + ip += scvfCorners[0]; + return ip; } // returns a vector which maps true to each vertex on processor boundaries and false otherwise @@ -617,7 +603,7 @@ public: if (Dune::MPIHelper::getCollectiveCommunication().size() == 1) return ghostVertices; - // mpfa methods can not yet handle ghost cells + // mpfa methods cannot yet handle ghost cells if (gridView.ghostSize(0) > 0) DUNE_THROW(Dune::InvalidStateException, "Mpfa methods in parallel do not work with ghost cells. Use overlap cells instead."); @@ -660,16 +646,6 @@ public: { return std::find(vector.begin(), vector.end(), value) != vector.end(); } }; -/*! - * \ingroup CCMpfaDiscretization - * \brief Helper class to obtain data required for mpfa methods. - * It inherits from dimension-, dimensionworld- and method-specific implementations. - */ -template<class TypeTag> -using CCMpfaHelper = CCMpfaHelperImplementation<TypeTag, - GET_PROP_TYPE(TypeTag, GridView)::dimension, - GET_PROP_TYPE(TypeTag, GridView)::dimensionworld>; - } // end namespace Dumux #endif diff --git a/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh b/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh index d5e46c9b0ff4a71744be6ffe45a8dd158bcac447..95bee55df5e2d5f922aee9ddd15164bb7d4fd4c1 100644 --- a/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh +++ b/dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh @@ -26,8 +26,6 @@ #include <dune/common/exceptions.hh> -#include <dumux/common/properties.hh> - namespace Dumux { @@ -39,21 +37,9 @@ namespace Dumux * The traits should contain the following type definitions: * * \code - * //! export the problem type (needed for iv-local assembly) - * using Problem = ...; - * //! export the type of the local view on the finite volume grid geometry - * using FVElementGeometry = ...; - * //! export the type of the local view on the grid volume variables - * using ElementVolumeVariables = ...; * //! export the type of grid view * using GridView = ...; - * //! export the type used for scalar values - * using ScalarType = ...; - * //! export the type of the mpfa helper class - * using MpfaHelper = ...; * //! export the type used for local indices - * using LocalIndexType = ...; - * //! export the type for the interaction volume index set * using IndexSet = ...; * //! export the type of interaction-volume local scvs * using LocalScvType = ...; @@ -61,12 +47,8 @@ namespace Dumux * using LocalScvfType = ...; * //! export the type of used for the iv-local face data * using LocalFaceData = ...; - * //! export the type used for iv-local matrices - * using Matrix = ...; - * //! export the type used for iv-local vectors - * using Vector = ...; - * //! export the data handle type for this iv - * using DataHandle = ...; + * //! export the matrix/vector type traits to be used by the iv + * using MatVecTraits = ...; * \endcode */ @@ -78,25 +60,27 @@ namespace Dumux * \tparam Impl The actual implementation of the interaction volume * \tparam T The traits class to be used */ -template< class Impl, class T> +template< class Impl, class T > class CCMpfaInteractionVolumeBase { // Curiously recurring template pattern Impl& asImp() { return static_cast<Impl&>(*this); } const Impl& asImp() const { return static_cast<const Impl&>(*this); } - using Problem = typename T::Problem; - using FVElementGeometry = typename T::FVElementGeometry; - using ElementVolumeVariables = typename T::ElementVolumeVariables; - using GridView = typename T::GridView; using Element = typename GridView::template Codim<0>::Entity; + using NodalStencilType = typename T::IndexSet::NodalGridStencilType; + using LocalIndexType = typename T::IndexSet::LocalIndexType; + using LocalScvType = typename T::LocalScvType; + using LocalScvfType = typename T::LocalScvfType; + public: //! state the traits type publicly using Traits = T; //! Prepares everything for the assembly + template< class Problem, class FVElementGeometry > void setUpLocalScope(const typename Traits::IndexSet& indexSet, const Problem& problem, const FVElementGeometry& fvGeometry) @@ -121,32 +105,32 @@ public: { DUNE_THROW(Dune::NotImplemented, "Interaction volume implementation does not provide a localFaceData() funtion"); } //! returns the cell-stencil of this interaction volume - const typename Traits::IndexSet::GridStencilType& stencil() const { return asImp().stencil(); } + const NodalStencilType& stencil() const { return asImp().stencil(); } //! returns the local scvf entity corresponding to a given iv-local scvf idx - const typename Traits::LocalScvfType& localScvf(typename Traits::LocalIndexType ivLocalScvfIdx) const - { return asImp().localScvf(ivLocalScvfIdx); } + const LocalScvfType& localScvf(LocalIndexType ivLocalScvfIdx) const { return asImp().localScvf(ivLocalScvfIdx); } //! returns the local scv entity corresponding to a given iv-local scv idx - const typename Traits::LocalScvType& localScv(typename Traits::LocalIndexType ivLocalScvIdx) const - { return asImp().localScv(ivLocalScvIdx); } + const LocalScvType& localScv(LocalIndexType ivLocalScvIdx) const { return asImp().localScv(ivLocalScvIdx); } //! returns the element in which the scv with the given local idx is embedded in - const Element& element(typename Traits::LocalIndexType ivLocalScvIdx) const - { return asImp().element(); } + const Element& element(LocalIndexType ivLocalScvIdx) const { return asImp().element(); } //! returns the number of interaction volumes living around a vertex template< class NodalIndexSet > - static std::size_t numInteractionVolumesAtVertex(const NodalIndexSet& nodalIndexSet) - { return Impl::numInteractionVolumesAtVertex(nodalIndexSet); } + static std::size_t numIVAtVertex(const NodalIndexSet& nodalIndexSet) { return Impl::numIVAtVertex(nodalIndexSet); } //! adds the iv index sets living around a vertex to a given container //! and stores the the corresponding index in a map for each scvf - template<class IvIndexSetContainer, class ScvfIndexMap, class NodalIndexSet> - static void addInteractionVolumeIndexSets(IvIndexSetContainer& ivIndexSetContainer, - ScvfIndexMap& scvfIndexMap, - const NodalIndexSet& nodalIndexSet) - { Impl::addInteractionVolumeIndexSets(ivIndexSetContainer, scvfIndexMap, nodalIndexSet); } + template< class IvIndexSetContainer, + class ScvfIndexMap, + class NodalIndexSet, + class FlipScvfIndexSet > + static void addIVIndexSets(IvIndexSetContainer& ivIndexSetContainer, + ScvfIndexMap& scvfIndexMap, + const NodalIndexSet& nodalIndexSet, + const FlipScvfIndexSet& flipScvfIndexSet) + { Impl::addIVIndexSets(ivIndexSetContainer, scvfIndexMap, nodalIndexSet, flipScvfIndexSet); } }; } // end namespace Dumux diff --git a/dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh b/dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh index 7a41428485d51205c0db03158f21ed971346ac07..72e2ddc632184a61f1083d35e6d09501218890b4 100644 --- a/dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh +++ b/dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh @@ -26,7 +26,8 @@ #include <vector> -#include <dumux/common/properties.hh> +#include <dune/common/dynvector.hh> + #include <dumux/common/parameters.hh> #include <dumux/common/matrixvectorhelper.hh> @@ -42,26 +43,26 @@ public: }; //! Data handle for quantities related to advection -template<class TypeTag, class M, class V, class LI, bool EnableAdvection> +template<class MatVecTraits, class PhysicsTraits, bool EnableAdvection> class AdvectionDataHandle { // export matrix & vector types from interaction volume - using Matrix = M; - using Vector = V; - using LocalIndexType = LI; - using Scalar = typename Vector::value_type; - - using OutsideDataContainer = std::vector< std::vector<Vector> >; + using AMatrix = typename MatVecTraits::AMatrix; + using CMatrix = typename MatVecTraits::CMatrix; + using TMatrix = typename MatVecTraits::TMatrix; + using CellVector = typename MatVecTraits::CellVector; + using FaceVector = typename MatVecTraits::FaceVector; + using FaceScalar = typename FaceVector::value_type; + using OutsideGravityStorage = std::vector< Dune::DynamicVector<FaceScalar> >; - static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension; - static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld; - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); + static constexpr int numPhases = PhysicsTraits::numPhases; public: //! prepare data handle for subsequent fill (normal grids) - template< class InteractionVolume, int d = dim, int dw = dimWorld, std::enable_if_t<(d==dw), int> = 0> - void resize(const InteractionVolume& iv) + template< class IV, + std::enable_if_t<(IV::Traits::GridView::dimension==IV::Traits::GridView::dimensionworld), int> = 0> + void resize(const IV& iv) { // resize transmissibility matrix & pressure vectors resizeMatrix(T_, iv.numFaces(), iv.numKnowns()); @@ -69,7 +70,7 @@ public: resizeVector(p_[pIdx], iv.numKnowns()); // maybe resize gravity container - static const bool enableGravity = getParamFromGroup<bool>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Problem.EnableGravity"); + static const bool enableGravity = getParam<bool>("Problem.EnableGravity"); if (enableGravity) { resizeMatrix(CA_, iv.numFaces(), iv.numUnknowns()); @@ -80,11 +81,13 @@ public: //! prepare data handle for subsequent fill (surface grids) - template< class InteractionVolume, int d = dim, int dw = dimWorld, std::enable_if_t<(d<dw), int> = 0> - void resize(const InteractionVolume& iv) + template< class IV, + std::enable_if_t<(IV::Traits::GridView::dimension<IV::Traits::GridView::dimensionworld), int> = 0> + void resize(const IV& iv) { - static const bool enableGravity = getParamFromGroup<bool>(GET_PROP_VALUE(TypeTag, ModelParameterGroup), "Problem.EnableGravity"); + using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType; + static const bool enableGravity = getParam<bool>("Problem.EnableGravity"); if (!enableGravity) { resizeMatrix(T_, iv.numFaces(), iv.numKnowns()); @@ -129,66 +132,61 @@ public: } //! Access to the iv-wide pressure of one phase - const Vector& pressures(unsigned int pIdx) const { return p_[pIdx]; } - Vector& pressures(unsigned int pIdx) { return p_[pIdx]; } + const CellVector& pressures(unsigned int pIdx) const { return p_[pIdx]; } + CellVector& pressures(unsigned int pIdx) { return p_[pIdx]; } //! Access to the gravitational flux contributions for one phase - const Vector& gravity(unsigned int pIdx) const { return g_[pIdx]; } - Vector& gravity(unsigned int pIdx) { return g_[pIdx]; } + const FaceVector& gravity(unsigned int pIdx) const { return g_[pIdx]; } + FaceVector& gravity(unsigned int pIdx) { return g_[pIdx]; } //! Access to the gravitational flux contributions for all phases - const std::array< Vector, numPhases >& gravity() const { return g_; } - std::array< Vector, numPhases >& gravity() { return g_; } + const std::array< FaceVector, numPhases >& gravity() const { return g_; } + std::array< FaceVector, numPhases >& gravity() { return g_; } //! Projection matrix for gravitational acceleration - const Matrix& advectionCA() const { return CA_; } - Matrix& advectionCA() { return CA_; } + const CMatrix& advectionCA() const { return CA_; } + CMatrix& advectionCA() { return CA_; } //! Additional projection matrix needed on surface grids - const Matrix& advectionA() const { return A_; } - Matrix& advectionA() { return A_; } + const AMatrix& advectionA() const { return A_; } + AMatrix& advectionA() { return A_; } //! The transmissibilities associated with advective fluxes - const Matrix& advectionT() const { return T_; } - Matrix& advectionT() { return T_; } + const TMatrix& advectionT() const { return T_; } + TMatrix& advectionT() { return T_; } //! The transmissibilities for "outside" faces (used on surface grids) - const std::vector< std::vector<Vector> >& advectionTout() const { return outsideT_; } - std::vector< std::vector<Vector> >& advectionTout() { return outsideT_; } + const std::vector< std::vector<CellVector> >& advectionTout() const { return outsideT_; } + std::vector< std::vector<CellVector> >& advectionTout() { return outsideT_; } //! The gravitational acceleration for "outside" faces (used on surface grids) - const std::array< std::vector<Vector>, numPhases >& gravityOutside() const { return outsideG_; } - std::array< std::vector<Vector>, numPhases >& gravityOutside() { return outsideG_; } + const std::array< OutsideGravityStorage, numPhases >& gravityOutside() const { return outsideG_; } + std::array< OutsideGravityStorage, numPhases >& gravityOutside() { return outsideG_; } //! The gravitational acceleration for one phase on "outside" faces (used on surface grids) - const std::vector<Vector>& gravityOutside(unsigned int pIdx) const { return outsideG_[pIdx]; } - std::vector<Vector>& gravityOutside(unsigned int pIdx) { return outsideG_[pIdx]; } + const OutsideGravityStorage& gravityOutside(unsigned int pIdx) const { return outsideG_[pIdx]; } + OutsideGravityStorage& gravityOutside(unsigned int pIdx) { return outsideG_[pIdx]; } private: - //! advection-related variables - Matrix T_; //!< The transmissibilities such that f_i = T_ij*p_j - Matrix CA_; //!< Matrix to project gravitational acceleration to all scvfs - Matrix A_; //!< Matrix additionally needed for the projection on surface grids - std::array< Vector, numPhases > p_; //!< The interaction volume-wide phase pressures - std::array< Vector, numPhases > g_; //!< The gravitational acceleration at each scvf (only for enabled gravity) - std::vector< std::vector<Vector> > outsideT_; //!< The transmissibilities for "outside" faces (only on surface grids) - std::array< std::vector<Vector>, numPhases > outsideG_; //!< The gravitational acceleration on "outside" faces (only on surface grids) + TMatrix T_; //!< The transmissibilities such that f_i = T_ij*p_j + CMatrix CA_; //!< Matrix to project gravitational acceleration to all scvfs + AMatrix A_; //!< Matrix additionally needed for the projection on surface grids + std::array< CellVector, numPhases > p_; //!< The interaction volume-wide phase pressures + std::array< FaceVector, numPhases > g_; //!< The gravitational acceleration at each scvf (only for enabled gravity) + std::vector< std::vector<CellVector> > outsideT_; //!< The transmissibilities for "outside" faces (only on surface grids) + std::array< OutsideGravityStorage, numPhases > outsideG_; //!< The gravitational acceleration on "outside" faces (only on surface grids) }; //! Data handle for quantities related to diffusion -template<class TypeTag, class M, class V, class LI, bool EnableDiffusion> +template<class MatVecTraits, class PhysicsTraits, bool EnableDiffusion> class DiffusionDataHandle { - // export matrix & vector types from interaction volume - using Matrix = M; - using Vector = V; - using OutsideTContainer = std::vector< std::vector<Vector> >; - - static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension; - static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld; + using TMatrix = typename MatVecTraits::TMatrix; + using CellVector = typename MatVecTraits::CellVector; + using OutsideTContainer = std::vector< std::vector<CellVector> >; - static constexpr int numPhases = GET_PROP_VALUE(TypeTag, NumPhases); - static constexpr int numComponents = GET_PROP_VALUE(TypeTag, NumComponents); + static constexpr int numPhases = PhysicsTraits::numPhases; + static constexpr int numComponents = PhysicsTraits::numComponents; public: //! diffusion caches need to set phase and component index @@ -203,19 +201,17 @@ public: { for (unsigned int cIdx = 0; cIdx < numComponents; ++cIdx) { - if (pIdx == cIdx) - continue; - // resize transmissibility matrix & mole fraction vector resizeMatrix(T_[pIdx][cIdx], iv.numFaces(), iv.numKnowns()); resizeVector(xj_[pIdx][cIdx], iv.numKnowns()); // resize outsideTij on surface grids - if (dim < dimWorld) + using GridView = typename InteractionVolume::Traits::GridView; + if (int(GridView::dimension) < int(GridView::dimensionworld)) { outsideT_[pIdx][cIdx].resize(iv.numFaces()); - using LocalIndexType = typename InteractionVolume::Traits::LocalIndexType; + using LocalIndexType = typename InteractionVolume::Traits::IndexSet::LocalIndexType; for (LocalIndexType i = 0; i < iv.numFaces(); ++i) { const auto numNeighbors = iv.localScvf(i).neighboringLocalScvIndices().size() - 1; @@ -229,12 +225,12 @@ public: } //! Access to the iv-wide mole fractions of a component in one phase - const Vector& moleFractions(unsigned int pIdx, unsigned int compIdx) const { return xj_[pIdx][compIdx]; } - Vector& moleFractions(unsigned int pIdx, unsigned int compIdx) { return xj_[pIdx][compIdx]; } + const CellVector& moleFractions(unsigned int pIdx, unsigned int compIdx) const { return xj_[pIdx][compIdx]; } + CellVector& moleFractions(unsigned int pIdx, unsigned int compIdx) { return xj_[pIdx][compIdx]; } //! The transmissibilities associated with diffusive fluxes - const Matrix& diffusionT() const { return T_[phaseIdx_][compIdx_]; } - Matrix& diffusionT() { return T_[phaseIdx_][compIdx_]; } + const TMatrix& diffusionT() const { return T_[phaseIdx_][compIdx_]; } + TMatrix& diffusionT() { return T_[phaseIdx_][compIdx_]; } //! The transmissibilities for "outside" faces (used on surface grids) const OutsideTContainer& diffusionTout() const { return outsideT_[phaseIdx_][compIdx_]; } @@ -242,22 +238,19 @@ public: private: //! diffusion-related variables - unsigned int phaseIdx_; //!< The phase index set for the context - unsigned int compIdx_; //!< The component index set for the context - std::array< std::array<Matrix, numComponents>, numPhases > T_; //!< The transmissibilities such that f_i = T_ij*x_j - std::array< std::array<Vector, numComponents>, numPhases > xj_; //!< The interaction volume-wide mole fractions + unsigned int phaseIdx_; //!< The phase index set for the context + unsigned int compIdx_; //!< The component index set for the context + std::array< std::array<TMatrix, numComponents>, numPhases > T_; //!< The transmissibilities such that f_i = T_ij*x_j + std::array< std::array<CellVector, numComponents>, numPhases > xj_; //!< The interaction volume-wide mole fractions std::array< std::array<OutsideTContainer, numComponents>, numPhases> outsideT_; }; //! Data handle for quantities related to heat conduction -template<class TypeTag, class M, class V, class LI, bool EnableHeatConduction> +template<class MatVecTraits, class PhysicsTraits, bool enableHeatConduction> class HeatConductionDataHandle { - using Matrix = M; - using Vector = V; - - static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension; - static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld; + using TMatrix = typename MatVecTraits::TMatrix; + using CellVector = typename MatVecTraits::CellVector; public: //! prepare data handle for subsequent fill @@ -269,11 +262,12 @@ public: resizeVector(Tj_, iv.numKnowns()); //! resize outsideTij on surface grids - if (dim < dimWorld) + using GridView = typename InteractionVolume::Traits::GridView; + if (int(GridView::dimension) < int(GridView::dimensionworld)) { outsideT_.resize(iv.numFaces()); - using LocalIndexType = typename InteractionVolume::Traits::LocalIndexType; + using LocalIndexType = typename InteractionVolume::Traits::IndexSet::LocalIndexType; for (LocalIndexType i = 0; i < iv.numFaces(); ++i) { const auto numNeighbors = iv.localScvf(i).neighboringLocalScvIndices().size() - 1; @@ -285,49 +279,47 @@ public: } //! Access to the iv-wide temperatures - const Vector& temperatures() const { return Tj_; } - Vector& temperatures() { return Tj_; } + const CellVector& temperatures() const { return Tj_; } + CellVector& temperatures() { return Tj_; } //! The transmissibilities associated with conductive fluxes - const Matrix& heatConductionT() const { return T_; } - Matrix& heatConductionT() { return T_; } + const TMatrix& heatConductionT() const { return T_; } + TMatrix& heatConductionT() { return T_; } //! The transmissibilities for "outside" faces (used on surface grids) - const std::vector< std::vector<Vector> >& heatConductionTout() const { return outsideT_; } - std::vector< std::vector<Vector> >& heatConductionTout() { return outsideT_; } + const std::vector< std::vector<CellVector> >& heatConductionTout() const { return outsideT_; } + std::vector< std::vector<CellVector> >& heatConductionTout() { return outsideT_; } private: // heat conduction-related variables - Matrix T_; //!< The transmissibilities such that f_i = T_ij*T_j - Vector Tj_; //!< The interaction volume-wide temperatures - std::vector< std::vector<Vector> > outsideT_; //!< The transmissibilities for "outside" faces (only necessary on surface grids) + TMatrix T_; //!< The transmissibilities such that f_i = T_ij*T_j + CellVector Tj_; //!< The interaction volume-wide temperatures + std::vector< std::vector<CellVector> > outsideT_; //!< The transmissibilities for "outside" faces (only necessary on surface grids) }; //! Process-dependent data handles when related process is disabled -template<class TypeTag, class M, class V, class LI> -class AdvectionDataHandle<TypeTag, M, V, LI, false> : public EmptyDataHandle {}; -template<class TypeTag, class M, class V, class LI> -class DiffusionDataHandle<TypeTag, M, V, LI, false> : public EmptyDataHandle {}; -template<class TypeTag, class M, class V, class LI> -class HeatConductionDataHandle<TypeTag, M, V, LI, false> : public EmptyDataHandle {}; +template<class MatVecTraits, class PhysicsTraits> +class AdvectionDataHandle<MatVecTraits, PhysicsTraits, false> : public EmptyDataHandle {}; +template<class MatVecTraits, class PhysicsTraits> +class DiffusionDataHandle<MatVecTraits, PhysicsTraits, false> : public EmptyDataHandle {}; +template<class MatVecTraits, class PhysicsTraits> +class HeatConductionDataHandle<MatVecTraits, PhysicsTraits, false> : public EmptyDataHandle {}; /*! * \ingroup CCMpfaDiscretization * \brief Class for the interaction volume data handle. * - * \tparam TypeTag The problem TypeTag - * \tparam M The type used for iv-local matrices - * \tparam V The type used for iv-local vectors - * \tparam LI The type used for iv-local indexing + * \tparam MVT The matrix/vector traits collecting type information used by the iv + * \tparam PT The physics traits collecting data on the physical processes to be considered */ -template<class TypeTag, class M, class V, class LI> -class InteractionVolumeDataHandle : public AdvectionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableAdvection)>, - public DiffusionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion)>, - public HeatConductionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableEnergyBalance)> +template<class MVT, class PT> +class InteractionVolumeDataHandle : public AdvectionDataHandle<MVT, PT, PT::enableAdvection>, + public DiffusionDataHandle<MVT, PT, PT::enableMolecularDiffusion>, + public HeatConductionDataHandle<MVT, PT, PT::enableHeatConduction> { - using AdvectionHandle = AdvectionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableAdvection)>; - using DiffusionHandle = DiffusionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableMolecularDiffusion)>; - using HeatConductionHandle = HeatConductionDataHandle<TypeTag, M, V, LI, GET_PROP_VALUE(TypeTag, EnableEnergyBalance)>; + using AdvectionHandle = AdvectionDataHandle<MVT, PT, PT::enableAdvection>; + using DiffusionHandle = DiffusionDataHandle<MVT, PT, PT::enableMolecularDiffusion>; + using HeatConductionHandle = HeatConductionDataHandle<MVT, PT, PT::enableHeatConduction>; public: //! prepare data handles for subsequent fills diff --git a/dumux/discretization/cellcentered/mpfa/localassembler.hh b/dumux/discretization/cellcentered/mpfa/localassembler.hh index d5eb6bf8289f43f07a475a4cf63aaf24546e5b77..ad06867aee3fb0c3b0c2ca9b89eb32e9ad6e3e91 100644 --- a/dumux/discretization/cellcentered/mpfa/localassembler.hh +++ b/dumux/discretization/cellcentered/mpfa/localassembler.hh @@ -33,11 +33,11 @@ namespace Dumux { //! Forward declaration of the implementation -template< class IVTraits, MpfaMethods M > class InteractionVolumeAssemblerImpl; +template< class P, class EG, class EV, MpfaMethods M > class InteractionVolumeAssemblerImpl; //! Alias to select the right implementation. -template< class IVTraits, MpfaMethods M > -using InteractionVolumeAssembler = InteractionVolumeAssemblerImpl< IVTraits, M >; +template< class P, class EG, class EV, MpfaMethods M > +using InteractionVolumeAssembler = InteractionVolumeAssemblerImpl< P, EG, EV, M >; /*! * \ingroup CCMpfaDiscretization @@ -47,17 +47,16 @@ using InteractionVolumeAssembler = InteractionVolumeAssemblerImpl< IVTraits, M > * for the available interaction volume implementations. these * should derive from this base clases. * - * \tparam IVTraits The Traits class used by the interaction volume + * \tparam P The problem type + * \tparam EG The element finite volume geometry + * \tparam EV The element volume variables type */ -template< class IVTraits > +template< class P, class EG, class EV > class InteractionVolumeAssemblerBase { - using Matrix = typename IVTraits::Matrix; - using Vector = typename IVTraits::Vector; - - using Problem = typename IVTraits::Problem; - using FVElementGeometry = typename IVTraits::FVElementGeometry; - using ElementVolumeVariables = typename IVTraits::ElementVolumeVariables; + using Problem = P; + using FVElementGeometry = EG; + using ElementVolumeVariables = EV; public: /*! @@ -87,15 +86,15 @@ class InteractionVolumeAssemblerBase * interaction volume-local transmissibility matrix. * * \tparam IV Interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param T The transmissibility matrix to be assembled * \param iv The interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class IV, class GetTensor > - void assemble(Matrix& T, IV& iv, const GetTensor& getTensor) + template< class IV, class TensorFunc > + void assemble(typename IV::Traits::MatVecTraits::MatVecTraits::TMatrix& T, IV& iv, const TensorFunc& getT) { DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assemble() function"); } @@ -108,16 +107,16 @@ class InteractionVolumeAssemblerBase * * \tparam TOutside Container to store the "outside" transmissibilities * \tparam IV Interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param outsideTij tij on "outside" faces to be assembled * \param T The transmissibility matrix tij to be assembled * \param iv The mpfa-o interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class TOutside, class IV, class GetTensor > - void assemble(TOutside& outsideTij, Matrix& T, IV& iv, const GetTensor& getTensor) + template< class TOutside, class IV, class TensorFunc > + void assemble(TOutside& outsideTij, typename IV::Traits::MatVecTraits::TMatrix& T, IV& iv, const TensorFunc& getT) { DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assemble() function to be used on surface grids"); } @@ -130,17 +129,21 @@ class InteractionVolumeAssemblerBase * \tparam GC The type of container used to store the * gravitational acceleration per scvf & phase * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param T The transmissibility matrix to be assembled * \param g Container to assemble gravity per scvf & phase * \param CA Matrix to store matrix product C*A^-1 * \param iv The interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class GC, class IV, class GetTensor > - void assembleWithGravity(Matrix& T, GC& g, Matrix& CA, IV& iv, const GetTensor& getTensor) + template< class GC, class IV, class TensorFunc > + void assembleWithGravity(typename IV::Traits::MatVecTraits::TMatrix& T, + GC& g, + typename IV::Traits::MatVecTraits::CMatrix& CA, + IV& iv, + const TensorFunc& getT) { DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assembleWithGravity() function"); } @@ -158,8 +161,8 @@ class InteractionVolumeAssemblerBase * \tparam GOut Type of container used to store gravity on "outside" faces * \tparam TOutside Container to store the "outside" transmissibilities * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param outsideTij tij on "outside" faces to be assembled * \param T The transmissibility matrix to be assembled @@ -168,17 +171,17 @@ class InteractionVolumeAssemblerBase * \param CA Matrix to store matrix product C*A^-1 * \param A Matrix to store the inverse A^-1 * \param iv The interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class GC, class GOut, class TOutside, class IV, class GetTensor > + template< class GC, class GOut, class TOutside, class IV, class TensorFunc > void assembleWithGravity(TOutside& outsideTij, - Matrix& T, + typename IV::Traits::MatVecTraits::TMatrix& T, GOut& outsideG, GC& g, - Matrix& CA, - Matrix& A, + typename IV::Traits::MatVecTraits::CMatrix& CA, + typename IV::Traits::MatVecTraits::AMatrix& A, IV& iv, - const GetTensor& getTensor) + const TensorFunc& getT) { DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assembleWithGravity() function to be used on surface grids"); } @@ -196,7 +199,7 @@ class InteractionVolumeAssemblerBase * \param getU Lambda to obtain the desired cell value from grid indices */ template< class IV, class GetU > - void assemble(Vector& u, const IV& iv, const GetU& getU) + void assemble(typename IV::Traits::MatVecTraits::CellVector& u, const IV& iv, const GetU& getU) { DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assemble() function for the cell unknowns"); } @@ -211,17 +214,17 @@ class InteractionVolumeAssemblerBase * * \tparam GC The type of container used to store the * gravitational acceleration per scvf & phase - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param g Container to assemble gravity per scvf & phase * \param iv The interaction volume * \param CA Projection matrix transforming the gravity terms in the local system of * equations to the entire set of faces within the interaction volume - * \param getTensor Lambda to evaluate scv-wise hydraulic conductivities + * \param getT Lambda to evaluate scv-wise hydraulic conductivities */ - template< class GC, class IV, class GetTensor > - void assembleGravity(GC& g, const IV& iv, const Matrix& CA, const GetTensor& getTensor) + template< class GC, class IV, class TensorFunc > + void assembleGravity(GC& g, const IV& iv, const typename IV::Traits::MatVecTraits::CMatrix& CA, const TensorFunc& getT) { DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assembleGravity() function"); } @@ -240,8 +243,8 @@ class InteractionVolumeAssemblerBase * gravitational acceleration per scvf & phase * \tparam GOut Type of container used to store gravity on "outside" faces * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param g Container to store gravity per scvf & phase * \param outsideG Container to store gravity per "outside" scvf & phase @@ -249,15 +252,15 @@ class InteractionVolumeAssemblerBase * \param CA Projection matrix transforming the gravity terms in the local system of * equations to the entire set of faces within the interaction volume * \param A Matrix needed for the "reconstruction" of face unknowns as a function of gravity - * \param getTensor Lambda to evaluate scv-wise hydraulic conductivities + * \param getT Lambda to evaluate scv-wise hydraulic conductivities */ - template< class GC, class GOut, class IV, class GetTensor > + template< class GC, class GOut, class IV, class TensorFunc > void assembleGravity(GC& g, GOut& outsideG, const IV& iv, - const Matrix& CA, - const Matrix& A, - const GetTensor& getTensor) + const typename IV::Traits::MatVecTraits::CMatrix& CA, + const typename IV::Traits::MatVecTraits::AMatrix& A, + const TensorFunc& getT) { DUNE_THROW(Dune::NotImplemented, "Implementation does not provide a assembleGravity() function to be used on surface grids"); } diff --git a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh index be2e526ac16536fd6a71bc3d72877fc9dd503a4a..7549c2447956bc675a8198a0b0bab0d990dd705d 100644 --- a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh +++ b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh @@ -24,15 +24,16 @@ #ifndef DUMUX_DISCRETIZATION_CC_MPFA_O_INTERACTIONVOLUME_HH #define DUMUX_DISCRETIZATION_CC_MPFA_O_INTERACTIONVOLUME_HH +#include <type_traits> + #include <dune/common/dynmatrix.hh> #include <dune/common/dynvector.hh> #include <dune/common/fvector.hh> +#include <dune/common/reservedvector.hh> #include <dumux/common/math.hh> -#include <dumux/common/properties.hh> #include <dumux/common/matrixvectorhelper.hh> -#include <dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh> #include <dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh> #include <dumux/discretization/cellcentered/mpfa/dualgridindexset.hh> #include <dumux/discretization/cellcentered/mpfa/localfacedata.hh> @@ -46,45 +47,51 @@ namespace Dumux //! Forward declaration of the o-method's interaction volume template< class Traits > class CCMpfaOInteractionVolume; -//! Specialization of the default interaction volume traits class for the mpfa-o method -template< class TypeTag > +/*! + * \ingroup CCMpfaDiscretization + * \brief The default interaction volume traits class for the mpfa-o method. + * This uses dynamic types types for matrices/vectors in order to work + * on general grids. For interaction volumes known at compile time use + * the static interaction volume implementation. + * + * \tparam NodalIndexSet The type used for the dual grid's nodal index sets + * \tparam Scalar The Type used for scalar values + */ +template< class NodalIndexSet, class Scalar > struct CCMpfaODefaultInteractionVolumeTraits { private: - using NodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet); using GridIndexType = typename NodalIndexSet::GridIndexType; - static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension; - static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld; + using LocalIndexType = typename NodalIndexSet::LocalIndexType; + + static constexpr int dim = NodalIndexSet::Traits::GridView::dimension; + static constexpr int dimWorld = NodalIndexSet::Traits::GridView::dimensionworld; + + //! Matrix/Vector traits to be used by the data handle + struct MVTraits + { + using AMatrix = Dune::DynamicMatrix< Scalar >; + using BMatrix = Dune::DynamicMatrix< Scalar >; + using CMatrix = Dune::DynamicMatrix< Scalar >; + using DMatrix = Dune::DynamicMatrix< Scalar >; + using TMatrix = Dune::DynamicMatrix< Scalar >; + using CellVector = Dune::DynamicVector< Scalar >; + using FaceVector = Dune::DynamicVector< Scalar >; + }; public: - //! export the problem type (needed for iv-local assembly) - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - //! export the type of the local view on the finite volume grid geometry - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView; - //! export the type of the local view on the grid volume variables - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); //! export the type of grid view - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - //! export the type used for scalar values - using ScalarType = typename GET_PROP_TYPE(TypeTag, Scalar); - //! export the type of the mpfa helper class - using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); - //! export the type used for local indices - using LocalIndexType = typename NodalIndexSet::LocalIndexType; + using GridView = typename NodalIndexSet::Traits::GridView; //! export the type for the interaction volume index set using IndexSet = CCMpfaOInteractionVolumeIndexSet< NodalIndexSet >; //! export the type of interaction-volume local scvs - using LocalScvType = CCMpfaOInteractionVolumeLocalScv< IndexSet, ScalarType, dim, dimWorld >; + using LocalScvType = CCMpfaOInteractionVolumeLocalScv< IndexSet, Scalar, dim, dimWorld >; //! export the type of interaction-volume local scvfs using LocalScvfType = CCMpfaOInteractionVolumeLocalScvf< IndexSet >; //! export the type of used for the iv-local face data using LocalFaceData = InteractionVolumeLocalFaceData<GridIndexType, LocalIndexType>; - //! export the type used for iv-local matrices - using Matrix = Dune::DynamicMatrix< ScalarType >; - //! export the type used for iv-local vectors - using Vector = Dune::DynamicVector< ScalarType >; - //! export the data handle type for this iv - using DataHandle = InteractionVolumeDataHandle< TypeTag, Matrix, Vector, LocalIndexType >; + //! export the matrix/vector traits to be used by the iv + using MatVecTraits = MVTraits; }; /*! @@ -94,38 +101,41 @@ public: * and can be used at boundaries and on unstructured grids. */ template< class Traits > -class CCMpfaOInteractionVolume : public CCMpfaInteractionVolumeBase< CCMpfaOInteractionVolume<Traits>, Traits > +class CCMpfaOInteractionVolume + : public CCMpfaInteractionVolumeBase< CCMpfaOInteractionVolume<Traits>, Traits > { - using ThisType = CCMpfaOInteractionVolume< Traits >; - using ParentType = CCMpfaInteractionVolumeBase< CCMpfaOInteractionVolume<Traits>, Traits >; - - using Scalar = typename Traits::ScalarType; - using Helper = typename Traits::MpfaHelper; - using Problem = typename Traits::Problem; - using FVElementGeometry = typename Traits::FVElementGeometry; - using GridView = typename Traits::GridView; using Element = typename GridView::template Codim<0>::Entity; + using IndexSet = typename Traits::IndexSet; + using GridIndexType = typename IndexSet::GridIndexType; + using LocalIndexType = typename IndexSet::LocalIndexType; + using Stencil = typename IndexSet::NodalGridStencilType; + static constexpr int dim = GridView::dimension; + static constexpr int dimWorld = GridView::dimensionworld; + + //! export scalar type from T matrix and define omegas + using Scalar = typename Traits::MatVecTraits::TMatrix::value_type; using DimVector = Dune::FieldVector<Scalar, dim>; + using FaceOmegas = typename std::conditional< (dim<dimWorld), + std::vector<DimVector>, + Dune::ReservedVector<DimVector, 2> >::type; + + using AMatrix = typename Traits::MatVecTraits::AMatrix; + using BMatrix = typename Traits::MatVecTraits::BMatrix; + using CMatrix = typename Traits::MatVecTraits::CMatrix; - using Matrix = typename Traits::Matrix; using LocalScvType = typename Traits::LocalScvType; using LocalScvfType = typename Traits::LocalScvfType; using LocalFaceData = typename Traits::LocalFaceData; - using IndexSet = typename Traits::IndexSet; - using GridIndexType = typename GridView::IndexSet::IndexType; - using LocalIndexType = typename Traits::LocalIndexType; - using Stencil = typename IndexSet::GridStencilType; - +public: //! Data attached to scvf touching Dirichlet boundaries. //! For the default o-scheme, we only store the corresponding vol vars index. class DirichletData { GridIndexType volVarIndex_; - public: //! Constructor DirichletData(const GridIndexType index) : volVarIndex_(index) {} @@ -134,11 +144,14 @@ class CCMpfaOInteractionVolume : public CCMpfaInteractionVolumeBase< CCMpfaOInte GridIndexType volVarIndex() const { return volVarIndex_; } }; -public: + //! export the type used for transmissibility storage + using TransmissibilityStorage = std::vector< FaceOmegas >; + //! publicly state the mpfa-scheme this interaction volume is associated with static constexpr MpfaMethods MpfaMethod = MpfaMethods::oMethod; //! Sets up the local scope for a given iv index set + template< class Problem, class FVElementGeometry > void setUpLocalScope(const IndexSet& indexSet, const Problem& problem, const FVElementGeometry& fvGeometry) @@ -147,7 +160,7 @@ public: // index set of the dual grid's nodal index set stencil_ = &indexSet.nodalIndexSet().globalScvIndices(); - // number of interaction-volume-local (= node-local for o-scheme) scvs/scvf + // number of interaction-volume-local scvs(=node-local for o-scheme) and scvfs numFaces_ = indexSet.numFaces(); const auto numLocalScvs = indexSet.numScvs(); const auto numGlobalScvfs = indexSet.nodalIndexSet().numScvfs(); @@ -164,29 +177,26 @@ public: dirichletData_.reserve(numFaces_); localFaceData_.reserve(numGlobalScvfs); - // set up quantities related to sub-control volumes + // set up stuff related to sub-control volumes const auto& scvIndices = indexSet.globalScvIndices(); for (LocalIndexType scvIdxLocal = 0; scvIdxLocal < numLocalScvs; scvIdxLocal++) { - scvs_.emplace_back(Helper(), + elements_.emplace_back(fvGeometry.fvGridGeometry().element( scvIndices[scvIdxLocal] )); + scvs_.emplace_back(fvGeometry.fvGridGeometry().mpfaHelper(), fvGeometry, fvGeometry.scv( scvIndices[scvIdxLocal] ), scvIdxLocal, indexSet); - elements_.emplace_back(fvGeometry.fvGridGeometry().element( scvIndices[scvIdxLocal] )); } // keep track of the number of unknowns etc numUnknowns_ = 0; numKnowns_ = numLocalScvs; - // resize omega storage container - wijk_.resize(numFaces_); - // set up quantitites related to sub-control volume faces + wijk_.resize(numFaces_); for (LocalIndexType faceIdxLocal = 0; faceIdxLocal < numFaces_; ++faceIdxLocal) { - // get corresponding grid scvf const auto& scvf = fvGeometry.scvf(indexSet.scvfIdxGlobal(faceIdxLocal)); // the neighboring scvs in local indices (order: 0 - inside scv, 1..n - outside scvs) @@ -195,6 +205,10 @@ public: // create local face data object for this face localFaceData_.emplace_back(faceIdxLocal, neighborScvIndicesLocal[0], scvf.index()); + // we will need as many omegas as scvs around the face + const auto numNeighborScvs = neighborScvIndicesLocal.size(); + wijk_[faceIdxLocal].resize(numNeighborScvs); + // create iv-local scvf object if (scvf.boundary()) { @@ -207,18 +221,11 @@ public: } else scvfs_.emplace_back(scvf, neighborScvIndicesLocal, numUnknowns_++, /*isDirichlet*/false); - - // on boundary faces we will only need one inside omega - wijk_[faceIdxLocal].resize(1); } else { scvfs_.emplace_back(scvf, neighborScvIndicesLocal, numUnknowns_++, /*isDirichlet*/false); - // we will need as many omegas as scvs around the face - const auto numNeighborScvs = neighborScvIndicesLocal.size(); - wijk_[faceIdxLocal].resize(numNeighborScvs); - // add local face data objects for the outside faces for (LocalIndexType i = 1; i < numNeighborScvs; ++i) { @@ -234,8 +241,12 @@ public: outsideLocalScvIdx, // iv-local scv index i-1, // scvf-local index in outside faces flipScvf.index()); // global scvf index + break; // go to next outside face } } + + // make sure we found it + assert(localFaceData_.back().ivLocalInsideScvIndex() == outsideLocalScvIdx); } } } @@ -262,13 +273,13 @@ public: const Stencil& stencil() const { return *stencil_; } //! returns the grid element corresponding to a given iv-local scv idx - const Element& element(const LocalIndexType ivLocalScvIdx) const { return elements_[ivLocalScvIdx]; } + const Element& element(LocalIndexType ivLocalScvIdx) const { return elements_[ivLocalScvIdx]; } //! returns the local scvf entity corresponding to a given iv-local scvf idx - const LocalScvfType& localScvf(const LocalIndexType ivLocalScvfIdx) const { return scvfs_[ivLocalScvfIdx]; } + const LocalScvfType& localScvf(LocalIndexType ivLocalScvfIdx) const { return scvfs_[ivLocalScvfIdx]; } //! returns the local scv entity corresponding to a given iv-local scv idx - const LocalScvType& localScv(const LocalIndexType ivLocalScvIdx) const { return scvs_[ivLocalScvIdx]; } + const LocalScvType& localScv(LocalIndexType ivLocalScvIdx) const { return scvs_[ivLocalScvIdx]; } //! returns a reference to the container with the local face data const std::vector<LocalFaceData>& localFaceData() const { return localFaceData_; } @@ -277,38 +288,41 @@ public: const std::vector<DirichletData>& dirichletData() const { return dirichletData_; } //! returns the matrix associated with face unknowns in local equation system - const Matrix& A() const { return A_; } - Matrix& A() { return A_; } + const AMatrix& A() const { return A_; } + AMatrix& A() { return A_; } //! returns the matrix associated with cell unknowns in local equation system - const Matrix& B() const { return B_; } - Matrix& B() { return B_; } + const BMatrix& B() const { return B_; } + BMatrix& B() { return B_; } //! returns the matrix associated with face unknowns in flux expressions - const Matrix& C() const { return C_; } - Matrix& C() { return C_; } + const CMatrix& C() const { return C_; } + CMatrix& C() { return C_; } //! returns container storing the transmissibilities for each face & coordinate - const std::vector< std::vector< DimVector > >& omegas() const { return wijk_; } - std::vector< std::vector< DimVector > >& omegas() { return wijk_; } + const TransmissibilityStorage& omegas() const { return wijk_; } + TransmissibilityStorage& omegas() { return wijk_; } //! returns the number of interaction volumes living around a vertex - //! the mpfa-o scheme always constructs one iv per vertex - template< class NodalIndexSet > - static std::size_t numInteractionVolumesAtVertex(const NodalIndexSet& nodalIndexSet) { return 1; } + template< class NI > + static constexpr std::size_t numIVAtVertex(const NI& nodalIndexSet) { return 1; } //! adds the iv index sets living around a vertex to a given container //! and stores the the corresponding index in a map for each scvf - template<class IvIndexSetContainer, class ScvfIndexMap, class NodalIndexSet> - static void addInteractionVolumeIndexSets(IvIndexSetContainer& ivIndexSetContainer, - ScvfIndexMap& scvfIndexMap, - const NodalIndexSet& nodalIndexSet) + template< class IvIndexSetContainer, + class ScvfIndexMap, + class NodalIndexSet, + class FlipScvfIndexSet > + static void addIVIndexSets(IvIndexSetContainer& ivIndexSetContainer, + ScvfIndexMap& scvfIndexMap, + const NodalIndexSet& nodalIndexSet, + const FlipScvfIndexSet& flipScvfIndexSet) { // the global index of the iv index set that is about to be created const auto curGlobalIndex = ivIndexSetContainer.size(); // make the one index set for this node - ivIndexSetContainer.emplace_back(nodalIndexSet); + ivIndexSetContainer.emplace_back(nodalIndexSet, flipScvfIndexSet); // store the index mapping for (const auto scvfIdx : nodalIndexSet.globalScvfIndices()) @@ -327,12 +341,12 @@ private: std::vector<DirichletData> dirichletData_; // Matrices needed for computation of transmissibilities - Matrix A_; - Matrix B_; - Matrix C_; + AMatrix A_; + BMatrix B_; + CMatrix C_; // The omega factors are stored during assembly of local system - std::vector< std::vector< DimVector > > wijk_; + TransmissibilityStorage wijk_; // sizes involved in the local system equations std::size_t numFaces_; diff --git a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolumeindexset.hh b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolumeindexset.hh index 1d63d804f259675a3619111b2056aa24dcd9430f..51894f6ce22f42b0c708117f76a06b45fe062243 100644 --- a/dumux/discretization/cellcentered/mpfa/omethod/interactionvolumeindexset.hh +++ b/dumux/discretization/cellcentered/mpfa/omethod/interactionvolumeindexset.hh @@ -47,22 +47,23 @@ public: using LocalIndexType = typename DualGridNodalIndexSet::LocalIndexType; using GridIndexType = typename DualGridNodalIndexSet::GridIndexType; - // Export the types used for local/grid stencils - using LocalStencilType = typename DualGridNodalIndexSet::LocalStencilType; - using GridStencilType = typename DualGridNodalIndexSet::GridStencilType; - using GridScvfStencilType = typename DualGridNodalIndexSet::GridScvfStencilType; + //! Export the stencil types used + using NodalGridStencilType = typename DualGridNodalIndexSet::NodalGridStencilType; + using NodalLocalStencilType = typename DualGridNodalIndexSet::NodalLocalStencilType; + using NodalGridScvfStencilType = typename DualGridNodalIndexSet::NodalGridScvfStencilType; //! Export the type used for the neighbor scv index sets of the scvfs using ScvfNeighborLocalIndexSet = typename DualGridNodalIndexSet::ScvfNeighborLocalIndexSet; //! The constructor - CCMpfaOInteractionVolumeIndexSet(const NodalIndexSet& nodalIndexSet) : nodalIndexSet_(nodalIndexSet) + template< class FlipScvfIndexSet > + CCMpfaOInteractionVolumeIndexSet(const NodalIndexSet& nodalIndexSet, const FlipScvfIndexSet& flipScvfIndexSet) + : nodalIndexSet_(nodalIndexSet) { - // determine the number of iv-local faces for memory reservation - // note that this might be a vast overestimation on surface grids! const auto numNodalScvfs = nodalIndexSet.numScvfs(); - // keeps track of which nodal scvfs have been handled already + // kee track of which nodal scvfs have been handled already + nodeToIvScvf_.resize(numNodalScvfs); std::vector<bool> isHandled(numNodalScvfs, false); // go over faces in nodal index set, check if iv-local face has been @@ -77,6 +78,7 @@ public: // for scvfs touching the boundary there are no "outside" scvfs if (nodalIndexSet.scvfIsOnBoundary(i)) { + scvfNeighborScvLocalIndices_.push_back({nodalIndexSet.insideScvIdxLocal(i)}); nodeToIvScvf_[i] = ivToNodeScvf_.size(); isHandled[i] = true; ivToNodeScvf_.push_back(i); @@ -84,79 +86,46 @@ public: continue; } - // We insert a new iv-local face and find all "outside" scvfs that map - // to this face as well by comparing the set of neighboring scv indices. - const auto scvIndices = [&nodalIndexSet, i] () - { - auto tmp = nodalIndexSet.neighboringScvIndices(i); - std::sort(tmp.begin(), tmp.end()); - return tmp; - } (); - const auto numNeighborsI = scvIndices.size(); - - std::vector<LocalIndexType> outsideScvfs; - for (LocalIndexType j = i+1; j < numNodalScvfs; ++j) - { - // a face that has been handled already cannot be an "outside" face here - if (!isHandled[j]) - { - const auto scvIndices2 = [&nodalIndexSet, j] () - { - auto tmp = nodalIndexSet.neighboringScvIndices(j); - std::sort(tmp.begin(), tmp.end()); - return tmp; - } (); - - // if the sizes aren't equal, this can't be an "outside" face - if (scvIndices2.size() != numNeighborsI) - continue; - - // if the neighboring scv indices are the same, this is an "outside" face - if (std::equal(scvIndices.begin(), scvIndices.end(), scvIndices2.begin())) - outsideScvfs.push_back(j); - } - } - - // insert mappings + // insert a new iv-local face const auto curIvLocalScvfIdx = ivToNodeScvf_.size(); nodeToIvScvf_[i] = curIvLocalScvfIdx; isHandled[i] = true; - for (const auto nodeLocalScvfIdx : outsideScvfs) + + // construct local index sets + const auto& flipScvfIndices = flipScvfIndexSet[nodalIndexSet.scvfIdxGlobal(i)]; + const auto numFlipIndices = flipScvfIndices.size(); + + ScvfNeighborLocalIndexSet neighborsLocal; + neighborsLocal.resize(numFlipIndices + 1); + neighborsLocal[0] = nodalIndexSet.insideScvIdxLocal(i); + + // mappings for all flip scvf + for (unsigned int j = 0; j < numFlipIndices; ++j) { - nodeToIvScvf_[nodeLocalScvfIdx] = curIvLocalScvfIdx; - isHandled[nodeLocalScvfIdx] = true; + const auto outsideScvfIdx = flipScvfIndices[j]; + for (unsigned int nodeLocalIdx = 0; nodeLocalIdx < nodalIndexSet.numScvfs(); ++nodeLocalIdx) + { + if (nodalIndexSet.scvfIdxGlobal(nodeLocalIdx) == outsideScvfIdx) + { + neighborsLocal[j+1] = nodalIndexSet.insideScvIdxLocal(nodeLocalIdx); + nodeToIvScvf_[nodeLocalIdx] = curIvLocalScvfIdx; + isHandled[nodeLocalIdx] = true; + break; // go to next outside scvf + } + } } + + scvfNeighborScvLocalIndices_.push_back(neighborsLocal); ivToNodeScvf_.push_back(i); numFaces_++; } - - // compute local neighboring scv indices for the iv-local scvfs - scvfNeighborScvLocalIndices_.resize(numFaces_); - for (unsigned int i = 0; i < numFaces_; ++i) - { - const auto& neighborsGlobal = nodalIndexSet_.neighboringScvIndices(ivToNodeScvf_[i]); - const auto numNeighbors = nodalIndexSet_.scvfIsOnBoundary(ivToNodeScvf_[i]) ? 1 : neighborsGlobal.size(); - - scvfNeighborScvLocalIndices_[i].resize(numNeighbors); - for (unsigned int j = 0; j < numNeighbors; ++j) - scvfNeighborScvLocalIndices_[i][j] = findLocalScvIdx_(neighborsGlobal[j]); - } } //! returns the corresponding nodal index set - const DualGridNodalIndexSet& nodalIndexSet() const { return nodalIndexSet_; } - - //! returns a global scvf idx for a given iv_local scvf index - GridIndexType scvfIdxGlobal(LocalIndexType ivLocalScvfIdx) const - { return nodalIndexSet_.scvfIdxGlobal( ivToNodeScvf_[ivLocalScvfIdx] ); } + const NodalIndexSet& nodalIndexSet() const { return nodalIndexSet_; } - //! returns the iv-local scvf idx of the i-th scvfs embedded in a local scv - LocalIndexType scvfIdxLocal(LocalIndexType scvIdxLocal, unsigned int i) const - { return nodeToIvScvf_[ nodalIndexSet_.scvfIdxLocal(scvIdxLocal, i) ]; } - - //! returns the local indices of the neighboring scvs of an scvf - const ScvfNeighborLocalIndexSet& neighboringLocalScvIndices(LocalIndexType ivLocalScvfIdx) const - { return scvfNeighborScvLocalIndices_[ivLocalScvfIdx]; } + //! returns the global scv indices connected to this dual grid node + const NodalGridStencilType& globalScvIndices() const { return nodalIndexSet_.globalScvIndices(); } //! returns the number of faces in the interaction volume std::size_t numFaces() const { return numFaces_; } @@ -164,30 +133,40 @@ public: //! returns the number of scvs in the interaction volume std::size_t numScvs() const { return nodalIndexSet_.numScvs(); } - //! returns the global scv indices connected to this dual grid node - const GridStencilType& globalScvIndices() const { return nodalIndexSet_.globalScvIndices(); } + //! returns a global scvf idx for a given iv-local scvf index + GridIndexType scvfIdxGlobal(LocalIndexType ivLocalScvfIdx) const + { + assert(ivLocalScvfIdx < numFaces()); + return nodalIndexSet_.scvfIdxGlobal( ivToNodeScvf_[ivLocalScvfIdx] ); + } - //! returns the global scvf indices connected to this dual grid node - const GridScvfStencilType& globalScvfIndices() const { return nodalIndexSet_.globalScvfIndices(); } + //! returns the iv-local scvf idx of the i-th scvf embedded in a local scv + LocalIndexType scvfIdxLocal(LocalIndexType scvIdxLocal, unsigned int i) const + { + assert(nodalIndexSet_.scvfIdxLocal(scvIdxLocal, i) < nodeToIvScvf_.size()); + return nodeToIvScvf_[ nodalIndexSet_.scvfIdxLocal(scvIdxLocal, i) ]; + } -private: - //! returns the local scv index to a given global scv index - unsigned int findLocalScvIdx_(GridIndexType globalScvIdx) const + //! returns the local indices of the neighboring scvs of an scvf + const ScvfNeighborLocalIndexSet& neighboringLocalScvIndices(LocalIndexType ivLocalScvfIdx) const { - auto it = std::find( nodalIndexSet_.globalScvIndices().begin(), nodalIndexSet_.globalScvIndices().end(), globalScvIdx ); - assert(it != nodalIndexSet_.globalScvIndices().end() && "Global scv index not found in local container!"); - return std::distance(nodalIndexSet_.globalScvIndices().begin(), it); + assert(ivLocalScvfIdx < numFaces()); + return scvfNeighborScvLocalIndices_[ivLocalScvfIdx]; } - const DualGridNodalIndexSet& nodalIndexSet_; +private: + using NI = NodalIndexSet; std::size_t numFaces_; - Dune::ReservedVector< LocalIndexType, NodalIndexSet::maxNumScvfsAtNode > ivToNodeScvf_; - Dune::ReservedVector< LocalIndexType, NodalIndexSet::maxNumScvfsAtNode > nodeToIvScvf_; - + const NI& nodalIndexSet_; + // Index maps from and to nodal index set. For the map to the + // nodal set we use the same storage type as we know the nodal + // has more faces, thus sufficient guaranteed here! + typename NI::Traits::template NodalScvfDataStorage< LocalIndexType > ivToNodeScvf_; + typename NI::Traits::template NodalScvfDataStorage< LocalIndexType > nodeToIvScvf_; // maps to each scvf a list of neighbouring scv indices // ordering: 0 - inside scv idx; 1..n - outside scv indices - Dune::ReservedVector< ScvfNeighborLocalIndexSet, NodalIndexSet::maxNumScvfsAtNode > scvfNeighborScvLocalIndices_; + typename NI::Traits::template NodalScvfDataStorage< ScvfNeighborLocalIndexSet > scvfNeighborScvLocalIndices_; }; } // end namespace Dumux diff --git a/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh b/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh index fd6700c7273d300f4433326e262320f653e77614..50116c73c6426a33c0309c797891c1dc7c801144 100644 --- a/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh +++ b/dumux/discretization/cellcentered/mpfa/omethod/localassembler.hh @@ -41,20 +41,15 @@ namespace Dumux * \brief Specialization of the interaction volume-local * assembler class for the schemes using an mpfa-o type assembly. * - * \tparam IVTraits The traits class used by the interaction volume implemetation + * \tparam P The problem type + * \tparam EG The element finite volume geometry + * \tparam EV The element volume variables type */ -template< class IVTraits > -class InteractionVolumeAssemblerImpl< IVTraits, MpfaMethods::oMethod > - : public InteractionVolumeAssemblerBase< IVTraits > +template< class P, class EG, class EV > +class InteractionVolumeAssemblerImpl< P, EG, EV, MpfaMethods::oMethod > + : public InteractionVolumeAssemblerBase< P, EG, EV > { - using ParentType = InteractionVolumeAssemblerBase< IVTraits >; - - using LocalIndexType = typename IVTraits::LocalIndexType; - using Matrix = typename IVTraits::Matrix; - using Vector = typename IVTraits::Vector; - - static constexpr int dim = IVTraits::LocalScvType::myDimension; - static constexpr int dimWorld = IVTraits::LocalScvType::worldDimension; + using ParentType = InteractionVolumeAssemblerBase< P, EG, EV >; public: //! Use the constructor of the base class @@ -65,18 +60,18 @@ public: * interaction volume in an mpfa-o type way. * * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. * which the local system is to be solved * * \param T The transmissibility matrix to be assembled * \param iv The interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class IV, class GetTensor > - void assemble(Matrix& T, IV& iv, const GetTensor& getTensor) + template< class IV, class TensorFunc > + void assemble(typename IV::Traits::MatVecTraits::TMatrix& T, IV& iv, const TensorFunc& getT) { // assemble D into T directly - assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getTensor); + assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getT); // maybe solve the local system if (iv.numUnknowns() > 0) @@ -95,19 +90,19 @@ public: * * \tparam TOutside Container to store the "outside" transmissibilities * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param outsideTij tij on "outside" faces to be assembled * \param T The transmissibility matrix tij to be assembled * \param iv The interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class TOutside, class IV, class GetTensor > - void assemble(TOutside& outsideTij, Matrix& T, IV& iv, const GetTensor& getTensor) + template< class TOutside, class IV, class TensorFunc > + void assemble(TOutside& outsideTij, typename IV::Traits::MatVecTraits::TMatrix& T, IV& iv, const TensorFunc& getT) { // assemble D into T directly - assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getTensor); + assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getT); // maybe solve the local system if (iv.numUnknowns() > 0) @@ -135,7 +130,8 @@ public: tij = 0.0; // add contributions from all local directions - for (LocalIndexType localDir = 0; localDir < dim; localDir++) + using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType; + for (LocalIndexType localDir = 0; localDir < IV::Traits::GridView::dimension; localDir++) { // the scvf corresponding to this local direction in the scv const auto& curLocalScvf = iv.localScvf(posLocalScv.scvfIdxLocal(localDir)); @@ -166,20 +162,24 @@ public: * \tparam GC The type of container used to store the * gravitational acceleration per scvf & phase * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param T The transmissibility matrix to be assembled * \param g Container to assemble gravity per scvf & phase * \param CA Matrix to store matrix product C*A^-1 * \param iv The mpfa-o interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class GC, class IV, class GetTensor > - void assembleWithGravity(Matrix& T, GC& g, Matrix& CA, IV& iv, const GetTensor& getTensor) + template< class GC, class IV, class TensorFunc > + void assembleWithGravity(typename IV::Traits::MatVecTraits::TMatrix& T, + GC& g, + typename IV::Traits::MatVecTraits::CMatrix& CA, + IV& iv, + const TensorFunc& getT) { // assemble D into T & C into CA directly - assembleLocalMatrices_(iv.A(), iv.B(), CA, T, iv, getTensor); + assembleLocalMatrices_(iv.A(), iv.B(), CA, T, iv, getT); // maybe solve the local system if (iv.numUnknowns() > 0) @@ -191,7 +191,7 @@ public: } // assemble gravitational acceleration container (enforce usage of mpfa-o type version) - assembleGravity(g, iv, CA, getTensor); + assembleGravity(g, iv, CA, getT); } /*! @@ -206,8 +206,8 @@ public: * \tparam GOut Type of container used to store gravity on "outside" faces * \tparam TOutside Container to store the "outside" transmissibilities * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param outsideTij tij on "outside" faces to be assembled * \param T The transmissibility matrix to be assembled @@ -216,20 +216,20 @@ public: * \param CA Matrix to store matrix product C*A^-1 * \param A Matrix to store the inverse A^-1 * \param iv The mpfa-o interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class GC, class GOut, class TOutside, class IV, class GetTensor > + template< class GC, class GOut, class TOutside, class IV, class TensorFunc > void assembleWithGravity(TOutside& outsideTij, - Matrix& T, + typename IV::Traits::MatVecTraits::TMatrix& T, GOut& outsideG, GC& g, - Matrix& CA, - Matrix& A, + typename IV::Traits::MatVecTraits::CMatrix& CA, + typename IV::Traits::MatVecTraits::AMatrix& A, IV& iv, - const GetTensor& getTensor) + const TensorFunc& getT) { // assemble D into T directly - assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getTensor); + assembleLocalMatrices_(iv.A(), iv.B(), iv.C(), T, iv, getT); // maybe solve the local system if (iv.numUnknowns() > 0) @@ -259,7 +259,8 @@ public: tij = 0.0; // add contributions from all local directions - for (LocalIndexType localDir = 0; localDir < dim; localDir++) + using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType; + for (LocalIndexType localDir = 0; localDir < IV::Traits::GridView::dimension; localDir++) { // the scvf corresponding to this local direction in the scv const auto& curLocalScvf = iv.localScvf(posLocalScv.scvfIdxLocal(localDir)); @@ -280,7 +281,7 @@ public: } } - assembleGravity(g, outsideG, iv, CA, A, getTensor); + assembleGravity(g, outsideG, iv, CA, A, getT); } /*! @@ -295,14 +296,15 @@ public: * \param getU Lambda to obtain the desired cell/Dirichlet value from grid index */ template< class IV, class GetU > - void assemble(Vector& u, const IV& iv, const GetU& getU) + void assemble(typename IV::Traits::MatVecTraits::CellVector& u, const IV& iv, const GetU& getU) { // put the cell pressures first + using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType; for (LocalIndexType i = 0; i < iv.numScvs(); ++i) u[i] = getU( iv.localScv(i).globalScvIndex() ); // Dirichlet BCs come afterwards - unsigned int i = iv.numScvs(); + LocalIndexType i = iv.numScvs(); for (const auto& data : iv.dirichletData()) u[i++] = getU( data.volVarIndex() ); } @@ -317,37 +319,40 @@ public: * * \tparam GC The type of container used to store the * gravitational acceleration per scvf & phase - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param g Container to assemble gravity per scvf & phase * \param iv The mpfa-o interaction volume * \param CA Projection matrix transforming the gravity terms in the local system of * equations to the entire set of faces within the interaction volume - * \param getTensor Lambda to evaluate scv-wise hydraulic conductivities + * \param getT Lambda to evaluate scv-wise hydraulic conductivities */ - template< class GC, class IV, class GetTensor > - void assembleGravity(GC& g, const IV& iv, const Matrix& CA, const GetTensor& getTensor) + template< class GC, class IV, class TensorFunc > + void assembleGravity(GC& g, + const IV& iv, + const typename IV::Traits::MatVecTraits::CMatrix& CA, + const TensorFunc& getT) { //! We require the gravity container to be a two-dimensional vector/array type, structured as follows: //! - first index adresses the respective phases //! - second index adresses the face within the interaction volume - // make sure CA matrix and the g vector to have the correct size already - assert(std::all_of(g.begin(), g.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); }) - && "size of gravity vector does not match the number of iv-local faces!"); - assert(CA.rows() == iv.numFaces() && CA.cols() == iv.numUnknowns() && "Matrix CA does not have the correct size"); + // make sure g vector and CA matrix have the correct sizes already + assert(std::all_of(g.begin(), g.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); })); + assert(CA.rows() == iv.numFaces() && CA.cols() == iv.numUnknowns()); //! For each face, we... //! - arithmetically average the phase densities //! - compute the term \f$ \alpha := A \rho \ \mathbf{n}^T \mathbf{K} \mathbf{g} \f$ in each neighboring cell //! - compute \f$ \alpha^* = \alpha_{outside} - \alpha_{inside} \f$ - using Scalar = typename Vector::value_type; + using Scalar = typename IV::Traits::MatVecTraits::TMatrix::value_type; + using FaceVector = typename IV::Traits::MatVecTraits::FaceVector; + using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType; // reset gravity containers to zero const auto numPhases = g.size(); - std::vector< Vector > sum_alphas(numPhases); - + std::vector< FaceVector > sum_alphas(numPhases); for (unsigned int pIdx = 0; pIdx < numPhases; ++pIdx) { resizeVector(sum_alphas[pIdx], iv.numUnknowns()); @@ -368,11 +373,10 @@ public: const auto& posGlobalScv = this->fvGeometry().scv(posLocalScv.globalScvIndex()); const auto& posVolVars = this->elemVolVars()[posGlobalScv]; const auto& posElement = iv.element(neighborScvIndices[0]); - const auto tensor = getTensor(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); + const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); - // This function should never be called for surface grids, - // for which there is the specialization of this function below - assert(neighborScvIndices.size() <= 2 && "Scvf seems to have more than one outside scv!"); + // On surface grids one should use the function specialization below + assert(neighborScvIndices.size() <= 2); std::vector< Scalar > rho(numPhases); const auto alpha_inside = posVolVars.extrusionFactor()*vtmv(curGlobalScvf.unitOuterNormal(), tensor, gravity); @@ -388,7 +392,7 @@ public: const auto& negGlobalScv = this->fvGeometry().scv(negLocalScv.globalScvIndex()); const auto& negVolVars = this->elemVolVars()[negGlobalScv]; const auto& negElement = iv.element( neighborScvIndices[1] ); - const auto negTensor = getTensor(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv); + const auto negTensor = getT(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv); const auto sum_alpha = negVolVars.extrusionFactor() * vtmv(curGlobalScvf.unitOuterNormal(), negTensor, gravity) @@ -439,8 +443,8 @@ public: * gravitational acceleration per scvf & phase * \tparam GOut Type of container used to store gravity on "outside" faces * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param g Container to store gravity per scvf & phase * \param outsideG Container to store gravity per "outside" scvf & phase @@ -448,15 +452,15 @@ public: * \param CA Projection matrix transforming the gravity terms in the local system of * equations to the entire set of faces within the interaction volume * \param A Matrix needed for the "reconstruction" of face unknowns as a function of gravity - * \param getTensor Lambda to evaluate scv-wise hydraulic conductivities + * \param getT Lambda to evaluate scv-wise hydraulic conductivities */ - template< class GC, class GOut, class IV, class GetTensor > + template< class GC, class GOut, class IV, class TensorFunc > void assembleGravity(GC& g, GOut& outsideG, const IV& iv, - const Matrix& CA, - const Matrix& A, - const GetTensor& getTensor) + const typename IV::Traits::MatVecTraits::CMatrix& CA, + const typename IV::Traits::MatVecTraits::AMatrix& A, + const TensorFunc& getT) { //! We require the gravity container to be a two-dimensional vector/array type, structured as follows: //! - first index adresses the respective phases @@ -467,22 +471,21 @@ public: //! - third index adresses the i-th "outside" face of the current face // we require the CA matrix and the gravity containers to have the correct size already - assert(CA.rows() == iv.numFaces() && CA.cols() == iv.numUnknowns() && "Matrix CA does not have the correct size"); - assert(std::all_of(g.begin(), g.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); }) - && "size of gravity container does not match the number of iv-local faces!"); - assert(std::all_of(outsideG.begin(), outsideG.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); }) - && "Outside gravity container does not match the number of iv-local faces!"); + assert(CA.rows() == iv.numFaces() && CA.cols() == iv.numUnknowns()); + assert(std::all_of(g.begin(), g.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); })); + assert(std::all_of(outsideG.begin(), outsideG.end(), [&iv](const auto& v) { return v.size() == iv.numFaces(); })); //! For each face, we... //! - arithmetically average the phase densities //! - compute the term \f$ \alpha := \mathbf{A} \rho \ \mathbf{n}^T \mathbf{K} \mathbf{g} \f$ in each neighboring cell //! - compute \f$ \alpha^* = \sum{\alpha_{outside, i}} - \alpha_{inside} \f$ - using Scalar = typename Vector::value_type; + using Scalar = typename IV::Traits::MatVecTraits::TMatrix::value_type; + using FaceVector = typename IV::Traits::MatVecTraits::FaceVector; + using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType; // reset everything to zero const auto numPhases = g.size(); - std::vector< Vector > sum_alphas(numPhases); - + std::vector< FaceVector > sum_alphas(numPhases); for (unsigned int pIdx = 0; pIdx < numPhases; ++pIdx) { resizeVector(sum_alphas[pIdx], iv.numUnknowns()); @@ -504,7 +507,7 @@ public: const auto& posGlobalScv = this->fvGeometry().scv(posLocalScv.globalScvIndex()); const auto& posVolVars = this->elemVolVars()[posGlobalScv]; const auto& posElement = iv.element(neighborScvIndices[0]); - const auto tensor = getTensor(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); + const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); const auto alpha_inside = posVolVars.extrusionFactor()*vtmv(curGlobalScvf.unitOuterNormal(), tensor, gravity); const auto numOutsideFaces = curGlobalScvf.boundary() ? 0 : curGlobalScvf.numOutsideScvs(); @@ -527,11 +530,10 @@ public: const auto& negGlobalScv = this->fvGeometry().scv(negLocalScv.globalScvIndex()); const auto& negVolVars = this->elemVolVars()[negGlobalScv]; const auto& negElement = iv.element( neighborScvIndices[idxInOutside] ); - const auto negTensor = getTensor(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv); + const auto negTensor = getT(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv); const auto& flipScvf = this->fvGeometry().flipScvf(curGlobalScvf.index(), idxInOutside); - alpha_outside[idxInOutside] = negVolVars.extrusionFactor() - * vtmv(flipScvf.unitOuterNormal(), negTensor, gravity); + alpha_outside[idxInOutside] = negVolVars.extrusionFactor()*vtmv(flipScvf.unitOuterNormal(), negTensor, gravity); for (unsigned int pIdx = 0; pIdx < numPhases; ++pIdx) { @@ -572,7 +574,7 @@ public: { CA.umv(sum_alphas[pIdx], g[pIdx]); - Vector AG(iv.numUnknowns()); + FaceVector AG(iv.numUnknowns()); A.mv(sum_alphas[pIdx], AG); // compute gravitational accelerations @@ -588,8 +590,11 @@ public: const auto& posLocalScv = iv.localScv(localScvIdx); const auto& wijk = iv.omegas()[localScvfIdx][idxInOutside+1]; + // make sure the given outside gravity container has the right size + assert(outsideG[pIdx][localScvfIdx].size() == iv.localScvf(localScvfIdx).neighboringLocalScvIndices().size()); + // add contributions from all local directions - for (LocalIndexType localDir = 0; localDir < dim; localDir++) + for (LocalIndexType localDir = 0; localDir < IV::Traits::GridView::dimension; localDir++) { // the scvf corresponding to this local direction in the scv const auto& curLocalScvf = iv.localScvf(posLocalScv.scvfIdxLocal(localDir)); @@ -616,22 +621,29 @@ private: * \note The matrices are expected to have been resized beforehand. * * \tparam IV The interaction volume type implementation - * \tparam GetTensor Lambda to obtain the tensor w.r.t. - * which the local system is to be solved + * \tparam TensorFunc Lambda to obtain the tensor w.r.t. + * which the local system is to be solved * * \param A The A matrix of the iv-local equation system * \param B The B matrix of the iv-local equation system * \param C The C matrix of the iv-local flux expressions * \param D The D matrix of the iv-local flux expressions * \param iv The mpfa-o interaction volume - * \param getTensor Lambda to evaluate the scv-wise tensors + * \param getT Lambda to evaluate the scv-wise tensors */ - template< class IV, class GetTensor > - void assembleLocalMatrices_(Matrix& A, Matrix& B, Matrix& C, Matrix& D, - IV& iv, const GetTensor& getTensor) + template< class IV, class TensorFunc > + void assembleLocalMatrices_(typename IV::Traits::MatVecTraits::AMatrix& A, + typename IV::Traits::MatVecTraits::BMatrix& B, + typename IV::Traits::MatVecTraits::CMatrix& C, + typename IV::Traits::MatVecTraits::DMatrix& D, + IV& iv, const TensorFunc& getT) { + using LocalIndexType = typename IV::Traits::IndexSet::LocalIndexType; + static constexpr int dim = IV::Traits::GridView::dimension; + static constexpr int dimWorld = IV::Traits::GridView::dimensionworld; + // Matrix D is assumed to have the right size already - assert(D.rows() == iv.numFaces() && D.cols() == iv.numKnowns() && "Matrix D does not have the correct size"); + assert(D.rows() == iv.numFaces() && D.cols() == iv.numKnowns()); // if only Dirichlet faces are present in the iv, // the matrices A, B & C are undefined and D = T @@ -652,7 +664,7 @@ private: const auto& posGlobalScv = this->fvGeometry().scv(posLocalScv.globalScvIndex()); const auto& posVolVars = this->elemVolVars()[posGlobalScv]; const auto& posElement = iv.element(neighborScvIndices[0]); - const auto tensor = getTensor(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); + const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); // the omega factors of the "positive" sub volume const auto wijk = computeMpfaTransmissibility(posLocalScv, curGlobalScvf, tensor, posVolVars.extrusionFactor()); @@ -670,9 +682,9 @@ private: else { // we require the matrices A,B,C to have the correct size already - assert(A.rows() == iv.numUnknowns() && A.cols() == iv.numUnknowns() && "Matrix A does not have the correct size"); - assert(B.rows() == iv.numUnknowns() && B.cols() == iv.numKnowns() && "Matrix B does not have the correct size"); - assert(C.rows() == iv.numFaces() && C.cols() == iv.numUnknowns() && "Matrix C does not have the correct size"); + assert(A.rows() == iv.numUnknowns() && A.cols() == iv.numUnknowns()); + assert(B.rows() == iv.numUnknowns() && B.cols() == iv.numKnowns()); + assert(C.rows() == iv.numFaces() && C.cols() == iv.numUnknowns()); // reset matrices A = 0.0; @@ -694,7 +706,7 @@ private: const auto& posGlobalScv = this->fvGeometry().scv(posLocalScv.globalScvIndex()); const auto& posVolVars = this->elemVolVars()[posGlobalScv]; const auto& posElement = iv.element(neighborScvIndices[0]); - const auto tensor = getTensor(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); + const auto tensor = getT(this->problem(), posElement, posVolVars, this->fvGeometry(), posGlobalScv); // the omega factors of the "positive" sub volume wijk[faceIdx][0] = computeMpfaTransmissibility(posLocalScv, curGlobalScvf, tensor, posVolVars.extrusionFactor()); @@ -740,7 +752,7 @@ private: const auto& negGlobalScv = this->fvGeometry().scv(negLocalScv.globalScvIndex()); const auto& negVolVars = this->elemVolVars()[negGlobalScv]; const auto& negElement = iv.element( neighborScvIndices[idxOnScvf] ); - const auto negTensor = getTensor(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv); + const auto negTensor = getT(this->problem(), negElement, negVolVars, this->fvGeometry(), negGlobalScv); // On surface grids, use outside face for "negative" transmissibility calculation const auto& scvf = dim < dimWorld ? this->fvGeometry().flipScvf(curGlobalScvf.index(), idxInOutside) diff --git a/dumux/discretization/cellcentered/mpfa/omethod/staticinteractionvolume.hh b/dumux/discretization/cellcentered/mpfa/omethod/staticinteractionvolume.hh index 2304ac87383f7a48bcff8af92db2d87b91843bbf..7456191a3568c08f0be1eab130904c03ca59992c 100644 --- a/dumux/discretization/cellcentered/mpfa/omethod/staticinteractionvolume.hh +++ b/dumux/discretization/cellcentered/mpfa/omethod/staticinteractionvolume.hh @@ -30,15 +30,13 @@ #include <dune/common/fvector.hh> #include <dumux/common/math.hh> -#include <dumux/common/properties.hh> #include <dumux/common/matrixvectorhelper.hh> -#include <dumux/discretization/cellcentered/mpfa/interactionvolumedatahandle.hh> #include <dumux/discretization/cellcentered/mpfa/interactionvolumebase.hh> -#include <dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh> #include <dumux/discretization/cellcentered/mpfa/dualgridindexset.hh> #include <dumux/discretization/cellcentered/mpfa/localfacedata.hh> #include <dumux/discretization/cellcentered/mpfa/methods.hh> +#include <dumux/discretization/cellcentered/mpfa/omethod/interactionvolume.hh> #include "localsubcontrolentities.hh" #include "interactionvolumeindexset.hh" @@ -46,47 +44,59 @@ namespace Dumux { //! Forward declaration of the o-method's static interaction volume -template< class Traits, int localSize > class CCMpfaOStaticInteractionVolume; +template< class Traits > class CCMpfaOStaticInteractionVolume; -//! Specialization of the default interaction volume traits class for the mpfa-o method -template< class TypeTag, int localSize > +/*! + * \ingroup CCMpfaDiscretization + * \brief The default interaction volume traits class for the mpfa-o method + * with known size of the interaction volumes at compile time. It uses + * statically sized containers for the iv-local data structures and static + * matrices and vectors. + * + * \tparam NI The type used for the dual grid's nodal index sets + * \tparam S The Type used for scalar values + * \tparam C The number of sub-control volumes (cells) in the ivs + * \tparam F The number of sub-control volume faces in the ivs + */ +template< class NI, class S, int C, int F > struct CCMpfaODefaultStaticInteractionVolumeTraits { private: - using NodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet); - using GridIndexType = typename NodalIndexSet::GridIndexType; - static constexpr int dim = GET_PROP_TYPE(TypeTag, GridView)::dimension; - static constexpr int dimWorld = GET_PROP_TYPE(TypeTag, GridView)::dimensionworld; + using GridIndexType = typename NI::GridIndexType; + using LocalIndexType = typename NI::LocalIndexType; + + static constexpr int dim = NI::Traits::GridView::dimension; + static constexpr int dimWorld = NI::Traits::GridView::dimensionworld; + + //! Matrix/Vector traits to be used by the data handle + struct MVTraits + { + using AMatrix = Dune::FieldMatrix< S, F, F >; + using BMatrix = Dune::FieldMatrix< S, F, C >; + using CMatrix = Dune::FieldMatrix< S, F, F >; + using DMatrix = Dune::FieldMatrix< S, F, C >; + using TMatrix = Dune::FieldMatrix< S, F, C >; + using CellVector = Dune::FieldVector< S, C >; + using FaceVector = Dune::FieldVector< S, F >; + }; public: - //! export the problem type (needed for iv-local assembly) - using Problem = typename GET_PROP_TYPE(TypeTag, Problem); - //! export the type of the local view on the finite volume grid geometry - using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::LocalView; - //! export the type of the local view on the grid volume variables - using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables); //! export the type of grid view - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - //! export the type used for scalar values - using ScalarType = typename GET_PROP_TYPE(TypeTag, Scalar); - //! export the type of the mpfa helper class - using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); - //! export the type used for local indices - using LocalIndexType = typename NodalIndexSet::LocalIndexType; + using GridView = typename NI::Traits::GridView; //! export the type for the interaction volume index set - using IndexSet = CCMpfaOInteractionVolumeIndexSet< NodalIndexSet >; + using IndexSet = CCMpfaOInteractionVolumeIndexSet< NI >; //! export the type of interaction-volume local scvs - using LocalScvType = CCMpfaOInteractionVolumeLocalScv< IndexSet, ScalarType, dim, dimWorld >; + using LocalScvType = CCMpfaOInteractionVolumeLocalScv< IndexSet, S, dim, dimWorld >; //! export the type of interaction-volume local scvfs using LocalScvfType = CCMpfaOInteractionVolumeLocalScvf< IndexSet >; //! export the type of used for the iv-local face data using LocalFaceData = InteractionVolumeLocalFaceData<GridIndexType, LocalIndexType>; - //! export the type used for iv-local matrices - using Matrix = Dune::FieldMatrix< ScalarType, localSize, localSize >; - //! export the type used for iv-local vectors - using Vector = Dune::FieldVector< ScalarType, localSize >; - //! export the data handle type for this iv - using DataHandle = InteractionVolumeDataHandle< TypeTag, Matrix, Vector, LocalIndexType >; + //! export the matrix/vector traits to be used by the iv + using MatVecTraits = MVTraits; + //! export the number of scvs in the interaction volumes + static constexpr int numScvs = C; + //! export the number of scvfs in the interaction volumes + static constexpr int numScvfs = F; }; /*! @@ -98,182 +108,180 @@ public: * vectors/matrices defined in the traits class in case static types are used. * * \tparam Traits The type traits class to be used - * \tparam localSize The size of the local eq system - * This also is the number of local scvs/scvfs */ -template< class Traits, int localSize > -class CCMpfaOStaticInteractionVolume : public CCMpfaInteractionVolumeBase< CCMpfaOInteractionVolume<Traits>, Traits > +template< class Traits > +class CCMpfaOStaticInteractionVolume + : public CCMpfaInteractionVolumeBase< CCMpfaOStaticInteractionVolume<Traits>, Traits > { - using ParentType = CCMpfaInteractionVolumeBase< CCMpfaOInteractionVolume<Traits>, Traits >; - - using Scalar = typename Traits::ScalarType; - using Helper = typename Traits::MpfaHelper; - using Problem = typename Traits::Problem; - using FVElementGeometry = typename Traits::FVElementGeometry; - using GridView = typename Traits::GridView; using Element = typename GridView::template Codim<0>::Entity; + using IndexSet = typename Traits::IndexSet; + using GridIndexType = typename IndexSet::GridIndexType; + using LocalIndexType = typename IndexSet::LocalIndexType; + using Stencil = typename IndexSet::NodalGridStencilType; + static constexpr int dim = GridView::dimension; + static constexpr int dimWorld = GridView::dimensionworld; + + //! export scalar type from T matrix and define omegas + using Scalar = typename Traits::MatVecTraits::TMatrix::value_type; using DimVector = Dune::FieldVector<Scalar, dim>; + using FaceOmegas = typename Dune::ReservedVector<DimVector, 2>; + + using AMatrix = typename Traits::MatVecTraits::AMatrix; + using BMatrix = typename Traits::MatVecTraits::BMatrix; + using CMatrix = typename Traits::MatVecTraits::CMatrix; - using Matrix = typename Traits::Matrix; using LocalScvType = typename Traits::LocalScvType; using LocalScvfType = typename Traits::LocalScvfType; using LocalFaceData = typename Traits::LocalFaceData; - using IndexSet = typename Traits::IndexSet; - using GridIndexType = typename GridView::IndexSet::IndexType; - using LocalIndexType = typename Traits::LocalIndexType; - using Stencil = typename IndexSet::GridStencilType; - - //! Data attached to scvf touching Dirichlet boundaries. - //! For the default o-scheme, we only store the corresponding vol vars index. - class DirichletData - { - GridIndexType volVarIndex_; + static constexpr int numScvf = Traits::numScvfs; + static constexpr int numScv = Traits::numScvs; - public: - //! Constructor - DirichletData(const GridIndexType index) : volVarIndex_(index) {} +public: + //! export the standard o-methods dirichlet data + using DirichletData = typename CCMpfaOInteractionVolume< Traits >::DirichletData; - //! Return corresponding vol var index - GridIndexType volVarIndex() const { return volVarIndex_; } - }; + //! export the type used for transmissibility storage + using TransmissibilityStorage = std::array< FaceOmegas, numScvf >; -public: //! publicly state the mpfa-scheme this interaction volume is associated with static constexpr MpfaMethods MpfaMethod = MpfaMethods::oMethod; //! Sets up the local scope for a given iv index set + template< class Problem, class FVElementGeometry > void setUpLocalScope(const IndexSet& indexSet, const Problem& problem, const FVElementGeometry& fvGeometry) { // for the o-scheme, the stencil is equal to the scv // index set of the dual grid's nodal index set + assert(indexSet.numScvs() == numScv); stencil_ = &indexSet.nodalIndexSet().globalScvIndices(); - // set up local geometry containers + // set up stuff related to sub-control volumes const auto& scvIndices = indexSet.globalScvIndices(); - for (LocalIndexType localIdx = 0; localIdx < localSize; localIdx++) + for (LocalIndexType scvIdxLocal = 0; scvIdxLocal < numScv; scvIdxLocal++) { - // scv-related quantities - scvs_[localIdx] = LocalScvType(Helper(), + elements_[scvIdxLocal] = fvGeometry.fvGridGeometry().element( scvIndices[scvIdxLocal] ); + scvs_[scvIdxLocal] = LocalScvType(fvGeometry.fvGridGeometry().mpfaHelper(), fvGeometry, - fvGeometry.scv( scvIndices[localIdx] ), - localIdx, + fvGeometry.scv( scvIndices[scvIdxLocal] ), + scvIdxLocal, indexSet); - elements_[localIdx] = fvGeometry.fvGridGeometry().element( scvIndices[localIdx] ); + } - // scvf-related quantities - const auto& scvf = fvGeometry.scvf(indexSet.scvfIdxGlobal(localIdx)); + // set up quantitites related to sub-control volume faces + for (LocalIndexType faceIdxLocal = 0; faceIdxLocal < numScvf; ++faceIdxLocal) + { + const auto& scvf = fvGeometry.scvf(indexSet.scvfIdxGlobal(faceIdxLocal)); + + // the neighboring scvs in local indices (order: 0 - inside scv, 1..n - outside scvs) + const auto& neighborScvIndicesLocal = indexSet.neighboringLocalScvIndices(faceIdxLocal); - // this interaction volume implementation does not work on boundaries - assert(!scvf.boundary() && "static mpfa-o interaction volume cannot be used on boundaries"); + // this does not work for network grids or on boundaries + assert(!scvf.boundary()); + assert(neighborScvIndicesLocal.size() == 2); - const auto& neighborScvIndicesLocal = indexSet.neighboringLocalScvIndices(localIdx); - scvfs_[localIdx] = LocalScvfType(scvf, neighborScvIndicesLocal, localIdx, /*isDirichlet*/false); - localFaceData_[localIdx*2] = LocalFaceData(localIdx, neighborScvIndicesLocal[0], scvf.index()); + // create iv-local scvf objects + scvfs_[faceIdxLocal] = LocalScvfType(scvf, neighborScvIndicesLocal, faceIdxLocal, /*isDirichlet*/false); + localFaceData_[faceIdxLocal*2] = LocalFaceData(faceIdxLocal, neighborScvIndicesLocal[0], scvf.index()); + // add local face data objects for the outside face const auto outsideLocalScvIdx = neighborScvIndicesLocal[1]; - // loop over scvfs in outside scv until we find the one coinciding with current scvf for (int coord = 0; coord < dim; ++coord) { - if (indexSet.scvfIdxLocal(outsideLocalScvIdx, coord) == localIdx) + if (indexSet.scvfIdxLocal(outsideLocalScvIdx, coord) == faceIdxLocal) { const auto globalScvfIdx = indexSet.nodalIndexSet().scvfIdxGlobal(outsideLocalScvIdx, coord); const auto& flipScvf = fvGeometry.scvf(globalScvfIdx); - localFaceData_[localIdx*2 + 1] = LocalFaceData(localIdx, // iv-local scvf idx - outsideLocalScvIdx, // iv-local scv index - 0, // scvf-local index in outside faces - flipScvf.index()); // global scvf index + localFaceData_[faceIdxLocal*2+1] = LocalFaceData(faceIdxLocal, // iv-local scvf idx + outsideLocalScvIdx, // iv-local scv index + 0, // scvf-local index in outside faces + flipScvf.index()); // global scvf index + break; // go to next outside face } } + + // make sure we found it + assert(localFaceData_[faceIdxLocal*2+1].ivLocalInsideScvIndex() == outsideLocalScvIdx); } // Maybe resize local matrices if dynamic types are used - resizeMatrix(A_, localSize, localSize); - resizeMatrix(B_, localSize, localSize); - resizeMatrix(C_, localSize, localSize); + resizeMatrix(A_, numScvf, numScvf); + resizeMatrix(B_, numScvf, numScv); + resizeMatrix(C_, numScvf, numScv); } //! returns the number of primary scvfs of this interaction volume - static constexpr std::size_t numFaces() { return localSize; } + static constexpr std::size_t numFaces() { return numScvf; } //! returns the number of intermediate unknowns within this interaction volume - static constexpr std::size_t numUnknowns() { return localSize; } + static constexpr std::size_t numUnknowns() { return numScvf; } //! returns the number of (in this context) known solution values within this interaction volume - static constexpr std::size_t numKnowns() { return localSize; } + static constexpr std::size_t numKnowns() { return numScv; } //! returns the number of scvs embedded in this interaction volume - static constexpr std::size_t numScvs() { return localSize; } + static constexpr std::size_t numScvs() { return numScv; } //! returns the cell-stencil of this interaction volume const Stencil& stencil() const { return *stencil_; } //! returns the grid element corresponding to a given iv-local scv idx - const Element& element(const LocalIndexType ivLocalScvIdx) const - { - assert(ivLocalScvIdx < localSize); - return elements_[ivLocalScvIdx]; - } + const Element& element(LocalIndexType ivLocalScvIdx) const { return elements_[ivLocalScvIdx]; } //! returns the local scvf entity corresponding to a given iv-local scvf idx - const LocalScvfType& localScvf(const LocalIndexType ivLocalScvfIdx) const - { - assert(ivLocalScvfIdx < localSize); - return scvfs_[ivLocalScvfIdx]; - } + const LocalScvfType& localScvf(LocalIndexType ivLocalScvfIdx) const { return scvfs_[ivLocalScvfIdx]; } //! returns the local scv entity corresponding to a given iv-local scv idx - const LocalScvType& localScv(const LocalIndexType ivLocalScvIdx) const - { - assert(ivLocalScvIdx < localSize); - return scvs_[ivLocalScvIdx]; - } + const LocalScvType& localScv(LocalIndexType ivLocalScvIdx) const { return scvs_[ivLocalScvIdx]; } //! returns a reference to the container with the local face data - const std::array<LocalFaceData, 2*localSize>& localFaceData() const { return localFaceData_; } + const std::array<LocalFaceData, numScvf*2>& localFaceData() const { return localFaceData_; } //! Returns a reference to the information container on Dirichlet BCs within this iv. //! Here, we return an empty container as this implementation cannot be used on boundaries. const std::array<DirichletData, 0>& dirichletData() const { return dirichletData_; } //! returns the matrix associated with face unknowns in local equation system - const Matrix& A() const { return A_; } - Matrix& A() { return A_; } + const AMatrix& A() const { return A_; } + AMatrix& A() { return A_; } //! returns the matrix associated with cell unknowns in local equation system - const Matrix& B() const { return B_; } - Matrix& B() { return B_; } + const BMatrix& B() const { return B_; } + BMatrix& B() { return B_; } //! returns the matrix associated with face unknowns in flux expressions - const Matrix& C() const { return C_; } - Matrix& C() { return C_; } + const CMatrix& C() const { return C_; } + CMatrix& C() { return C_; } //! returns container storing the transmissibilities for each face & coordinate - const std::array< std::array<DimVector, 2>, localSize >& omegas() const { return wijk_; } - std::array< std::array<DimVector, 2>, localSize >& omegas() { return wijk_; } + const TransmissibilityStorage& omegas() const { return wijk_; } + TransmissibilityStorage& omegas() { return wijk_; } //! returns the number of interaction volumes living around a vertex - //! the mpfa-o scheme always constructs one iv per vertex - template< class NodalIndexSet > - static std::size_t numInteractionVolumesAtVertex(const NodalIndexSet& nodalIndexSet) { return 1; } + template< class NI > + static constexpr std::size_t numIVAtVertex(const NI& nodalIndexSet) { return 1; } //! adds the iv index sets living around a vertex to a given container //! and stores the the corresponding index in a map for each scvf - template<class IvIndexSetContainer, class ScvfIndexMap, class NodalIndexSet> - static void addInteractionVolumeIndexSets(IvIndexSetContainer& ivIndexSetContainer, - ScvfIndexMap& scvfIndexMap, - const NodalIndexSet& nodalIndexSet) + template< class IvIndexSetContainer, + class ScvfIndexMap, + class NodalIndexSet, + class FlipScvfIndexSet > + static void addIVIndexSets(IvIndexSetContainer& ivIndexSetContainer, + ScvfIndexMap& scvfIndexMap, + const NodalIndexSet& nodalIndexSet, + const FlipScvfIndexSet& flipScvfIndexSet) { // the global index of the iv index set that is about to be created const auto curGlobalIndex = ivIndexSetContainer.size(); // make the one index set for this node - ivIndexSetContainer.emplace_back(nodalIndexSet); + ivIndexSetContainer.emplace_back(nodalIndexSet, flipScvfIndexSet); // store the index mapping for (const auto scvfIdx : nodalIndexSet.globalScvfIndices()) @@ -285,22 +293,21 @@ private: const Stencil* stencil_; // Variables defining the local scope - std::array<Element, localSize> elements_; - std::array<LocalScvType, localSize> scvs_; - std::array<LocalScvfType, localSize> scvfs_; - std::array<LocalFaceData, 2*localSize> localFaceData_; - - // Empty Dirichlet container to be compatible with dynamic assembly - std::array<DirichletData, 0> dirichletData_; + std::array<Element, numScv> elements_; + std::array<LocalScvType, numScv> scvs_; + std::array<LocalScvfType, numScvf> scvfs_; + std::array<LocalFaceData, numScvf*2> localFaceData_; // Matrices needed for computation of transmissibilities - Matrix A_; - Matrix B_; - Matrix C_; + AMatrix A_; + BMatrix B_; + CMatrix C_; // The omega factors are stored during assembly of local system - // we assume one "outside" face per scvf (does not work on surface grids) - std::array< std::array<DimVector, 2>, localSize > wijk_; + TransmissibilityStorage wijk_; + + // Dummy dirichlet data container (compatibility with dynamic o-iv) + std::array<DirichletData, 0> dirichletData_; }; } // end namespace diff --git a/dumux/discretization/cellcentered/mpfa/properties.hh b/dumux/discretization/cellcentered/mpfa/properties.hh index 06f3d8704a822edb5cd882f1d935ea00745607e5..3f9cba7bc470264286d22f48471dacbaa3a46c42 100644 --- a/dumux/discretization/cellcentered/mpfa/properties.hh +++ b/dumux/discretization/cellcentered/mpfa/properties.hh @@ -25,6 +25,8 @@ #ifndef DUMUX_CC_MPFA_PROPERTIES_HH #define DUMUX_CC_MPFA_PROPERTIES_HH +#include <dune/common/reservedvector.hh> + #include <dumux/common/properties.hh> #include <dumux/common/defaultmappertraits.hh> @@ -64,63 +66,49 @@ SET_PROP(CCMpfaModel, DiscretizationMethod) static const DiscretizationMethods value = DiscretizationMethods::CCMpfa; }; -//! Set the maximum admissible number of branches per scvf -SET_PROP(CCMpfaModel, MaxNumNeighborsPerScvf) -{ -private: - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - static constexpr int dim = GridView::dimension; - static constexpr int dimWorld = GridView::dimensionworld; - -public: - // Per default, we allow for 8 neighbors on network/surface grids - static constexpr std::size_t value = dim < dimWorld ? 9 : 2; -}; - //! Set the index set type used on the dual grid nodes SET_PROP(CCMpfaModel, DualGridNodalIndexSet) { + using GV = typename GET_PROP_TYPE(TypeTag, GridView); + static constexpr int dim = GV::dimension; + static constexpr int dimWorld = GV::dimensionworld; private: - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - - // Use the grid view's index type for grid indices - using GI = typename GridView::IndexSet::IndexType; - - // per default, use uint8_t as iv-local index type - using LI = std::uint8_t; - - // the specified maximum admissible number of branches per scvf - static constexpr int maxB = GET_PROP_VALUE(TypeTag, MaxNumNeighborsPerScvf); - - // maximum admissible number of elements around a node - // if for a given grid this number is still not high enough, - // overwrite this property in your problem with a higher number - static constexpr int dim = GridView::dimension; - static constexpr int maxE = dim == 3 ? 45 : 15; - + struct Traits + { + using GridView = GV; + using GridIndexType = typename GV::IndexSet::IndexType; + using LocalIndexType = std::uint8_t; + + //! per default, we use dynamic data containers (iv size unknown) + template< class T > using NodalScvDataStorage = std::vector< T >; + template< class T > using NodalScvfDataStorage = std::vector< T >; + + //! store data on neighbors of scvfs in static containers if possible + template< class T > + using ScvfNeighborDataStorage = typename std::conditional_t< (dim<dimWorld), + std::vector< T >, + Dune::ReservedVector< T, 2 > >; + }; public: - using type = CCMpfaDualGridNodalIndexSet<GI, LI, dim, maxE, maxB>; + using type = CCMpfaDualGridNodalIndexSet< Traits >; }; -//! The mpfa helper class -SET_TYPE_PROP(CCMpfaModel, MpfaHelper, CCMpfaHelper<TypeTag>); - //! Per default, we use the dynamic mpfa-o interaction volume SET_PROP(CCMpfaModel, PrimaryInteractionVolume) { -private: - //! use the default traits - using Traits = CCMpfaODefaultInteractionVolumeTraits< TypeTag >; public: - using type = CCMpfaOInteractionVolume< Traits >; + using type = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); }; -//! Per default, we use the dynamic mpfa-o interaction volume as secondary type +//! Per default, we use the dynamic mpfa-o interaction volume on boundaries SET_PROP(CCMpfaModel, SecondaryInteractionVolume) { private: - //! use the default traits - using Traits = CCMpfaODefaultInteractionVolumeTraits< TypeTag >; + using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar); + using NodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet); + + // use the default traits + using Traits = CCMpfaODefaultInteractionVolumeTraits< NodalIndexSet, Scalar >; public: using type = CCMpfaOInteractionVolume< Traits >; }; @@ -133,30 +121,27 @@ private: using PrimaryIV = typename GET_PROP_TYPE(TypeTag, PrimaryInteractionVolume); using SecondaryIV = typename GET_PROP_TYPE(TypeTag, SecondaryInteractionVolume); - static constexpr bool enableCache = GET_PROP_VALUE(TypeTag, EnableFVGridGeometryCache); - struct Traits : public DefaultMapperTraits<GridView> { using SubControlVolume = CCSubControlVolume<GridView>; using SubControlVolumeFace = CCMpfaSubControlVolumeFace<GridView>; - using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); using NodalIndexSet = typename GET_PROP_TYPE(TypeTag, DualGridNodalIndexSet); - template< class FVGridGeometry > - using GridIvIndexSets = CCMpfaGridInteractionVolumeIndexSets< FVGridGeometry, - NodalIndexSet, - PrimaryIV, - SecondaryIV >; + //! type definitions depending on the FVGridGeometry itself + template< class FVGridGeom > + using MpfaHelper = CCMpfaHelper< FVGridGeom >; + + template< class FVGridGeom > + using ConnectivityMap = CCMpfaConnectivityMap<FVGridGeom, FVGridGeom::GridIVIndexSets::PrimaryInteractionVolume::MpfaMethod>; - template< class FVGridGeometry, bool enableCache > - using LocalView = CCMpfaFVElementGeometry<FVGridGeometry, enableCache>; + template< class FVGridGeom > + using GridIvIndexSets = CCMpfaGridInteractionVolumeIndexSets< FVGridGeom, NodalIndexSet, PrimaryIV, SecondaryIV >; - //! Per default, we use the o-method and thus the simple assembly map - template< class FVGridGeometry > - using ConnectivityMap = CCMpfaConnectivityMap<FVGridGeometry, FVGridGeometry::GridIVIndexSets::PrimaryInteractionVolume::MpfaMethod>; + template< class FVGridGeom, bool enableCache > + using LocalView = CCMpfaFVElementGeometry<FVGridGeom, enableCache>; }; public: - using type = CCMpfaFVGridGeometry<GridView, Traits, enableCache>; + using type = CCMpfaFVGridGeometry<GridView, Traits, GET_PROP_VALUE(TypeTag, EnableFVGridGeometryCache)>; }; //! The global flux variables cache vector class diff --git a/dumux/discretization/cellcentered/tpfa/properties.hh b/dumux/discretization/cellcentered/tpfa/properties.hh index c0efc9cdb342547361e7d01e8e3a7b79048c2a28..8e9cb32413add7152cf826cd722ceb885fb6fa92 100644 --- a/dumux/discretization/cellcentered/tpfa/properties.hh +++ b/dumux/discretization/cellcentered/tpfa/properties.hh @@ -85,19 +85,6 @@ SET_TYPE_PROP(CCTpfaModel, ElementFluxVariablesCache, CCTpfaElementFluxVariables //! The global current volume variables vector class SET_TYPE_PROP(CCTpfaModel, GridVolumeVariables, CCGridVolumeVariables<TypeTag, GET_PROP_VALUE(TypeTag, EnableGridVolumeVariablesCache)>); -//! Set the maximum admissible number of branches per scvf -SET_PROP(CCTpfaModel, MaxNumNeighborsPerScvf) -{ -private: - using GridView = typename GET_PROP_TYPE(TypeTag, GridView); - static constexpr int dim = GridView::dimension; - static constexpr int dimWorld = GridView::dimensionworld; - -public: - // Per default, we allow for 8 neighbors on network/surface grids - static constexpr std::size_t value = dim < dimWorld ? 9 : 2; -}; - //! Set the solution vector type for an element SET_TYPE_PROP(CCTpfaModel, ElementSolutionVector, CCElementSolution<TypeTag>); diff --git a/dumux/discretization/fluxstencil.hh b/dumux/discretization/fluxstencil.hh index e34321cf03a10707a3a534099c732a2af21cf89b..b249dbe5a8afce8670470f82d633433a44024dc5 100644 --- a/dumux/discretization/fluxstencil.hh +++ b/dumux/discretization/fluxstencil.hh @@ -104,7 +104,7 @@ public: using ScvfStencilIForJ = std::vector<IndexType>; //! The flux stencil type - using Stencil = typename NodalIndexSet::GridStencilType; + using Stencil = typename NodalIndexSet::NodalGridStencilType; //! Returns the indices of the elements required for flux calculation on an scvf. static const Stencil& stencil(const Element& element, diff --git a/dumux/porousmediumflow/fluxvariablescache.hh b/dumux/porousmediumflow/fluxvariablescache.hh index 57662df20fb9661fd1d5cc89f29f4df87e46378a..f775ba98a54191ed594749a48b5f2ac79da3b0a7 100644 --- a/dumux/porousmediumflow/fluxvariablescache.hh +++ b/dumux/porousmediumflow/fluxvariablescache.hh @@ -152,7 +152,7 @@ class PorousMediumFluxVariablesCacheImplementation<TypeTag, DiscretizationMethod { using GridIndexType = typename GET_PROP_TYPE(TypeTag, GridView)::IndexSet::IndexType; - using MpfaHelper = typename GET_PROP_TYPE(TypeTag, MpfaHelper); + using MpfaHelper = typename GET_PROP_TYPE(TypeTag, FVGridGeometry)::MpfaHelper; static constexpr bool considerSecondary = MpfaHelper::considerSecondaryIVs(); public: //! Returns whether or not this cache has been updated