From b8fcee85c3be1ef6ae8ff94e01e62e02fa2b2ab3 Mon Sep 17 00:00:00 2001
From: DennisGlaeser <dennis.glaeser@iws.uni-stuttgart.de>
Date: Thu, 1 Feb 2018 13:44:07 +0100
Subject: [PATCH] [mpfa-o][iv] make static iv more flexible

The traits class now has to contain both the number of scvs and scvfs
in the ivs. This allows the applicability in 3d where numScvs != numScvfs.
---
 .../mpfa/omethod/staticinteractionvolume.hh   | 262 +++++++++---------
 1 file changed, 136 insertions(+), 126 deletions(-)

diff --git a/dumux/discretization/cellcentered/mpfa/omethod/staticinteractionvolume.hh b/dumux/discretization/cellcentered/mpfa/omethod/staticinteractionvolume.hh
index 2304ac8738..ae77cdb463 100644
--- a/dumux/discretization/cellcentered/mpfa/omethod/staticinteractionvolume.hh
+++ b/dumux/discretization/cellcentered/mpfa/omethod/staticinteractionvolume.hh
@@ -30,15 +30,14 @@
 #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 +45,64 @@
 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 PT Traits class encapsulating info on the physical processes
+ * \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, class PT, 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::GridView::dimension;
+    static constexpr int dimWorld = NI::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);
+    using GridView = typename NI::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 ScalarType = S;
     //! 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 >;
     //! 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 matrix/vector traits to be used by the iv
+    using MatVecTraits = MVTraits;
     //! export the data handle type for this iv
-    using DataHandle = InteractionVolumeDataHandle< TypeTag, Matrix, Vector, LocalIndexType >;
+    using DataHandle = InteractionVolumeDataHandle< MatVecTraits, PT >;
+    //! 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 +114,177 @@ 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::GridStencilType;
+
     static constexpr int dim = GridView::dimension;
-    using DimVector = Dune::FieldVector<Scalar, dim>;
+    static constexpr int dimWorld = GridView::dimensionworld;
+    using DimVector = Dune::FieldVector<typename Traits::ScalarType, 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;
+    static constexpr int numScvf = Traits::numScvfs;
+    static constexpr int numScv = Traits::numScvs;
 
-    //! 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) {}
+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 numInteractionVolumesAtVertex(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>
+    template< class IvIndexSetContainer,
+              class ScvfIndexMap,
+              class NodalIndexSet,
+              class FlipScvfIndexSet >
     static void addInteractionVolumeIndexSets(IvIndexSetContainer& ivIndexSetContainer,
                                               ScvfIndexMap& scvfIndexMap,
-                                              const NodalIndexSet& nodalIndexSet)
+                                              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 +296,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
-- 
GitLab