From b7fbfc28023ad1f3062de0a9405691469677656b Mon Sep 17 00:00:00 2001
From: Kilian Weishaupt <kilian.weishaupt@iws.uni-stuttgart.de>
Date: Fri, 11 Nov 2016 15:35:22 +0100
Subject: [PATCH] [staggeredGrid] Add basic folder structure and first test

---
 dumux/discretization/staggered/darcyslaw.hh   | 226 +++++++++++
 .../staggered/fvelementgeometry.hh            | 355 +++++++++++++++++
 .../staggered/globalfluxvariablescache.hh     | 138 +++++++
 .../staggered/globalfvgeometry.hh             | 363 ++++++++++++++++++
 .../staggered/staggeredgeometryhelper.hh      |  39 ++
 .../staggered/subcontrolvolume.hh             | 139 +++++++
 .../staggered/subcontrolvolumeface.hh         | 220 +++++++++++
 dumux/implicit/staggered/properties.hh        |  52 +++
 dumux/implicit/staggered/propertydefaults.hh  | 115 ++++++
 test/discretization/CMakeLists.txt            |   1 +
 test/discretization/staggered/CMakeLists.txt  |   2 +
 .../staggered/test_staggered.cc               | 149 +++++++
 12 files changed, 1799 insertions(+)
 create mode 100644 dumux/discretization/staggered/darcyslaw.hh
 create mode 100644 dumux/discretization/staggered/fvelementgeometry.hh
 create mode 100644 dumux/discretization/staggered/globalfluxvariablescache.hh
 create mode 100644 dumux/discretization/staggered/globalfvgeometry.hh
 create mode 100644 dumux/discretization/staggered/staggeredgeometryhelper.hh
 create mode 100644 dumux/discretization/staggered/subcontrolvolume.hh
 create mode 100644 dumux/discretization/staggered/subcontrolvolumeface.hh
 create mode 100644 dumux/implicit/staggered/properties.hh
 create mode 100644 dumux/implicit/staggered/propertydefaults.hh
 create mode 100644 test/discretization/staggered/CMakeLists.txt
 create mode 100644 test/discretization/staggered/test_staggered.cc

diff --git a/dumux/discretization/staggered/darcyslaw.hh b/dumux/discretization/staggered/darcyslaw.hh
new file mode 100644
index 0000000000..06c5d58d1c
--- /dev/null
+++ b/dumux/discretization/staggered/darcyslaw.hh
@@ -0,0 +1,226 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief This file contains the data which is required to calculate
+ *        volume and mass fluxes of fluid phases over a face of a finite volume by means
+ *        of the Darcy approximation. Specializations are provided for the different discretization methods.
+ */
+#ifndef DUMUX_DISCRETIZATION_STAGGERED_DARCYS_LAW_HH
+#define DUMUX_DISCRETIZATION_STAGGERED_DARCYS_LAW_HH
+
+#include <memory>
+
+#include <dune/common/float_cmp.hh>
+
+#include <dumux/common/math.hh>
+#include <dumux/common/parameters.hh>
+
+#include <dumux/implicit/properties.hh>
+#include <dumux/discretization/methods.hh>
+
+namespace Dumux
+{
+
+namespace Properties
+{
+// forward declaration of properties
+NEW_PROP_TAG(ProblemEnableGravity);
+}
+
+/*!
+ * \ingroup DarcysLaw
+ * \brief Specialization of Darcy's Law for the CCTpfa method. TODO: dummy, remove this class
+ */
+template <class TypeTag>
+class DarcysLawImplementation<TypeTag, DiscretizationMethods::Staggered>
+{
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
+    using FluxVarsCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache);
+
+    using Element = typename GridView::template Codim<0>::Entity;
+    using IndexType = typename GridView::IndexSet::IndexType;
+    using Stencil = std::vector<IndexType>;
+
+    enum { dim = GridView::dimension} ;
+    enum { dimWorld = GridView::dimensionworld} ;
+
+    using DimWorldMatrix = Dune::FieldMatrix<Scalar, dimWorld, dimWorld>;
+    using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
+
+public:
+
+    static Scalar flux(const Problem& problem,
+                       const Element& element,
+                       const FVElementGeometry& fvGeometry,
+                       const ElementVolumeVariables& elemVolVars,
+                       const SubControlVolumeFace& scvFace,
+                       int phaseIdx,
+                       const FluxVarsCache& fluxVarsCache)
+    {
+        const auto& tij = fluxVarsCache.tij();
+
+        // Get the inside and outside volume variables
+        const auto& insideScv = fvGeometry.scv(scvFace.insideScvIdx());
+        const auto& insideVolVars = elemVolVars[insideScv];
+        const auto& outsideVolVars = elemVolVars[scvFace.outsideScvIdx()];
+
+        auto hInside = insideVolVars.pressure(phaseIdx);
+        auto hOutside = outsideVolVars.pressure(phaseIdx);
+
+        if (GET_PARAM_FROM_GROUP(TypeTag, bool, Problem, EnableGravity))
+        {
+            // do averaging for the density
+            const auto rhoInside = insideVolVars.density(phaseIdx);
+            const auto rhoOutide = outsideVolVars.density(phaseIdx);
+            const auto rho = (rhoInside + rhoOutide)*0.5;
+
+            // ask for the gravitational acceleration in the inside neighbor
+            const auto xInside = insideScv.center();
+            const auto gInside = problem.gravityAtPos(xInside);
+
+            hInside -= rho*(gInside*xInside);
+
+            // and the outside neighbor
+            if (scvFace.boundary())
+            {
+                const auto xOutside = scvFace.center();
+                const auto gOutside = problem.gravityAtPos(xOutside);
+                hOutside -= rho*(gOutside*xOutside);
+            }
+            else
+            {
+                const auto outsideScvIdx = scvFace.outsideScvIdx();
+                // as we assemble fluxes from the neighbor to our element the outside index
+                // refers to the scv of our element, so we use the scv method
+                const auto& outsideScv = fvGeometry.scv(outsideScvIdx);
+                const auto xOutside = outsideScv.center();
+                const auto gOutside = problem.gravityAtPos(xOutside);
+                hOutside -= rho*(gOutside*xOutside);
+            }
+        }
+
+        return tij*(hInside - hOutside);
+    }
+
+    static Stencil stencil(const Problem& problem,
+                           const Element& element,
+                           const FVElementGeometry& fvGeometry,
+                           const SubControlVolumeFace& scvFace)
+    {
+        Stencil stencil;
+        if (!scvFace.boundary())
+        {
+            stencil.push_back(scvFace.insideScvIdx());
+            stencil.push_back(scvFace.outsideScvIdx());
+        }
+        else
+            stencil.push_back(scvFace.insideScvIdx());
+
+        return stencil;
+    }
+
+    // The flux variables cache has to be bound to an element prior to flux calculations
+    // During the binding, the transmissibilities will be computed and stored using the method below.
+    static Scalar calculateTransmissibilities(const Problem& problem,
+                                              const Element& element,
+                                              const FVElementGeometry& fvGeometry,
+                                              const ElementVolumeVariables& elemVolVars,
+                                              const SubControlVolumeFace& scvFace)
+    {
+        Scalar tij;
+
+        const auto insideScvIdx = scvFace.insideScvIdx();
+        const auto& insideScv = fvGeometry.scv(insideScvIdx);
+        const auto& insideVolVars = elemVolVars[insideScvIdx];
+        const auto insideK = problem.spatialParams().intrinsicPermeability(insideScv, insideVolVars);
+        Scalar ti = calculateOmega_(problem, scvFace, insideK, element, insideScv);
+
+        if (!scvFace.boundary())
+        {
+            const auto outsideScvIdx = scvFace.outsideScvIdx();
+            // as we assemble fluxes from the neighbor to our element the outside index
+            // refers to the scv of our element, so we use the scv method
+            const auto& outsideScv = fvGeometry.scv(outsideScvIdx);
+            const auto outsideElement = fvGeometry.globalFvGeometry().element(outsideScvIdx);
+            const auto& outsideVolVars = elemVolVars[outsideScvIdx];
+            const auto outsideK = problem.spatialParams().intrinsicPermeability(outsideScv, outsideVolVars);
+            Scalar tj = -1.0*calculateOmega_(problem, scvFace, outsideK, outsideElement, outsideScv);
+
+            // check for division by zero!
+            if (ti*tj <= 0.0)
+                tij = 0;
+            else
+                tij = scvFace.area()*(ti * tj)/(ti + tj);
+        }
+        else
+        {
+            tij = scvFace.area()*ti;
+        }
+
+        return tij;
+    }
+
+private:
+
+    static Scalar calculateOmega_(const Problem& problem,
+                                  const SubControlVolumeFace& scvFace,
+                                  const DimWorldMatrix &K,
+                                  const Element& element,
+                                  const SubControlVolume &scv)
+    {
+        GlobalPosition Knormal;
+        K.mv(scvFace.unitOuterNormal(), Knormal);
+
+        auto distanceVector = scvFace.center();
+        distanceVector -= scv.center();
+        distanceVector /= distanceVector.two_norm2();
+
+        Scalar omega = Knormal * distanceVector;
+        omega *= problem.boxExtrusionFactor(element, scv);
+
+        return omega;
+    }
+
+    static Scalar calculateOmega_(const Problem& problem,
+                                  const SubControlVolumeFace& scvFace,
+                                  const Scalar K,
+                                  const Element& element,
+                                  const SubControlVolume &scv)
+    {
+        auto distanceVector = scvFace.center();
+        distanceVector -= scv.center();
+        distanceVector /= distanceVector.two_norm2();
+
+        Scalar omega = K * (distanceVector * scvFace.unitOuterNormal());
+        omega *= problem.boxExtrusionFactor(element, scv);
+
+        return omega;
+    }
+};
+
+} // end namespace
+
+#endif
diff --git a/dumux/discretization/staggered/fvelementgeometry.hh b/dumux/discretization/staggered/fvelementgeometry.hh
new file mode 100644
index 0000000000..7e12e9fc43
--- /dev/null
+++ b/dumux/discretization/staggered/fvelementgeometry.hh
@@ -0,0 +1,355 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief Base class for a local finite volume geometry for staggered models
+ *        This builds up the sub control volumes and sub control volume faces
+ *        for each element in the local scope we are restricting to, e.g. stencil or element.
+ */
+#ifndef DUMUX_DISCRETIZATION_STAGGERED_FV_ELEMENT_GEOMETRY_HH
+#define DUMUX_DISCRETIZATION_STAGGERED_FV_ELEMENT_GEOMETRY_HH
+
+#include <dune/common/iteratorrange.hh>
+
+#include <dumux/discretization/scvandscvfiterators.hh>
+#include <dumux/implicit/staggered/properties.hh>
+#include <dumux/discretization/staggered/subcontrolvolume.hh>
+
+namespace Dumux
+{
+
+//! forward declaration of the global finite volume geometry
+template<class TypeTag, bool EnableGlobalFVGeometryCache>
+class StaggeredGlobalFVGeometry;
+
+/*!
+ * \ingroup ImplicitModel
+ * \brief Base class for the finite volume geometry vector for staggered models
+ *        This builds up the sub control volumes and sub control volume faces
+ *        for each element.
+ */
+template<class TypeTag, bool EnableGlobalFVGeometryCache>
+class StaggeredFVElementGeometry
+{};
+
+//! specialization in case the FVElementGeometries are stored globally
+//! In this case we just forward internally to the global object
+template<class TypeTag>
+class StaggeredFVElementGeometry<TypeTag, true>
+{
+    using ThisType = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using IndexType = typename GridView::IndexSet::IndexType;
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
+    using Element = typename GridView::template Codim<0>::Entity;
+    using GlobalFVGeometry = typename GET_PROP_TYPE(TypeTag, GlobalFVGeometry);
+
+    using ScvIterator = Dumux::ScvIterator<SubControlVolume, std::vector<IndexType>, ThisType>;
+    using ScvfIterator = Dumux::ScvfIterator<SubControlVolumeFace, std::vector<IndexType>, ThisType>;
+
+public:
+    //! Constructor
+    StaggeredFVElementGeometry(const GlobalFVGeometry& globalFvGeometry)
+    : globalFvGeometryPtr_(&globalFvGeometry) {}
+
+    //! Get an elment sub control volume with a global scv index
+    //! We separate element and neighbor scvs to speed up mapping
+    const SubControlVolume& scv(IndexType scvIdx) const
+    {
+        return globalFvGeometry().scv(scvIdx);
+    }
+
+    //! Get an element sub control volume face with a global scvf index
+    //! We separate element and neighbor scvfs to speed up mapping
+    const SubControlVolumeFace& scvf(IndexType scvfIdx) const
+    {
+        return globalFvGeometry().scvf(scvfIdx);
+    }
+
+    //! iterator range for sub control volumes. Iterates over
+    //! all scvs of the bound element (not including neighbor scvs)
+    //! This is a free function found by means of ADL
+    //! To iterate over all sub control volumes of this FVElementGeometry use
+    //! for (auto&& scv : scvs(fvGeometry))
+    friend inline Dune::IteratorRange<ScvIterator>
+    scvs(const StaggeredFVElementGeometry& fvGeometry)
+    {
+        return Dune::IteratorRange<ScvIterator>(ScvIterator(fvGeometry.scvIndices_.begin(), fvGeometry),
+                                                ScvIterator(fvGeometry.scvIndices_.end(), fvGeometry));
+    }
+
+    //! iterator range for sub control volumes faces. Iterates over
+    //! all scvfs of the bound element (not including neighbor scvfs)
+    //! This is a free function found by means of ADL
+    //! To iterate over all sub control volume faces of this FVElementGeometry use
+    //! for (auto&& scvf : scvfs(fvGeometry))
+    friend inline Dune::IteratorRange<ScvfIterator>
+    scvfs(const StaggeredFVElementGeometry& fvGeometry)
+    {
+        const auto& g = fvGeometry.globalFvGeometry();
+        const auto scvIdx = fvGeometry.scvIndices_[0];
+        return Dune::IteratorRange<ScvfIterator>(ScvfIterator(g.scvfIndicesOfScv(scvIdx).begin(), fvGeometry),
+                                                 ScvfIterator(g.scvfIndicesOfScv(scvIdx).end(), fvGeometry));
+    }
+
+    //! number of sub control volumes in this fv element geometry
+    std::size_t numScv() const
+    {
+        return scvIndices_.size();
+    }
+
+    //! number of sub control volumes in this fv element geometry
+    std::size_t numScvf() const
+    {
+        return globalFvGeometry().scvfIndicesOfScv(scvIndices_[0]).size();
+    }
+
+    //! Binding of an element, called by the local jacobian to prepare element assembly
+    void bind(const Element& element)
+    {
+        this->bindElement(element);
+    }
+
+    //! Bind only element-local
+    void bindElement(const Element& element)
+    {
+        elementPtr_ = &element;
+        scvIndices_ = std::vector<IndexType>({globalFvGeometry().problem_().elementMapper().index(*elementPtr_)});
+    }
+
+    //! The global finite volume geometry we are a restriction of
+    const GlobalFVGeometry& globalFvGeometry() const
+    { return *globalFvGeometryPtr_; }
+
+private:
+
+    const Element* elementPtr_;
+    std::vector<IndexType> scvIndices_;
+    const GlobalFVGeometry* globalFvGeometryPtr_;
+};
+
+//! specialization in case the FVElementGeometries are not stored
+template<class TypeTag>
+class StaggeredFVElementGeometry<TypeTag, false>
+{
+    using ThisType = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using IndexType = typename GridView::IndexSet::IndexType;
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
+    using Element = typename GridView::template Codim<0>::Entity;
+    using GlobalFVGeometry = typename GET_PROP_TYPE(TypeTag, GlobalFVGeometry);
+
+    using ScvIterator = Dumux::ScvIterator<SubControlVolume, std::vector<IndexType>, ThisType>;
+    using ScvfIterator = Dumux::ScvfIterator<SubControlVolumeFace, std::vector<IndexType>, ThisType>;
+
+public:
+    //! Constructor
+    StaggeredFVElementGeometry(const GlobalFVGeometry& globalFvGeometry)
+    : globalFvGeometryPtr_(&globalFvGeometry) {}
+
+    //! Get an elment sub control volume with a global scv index
+    //! We separate element and neighbor scvs to speed up mapping
+    const SubControlVolume& scv(IndexType scvIdx) const
+    {
+        if (scvIdx == scvIndices_[0])
+            return scvs_[0];
+        else
+            return neighborScvs_[findLocalIndex(scvIdx, neighborScvIndices_)];
+    }
+
+    //! Get an element sub control volume face with a global scvf index
+    //! We separate element and neighbor scvfs to speed up mapping
+    const SubControlVolumeFace& scvf(IndexType scvfIdx) const
+    {
+        auto it = std::find(scvfIndices_.begin(), scvfIndices_.end(), scvfIdx);
+        if (it != scvfIndices_.end())
+            return scvfs_[std::distance(scvfIndices_.begin(), it)];
+        else
+            return neighborScvfs_[findLocalIndex(scvfIdx, neighborScvfIndices_)];
+    }
+
+    //! iterator range for sub control volumes. Iterates over
+    //! all scvs of the bound element (not including neighbor scvs)
+    //! This is a free function found by means of ADL
+    //! To iterate over all sub control volumes of this FVElementGeometry use
+    //! for (auto&& scv : scvs(fvGeometry))
+    friend inline Dune::IteratorRange<typename std::vector<SubControlVolume>::const_iterator>
+    scvs(const ThisType& g)
+    {
+        using Iter = typename std::vector<SubControlVolume>::const_iterator;
+        return Dune::IteratorRange<Iter>(g.scvs_.begin(), g.scvs_.end());
+    }
+
+    //! iterator range for sub control volumes faces. Iterates over
+    //! all scvfs of the bound element (not including neighbor scvfs)
+    //! This is a free function found by means of ADL
+    //! To iterate over all sub control volume faces of this FVElementGeometry use
+    //! for (auto&& scvf : scvfs(fvGeometry))
+    friend inline Dune::IteratorRange<typename std::vector<SubControlVolumeFace>::const_iterator>
+    scvfs(const ThisType& g)
+    {
+        using Iter = typename std::vector<SubControlVolumeFace>::const_iterator;
+        return Dune::IteratorRange<Iter>(g.scvfs_.begin(), g.scvfs_.end());
+    }
+
+    //! number of sub control volumes in this fv element geometry
+    std::size_t numScv() const
+    { return scvs_.size(); }
+
+    //! number of sub control volumes in this fv element geometry
+    std::size_t numScvf() const
+    { return scvfs_.size(); }
+
+    //! Binding of an element preparing the geometries of the whole stencil
+    //! called by the local jacobian to prepare element assembly
+    void bind(const Element& element)
+    {
+        bindElement(element);
+        for (const auto& intersection : intersections(globalFvGeometry().gridView(), element))
+        {
+            neighborScvs_.reserve(element.subEntities(1));
+            neighborScvfIndices_.reserve(element.subEntities(1));
+            if (intersection.neighbor())
+                makeNeighborGeometries(intersection.outside());
+        }
+    }
+
+    //! Binding of an element preparing the geometries only inside the element
+    void bindElement(const Element& element)
+    {
+        clear();
+        elementPtr_ = &element;
+        makeElementGeometries(element);
+    }
+
+    //! The global finite volume geometry we are a restriction of
+    const GlobalFVGeometry& globalFvGeometry() const
+    { return *globalFvGeometryPtr_; }
+
+private:
+
+    //! create scvs and scvfs of the bound element
+    void makeElementGeometries(const Element& element)
+    {
+        auto eIdx = globalFvGeometry().problem_().elementMapper().index(element);
+        scvs_.emplace_back(element.geometry(), eIdx);
+        scvIndices_.emplace_back(eIdx);
+
+        const auto& scvFaceIndices = globalFvGeometry().scvfIndicesOfScv(eIdx);
+        const auto& neighborVolVarIndices = globalFvGeometry().neighborVolVarIndices(eIdx);
+
+        int scvfCounter = 0;
+        for (const auto& intersection : intersections(globalFvGeometry().gridView(), element))
+        {
+            if (intersection.neighbor() || intersection.boundary())
+            {
+                scvfs_.emplace_back(intersection,
+                                    intersection.geometry(),
+                                    scvFaceIndices[scvfCounter],
+                                    std::vector<IndexType>({eIdx, neighborVolVarIndices[scvfCounter]})
+                                    );
+
+                scvfIndices_.emplace_back(scvFaceIndices[scvfCounter]);
+                scvfCounter++;
+            }
+        }
+    }
+
+    //! create the necessary scvs and scvfs of the neighbor elements to the bound elements
+    void makeNeighborGeometries(const Element& element)
+    {
+        // create the neighbor scv
+        auto eIdx = globalFvGeometry().problem_().elementMapper().index(element);
+        neighborScvs_.emplace_back(element.geometry(), eIdx);
+        neighborScvIndices_.push_back(eIdx);
+
+        const auto& scvFaceIndices = globalFvGeometry().scvfIndicesOfScv(eIdx);
+        const auto& neighborVolVarIndices = globalFvGeometry().neighborVolVarIndices(eIdx);
+
+        int scvfCounter = 0;
+        for (const auto& intersection : intersections(globalFvGeometry().gridView(), element))
+        {
+            if (intersection.neighbor())
+            {
+                // only create subcontrol faces where the outside element is the bound element
+                if (intersection.outside() == *elementPtr_)
+                {
+                    neighborScvfs_.emplace_back(intersection,
+                                                intersection.geometry(),
+                                                scvFaceIndices[scvfCounter],
+                                                std::vector<IndexType>({eIdx, neighborVolVarIndices[scvfCounter]})
+                                                );
+
+                    neighborScvfIndices_.push_back(scvFaceIndices[scvfCounter]);
+                }
+                // always increase local counter
+                scvfCounter++;
+            }
+            else if (intersection.boundary())
+            {
+                scvfCounter++;
+            }
+        }
+    }
+
+    const IndexType findLocalIndex(const IndexType idx,
+                                   const std::vector<IndexType>& indices) const
+    {
+        auto it = std::find(indices.begin(), indices.end(), idx);
+        assert(it != indices.end() && "Could not find the scv/scvf! Make sure to properly bind this class!");
+        return std::distance(indices.begin(), it);
+
+    }
+
+    void clear()
+    {
+        scvIndices_.clear();
+        scvfIndices_.clear();
+        scvs_.clear();
+        scvfs_.clear();
+
+        neighborScvIndices_.clear();
+        neighborScvfIndices_.clear();
+        neighborScvs_.clear();
+        neighborScvfs_.clear();
+    }
+
+    // the bound element
+    const Element* elementPtr_;
+
+    const GlobalFVGeometry* globalFvGeometryPtr_;
+
+    // local storage after binding an element
+    std::vector<IndexType> scvIndices_;
+    std::vector<IndexType> scvfIndices_;
+    std::vector<SubControlVolume> scvs_;
+    std::vector<SubControlVolumeFace> scvfs_;
+
+    std::vector<IndexType> neighborScvIndices_;
+    std::vector<IndexType> neighborScvfIndices_;
+    std::vector<SubControlVolume> neighborScvs_;
+    std::vector<SubControlVolumeFace> neighborScvfs_;
+};
+
+} // end namespace
+
+#endif
diff --git a/dumux/discretization/staggered/globalfluxvariablescache.hh b/dumux/discretization/staggered/globalfluxvariablescache.hh
new file mode 100644
index 0000000000..8cd7bc756a
--- /dev/null
+++ b/dumux/discretization/staggered/globalfluxvariablescache.hh
@@ -0,0 +1,138 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief The global object of flux var caches
+ */
+#ifndef DUMUX_DISCRETIZATION_CC_GLOBAL_FLUXVARSCACHE_HH
+#define DUMUX_DISCRETIZATION_CC_GLOBAL_FLUXVARSCACHE_HH
+
+#include <dumux/implicit/properties.hh>
+#include <dumux/discretization/cellcentered/elementfluxvariablescache.hh>
+
+namespace Dumux
+{
+
+/*!
+ * \ingroup ImplicitModel
+ * \brief Base class for the flux variables cache vector, we store one cache per face
+ */
+template<class TypeTag, bool EnableGlobalFluxVariablesCache>
+class CCGlobalFluxVariablesCache;
+
+/*!
+ * \ingroup ImplicitModel
+ * \brief Spezialization when caching globally
+ */
+template<class TypeTag>
+class CCGlobalFluxVariablesCache<TypeTag, true>
+{
+    // the local class needs access to the problem
+    friend CCElementFluxVariablesCache<TypeTag, true>;
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using IndexType = typename GridView::IndexSet::IndexType;
+    using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache);
+    using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache);
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
+
+public:
+    // When global caching is enabled, precompute transmissibilities and stencils for all the scv faces
+    void update(Problem& problem)
+    {
+        problemPtr_ = &problem;
+        const auto& globalFvGeometry = problem.model().globalFvGeometry();
+        fluxVarsCache_.resize(globalFvGeometry.numScvf());
+        for (const auto& element : elements(problem.gridView()))
+        {
+            // Prepare the geometries within the elements of the stencil
+            auto fvGeometry = localView(globalFvGeometry);
+            fvGeometry.bind(element);
+
+            auto elemVolVars = localView(problem.model().curGlobalVolVars());
+            elemVolVars.bind(element, fvGeometry, problem.model().curSol());
+
+            for (auto&& scvf : scvfs(fvGeometry))
+            {
+                fluxVarsCache_[scvf.index()].update(problem, element, fvGeometry, elemVolVars, scvf);
+            }
+        }
+    }
+
+    /*!
+     * \brief Return a local restriction of this global object
+     *        The local object is only functional after calling its bind/bindElement method
+     *        This is a free function that will be found by means of ADL
+     */
+    friend inline ElementFluxVariablesCache localView(const CCGlobalFluxVariablesCache& global)
+    { return ElementFluxVariablesCache(global); }
+
+private:
+    // access operators in the case of caching
+    const FluxVariablesCache& operator [](IndexType scvfIdx) const
+    { return fluxVarsCache_[scvfIdx]; }
+
+    FluxVariablesCache& operator [](IndexType scvfIdx)
+    { return fluxVarsCache_[scvfIdx]; }
+
+    const Problem& problem_() const
+    { return *problemPtr_; }
+
+    const Problem* problemPtr_;
+
+    std::vector<FluxVariablesCache> fluxVarsCache_;
+    std::vector<IndexType> globalScvfIndices_;
+};
+
+/*!
+ * \ingroup ImplicitModel
+ * \brief Spezialization when not using global caching
+ */
+template<class TypeTag>
+class CCGlobalFluxVariablesCache<TypeTag, false>
+{
+    // the local class needs access to the problem
+    friend CCElementFluxVariablesCache<TypeTag, false>;
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache);
+
+public:
+    // When global flux variables caching is disabled, we don't need to update the cache
+    void update(Problem& problem)
+    { problemPtr_ = &problem; }
+
+    /*!
+     * \brief Return a local restriction of this global object
+     *        The local object is only functional after calling its bind/bindElement method
+     *        This is a free function that will be found by means of ADL
+     */
+    friend inline ElementFluxVariablesCache localView(const CCGlobalFluxVariablesCache& global)
+    { return ElementFluxVariablesCache(global); }
+
+private:
+
+    const Problem& problem_() const
+    { return *problemPtr_; }
+
+    const Problem* problemPtr_;
+};
+
+} // end namespace
+
+#endif
diff --git a/dumux/discretization/staggered/globalfvgeometry.hh b/dumux/discretization/staggered/globalfvgeometry.hh
new file mode 100644
index 0000000000..bcfb8d03c1
--- /dev/null
+++ b/dumux/discretization/staggered/globalfvgeometry.hh
@@ -0,0 +1,363 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief Base class for the finite volume geometry vector for staggered models
+ *        This builds up the sub control volumes and sub control volume faces
+ *        for each element of the grid partition.
+ */
+#ifndef DUMUX_DISCRETIZATION_STAGGERED_GLOBAL_FVGEOMETRY_HH
+#define DUMUX_DISCRETIZATION_STAGGERED_GLOBAL_FVGEOMETRY_HH
+
+#include <dumux/common/elementmap.hh>
+#include <dumux/implicit/staggered/properties.hh>
+#include <dumux/discretization/staggered/fvelementgeometry.hh>
+
+namespace Dumux
+{
+
+/*!
+ * \ingroup ImplicitModel
+ * \brief Base class for the finite volume geometry vector for staggered models
+ *        This builds up the sub control volumes and sub control volume faces
+ *        for each element.
+ */
+template<class TypeTag, bool EnableGlobalFVGeometryCache>
+class StaggeredGlobalFVGeometry
+{};
+
+// specialization in case the FVElementGeometries are stored globally
+template<class TypeTag>
+class StaggeredGlobalFVGeometry<TypeTag, true>
+{
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using IndexType = typename GridView::IndexSet::IndexType;
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
+    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+    using Element = typename GridView::template Codim<0>::Entity;
+    //! The local class needs access to the scv, scvfs and the fv element geometry
+    //! as they are globally cached
+    friend typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+
+    enum {
+        // Grid and world dimension
+        dim = GridView::dimension,
+        dimWorld = GridView::dimensionworld
+    };
+
+public:
+    //! Constructor
+    StaggeredGlobalFVGeometry(const GridView& gridView)
+    : gridView_(gridView), elementMap_(gridView) {}
+
+    //! The total number of sub control volumes
+    std::size_t numScv() const
+    {
+        return scvs_.size();
+    }
+
+    //! The total number of sub control volume faces
+    std::size_t numScvf() const
+    {
+        return scvfs_.size();
+    }
+
+    //! The total number of boundary sub control volume faces
+    std::size_t numBoundaryScvf() const
+    {
+        return numBoundaryScvf_;
+    }
+
+    // Get an element from a sub control volume contained in it
+    Element element(const SubControlVolume& scv) const
+    { return elementMap_.element(scv.elementIndex()); }
+
+    // Get an element from a global element index
+    Element element(IndexType eIdx) const
+    { return elementMap_.element(eIdx); }
+
+    //! Return the gridView this global object lives on
+    const GridView& gridView() const
+    { return gridView_; }
+
+    //! update all fvElementGeometries (do this again after grid adaption)
+    void update(const Problem& problem)
+    {
+        problemPtr_ = &problem;
+
+        // clear containers (necessary after grid refinement)
+        scvs_.clear();
+        scvfs_.clear();
+        scvfIndicesOfScv_.clear();
+        elementMap_.clear();
+
+        // determine size of containers
+        const int numElements = gridView_.size(0);
+        IndexType numScvs = gridView_.size(0);
+        IndexType numScvf = 0;
+        for (const auto& element : elements(gridView_))
+            numScvf += element.subEntities(1);
+
+        // reserve memory
+        elementMap_.resize(numScvs);
+        scvs_.resize(numScvs);
+        scvfs_.reserve(numScvf);
+        scvfIndicesOfScv_.resize(numScvs);
+
+        // Build the scvs and scv faces
+        IndexType scvfIdx = 0;
+        numBoundaryScvf_ = 0;
+        for (const auto& element : elements(gridView_))
+        {
+            auto eIdx = problem.elementMapper().index(element);
+            scvs_[eIdx] = SubControlVolume(element.geometry(), eIdx);
+
+            // fill the element map with seeds
+            elementMap_[eIdx] = element.seed();
+
+            // the element-wise index sets for finite volume geometry
+            std::vector<IndexType> scvfsIndexSet;
+            scvfsIndexSet.reserve(element.subEntities(1));
+            for (const auto& intersection : intersections(gridView_, element))
+            {
+                //TODO: use proper intersection mapper!
+                const auto inIdx = intersection.indexInInside();
+                const auto globalIsIdx = gridView_.indexSet().subIndex(element, inIdx, dim-1) + numElements;
+
+                int oppoSiteIdx;
+
+                if(inIdx % 2) // face index is odd
+                {
+                    oppoSiteIdx = inIdx -1;
+                }
+                else
+                {
+                    oppoSiteIdx = inIdx +1;
+                }
+
+//                 std::cout << "faceSelf: " << inIdx << ", oppo: " << oppoSiteIdx << std::endl;
+                // inner sub control volume faces
+                if (intersection.neighbor())
+                {
+                    auto nIdx = problem.elementMapper().index(intersection.outside());
+                    scvfs_.emplace_back(intersection,
+                                        intersection.geometry(),
+                                        scvfIdx,
+                                        std::vector<IndexType>({eIdx, nIdx}),
+                                        globalIsIdx
+                                        );
+                    scvfsIndexSet.push_back(scvfIdx++);
+                }
+                // boundary sub control volume faces
+                else if (intersection.boundary())
+                {
+                    scvfs_.emplace_back(intersection,
+                                        intersection.geometry(),
+                                        scvfIdx,
+                                        std::vector<IndexType>({eIdx, gridView_.size(0) + numBoundaryScvf_++}),
+                                        globalIsIdx
+                                        );
+                    scvfsIndexSet.push_back(scvfIdx++);
+                }
+            }
+
+            // Save the scvf indices belonging to this scv to build up fv element geometries fast
+            scvfIndicesOfScv_[eIdx] = scvfsIndexSet;
+        }
+    }
+
+    /*!
+     * \brief Return a local restriction of this global object
+     *        The local object is only functional after calling its bind/bindElement method
+     *        This is a free function that will be found by means of ADL
+     */
+    friend inline FVElementGeometry localView(const StaggeredGlobalFVGeometry& global)
+    { return FVElementGeometry(global); }
+
+//private:
+
+    //! Get a sub control volume with a global scv index
+    const SubControlVolume& scv(IndexType scvIdx) const
+    {
+        return scvs_[scvIdx];
+    }
+
+    //! Get a sub control volume face with a global scvf index
+    const SubControlVolumeFace& scvf(IndexType scvfIdx) const
+    {
+        return scvfs_[scvfIdx];
+    }
+
+    //! Get the sub control volume face indices of an scv by global index
+    const std::vector<IndexType>& scvfIndicesOfScv(IndexType scvIdx) const
+    {
+        return scvfIndicesOfScv_[scvIdx];
+    }
+
+private:
+    const Problem& problem_() const
+    { return *problemPtr_; }
+
+    const Problem* problemPtr_;
+
+    const GridView gridView_;
+    Dumux::ElementMap<GridView> elementMap_;
+    std::vector<SubControlVolume> scvs_;
+    std::vector<SubControlVolumeFace> scvfs_;
+    std::vector<std::vector<IndexType>> scvfIndicesOfScv_;
+    IndexType numBoundaryScvf_;
+};
+
+// specialization in case the FVElementGeometries are not stored
+template<class TypeTag>
+class StaggeredGlobalFVGeometry<TypeTag, false>
+{
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using IndexType = typename GridView::IndexSet::IndexType;
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
+    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+    using Element = typename GridView::template Codim<0>::Entity;
+    //! The local fvGeometry needs access to the problem
+    friend typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+
+public:
+    //! Constructor
+    StaggeredGlobalFVGeometry(const GridView& gridView)
+    : gridView_(gridView), elementMap_(gridView) {}
+
+    //! The total number of sub control volumes
+    std::size_t numScv() const
+    {
+        return numScvs_;
+    }
+
+    //! The total number of sub control volume faces
+    std::size_t numScvf() const
+    {
+        return numScvf_;
+    }
+
+    //! The total number of boundary sub control volume faces
+    std::size_t numBoundaryScvf() const
+    {
+        return numBoundaryScvf_;
+    }
+
+    // Get an element from a sub control volume contained in it
+    Element element(const SubControlVolume& scv) const
+    { return elementMap_.element(scv.elementIndex()); }
+
+    // Get an element from a global element index
+    Element element(IndexType eIdx) const
+    { return elementMap_.element(eIdx); }
+
+    //! Return the gridView this global object lives on
+    const GridView& gridView() const
+    { return gridView_; }
+
+    //! update all fvElementGeometries (do this again after grid adaption)
+    void update(const Problem& problem)
+    {
+        problemPtr_ = &problem;
+        elementMap_.clear();
+
+        // reserve memory or resize the containers
+        numScvs_ = gridView_.size(0);
+        numScvf_ = 0;
+        numBoundaryScvf_ = 0;
+        elementMap_.resize(numScvs_);
+        scvfIndicesOfScv_.resize(numScvs_);
+        neighborVolVarIndices_.resize(numScvs_);
+
+        // Build the SCV and SCV face
+        for (const auto& element : elements(gridView_))
+        {
+            auto eIdx = problem.elementMapper().index(element);
+
+            // fill the element map with seeds
+            elementMap_[eIdx] = element.seed();
+
+            // the element-wise index sets for finite volume geometry
+            auto numLocalFaces = element.subEntities(1);
+            std::vector<IndexType> scvfsIndexSet;
+            std::vector<IndexType> neighborVolVarIndexSet;
+            scvfsIndexSet.reserve(numLocalFaces);
+            neighborVolVarIndexSet.reserve(numLocalFaces);
+            for (const auto& intersection : intersections(gridView_, element))
+            {
+                // inner sub control volume faces
+                if (intersection.neighbor())
+                {
+                    scvfsIndexSet.push_back(numScvf_++);
+                    neighborVolVarIndexSet.push_back(problem.elementMapper().index(intersection.outside()));
+                }
+                // boundary sub control volume faces
+                else if (intersection.boundary())
+                {
+                    scvfsIndexSet.push_back(numScvf_++);
+                    neighborVolVarIndexSet.push_back(numScvs_ + numBoundaryScvf_++);
+                }
+            }
+
+            // store the sets of indices in the data container
+            scvfIndicesOfScv_[eIdx] = scvfsIndexSet;
+            neighborVolVarIndices_[eIdx] = neighborVolVarIndexSet;
+        }
+    }
+
+    const std::vector<IndexType>& scvfIndicesOfScv(IndexType scvIdx) const
+    { return scvfIndicesOfScv_[scvIdx]; }
+
+    const std::vector<IndexType>& neighborVolVarIndices(IndexType scvIdx) const
+    { return neighborVolVarIndices_[scvIdx]; }
+
+    /*!
+     * \brief Return a local restriction of this global object
+     *        The local object is only functional after calling its bind/bindElement method
+     *        This is a free function that will be found by means of ADL
+     */
+    friend inline FVElementGeometry localView(const StaggeredGlobalFVGeometry& global)
+    { return FVElementGeometry(global); }
+
+private:
+    const Problem& problem_() const
+    { return *problemPtr_; }
+
+    const Problem* problemPtr_;
+
+    const GridView gridView_;
+
+    // Information on the global number of geometries
+    IndexType numScvs_;
+    IndexType numScvf_;
+    IndexType numBoundaryScvf_;
+
+    // vectors that store the global data
+    Dumux::ElementMap<GridView> elementMap_;
+    std::vector<std::vector<IndexType>> scvfIndicesOfScv_;
+    std::vector<std::vector<IndexType>> neighborVolVarIndices_;
+};
+
+} // end namespace
+
+#endif
diff --git a/dumux/discretization/staggered/staggeredgeometryhelper.hh b/dumux/discretization/staggered/staggeredgeometryhelper.hh
new file mode 100644
index 0000000000..6d7339bbde
--- /dev/null
+++ b/dumux/discretization/staggered/staggeredgeometryhelper.hh
@@ -0,0 +1,39 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief Helper class constructing the dual grid finite volume geometries
+ *        for the staggered discretizazion method
+ */
+#ifndef DUMUX_DISCRETIZATION_STAGGERED_GEOMETRY_HELPER_HH
+#define DUMUX_DISCRETIZATION_STAGGERED_GEOMETRY_HELPER_HH
+
+#include <dune/geometry/multilineargeometry.hh>
+#include <dune/geometry/referenceelements.hh>
+
+#include <dumux/common/math.hh>
+
+namespace Dumux
+{
+
+
+
+} // end namespace Dumux
+
+#endif
diff --git a/dumux/discretization/staggered/subcontrolvolume.hh b/dumux/discretization/staggered/subcontrolvolume.hh
new file mode 100644
index 0000000000..6cce08266d
--- /dev/null
+++ b/dumux/discretization/staggered/subcontrolvolume.hh
@@ -0,0 +1,139 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief Base class for a sub control volume
+ */
+#ifndef DUMUX_DISCRETIZATION_STAGGERED_SUBCONTROLVOLUME_HH
+#define DUMUX_DISCRETIZATION_STAGGERED_SUBCONTROLVOLUME_HH
+
+#include <dune/common/fvector.hh>
+#include <dumux/discretization/subcontrolvolumebase.hh>
+#include <dumux/common/optional.hh>
+
+namespace Dumux
+{
+template<class G, typename I>
+class StaggeredSubControlVolume : public SubControlVolumeBase<StaggeredSubControlVolume<G, I>, G, I>
+{
+    using ParentType = SubControlVolumeBase<StaggeredSubControlVolume<G, I>, G, I>;
+    using Geometry = G;
+    using IndexType = I;
+
+    using Scalar = typename Geometry::ctype;
+    enum { dimworld = Geometry::coorddimension };
+    using GlobalPosition = Dune::FieldVector<Scalar, dimworld>;
+
+public:
+    // the default constructor
+    StaggeredSubControlVolume() = default;
+
+    // the contructor in the cc case
+    StaggeredSubControlVolume(Geometry&& geometry,
+                       IndexType elementIndex)
+    : ParentType(), geometry_(std::move(geometry)), elementIndex_(elementIndex) {}
+
+    //! The copy constrcutor
+    StaggeredSubControlVolume(const StaggeredSubControlVolume& other) = default;
+
+    //! The move constrcutor
+    StaggeredSubControlVolume(StaggeredSubControlVolume&& other) = default;
+
+    //! The copy assignment operator
+    StaggeredSubControlVolume& operator=(const StaggeredSubControlVolume& other)
+    {
+        // We want to use the default copy/move assignment.
+        // But since geometry is not copy assignable :( we
+        // have to construct it again
+        geometry_.release();
+        geometry_.emplace(other.geometry_.value());
+        elementIndex_ = other.elementIndex_;
+        return *this;
+    }
+
+    //! The move assignment operator
+    StaggeredSubControlVolume& operator=(StaggeredSubControlVolume&& other)
+    {
+        // We want to use the default copy/move assignment.
+        // But since geometry is not copy assignable :( we
+        // have to construct it again
+        geometry_.release();
+        geometry_.emplace(other.geometry_.value());
+        elementIndex_ = std::move(other.elementIndex_);
+        return *this;
+    }
+
+    //! The center of the sub control volume
+    GlobalPosition center() const
+    {
+        return geometry().center();
+    }
+
+    //! The volume of the sub control volume
+    Scalar volume() const
+    {
+        return geometry().volume();
+    }
+
+    //! The geometry of the sub control volume
+    // e.g. for integration
+    const Geometry& geometry() const
+    {
+        return geometry_.value();
+    }
+
+    //! The global index of this scv
+    IndexType index() const
+    {
+        return elementIndex();
+    }
+
+    //! The index of the dof this scv is embedded in
+    IndexType dofIndex() const
+    {
+        return elementIndex();
+    }
+
+    // The position of the dof this scv is embedded in
+    GlobalPosition dofPosition() const
+    {
+        return geometry().center();
+    }
+
+    //! The global index of the element this scv is embedded in
+    IndexType elementIndex() const
+    {
+        return elementIndex_;
+    }
+
+    //! Return the corner for the given local index
+    GlobalPosition corner(unsigned int localIdx) const
+    {
+        assert(localIdx < geometry().corners().size() && "provided index exceeds the number of corners");
+        return geometry().corners(localIdx);
+    }
+
+private:
+    // Work around the fact that geometry is not default constructible
+    Optional<Geometry> geometry_;
+    IndexType elementIndex_;
+};
+} // end namespace
+
+#endif
diff --git a/dumux/discretization/staggered/subcontrolvolumeface.hh b/dumux/discretization/staggered/subcontrolvolumeface.hh
new file mode 100644
index 0000000000..a137e17722
--- /dev/null
+++ b/dumux/discretization/staggered/subcontrolvolumeface.hh
@@ -0,0 +1,220 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief Base class for a sub control volume face
+ */
+#ifndef DUMUX_DISCRETIZATION_STAGGERED_SUBCONTROLVOLUMEFACE_HH
+#define DUMUX_DISCRETIZATION_STAGGERED_SUBCONTROLVOLUMEFACE_HH
+
+#include <utility>
+#include <dune/common/fvector.hh>
+#include <dumux/discretization/subcontrolvolumefacebase.hh>
+#include <dumux/common/optional.hh>
+
+namespace Dumux
+{
+
+template<class G, typename I>
+class StaggeredSubFace
+{
+    using Geometry = G;
+    using IndexType = I;
+    using Scalar = typename Geometry::ctype;
+
+private:
+    std::vector<std::pair<int,int>> velocityDofIdxPair_;
+    std::vector<Scalar> distance_;
+    std::pair<int,int> elementPair_;
+    int commonVertexIdx_;
+};
+
+
+/*!
+ * \ingroup Discretization
+ * \brief Class for a sub control volume face in the box method, i.e a part of the boundary
+ *        of a sub control volume we compute fluxes on. We simply use the base class here.
+ */
+template<class G, typename I>
+class StaggeredSubControlVolumeFace : public SubControlVolumeFaceBase<StaggeredSubControlVolumeFace<G, I>, G, I>
+{
+    using ParentType = SubControlVolumeFaceBase<StaggeredSubControlVolumeFace<G, I>, G, I>;
+    using Geometry = G;
+    using IndexType = I;
+
+    using Scalar = typename Geometry::ctype;
+    static const int dim = Geometry::mydimension;
+    static const int dimworld = Geometry::coorddimension;
+
+    using GlobalPosition = Dune::FieldVector<Scalar, dimworld>;
+    using LocalPosition = Dune::FieldVector<Scalar, dim>;
+
+    using StaggeredSubFace = Dumux::StaggeredSubFace<G,I>;
+
+public:
+    // the default constructor
+    StaggeredSubControlVolumeFace() = default;
+
+    //! Constructor with intersection
+    template <class Intersection>
+    StaggeredSubControlVolumeFace(const Intersection& is,
+                               const typename Intersection::Geometry& isGeometry,
+                               IndexType scvfIndex,
+                               const std::vector<IndexType>& scvIndices,
+                               const int selfIdx
+                           )
+    : ParentType(),
+      geomType_(isGeometry.type()),
+      area_(isGeometry.volume()),
+      center_(isGeometry.center()),
+      unitOuterNormal_(is.centerUnitOuterNormal()),
+      scvfIndex_(scvfIndex),
+      scvIndices_(scvIndices),
+      boundary_(is.boundary()),
+      selfIdx_(selfIdx)
+      {
+          corners_.resize(isGeometry.corners());
+          for (int i = 0; i < isGeometry.corners(); ++i)
+              corners_[i] = isGeometry.corner(i);
+
+//           subfaces_.resize(2);
+
+//           const auto& element = is.inside();
+//           const int inIdx = is.indexInInside();
+//           gridView.indexSet().subIndex(element, inIdx, dimWorld-1);
+
+      }
+
+    /*//! The copy constrcutor
+    StaggeredSubControlVolumeFace(const StaggeredSubControlVolumeFace& other) = delete;
+
+    //! The move constrcutor
+    StaggeredSubControlVolumeFace(StaggeredSubControlVolumeFace&& other) = default;
+
+    //! The copy assignment operator
+    StaggeredSubControlVolumeFace& operator=(const StaggeredSubControlVolumeFace& other) = delete;
+
+    //! The move assignment operator
+    // StaggeredSubControlVolumeFace& operator=(StaggeredSubControlVolumeFace&& other)
+    // {
+    //     // We want to use the default copy/move assignment.
+    //     // But since geometry is not copy assignable :( we
+    //     // have to construct it again
+    //     geometry_.release();
+    //     geometry_.emplace(other.geometry_.value());
+    //     unitOuterNormal_ = std::move(other.unitOuterNormal_);
+    //     scvfIndex_ = std::move(other.scvfIndex_);
+    //     scvIndices_ = std::move(other.scvIndices_);
+    //     boundary_ = std::move(other.boundary_);
+    //     return *this;
+    // }*/
+
+    //! The center of the sub control volume face
+    GlobalPosition center() const
+    {
+        return center_;
+    }
+
+    //! The integration point for flux evaluations in global coordinates
+    GlobalPosition ipGlobal() const
+    {
+        // Return center for now
+        return center_;
+    }
+
+    //! The area of the sub control volume face
+    Scalar area() const
+    {
+        return area_;
+    }
+
+    //! returns bolean if the sub control volume face is on the boundary
+    bool boundary() const
+    {
+        return boundary_;
+    }
+
+    GlobalPosition unitOuterNormal() const
+    {
+        return unitOuterNormal_;
+    }
+
+    //! index of the inside sub control volume for spatial param evaluation
+    IndexType insideScvIdx() const
+    {
+        return scvIndices_[0];
+    }
+
+    //! index of the outside sub control volume for spatial param evaluation
+    // This results in undefined behaviour if boundary is true
+    IndexType outsideScvIdx() const
+    {
+        return scvIndices_[1];
+    }
+
+    //! The global index of this sub control volume face
+    IndexType index() const
+    {
+        return scvfIndex_;
+    }
+
+    GlobalPosition corner(unsigned int localIdx) const
+    {
+        assert(localIdx < corners_.size() && "provided index exceeds the number of corners");
+        return corners_[localIdx];
+    }
+
+    //! The geometry of the sub control volume face
+    const Geometry geometry() const
+    {
+        return Geometry(geomType_, corners_);
+    }
+
+    //! The global index of this sub control volume face
+    IndexType dofIndexSelf() const
+    {
+        return selfIdx_;
+    }
+
+    //! The global index of this sub control volume face
+    IndexType dofIndexOpposite() const
+    {
+        return oppositeIdx_;
+    }
+
+private:
+    Dune::GeometryType geomType_;
+    std::vector<GlobalPosition> corners_;
+    Scalar area_;
+    GlobalPosition center_;
+    GlobalPosition unitOuterNormal_;
+    IndexType scvfIndex_;
+    std::vector<IndexType> scvIndices_;
+    bool boundary_;
+
+    int selfIdx_;
+    int oppositeIdx_;
+    std::vector<StaggeredSubFace> subfaces_;
+};
+
+
+
+} // end namespace
+
+#endif
diff --git a/dumux/implicit/staggered/properties.hh b/dumux/implicit/staggered/properties.hh
new file mode 100644
index 0000000000..73510d65ab
--- /dev/null
+++ b/dumux/implicit/staggered/properties.hh
@@ -0,0 +1,52 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+#ifndef DUMUX_STAGGERED_PROPERTIES_HH
+#define DUMUX_STAGGERED_PROPERTIES_HH
+
+#include <dumux/implicit/properties.hh>
+
+/*!
+ * \ingroup Properties
+ * \ingroup ImplicitProperties
+ * \ingroup StaggeredModel
+ * \file
+ * \brief Specify the shape functions, operator assemblers, etc
+ *        used for the StaggeredModel.
+ */
+namespace Dumux
+{
+
+namespace Properties
+{
+// \{
+
+//////////////////////////////////////////////////////////////////
+// Type tags
+//////////////////////////////////////////////////////////////////
+
+//! The type tag for models based on staggered scheme
+NEW_TYPE_TAG(StaggeredModel, INHERITS_FROM(ImplicitBase));
+}
+}
+
+// \}
+
+#include <dumux/implicit/staggered/propertydefaults.hh>
+
+#endif
diff --git a/dumux/implicit/staggered/propertydefaults.hh b/dumux/implicit/staggered/propertydefaults.hh
new file mode 100644
index 0000000000..6f49cbfaba
--- /dev/null
+++ b/dumux/implicit/staggered/propertydefaults.hh
@@ -0,0 +1,115 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \ingroup Properties
+ * \ingroup CCTpfaProperties
+ * \ingroup StaggeredModel
+ * \file
+ *
+ * \brief Default properties for cell centered models
+ */
+#ifndef DUMUX_STAGGERED_PROPERTY_DEFAULTS_HH
+#define DUMUX_STAGGERED_PROPERTY_DEFAULTS_HH
+
+#include <dumux/implicit/propertydefaults.hh>
+#include <dumux/porousmediumflow/implicit/fluxvariablescache.hh>
+#include <dumux/discretization/staggered/globalfvgeometry.hh>
+#include <dumux/discretization/staggered/fvelementgeometry.hh>
+#include <dumux/discretization/staggered/subcontrolvolumeface.hh>
+#include <dumux/implicit/staggered/properties.hh>
+#include <dumux/discretization/methods.hh>
+#include <dumux/discretization/cellcentered/stencils.hh>
+
+namespace Dumux {
+
+// forward declarations
+template<class TypeTag> class CCElementBoundaryTypes;
+
+namespace Properties {
+//! Set the corresponding discretization method property
+SET_PROP(StaggeredModel, DiscretizationMethod)
+{
+    static const DiscretizationMethods value = DiscretizationMethods::Staggered;
+};
+
+//! Set the default for the global finite volume geometry
+SET_TYPE_PROP(StaggeredModel, GlobalFVGeometry, StaggeredGlobalFVGeometry<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFVGeometryCache)>);
+
+//! Set the default for the local finite volume geometry
+SET_TYPE_PROP(StaggeredModel, FVElementGeometry, StaggeredFVElementGeometry<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFVGeometryCache)>);
+
+//! The sub control volume
+SET_PROP(StaggeredModel, SubControlVolume)
+{
+private:
+    using Grid = typename GET_PROP_TYPE(TypeTag, Grid);
+    using ScvGeometry = typename Grid::template Codim<0>::Geometry;
+    using IndexType = typename Grid::LeafGridView::IndexSet::IndexType;
+public:
+    typedef Dumux::StaggeredSubControlVolume<ScvGeometry, IndexType> type;
+};
+
+SET_PROP(StaggeredModel, SubControlVolumeFace)
+{
+private:
+    using Grid = typename GET_PROP_TYPE(TypeTag, Grid);
+    using ScvfGeometry = typename Grid::template Codim<1>::Geometry;
+    using IndexType = typename Grid::LeafGridView::IndexSet::IndexType;
+public:
+    typedef Dumux::StaggeredSubControlVolumeFace<ScvfGeometry, IndexType> type;
+};
+
+//! Set the default for the ElementBoundaryTypes
+SET_TYPE_PROP(StaggeredModel, ElementBoundaryTypes, Dumux::CCElementBoundaryTypes<TypeTag>);
+
+//! Mapper for the degrees of freedoms.
+SET_TYPE_PROP(StaggeredModel, DofMapper, typename GET_PROP_TYPE(TypeTag, ElementMapper));
+
+//! The global current volume variables vector class
+SET_TYPE_PROP(StaggeredModel, GlobalVolumeVariables, Dumux::CCGlobalVolumeVariables<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalVolumeVariablesCache)>);
+
+//! The global flux variables cache vector class
+SET_TYPE_PROP(StaggeredModel, GlobalFluxVariablesCache, Dumux::CCGlobalFluxVariablesCache<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFluxVariablesCache)>);
+
+//! The local jacobian operator
+SET_TYPE_PROP(StaggeredModel, LocalJacobian, Dumux::CCLocalJacobian<TypeTag>);
+
+//! Assembler for the global jacobian matrix
+SET_TYPE_PROP(StaggeredModel, JacobianAssembler, Dumux::CCAssembler<TypeTag>);
+
+//! The stencil container
+SET_TYPE_PROP(StaggeredModel, StencilsVector, Dumux::CCStencilsVector<TypeTag>);
+
+//! The local flux variables cache vector class
+SET_TYPE_PROP(StaggeredModel, ElementFluxVariablesCache, Dumux::CCElementFluxVariablesCache<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalFluxVariablesCache)>);
+
+//! The global previous volume variables vector class
+SET_TYPE_PROP(StaggeredModel, ElementVolumeVariables, Dumux::CCElementVolumeVariables<TypeTag, GET_PROP_VALUE(TypeTag, EnableGlobalVolumeVariablesCache)>);
+
+//! Set the BaseLocalResidual to CCLocalResidual
+SET_TYPE_PROP(StaggeredModel, BaseLocalResidual, Dumux::CCLocalResidual<TypeTag>);
+
+//! indicate that this is no box discretization
+SET_BOOL_PROP(StaggeredModel, ImplicitIsBox, false);
+
+} // namespace Properties
+
+} // namespace Dumux
+
+#endif
diff --git a/test/discretization/CMakeLists.txt b/test/discretization/CMakeLists.txt
index a2f10ebf0a..0b5fb54664 100644
--- a/test/discretization/CMakeLists.txt
+++ b/test/discretization/CMakeLists.txt
@@ -1 +1,2 @@
 add_subdirectory("cellcentered")
+add_subdirectory("staggered")
diff --git a/test/discretization/staggered/CMakeLists.txt b/test/discretization/staggered/CMakeLists.txt
new file mode 100644
index 0000000000..806563abb4
--- /dev/null
+++ b/test/discretization/staggered/CMakeLists.txt
@@ -0,0 +1,2 @@
+add_dumux_test(test_staggered test_staggered test_staggered.cc
+               ${CMAKE_CURRENT_BINARY_DIR}/test_staggered)
diff --git a/test/discretization/staggered/test_staggered.cc b/test/discretization/staggered/test_staggered.cc
new file mode 100644
index 0000000000..1c3a0f9217
--- /dev/null
+++ b/test/discretization/staggered/test_staggered.cc
@@ -0,0 +1,149 @@
+// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+// vi: set et ts=4 sw=4 sts=4:
+/*****************************************************************************
+ *   See the file COPYING for full copying permissions.                      *
+ *                                                                           *
+ *   This program is free software: you can redistribute it and/or modify    *
+ *   it under the terms of the GNU General Public License as published by    *
+ *   the Free Software Foundation, either version 2 of the License, or       *
+ *   (at your option) any later version.                                     *
+ *                                                                           *
+ *   This program is distributed in the hope that it will be useful,         *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
+ *   GNU General Public License for more details.                            *
+ *                                                                           *
+ *   You should have received a copy of the GNU General Public License       *
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
+ *****************************************************************************/
+/*!
+ * \file
+ * \brief Test for finite volume element geometry, sub control volume, and sub
+          control volume faces
+ */
+#include <config.h>
+
+#include <iostream>
+#include <utility>
+
+#include <dune/common/test/iteratortest.hh>
+#include <dune/grid/utility/structuredgridfactory.hh>
+#include <dune/grid/yaspgrid.hh>
+#include <dune/grid/common/mcmgmapper.hh>
+
+#include <dumux/implicit/staggered/properties.hh>
+#include <dumux/discretization/staggered/globalfvgeometry.hh>
+#include <dumux/discretization/staggered/fvelementgeometry.hh>
+#include <dumux/discretization/staggered/subcontrolvolume.hh>
+#include <dumux/discretization/staggered/subcontrolvolumeface.hh>
+
+namespace Dumux
+{
+
+template<class TypeTag>
+class MockProblem
+{
+    using ElementMapper = typename GET_PROP_TYPE(TypeTag, DofMapper);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+public:
+    MockProblem(const GridView& gridView) : mapper_(gridView) {}
+
+    const ElementMapper& elementMapper() const
+    { return mapper_; }
+private:
+    ElementMapper mapper_;
+};
+
+namespace Properties
+{
+NEW_TYPE_TAG(TestFVGeometry, INHERITS_FROM(StaggeredModel));
+
+SET_TYPE_PROP(TestFVGeometry, Grid, Dune::YaspGrid<2>);
+
+SET_TYPE_PROP(TestFVGeometry, Problem, Dumux::MockProblem<TypeTag>);
+
+SET_BOOL_PROP(TestFVGeometry, EnableGlobalFVGeometryCache, true);
+}
+
+}
+
+template<class T>
+class NoopFunctor {
+public:
+  NoopFunctor() {}
+  void operator()(const T& t){}
+};
+
+int main (int argc, char *argv[]) try
+{
+    // maybe initialize mpi
+    Dune::MPIHelper::instance(argc, argv);
+
+    std::cout << "Checking the FVGeometries, SCVs and SCV faces" << std::endl;
+
+    // aliases
+    using TypeTag = TTAG(TestFVGeometry);
+    using Grid = typename GET_PROP_TYPE(TypeTag, Grid);
+    using GridView = typename Grid::LeafGridView;
+
+    constexpr int dim = GridView::dimension;
+    constexpr int dimworld = GridView::dimensionworld;
+
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using GlobalPosition = Dune::FieldVector<Scalar, dimworld>;
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
+    using GlobalFVGeometry = typename GET_PROP_TYPE(TypeTag, GlobalFVGeometry);
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+
+    // make a grid
+    GlobalPosition lower(0.0);
+    GlobalPosition upper(1.0);
+    std::array<unsigned int, dim> els{{2, 2}};
+    std::shared_ptr<Grid> grid = Dune::StructuredGridFactory<Grid>::createCubeGrid(lower, upper, els);
+    auto leafGridView = grid->leafGridView();
+
+    Problem problem(leafGridView);
+
+    GlobalFVGeometry global(leafGridView);
+    global.update(problem);
+
+    // iterate over elements. For every element get fv geometry and loop over scvs and scvfaces
+    for (const auto& element : elements(leafGridView))
+    {
+        auto eIdx = problem.elementMapper().index(element);
+        std::cout << std::endl << "Checking fvGeometry of element " << eIdx << std::endl;
+        auto fvGeometry = localView(global);
+        fvGeometry.bind(element);
+
+        auto range = scvs(fvGeometry);
+        NoopFunctor<SubControlVolume> op;
+        if(0 != testForwardIterator(range.begin(), range.end(), op))
+            DUNE_THROW(Dune::Exception, "Iterator does not fulfill the forward iterator concept");
+
+        for (auto&& scv : scvs(fvGeometry))
+        {
+            std::cout << "-- scv " << scv.index() << " center at: " << scv.center() << std::endl;
+        }
+
+        auto range2 = scvfs(fvGeometry);
+        NoopFunctor<SubControlVolumeFace> op2;
+        if(0 != testForwardIterator(range2.begin(), range2.end(), op2))
+            DUNE_THROW(Dune::Exception, "Iterator does not fulfill the forward iterator concept");
+
+        for (auto&& scvf : scvfs(fvGeometry))
+        {
+            std::cout << "-- scvf " << scvf.index() << " ip at: " << scvf.ipGlobal();
+            if (scvf.boundary()) std::cout << " (on boundary).";
+            std::cout << std::endl;
+        }
+    }
+}
+// //////////////////////////////////
+//   Error handler
+// /////////////////////////////////
+catch (Dune::Exception e) {
+
+    std::cout << e << std::endl;
+    return 1;
+}
-- 
GitLab