diff --git a/dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh b/dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh
index 47bb3ddedb8364a1eb41fc426fce6257b923a0da..b4b6b14e98cd5f8c76caac992ca38e8939b1a7bb 100644
--- a/dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh
+++ b/dumux/discretization/cellcentered/tpfa/fvelementgeometry.hh
@@ -137,7 +137,7 @@ public:
     void bindElement(const Element& element)
     {
         elementPtr_ = &element;
-        scvIndices_ = std::vector<IndexType>({fvGridGeometry().problem_().elementMapper().index(*elementPtr_)});
+        scvIndices_ = std::vector<IndexType>({fvGridGeometry().elementMapper().index(*elementPtr_)});
     }
 
     //! The global finite volume geometry we are a restriction of
@@ -299,21 +299,20 @@ public:
             }
         }
 
-        //! Check if user added additional DOF dependencies, i.e. the residual of DOF globalI depends
+        //! TODO Check if user added additional DOF dependencies, i.e. the residual of DOF globalI depends
         //! on additional DOFs not included in the discretization schemes' occupation pattern
-        const auto& problem = fvGridGeometry().problem_();
-        const auto globalI = problem.elementMapper().index(element);
-        const auto& additionalDofDependencies = problem.getAdditionalDofDependencies(globalI);
-        if (!additionalDofDependencies.empty())
-        {
-            neighborScvs_.reserve(neighborScvs_.size() + additionalDofDependencies.size());
-            neighborScvIndices_.reserve(neighborScvIndices_.size() + additionalDofDependencies.size());
-            for (auto globalJ : additionalDofDependencies)
-            {
-                neighborScvs_.emplace_back(fvGridGeometry().element(globalJ).geometry(), globalJ);
-                neighborScvIndices_.emplace_back(globalJ);
-            }
-        }
+        // const auto globalI = fvGridGeometry().elementMapper().index(element);
+        // const auto& additionalDofDependencies = problem.getAdditionalDofDependencies(globalI);
+        // if (!additionalDofDependencies.empty())
+        // {
+        //     neighborScvs_.reserve(neighborScvs_.size() + additionalDofDependencies.size());
+        //     neighborScvIndices_.reserve(neighborScvIndices_.size() + additionalDofDependencies.size());
+        //     for (auto globalJ : additionalDofDependencies)
+        //     {
+        //         neighborScvs_.emplace_back(fvGridGeometry().element(globalJ).geometry(), globalJ);
+        //         neighborScvIndices_.emplace_back(globalJ);
+        //     }
+        // }
     }
 
     //! Binding of an element preparing the geometries only inside the element
@@ -361,7 +360,7 @@ private:
     //! create scvs and scvfs of the bound element
     void makeElementGeometries(const Element& element)
     {
-        auto eIdx = fvGridGeometry().problem_().elementMapper().index(element);
+        const auto eIdx = fvGridGeometry().elementMapper().index(element);
         scvs_.emplace_back(element.geometry(), eIdx);
         scvIndices_.emplace_back(eIdx);
 
@@ -378,8 +377,8 @@ private:
         int scvfCounter = 0;
         for (const auto& intersection : intersections(fvGridGeometry().gridView(), element))
         {
-            // check if intersection is on interior boundary
-            const auto isInteriorBoundary = fvGridGeometry().problem_().isInteriorBoundary(element, intersection);
+            // TODO check if intersection is on interior boundary
+            const auto isInteriorBoundary = false;
 
             if (dim < dimWorld)
                 if (handledScvf[intersection.indexInInside()])
@@ -408,7 +407,7 @@ private:
     void makeNeighborGeometries(const Element& element)
     {
         // create the neighbor scv
-        auto eIdx = fvGridGeometry().problem_().elementMapper().index(element);
+        const auto eIdx = fvGridGeometry().elementMapper().index(element);
         neighborScvs_.emplace_back(element.geometry(), eIdx);
         neighborScvIndices_.push_back(eIdx);
 
@@ -425,8 +424,8 @@ private:
         int scvfCounter = 0;
         for (const auto& intersection : intersections(fvGridGeometry().gridView(), element))
         {
-            // check if intersection is on interior boundary
-            const auto isInteriorBoundary = fvGridGeometry().problem_().isInteriorBoundary(element, intersection);
+            // TODO check if intersection is on interior boundary
+            const auto isInteriorBoundary = false;
 
             if (dim < dimWorld)
                 if (handledScvf[intersection.indexInInside()])
@@ -458,7 +457,7 @@ private:
                 {
                     for (unsigned outsideScvIdx = 0; outsideScvIdx < neighborVolVarIndices[scvfCounter].size(); ++outsideScvIdx)
                     {
-                        if (neighborVolVarIndices[scvfCounter][outsideScvIdx] == fvGridGeometry().problem_().elementMapper().index(*elementPtr_))
+                        if (neighborVolVarIndices[scvfCounter][outsideScvIdx] == fvGridGeometry().elementMapper().index(*elementPtr_))
                         {
                             std::vector<IndexType> scvIndices({eIdx});
                             scvIndices.insert(scvIndices.end(), neighborVolVarIndices[scvfCounter].begin(), neighborVolVarIndices[scvfCounter].end());
diff --git a/dumux/implicit/cellcentered/assembler.hh b/dumux/implicit/cellcentered/assembler.hh
index ae80971092189c22109c76ef1d49559b62a0baa9..c00c49716ac61cad79389c79aecb7a72297ab689 100644
--- a/dumux/implicit/cellcentered/assembler.hh
+++ b/dumux/implicit/cellcentered/assembler.hh
@@ -32,15 +32,21 @@
 
 namespace Dumux {
 
+template<class TypeTag, DiscretizationMethods DM>
+class ImplicitAssemblerImplementation;
+
+template<class TypeTag>
+class CCImplicitAssembler;
+
 //! TPFA and MPFA use the same assembler class
 template<class TypeTag>
-class ImplicitAssemblerImplementation<TypeTag, DiscretizationMethods::CCTpfa> : CCImplicitAssembler<TypeTag>
+class ImplicitAssemblerImplementation<TypeTag, DiscretizationMethods::CCTpfa> : public CCImplicitAssembler<TypeTag>
 {
     using CCImplicitAssembler<TypeTag>::CCImplicitAssembler;
 };
 
 template<class TypeTag>
-class ImplicitAssemblerImplementation<TypeTag, DiscretizationMethods::CCMpfa> : CCImplicitAssembler<TypeTag>
+class ImplicitAssemblerImplementation<TypeTag, DiscretizationMethods::CCMpfa> : public CCImplicitAssembler<TypeTag>
 {
     using CCImplicitAssembler<TypeTag>::CCImplicitAssembler;
 };
@@ -54,21 +60,23 @@ template<class TypeTag>
 class CCImplicitAssembler
 {
     using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
     using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
     using AssemblyMap = typename GET_PROP_TYPE(TypeTag, AssemblyMap);
     using LocalResidual = typename GET_PROP_TYPE(TypeTag, LocalResidual);
-    using GridFvGeometry = typename GET_PROP_TYPE(TypeTag, GridFvGeometry);
+    using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
     using GridVariables = typename GET_PROP_TYPE(TypeTag, GridVariables);
     using JacobianMatrix = typename GET_PROP_TYPE(TypeTag, JacobianMatrix);
     using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
-    using LocalAssembler = typename GET_PROP_TYPE(TypeTag, LocalAssembler);
+    // using LocalAssembler = typename GET_PROP_TYPE(TypeTag, LocalAssembler);
+     using LocalAssembler = CCImplicitLocalAssembler<TypeTag, DifferentiationMethods::numeric>;
 
 public:
     using ResidualType = SolutionVector;
 
     //! The constructor
     CCImplicitAssembler(std::shared_ptr<const Problem> problem,
-                        std::shared_ptr<const GridFvGeometry> gridFvGeometry,
+                        std::shared_ptr<const FVGridGeometry> gridFvGeometry,
                         std::shared_ptr<const SolutionVector> prevSol,
                         std::shared_ptr<const SolutionVector> curSol,
                         std::shared_ptr<GridVariables> gridVariables)
@@ -79,7 +87,7 @@ public:
     , gridVariables_(gridVariables)
     {
         // build assembly map
-        assemblyMap_.init(globalFvGeometry);
+        assemblyMap_.init(gridFvGeometry);
     }
 
     /*!
@@ -100,18 +108,18 @@ public:
 
             // if we get here, everything worked well
             succeeded = true;
-            if (gridView_().comm().size() > 1)
-                succeeded = gridView_().comm().min(succeeded);
+            if (gridView().comm().size() > 1)
+                succeeded = gridView().comm().min(succeeded);
         }
         // throw exception if a problem ocurred
         catch (NumericalProblem &e)
         {
-            std::cout << "rank " << problem_().gridView().comm().rank()
+            std::cout << "rank " << gridView().comm().rank()
                       << " caught an exception while assembling:" << e.what()
                       << "\n";
             succeeded = false;
-            if (gridView_().comm().size() > 1)
-                succeeded = gridView_().comm().min(succeeded);
+            if (gridView().comm().size() > 1)
+                succeeded = gridView().comm().min(succeeded);
         }
         if (!succeeded)
             DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
@@ -134,8 +142,8 @@ public:
 
             // if we get here, everything worked well
             succeeded = true;
-            if (gridView_().comm().size() > 1)
-                succeeded = gridView_().comm().min(succeeded);
+            if (gridView().comm().size() > 1)
+                succeeded = gridView().comm().min(succeeded);
         }
         // throw exception if a problem ocurred
         catch (NumericalProblem &e)
@@ -144,8 +152,8 @@ public:
                       << " caught an exception while assembling:" << e.what()
                       << "\n";
             succeeded = false;
-            if (gridView_().comm().size() > 1)
-                succeeded = gridView_().comm().min(succeeded);
+            if (gridView().comm().size() > 1)
+                succeeded = gridView().comm().min(succeeded);
         }
         if (!succeeded)
             DUNE_THROW(NumericalProblem, "A process did not succeed in linearizing the system");
@@ -229,7 +237,7 @@ public:
         // calculate the square norm of the residual
         Scalar result2 = residual.two_norm2();
         if (gridView().comm().size() > 1)
-            result2 = gridView_().comm().sum(result2);
+            result2 = gridView().comm().sum(result2);
 
         using std::sqrt;
         return sqrt(result2);
@@ -238,7 +246,7 @@ public:
     const Problem& problem() const
     { return *problem; }
 
-    const GridFvGeometry& gridFvGeometry() const
+    const FVGridGeometry& gridFvGeometry() const
     { return *gridFvGeometry_; }
 
     const GridView& gridView() const
@@ -302,7 +310,7 @@ private:
     std::shared_ptr<const Problem> problem_;
 
     // the finite volume geometry of the grid
-    std::shared_ptr<const GridFvGeometry> gridFvGeometry_;
+    std::shared_ptr<const FVGridGeometry> gridFvGeometry_;
 
     // previous and current solution to the problem
     std::shared_ptr<const SolutionVector> prevSol_;
diff --git a/dumux/implicit/cellcentered/assemblymap.hh b/dumux/implicit/cellcentered/assemblymap.hh
index 78ad0e17cf0c7acdb8f056fd4fc184baf5b35079..597e3fa0c308e68de0f7f9c267abfaf74101f60b 100644
--- a/dumux/implicit/cellcentered/assemblymap.hh
+++ b/dumux/implicit/cellcentered/assemblymap.hh
@@ -47,7 +47,7 @@ class CCSimpleAssemblyMap
 {
     using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
     using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables);
-
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
     using IndexType = typename GridView::IndexSet::IndexType;
 
     struct DataJ
diff --git a/dumux/implicit/cellcentered/localassembler.hh b/dumux/implicit/cellcentered/localassembler.hh
index a3461b54bed62a95c761848662a145ab1bc73bc7..04c856284cb613f0685fc0eb6b614c09e2e760fe 100644
--- a/dumux/implicit/cellcentered/localassembler.hh
+++ b/dumux/implicit/cellcentered/localassembler.hh
@@ -30,6 +30,11 @@
 
 namespace Dumux {
 
+enum DifferentiationMethods
+{
+    numeric
+};
+
 /*!
  * \ingroup ImplicitModel
  * \brief An assembler for the local contributions (per element) to the global
@@ -47,6 +52,10 @@ class CCImplicitLocalAssembler<TypeTag, DifferentiationMethods::numeric>
     using Implementation = typename GET_PROP_TYPE(TypeTag, LocalAssembler);
     using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes);
     using Element = typename GET_PROP_TYPE(TypeTag, GridView)::template Codim<0>::Entity;
+    using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
+    using ElementSolutionVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector);
+
+    enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
 
 public:
 
@@ -57,6 +66,7 @@ public:
     template<class Assembler>
     static void assemble(Assembler& assembler, SolutionVector& res, const Element& element)
     {
+        const auto globalI = assembler.fvGridGeometry().elementMapper().index(element);
         res[globalI] = Implementation::assemble_(assembler, element);
     }
 
@@ -76,7 +86,7 @@ public:
      *
      * \param priVar The value of the primary variable
      */
-    static Scalar numericEpsilon(const Scalar priVar) const
+    static Scalar numericEpsilon(const Scalar priVar)
     {
         // define the base epsilon as the geometric mean of 1 and the
         // resolution of the scalar type. E.g. for standard 64 bit
@@ -115,7 +125,7 @@ private:
         auto& A = assembler.matrix();
 
         // prepare the local views
-        auto fvGeometry = localView(globalFvGeometry());
+        auto fvGeometry = localView(assembler.fvGridGeometry());
         fvGeometry.bind(element);
 
         auto curElemVolVars = localView(gridVariables.curGlobalVolVars());
@@ -251,7 +261,7 @@ private:
                 neighborDeriv = origFlux;
             }
 
-            if (numericDifferenceMethod_ <= 0)
+            if (numericDifferenceMethod <= 0)
             {
                 // we are not using forward differences, i.e. we
                 // need to calculate f(x - \epsilon)
@@ -266,7 +276,8 @@ private:
 
                 // calculate the residual with the deflected primary variables and subtract it
                 if (!isGhost)
-                    partialDeriv -= localResidual.eval(element,
+                    partialDeriv -= localResidual.eval(problem,
+                                                       element,
                                                        fvGeometry,
                                                        prevElemVolVars,
                                                        curElemVolVars,
@@ -275,12 +286,13 @@ private:
 
                 // calculate the fluxes into element with the deflected primary variables
                 for (std::size_t k = 0; k < numNeighbors; ++k)
-                    for (auto scvfIdx : assemblyMap_[globalI][k].scvfsJ)
-                        neighborDeriv[k] -= this->localResidual().evalFlux_(neighborElements[k],
-                                                                            fvGeometry,
-                                                                            curElemVolVars,
-                                                                            fvGeometry.scvf(scvfIdx),
-                                                                            elemFluxVarsCache);
+                    for (auto scvfIdx : assemblyMap[globalI][k].scvfsJ)
+                        neighborDeriv[k] -= localResidual.evalFlux(problem,
+                                                                   neighborElements[k],
+                                                                   fvGeometry,
+                                                                   curElemVolVars,
+                                                                   fvGeometry.scvf(scvfIdx),
+                                                                   elemFluxVarsCache);
             }
             else
             {
@@ -312,7 +324,7 @@ private:
 
                 // off-diagonal entries
                 j = 0;
-                for (const auto& dataJ : assemblyMap_[globalI])
+                for (const auto& dataJ : assemblyMap[globalI])
                     A[dataJ.globalJ][globalI][eqIdx][pvIdx] += neighborDeriv[j++][pvIdx];
             }
         }
@@ -325,101 +337,103 @@ private:
         //                                                                                          //
         //////////////////////////////////////////////////////////////////////////////////////////////
 
-        const auto& additionalDofDepedencies = problem.getAdditionalDofDependencies(globalI);
-        if (!additionalDofDepedencies.empty() && !isGhost)
-        {
-            // compute the source in the undeflected state
-            auto source = localResidual.computeSource(element, fvGeometry, curElemVolVars, scv);
-            source *= -scv.volume()*curVolVarsI.extrusionFactor();
-
-            // deflect solution at given dofs and recalculate the source
-            for (auto globalJ : additionalDofDependencies)
-            {
-                const auto& scvJ = fvGeometry.scv(globalJ);
-                auto& curVolVarsJ = curElemVolVars[scv];
-                const auto& elementJ = gridFvGeometry.element(globalJ);
-
-                // save a copy of the original privars and volvars
-                // to restore original solution after deflection
-                const auto origPriVars = curSol[globalJ];
-                const auto origVolVarsJ = curVolVarsJ;
-
-                // derivatives with repect to the additional DOF we depend on
-                for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
-                {
-                    // derivatives of element dof with respect to itself
-                    NumEqVector partialDeriv(0.0);
-                    const auto eps = Implementation::numericEpsilon(curVolVarsJ.priVar(pvIdx));
-                    Scalar delta = 0;
-
-                    if (numericDifferenceMethod_ >= 0)
-                    {
-                        // we are not using backward differences, i.e. we need to
-                        // calculate f(x + \epsilon)
-
-                        // deflect primary variables
-                        curSol[globalJ][pvIdx] += eps;
-                        delta += eps;
-
-                        // update the volume variables and the flux var cache
-                        curVolVarsJ.update(gridVariables.elementSolution(elementJ, curSol), problem, elementJ, scvJ);
-
-                        // calculate the source with the deflected primary variables
-                        auto deflSource = localResidual.computeSource(element, fvGeometry, curElemVolVars, scv);
-                        deflSource *= -scv.volume()*curVolVarsI.extrusionFactor();
-                        partialDeriv = std::move(deflSource);
-                    }
-                    else
-                    {
-                        // we are using backward differences, i.e. we don't need
-                        // to calculate f(x + \epsilon) and we can recycle the
-                        // (already calculated) source f(x)
-                        partialDeriv = source;
-                    }
-
-                    if (numericDifferenceMethod_ <= 0)
-                    {
-                        // we are not using forward differences, i.e. we
-                        // need to calculate f(x - \epsilon)
-
-                        // deflect the primary variables
-                        curSol[globalJ][pvIdx] -= delta + eps;
-                        delta += eps;
-
-                        // update the volume variables and the flux var cache
-                        curVolVarsJ.update(gridVariables.elementSolution(elementJ, curSol), problem, elementJ, scvJ);
-
-                        // calculate the source with the deflected primary variables and subtract
-                        auto deflSource = localResidual.computeSource(element, fvGeometry, curElemVolVars, scv);
-                        deflSource *= -scv.volume()*curVolVarsI.extrusionFactor();
-                        partialDeriv -= std::move(deflSource);
-                    }
-                    else
-                    {
-                        // we are using forward differences, i.e. we don't need to
-                        // calculate f(x - \epsilon) and we can recycle the
-                        // (already calculated) source f(x)
-                        partialDeriv -= source;
-                    }
-
-                    // divide difference in residuals by the magnitude of the
-                    // deflections between the two function evaluation
-                    partialDeriv /= delta;
-
-                    // restore the original state of the dofs privars and the volume variables
-                    curSol[globalJ] = origPriVars;
-                    curVolVarsJ = origVolVarsJ;
-
-                    // add the current partial derivatives to the global jacobian matrix
-                    for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
-                        A[globalI][globalJ][eqIdx][pvIdx] += partialDeriv[eqIdx];
-                }
-            }
-        }
+        // const auto& additionalDofDepedencies = problem.getAdditionalDofDependencies(globalI);
+        // if (!additionalDofDepedencies.empty() && !isGhost)
+        // {
+        //     // compute the source in the undeflected state
+        //     auto source = localResidual.computeSource(element, fvGeometry, curElemVolVars, scv);
+        //     source *= -scv.volume()*curVolVarsI.extrusionFactor();
+
+        //     // deflect solution at given dofs and recalculate the source
+        //     for (auto globalJ : additionalDofDependencies)
+        //     {
+        //         const auto& scvJ = fvGeometry.scv(globalJ);
+        //         auto& curVolVarsJ = curElemVolVars[scv];
+        //         const auto& elementJ = gridFvGeometry.element(globalJ);
+
+        //         // save a copy of the original privars and volvars
+        //         // to restore original solution after deflection
+        //         const auto origPriVars = curSol[globalJ];
+        //         const auto origVolVarsJ = curVolVarsJ;
+
+        //         // derivatives with repect to the additional DOF we depend on
+        //         for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
+        //         {
+        //             // derivatives of element dof with respect to itself
+        //             NumEqVector partialDeriv(0.0);
+        //             const auto eps = Implementation::numericEpsilon(curVolVarsJ.priVar(pvIdx));
+        //             Scalar delta = 0;
+
+        //             if (numericDifferenceMethod >= 0)
+        //             {
+        //                 // we are not using backward differences, i.e. we need to
+        //                 // calculate f(x + \epsilon)
+
+        //                 // deflect primary variables
+        //                 curSol[globalJ][pvIdx] += eps;
+        //                 delta += eps;
+
+        //                 // update the volume variables and the flux var cache
+        //                 curVolVarsJ.update(gridVariables.elementSolution(elementJ, curSol), problem, elementJ, scvJ);
+
+        //                 // calculate the source with the deflected primary variables
+        //                 auto deflSource = localResidual.computeSource(element, fvGeometry, curElemVolVars, scv);
+        //                 deflSource *= -scv.volume()*curVolVarsI.extrusionFactor();
+        //                 partialDeriv = std::move(deflSource);
+        //             }
+        //             else
+        //             {
+        //                 // we are using backward differences, i.e. we don't need
+        //                 // to calculate f(x + \epsilon) and we can recycle the
+        //                 // (already calculated) source f(x)
+        //                 partialDeriv = source;
+        //             }
+
+        //             if (numericDifferenceMethod <= 0)
+        //             {
+        //                 // we are not using forward differences, i.e. we
+        //                 // need to calculate f(x - \epsilon)
+
+        //                 // deflect the primary variables
+        //                 curSol[globalJ][pvIdx] -= delta + eps;
+        //                 delta += eps;
+
+        //                 // update the volume variables and the flux var cache
+        //                 curVolVarsJ.update(gridVariables.elementSolution(elementJ, curSol), problem, elementJ, scvJ);
+
+        //                 // calculate the source with the deflected primary variables and subtract
+        //                 auto deflSource = localResidual.computeSource(element, fvGeometry, curElemVolVars, scv);
+        //                 deflSource *= -scv.volume()*curVolVarsI.extrusionFactor();
+        //                 partialDeriv -= std::move(deflSource);
+        //             }
+        //             else
+        //             {
+        //                 // we are using forward differences, i.e. we don't need to
+        //                 // calculate f(x - \epsilon) and we can recycle the
+        //                 // (already calculated) source f(x)
+        //                 partialDeriv -= source;
+        //             }
+
+        //             // divide difference in residuals by the magnitude of the
+        //             // deflections between the two function evaluation
+        //             partialDeriv /= delta;
+
+        //             // restore the original state of the dofs privars and the volume variables
+        //             curSol[globalJ] = origPriVars;
+        //             curVolVarsJ = origVolVarsJ;
+
+        //             // add the current partial derivatives to the global jacobian matrix
+        //             for (int eqIdx = 0; eqIdx < numEq; eqIdx++)
+        //                 A[globalI][globalJ][eqIdx][pvIdx] += partialDeriv[eqIdx];
+        //         }
+        //     }
+        // }
 
         // return the original residual
         return residual;
     }
 };
 
-}
\ No newline at end of file
+} // end namespace Dumux
+
+#endif
diff --git a/dumux/implicit/cellcentered/localresidual.hh b/dumux/implicit/cellcentered/localresidual.hh
index 56868fa1d154866060f7ed2e0bcd913663497927..b6d2abb8dcf42c076b6bfe3590113304790344d0 100644
--- a/dumux/implicit/cellcentered/localresidual.hh
+++ b/dumux/implicit/cellcentered/localresidual.hh
@@ -44,262 +44,62 @@ template<class TypeTag>
 class CCLocalResidual : public ImplicitLocalResidual<TypeTag>
 {
     using ParentType = ImplicitLocalResidual<TypeTag>;
-    friend class ImplicitLocalResidual<TypeTag>;
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-
-    enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) };
-
-    using Element = typename GridView::template Codim<0>::Entity;
-    using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
-    using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using Element = typename GET_PROP_TYPE(TypeTag, GridView)::template Codim<0>::Entity;
+    using ElementResidualVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector);
     using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes);
     using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
     using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache);
-    using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache);
     using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
-    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
     using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
 
 public:
-    // copying the local residual class is not a good idea
-    CCLocalResidual(const CCLocalResidual &) = delete;
-
-    CCLocalResidual() : ParentType() {}
-
-protected:
 
-    void evalFluxes_(const Element& element,
-                     const FVElementGeometry& fvGeometry,
-                     const ElementVolumeVariables& elemVolVars,
-                     const ElementBoundaryTypes& bcTypes,
-                     const ElementFluxVariablesCache& elemFluxVarsCache)
+    void evalFlux(ElementResidualVector& residual,
+                  const Problem& problem,
+                  const Element& element,
+                  const FVElementGeometry& fvGeometry,
+                  const ElementVolumeVariables& elemVolVars,
+                  const ElementBoundaryTypes& elemBcTypes,
+                  const ElementFluxVariablesCache& elemFluxVarsCache,
+                  const SubControlVolumeFace& scvf) const
     {
-        // calculate the mass flux over the scv faces
-        for (auto&& scvf : scvfs(fvGeometry))
-        {
-            this->residual_[0] += this->asImp_().computeFlux_(element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
-        }
-    }
+        const auto& scv = fvGeometry.scv(scvf.insideScvIdx());
+        const auto localScvIdx = scv.indexInElement();
 
-    PrimaryVariables computeFlux_(const Element &element,
-                                  const FVElementGeometry& fvGeometry,
-                                  const ElementVolumeVariables& elemVolVars,
-                                  const SubControlVolumeFace &scvf,
-                                  const ElementFluxVariablesCache& elemFluxVarsCache)
-    {
+        // inner faces
         if (!scvf.boundary())
-            return this->asImp_().computeFlux(element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
-        else
-            return PrimaryVariables(0.0);
-
-    }
-
-    void evalBoundary_(const Element &element,
-                       const FVElementGeometry& fvGeometry,
-                       const ElementVolumeVariables& elemVolVars,
-                       const ElementBoundaryTypes& elemBcTypes,
-                       const ElementFluxVariablesCache& elemFluxVarsCache)
-    {
-        for (auto&& scvf : scvfs(fvGeometry))
         {
-            if (scvf.boundary())
-            {
-                auto bcTypes = this->problem().boundaryTypes(element, scvf);
-                this->residual_[0] += evalBoundaryFluxes_(element, fvGeometry, elemVolVars, scvf, bcTypes, elemFluxVarsCache);
-            }
+            residual[localScvIdx] += this->asImp_().computeFlux(element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
         }
 
-        // additionally treat mixed D/N conditions in a strong sense
-        if (elemBcTypes.hasDirichlet())
+        // boundary faces
+        else
         {
-            for (auto&& scvf : scvfs(fvGeometry))
-            {
-                if (scvf.boundary())
-                    this->asImp_().evalDirichlet_(element, fvGeometry, elemVolVars, scvf);
-            }
-        }
-    }
-
-    /*!
-     * \brief Add all fluxes resulting from Neumann, outflow and pure Dirichlet
-     *        boundary conditions to the local residual.
-     */
-    PrimaryVariables evalBoundaryFluxes_(const Element &element,
-                                         const FVElementGeometry& fvGeometry,
-                                         const ElementVolumeVariables& elemVolVars,
-                                         const SubControlVolumeFace &scvf,
-                                         const BoundaryTypes& bcTypes,
-                                         const ElementFluxVariablesCache& elemFluxVarsCache)
-    {
-        // evaluate the Neumann conditions at the boundary face
-        PrimaryVariables flux(0);
-        if (bcTypes.hasNeumann())
-            flux += this->asImp_().evalNeumannSegment_(element, fvGeometry, elemVolVars, scvf, bcTypes);
-
-        // TODO: evaluate the outflow conditions at the boundary face
-        //if (bcTypes.hasOutflow())
-        //    flux += this->asImp_().evalOutflowSegment_(&intersection, bcTypes);
-
-        // evaluate the pure Dirichlet conditions at the boundary face
-        if (bcTypes.hasDirichlet() && !bcTypes.hasNeumann())
-            flux += this->asImp_().evalDirichletSegment_(element, fvGeometry, elemVolVars, scvf, bcTypes, elemFluxVarsCache);
-
-        return flux;
-    }
-
-
-    /*!
-     * \brief Evaluate Dirichlet conditions on faces that have mixed
-     *        Dirichlet/Neumann boundary conditions.
-     */
-    void evalDirichlet_(const Element &element,
-                        const FVElementGeometry& fvGeometry,
-                        const ElementVolumeVariables& elemVolVars,
-                        const SubControlVolumeFace &scvf)
-    {
-        BoundaryTypes bcTypes = this->problem().boundaryTypes(element, scvf);
-
-        if (bcTypes.hasDirichlet() && bcTypes.hasNeumann())
-            this->asImp_().evalDirichletSegmentMixed_(element, fvGeometry, elemVolVars, scvf, bcTypes);
-    }
+            const auto& bcTypes = elemBcTypes[localScvIdx];
 
-    /*!
-     * \brief Add Neumann boundary conditions for a single scv face
-     */
-    PrimaryVariables evalNeumannSegment_(const Element& element,
-                                         const FVElementGeometry& fvGeometry,
-                                         const ElementVolumeVariables& elemVolVars,
-                                         const SubControlVolumeFace &scvf,
-                                         const BoundaryTypes &bcTypes)
-    {
-        // temporary vector to store the neumann boundary fluxes
-        PrimaryVariables flux(0);
-
-        auto neumannFluxes = this->problem().neumann(element, fvGeometry, elemVolVars, scvf);
-
-        // multiply neumann fluxes with the area and the extrusion factor
-        auto&& scv = fvGeometry.scv(scvf.insideScvIdx());
-        neumannFluxes *= scvf.area()*elemVolVars[scv].extrusionFactor();
-
-        // add fluxes to the residual
-        for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
-            if (bcTypes.isNeumann(eqIdx))
-                flux[eqIdx] += neumannFluxes[eqIdx];
-
-        return flux;
-    }
-
-    /*!
-     * \brief Treat Dirichlet boundary conditions in a weak sense for a single
-     *        intersection that only has Dirichlet boundary conditions
-     */
-    PrimaryVariables evalDirichletSegment_(const Element& element,
-                                           const FVElementGeometry& fvGeometry,
-                                           const ElementVolumeVariables& elemVolVars,
-                                           const SubControlVolumeFace &scvf,
-                                           const BoundaryTypes &bcTypes,
-                                           const ElementFluxVariablesCache& elemFluxVarsCache)
-    {
-        // temporary vector to store the Dirichlet boundary fluxes
-        PrimaryVariables flux(0);
+            // Dirichlet boundaries
+            if (bcTypes.hasDirichlet() && !bcTypes.hasNeumann())
+                residual[localScvIdx] += this->asImp_().computeFlux(element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
 
-        auto dirichletFlux = this->asImp_().computeFlux(element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
-
-        // add fluxes to the residual
-        for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
-            if (bcTypes.isDirichlet(eqIdx))
-                flux[eqIdx] += dirichletFlux[eqIdx];
-
-        return flux;
-    }
-
-    /*!
-     * \brief Treat Dirichlet boundary conditions in a strong sense for a
-     *        single intersection that has mixed D/N boundary conditions
-     */
-    void evalDirichletSegmentMixed_(const Element& element,
-                                    const FVElementGeometry& fvGeometry,
-                                    const ElementVolumeVariables& elemVolVars,
-                                    const SubControlVolumeFace &scvf,
-                                    const BoundaryTypes &bcTypes)
-    {
-        // temporary vector to store the Dirichlet values
-        PrimaryVariables dirichletValues = this->problem().dirichlet(element, scvf);
-
-        // get the primary variables
-        const auto& priVars = elemVolVars[scvf.insideScvIdx()].priVars();
-
-        // set Dirichlet conditions in a strong sense
-        for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
-        {
-            if (bcTypes.isDirichlet(eqIdx))
+            // Neumann and Robin ("solution dependent Neumann") boundary conditions
+            else if (bcTypes.hasNeumann() && !bcTypes.hasDirichlet())
             {
-                auto pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
-                this->residual_[0][eqIdx] = priVars[pvIdx] - dirichletValues[pvIdx];
-            }
-        }
-    }
-
-    /*!
-     * \brief Add outflow boundary conditions for a single intersection
-     */
-    /*template <class IntersectionIterator>
-    void evalOutflowSegment_(const IntersectionIterator &isIt,
-                             const BoundaryTypes &bcTypes)
-    {
-        if (this->element_().geometry().type().isCube() == false)
-            DUNE_THROW(Dune::InvalidStateException,
-                       "for cell-centered models, outflow BCs only work for cubes.");
-
-        // store pointer to the current FVElementGeometry
-        const FVElementGeometry *oldFVGeometryPtr = this->fvElemGeomPtr_;
-
-        // copy the current FVElementGeometry to a local variable
-        // and set the pointer to this local variable
-        FVElementGeometry fvGeometry = this->fvGeometry_();
-        this->fvElemGeomPtr_ = &fvGeometry;
-
-        // get the index of the boundary face
-        unsigned bfIdx = isIt->indexInInside();
-        unsigned oppositeIdx = bfIdx^1;
+                auto neumannFluxes = this->problem().neumann(element, fvGeometry, elemVolVars, scvf);
 
-        // manipulate the corresponding subcontrolvolume face
-        SCVFace& boundaryFace = fvGeometry.boundaryFace[bfIdx];
+                // multiply neumann fluxes with the area and the extrusion factor
+                neumannFluxes *= scvf.area()*elemVolVars[scv].extrusionFactor();
 
-        // set the second flux approximation index for the boundary face
-        for (int nIdx = 0; nIdx < fvGeometry.numNeighbors-1; nIdx++)
-        {
-            // check whether the two faces are opposite of each other
-            if (fvGeometry.subContVolFace[nIdx].fIdx == oppositeIdx)
-            {
-                boundaryFace.j = nIdx+1;
-                break;
+                residual[localScvIdx] += neumannFluxes;
             }
-        }
-        boundaryFace.fapIndices[1] = boundaryFace.j;
-        boundaryFace.grad[0] *= -0.5;
-        boundaryFace.grad[1] *= -0.5;
-
-        // temporary vector to store the outflow boundary fluxes
-        PrimaryVariables values;
-        Valgrind::SetUndefined(values);
 
-        this->asImp_().computeFlux(values, bfIdx, true);
-        values *= this->curVolVars_(0).extrusionFactor();
-
-        // add fluxes to the residual
-        Valgrind::CheckDefined(values);
-        for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
-        {
-            if (bcTypes.isOutflow(eqIdx))
-                this->residual_[0][eqIdx] += values[eqIdx];
+            else
+                DUNE_THROW(Dune::NotImplemented, "Mixed boundary conditions. Use pure boundary conditions by converting Dirichlet BCs to Robin BCs");
         }
 
-        // restore the pointer to the FVElementGeometry
-        this->fvElemGeomPtr_ = oldFVGeometryPtr;
-    }*/
+    }
 };
 
-}
+} // end namespace Dumux
 
-#endif   // DUMUX_CC_LOCAL_RESIDUAL_HH
+#endif
diff --git a/dumux/implicit/cellcentered/propertydefaults.hh b/dumux/implicit/cellcentered/propertydefaults.hh
index 99fbb8925c9fadc81dfe84ac82ad9ae3929d5e99..dbc4672ce365ceac52f4b3ad5fd5d24868bee5ed 100644
--- a/dumux/implicit/cellcentered/propertydefaults.hh
+++ b/dumux/implicit/cellcentered/propertydefaults.hh
@@ -57,7 +57,7 @@ SET_TYPE_PROP(CCModel, DofMapper, typename GET_PROP_TYPE(TypeTag, ElementMapper)
 SET_TYPE_PROP(CCModel, LocalJacobian, CCLocalJacobian<TypeTag>);
 
 //! Assembler for the global jacobian matrix
-SET_TYPE_PROP(CCModel, JacobianAssembler, CCAssembler<TypeTag>);
+// SET_TYPE_PROP(CCModel, JacobianAssembler, CCAssembler<TypeTag>);
 
 //! The sub control volume
 SET_PROP(CCModel, SubControlVolume)
diff --git a/dumux/implicit/localresidual.hh b/dumux/implicit/localresidual.hh
index c86f3aff1580fed9ae31ed060c3647366f0f82d4..88a7add46147a75f3ce07514b2c52650f15b4865 100644
--- a/dumux/implicit/localresidual.hh
+++ b/dumux/implicit/localresidual.hh
@@ -42,18 +42,15 @@ namespace Dumux
 template<class TypeTag>
 class ImplicitLocalResidual
 {
-    friend typename GET_PROP_TYPE(TypeTag, LocalJacobian);
     using Implementation = typename GET_PROP_TYPE(TypeTag, LocalResidual);
     using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
-    using Model = typename GET_PROP_TYPE(TypeTag, Model);
     using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-    using Element = typename GridView::template Codim<0>::Entity;
+    using Element = typename GET_PROP_TYPE(TypeTag, GridView)::template Codim<0>::Entity;
     using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
     using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
     using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
-    using ElementSolutionVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector);
-    using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
+    using ElementResidualVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector);
+    using ResidualVector = typename GET_PROP_TYPE(TypeTag, NumEqVector);
     using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
     using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes);
     using FluxVariablesCache = typename GET_PROP_TYPE(TypeTag, FluxVariablesCache);
@@ -62,29 +59,11 @@ class ImplicitLocalResidual
     using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
 
 public:
-    // copying the local residual class is not a good idea
-    ImplicitLocalResidual(const ImplicitLocalResidual &) = delete;
-
-    // the default constructor
-    ImplicitLocalResidual() = default;
-
-    /*!
-     * \brief Initialize the local residual.
-     *
-     * This assumes that all objects of the simulation have been fully
-     * allocated but not necessarily initialized completely.
-     *
-     * \param problem The representation of the physical problem to be
-     *             solved.
-     */
-    void init(Problem &problem)
-    { problemPtr_ = &problem; }
-
 
     /*!
      * \name User interface
      * \note The following methods are usually expensive to evaluate
-     *       They are useful for outputting residual information.
+     *       They are useful for outputting / postprocessing residual information.
      */
     // \{
 
@@ -95,26 +74,26 @@ public:
      * \param element The DUNE Codim<0> entity for which the residual
      *                ought to be calculated
      */
-    void eval(const Element &element)
-    {
-        // make sure FVElementGeometry and volume variables are bound to the element
-        auto fvGeometry = localView(problem().model().fvGridGeometry());
-        fvGeometry.bind(element);
+    // ElementResidualVector eval(const Problem& problem, const Element &element)
+    // {
+    //     // make sure FVElementGeometry and volume variables are bound to the element
+    //     auto fvGeometry = localView(problem.model().globalFvGeometry());
+    //     fvGeometry.bind(element);
 
-        auto curElemVolVars = localView(problem().model().curGlobalVolVars());
-        curElemVolVars.bind(element, fvGeometry, problem().model().curSol());
+    //     auto curElemVolVars = localView(problem.model().curGlobalVolVars());
+    //     curElemVolVars.bind(element, fvGeometry, problem.model().curSol());
 
-        auto prevElemVolVars = localView(problem().model().prevGlobalVolVars());
-        prevElemVolVars.bindElement(element, fvGeometry, problem().model().prevSol());
+    //     auto prevElemVolVars = localView(problem.model().prevGlobalVolVars());
+    //     prevElemVolVars.bindElement(element, fvGeometry, problem.model().prevSol());
 
-        auto elemFluxVarsCache = localView(problem().model().globalFluxVarsCache());
-        elemFluxVarsCache.bindElement(element, fvGeometry, curElemVolVars);
+    //     auto elemFluxVarsCache = localView(problem.model().globalFluxVarsCache());
+    //     elemFluxVarsCache.bindElement(element, fvGeometry, curElemVolVars);
 
-        ElementBoundaryTypes bcTypes;
-        bcTypes.update(problem(), element, fvGeometry);
+    //     ElementBoundaryTypes bcTypes;
+    //     bcTypes.update(problem, element, fvGeometry);
 
-        asImp_().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, bcTypes, elemFluxVarsCache);
-    }
+    //     return asImp_().eval(element, fvGeometry, prevElemVolVars, curElemVolVars, bcTypes, elemFluxVarsCache);
+    // }
 
     /*!
      * \brief Compute the storage term for the current solution.
@@ -125,52 +104,33 @@ public:
      * \param element The DUNE Codim<0> entity for which the storage
      *                term ought to be calculated
      */
-    void evalStorage(const Element &element)
-    {
-        // make sure FVElementGeometry and volume variables are bound to the element
-        auto fvGeometry = localView(problem().model().fvGridGeometry());
-        fvGeometry.bindElement(element);
-
-        auto curElemVolVars = localView(problem().model().curGlobalVolVars());
-        curElemVolVars.bindElement(element, fvGeometry, problem().model().curSol());
-
-        auto prevElemVolVars = localView(problem().model().prevGlobalVolVars());
-        prevElemVolVars.bindElement(element, fvGeometry, problem().model().prevSol());
-
-        asImp_().evalStorage_(fvGeometry, prevElemVolVars, curElemVolVars);
-    }
-
-    // !
-    //  * \brief Compute the flux term for the current solution.
-    //  *
-    //  * \param element The DUNE Codim<0> entity for which the residual
-    //  *                ought to be calculated
-    //  * \param curVolVars The volume averaged variables for all
-    //  *                   sub-contol volumes of the element
-
-    // void evalFluxes(const Element &element)
+    // ElementResidualVector evalStorage(const Problem& problem, const Element &element)
     // {
-    //     elemPtr_ = &element;
-
     //     // make sure FVElementGeometry and volume variables are bound to the element
-    //     problem().model().fvGeometries_().bind(element);
-    //     problem().model().curVolVars_().bind(element);
-    //     problem().model().prevVolVars_().bindElement(element);
-    //     problem().model().fluxVariablesCache_().bindElement(element);
+    //     auto fvGeometry = localView(problem.model().globalFvGeometry());
+    //     fvGeometry.bindElement(element);
 
-    //     ElementBoundaryTypes bcTypes;
-    //     bcTypes.update(problem(), element, fvGeometry_());
+    //     auto curElemVolVars = localView(problem.model().curGlobalVolVars());
+    //     curElemVolVars.bindElement(element, fvGeometry, problem.model().curSol());
 
-    //     residual_.resize(fvGeometry_().numScv);
-    //     residual_ = 0;
+    //     ElementResidualVector storage(fvGeometry.numScv());
+    //     storage.resize(fvGeometry.numScv(), 0.0);
+
+    //     // calculate the amount of conservation each quantity inside
+    //     // all sub control volumes
+    //     for (auto&& scv : scvs(fvGeometry))
+    //     {
+    //         auto localScvIdx = scv.indexInElement();
+    //         const auto& volVars = elemVolVars[scv];
+    //         storage[localScvIdx] = asImp_().computeStorage(scv, volVars);
+    //         storage[localScvIdx] *= scv.volume() * volVars.extrusionFactor();
+    //     }
 
-    //     bcTypesPtr_ = &bcTypes;
-    //     asImp_().evalFluxes_();
+    //     return storage;
     // }
 
     // \}
 
-
     /*!
      * \name Main interface
      * \note Methods used by the assembler to compute derivatives and residual
@@ -180,7 +140,8 @@ public:
     /*!
      * \brief Compute the local residual, i.e. the deviation of the
      *        equations from zero.
-     *
+     * \param problem The problem to solve
+
      * \param element The DUNE Codim<0> entity for which the residual
      *                ought to be calculated
      * \param fvGeometry The finite-volume geometry of the element
@@ -193,230 +154,183 @@ public:
      * \param bcTypes The types of the boundary conditions for all
      *                vertices of the element
      */
-    void eval(const Element &element,
-              const FVElementGeometry& fvGeometry,
-              const ElementVolumeVariables& prevElemVolVars,
-              const ElementVolumeVariables& curElemVolVars,
-              const ElementBoundaryTypes &bcTypes,
-              const ElementFluxVariablesCache& elemFluxVarsCache)
+    ElementResidualVector eval(const Problem& problem,
+                               const Element& element,
+                               const FVElementGeometry& fvGeometry,
+                               const ElementVolumeVariables& prevElemVolVars,
+                               const ElementVolumeVariables& curElemVolVars,
+                               const ElementBoundaryTypes &bcTypes,
+                               const ElementFluxVariablesCache& elemFluxVarsCache) const
     {
-        // resize the vectors for all terms
-        auto numScv = fvGeometry.numScv();
-        residual_.resize(numScv);
-        storageTerm_.resize(numScv);
+        // initialize the residual vector for all scvs in this element
+        ElementResidualVector residual(fvGeometry.numScv(), 0.0);
 
-        residual_ = 0.0;
-        storageTerm_ = 0.0;
+        // evaluate the volume terms (storage + source terms)
+        for (auto&& scv : scvs(fvGeometry))
+        {
+            //! foward to the local residual specialized for the discretization methods
+            asImp_().evalStorage(residual, problem, element, fvGeometry, curElemVolVars, prevElemVolVars, scv);
+            asImp_().evalSource(residual, problem, element, fvGeometry, curElemVolVars, scv);
+        }
+
+        for (auto&& scvf : scvfs(fvGeometry))
+        {
+            //! foward to the local residual specialized for the discretization methods
+            asImp_().evalFlux(residual, problem, element, fvGeometry, curElemVolVars, bcTypes, elemFluxVarsCache, scvf);
+            asImp_().evalBoundary(residual, problem, element, fvGeometry, curElemVolVars, bcTypes, elemFluxVarsCache, scvf);
+        }
 
-        asImp_().evalVolumeTerms_(element, fvGeometry, prevElemVolVars, curElemVolVars, bcTypes);
-        asImp_().evalFluxes_(element, fvGeometry, curElemVolVars, bcTypes, elemFluxVarsCache);
-        asImp_().evalBoundary_(element, fvGeometry, curElemVolVars, bcTypes, elemFluxVarsCache);
+        return residual;
     }
 
+    // \}
+
+
+    /*!
+     * \name Model specific interface
+     * \note The following method are the model specific implementations of the actual residual
+     */
+    // \{
+
     /*!
      * \brief Calculate the source term of the equation
      *
      * \param scv The sub-control volume over which we integrate the source term
+     * \note has to be implemented by the model specific residual class
      *
      */
-    PrimaryVariables computeSource(const Element& element,
-                                   const FVElementGeometry& fvGeometry,
-                                   const ElementVolumeVariables& elemVolVars,
-                                   const SubControlVolume &scv)
+    ResidualVector computeStorage(const Problem& problem,
+                                  const SubControlVolume& scv,
+                                  const VolumeVariables& volVars) const
     {
-        PrimaryVariables source(0);
-
-        // add contributions from volume flux sources
-        source += this->problem().source(element, fvGeometry, elemVolVars, scv);
-
-        // add contribution from possible point sources
-        source += this->problem().scvPointSources(element, fvGeometry, elemVolVars, scv);
-
-        return source;
+        DUNE_THROW(Dune::NotImplemented, "This model does not implement a storage method!");
     }
 
     /*!
-     * \brief Returns the local residual for all sub-control
-     *        volumes of the element.
-     */
-    const ElementSolutionVector &residual() const
-    { return residual_; }
-
-    /*!
-     * \brief Returns the local residual for a given sub-control
-     *        volume of the element.
+     * \brief Calculate the source term of the equation
+     *
+     * \param scv The sub-control volume over which we integrate the source term
+     * \note This is the default implementation for all models as sources are computed
+     *       in the user interface of the problem
      *
-     * \param localScvIdx The local index of the sub-control volume
      */
-    const PrimaryVariables &residual(const int localScvIdx) const
-    { return residual_[localScvIdx]; }
+    ResidualVector computeSource(const Problem& problem,
+                                 const Element& element,
+                                 const FVElementGeometry& fvGeometry,
+                                 const ElementVolumeVariables& elemVolVars,
+                                 const SubControlVolume &scv) const
+    {
+        ResidualVector source(0.0);
 
-    /*!
-     * \brief Returns the storage term for all sub-control volumes of the
-     *        element.
-     */
-    const ElementSolutionVector &storageTerm() const
-    { return storageTerm_; }
+        // add contributions from volume flux sources
+        source += problem.source(element, fvGeometry, elemVolVars, scv);
 
-    /*!
-     * \brief Returns the storage term for a given sub-control volumes
-     *        of the element.
-     */
-    const PrimaryVariables &storageTerm(const int localScvIdx) const
-    { return storageTerm_[localScvIdx]; }
+        // add contribution from possible point sources
+        source += problem.scvPointSources(element, fvGeometry, elemVolVars, scv);
 
-    /*!
-     * \brief Return the problem we are solving. Only call this after init()!
-     */
-    const Problem& problem() const
-    { return *problemPtr_; }
+        return source;
+    }
 
     /*!
-     * \brief Return the problem we are solving. Only call this after init()!
+     * \brief Calculate the source term of the equation
+     *
+     * \param scv The sub-control volume over which we integrate the source term
+     * \note has to be implemented by the model specific residual class
+     *
      */
-    Problem& problem()
-    { return *problemPtr_; }
-
-    // \}
-
-protected:
-    Implementation &asImp_()
-    { return *static_cast<Implementation*>(this); }
-
-    const Implementation &asImp_() const
-    { return *static_cast<const Implementation*>(this); }
-
-    PrimaryVariables evalFlux_(const Element &element,
+    ResidualVector computeFlux(const Problem& problem,
+                               const Element& element,
                                const FVElementGeometry& fvGeometry,
                                const ElementVolumeVariables& elemVolVars,
                                const SubControlVolumeFace& scvf,
-                               const ElementFluxVariablesCache& elemFluxVarsCache)
-    {
-        return asImp_().computeFlux_(element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
-    }
-
-    /*!
-     * \brief Set the local residual to the storage terms of all
-     *        sub-control volumes of the current element.
-     */
-    void evalStorage_(const FVElementGeometry& fvGeometry,
-                      const ElementVolumeVariables& prevElemVolVars,
-                      const ElementVolumeVariables& curElemVolVars)
+                               const ElementFluxVariablesCache& elemFluxVarsCache) const
     {
-        storageTerm_.resize(fvGeometry.numScv());
-        storageTerm_ = 0;
-
-        // calculate the amount of conservation each quantity inside
-        // all sub control volumes
-        for (auto&& scv : scvs(fvGeometry))
-        {
-            auto localScvIdx = scv.indexInElement();
-            const auto& volVars = curElemVolVars[scv];
-            storageTerm_[localScvIdx] = asImp_().computeStorage(scv, volVars);
-            storageTerm_[localScvIdx] *= scv.volume() * volVars.extrusionFactor();
-        }
+        DUNE_THROW(Dune::NotImplemented, "This model does not implement a flux method!");
     }
 
-    // PrimaryVariables evalSource_(const Element& element,
-    //                              const FVElementGeometry& fvGeometry)
-    // {
-    //     PrimaryVariables source(0);
-    //     const auto& fvGeometry = fvGeometry.fvElementGeometry();
-    //     for (auto&& scv : scvs(fvGeometry))
-    //     {
-    //         source += this->problem().source(element, scv);
-
-    //         // add contribution from possible point sources
-    //         source += this->problem().scvPointSources(element, scv);
-    //     }
-
-    //     return source;
-    // }
+    // \}
 
     /*!
-     * \brief Add the change the source term for stationary problems
-     *        to the local residual of all sub-control volumes of the
-     *        current element.
+     * \name Discretization specific interface
+     * \note The following method are the discretization specific wrapper methods
      */
-    template<class P = Problem>
-    typename std::enable_if<Dumux::Capabilities::isStationary<P>::value, void>::type
-    evalVolumeTerms_(const Element &element,
-                     const FVElementGeometry& fvGeometry,
-                     const ElementVolumeVariables& prevElemVolVars,
-                     const ElementVolumeVariables& curElemVolVars,
-                     const ElementBoundaryTypes &bcTypes)
-    {
-        // evaluate the volume terms (storage + source terms)
-        for (auto&& scv : scvs(fvGeometry))
-        {
-            auto localScvIdx = scv.indexInElement();
-            auto curExtrusionFactor = curElemVolVars[scv].extrusionFactor();
-
-            // subtract the source term from the local rate
-            PrimaryVariables source = asImp_().computeSource(element, fvGeometry, curElemVolVars, scv);
-            source *= scv.volume()*curExtrusionFactor;
-
-            residual_[localScvIdx] -= source;
-        }
-    }
+    // \{
 
-    /*!
-     * \brief Add the change in the storage terms and the source term
-     *        to the local residual of all sub-control volumes of the
-     *        current element.
-     */
-    template<class P = Problem>
-    typename std::enable_if<!Dumux::Capabilities::isStationary<P>::value, void>::type
-    evalVolumeTerms_(const Element &element,
+    void evalStorage(ElementResidualVector& residual,
+                     const Problem& problem,
+                     const Element& element,
                      const FVElementGeometry& fvGeometry,
-                     const ElementVolumeVariables& prevElemVolVars,
                      const ElementVolumeVariables& curElemVolVars,
-                     const ElementBoundaryTypes &bcTypes)
+                     const ElementVolumeVariables& prevElemVolVars,
+                     const SubControlVolume& scv) const
     {
-        // evaluate the volume terms (storage + source terms)
-        for (auto&& scv : scvs(fvGeometry))
-        {
-            auto localScvIdx = scv.indexInElement();
+        const auto& curVolVars = curElemVolVars[scv];
+        const auto& prevVolVars = prevElemVolVars[scv];
 
-            const auto& curVolVars = curElemVolVars[scv];
-            const auto& prevVolVars = prevElemVolVars[scv];
+        // mass balance within the element. this is the
+        // \f$\frac{m}{\partial t}\f$ term if using implicit
+        // euler as time discretization.
+        //
+        // We might need a more explicit way for
+        // doing the time discretization...
 
-            // mass balance within the element. this is the
-            // \f$\frac{m}{\partial t}\f$ term if using implicit
-            // euler as time discretization.
-            //
-            // We might need a more explicit way for
-            // doing the time discretization...
-            PrimaryVariables prevStorage = asImp_().computeStorage(scv, prevVolVars);
-            PrimaryVariables curStorage = asImp_().computeStorage(scv, curVolVars);
+        //! Compute storage with the model specific storage residual
+        ResidualVector prevStorage = asImp_().computeStorage(problem, scv, prevVolVars);
+        ResidualVector storage = asImp_().computeStorage(problem, scv, curVolVars);
 
-            prevStorage *= prevVolVars.extrusionFactor();
-            curStorage *= curVolVars.extrusionFactor();
+        prevStorage *= prevVolVars.extrusionFactor();
+        storage *= curVolVars.extrusionFactor();
 
-            storageTerm_[localScvIdx] = std::move(curStorage);
-            storageTerm_[localScvIdx] -= std::move(prevStorage);
-            storageTerm_[localScvIdx] *= scv.volume();
-            storageTerm_[localScvIdx] /= problem().timeManager().timeStepSize();
+        storage -= prevStorage;
+        storage *= scv.volume();
+        storage /= problem.timeManager().timeStepSize();
 
-            // add the storage term to the residual
-            residual_[localScvIdx] += storageTerm_[localScvIdx];
+        residual[scv.indexInElement()] += storage;
+    }
 
-            // subtract the source term from the local rate
-            PrimaryVariables source = asImp_().computeSource(element, fvGeometry, curElemVolVars, scv);
-            source *= scv.volume()*curVolVars.extrusionFactor();
+    void evalSource(ElementResidualVector& residual,
+                    const Problem& problem,
+                    const Element& element,
+                    const FVElementGeometry& fvGeometry,
+                    const ElementVolumeVariables& curElemVolVars,
+                    const SubControlVolume& scv) const
+    {
+        //! Compute source with the model specific storage residual
+        const auto& curVolVars = curElemVolVars[scv];
+        ResidualVector source = asImp_().computeSource(problem, element, fvGeometry, curElemVolVars, scv);
+        source *= scv.volume()*curVolVars.extrusionFactor();
 
-            residual_[localScvIdx] -= source;
-        }
+        //! subtract source from local rate (sign convention in user interface)
+        residual[scv.indexInElement()] -= source;
     }
 
-protected:
-    ElementSolutionVector storageTerm_;
-    ElementSolutionVector residual_;
+    void evalFlux(ElementResidualVector& residual,
+                  const Problem& problem,
+                  const Element& element,
+                  const FVElementGeometry& fvGeometry,
+                  const ElementVolumeVariables& elemVolVars,
+                  const ElementBoundaryTypes& elemBcTypes,
+                  const ElementFluxVariablesCache& elemFluxVarsCache,
+                  const SubControlVolumeFace& scvf) const {}
+
+    void evalBoundary(ElementResidualVector& residual,
+                      const Problem& problem,
+                      const Element& element,
+                      const FVElementGeometry& fvGeometry,
+                      const ElementVolumeVariables& elemVolVars,
+                      const ElementBoundaryTypes& elemBcTypes,
+                      const ElementFluxVariablesCache& elemFluxVarsCache,
+                      const SubControlVolumeFace& scvf) const {}
 
-private:
-    Problem* problemPtr_;
+    // \}
+
+    Implementation &asImp_()
+    { return *static_cast<Implementation*>(this); }
+
+    const Implementation &asImp_() const
+    { return *static_cast<const Implementation*>(this); }
 };
 
-}
+} // end namespace Dumux
 
 #endif
diff --git a/dumux/implicit/properties.hh b/dumux/implicit/properties.hh
index 87b8cf07e1840ac4cbd7780a53651f180417eeb1..e7f872434023c84eedb94d99abb326bfd7a7c430 100644
--- a/dumux/implicit/properties.hh
+++ b/dumux/implicit/properties.hh
@@ -65,6 +65,7 @@ NEW_PROP_TAG(FVGridGeometry); //!< The type of the global finite volume geometry
 NEW_PROP_TAG(EnableFVGridGeometryCache); //! specifies if geometric data is be saved (faster, but more memory consuming)
 
 NEW_PROP_TAG(JacobianAssembler); //!< Assembles the global jacobian matrix
+NEW_PROP_TAG(LocalAssembler); //!< Assembles the global jacobian matrix
 NEW_PROP_TAG(JacobianMatrix); //!< Type of the global jacobian matrix
 NEW_PROP_TAG(BoundaryTypes); //!< Stores the boundary types of a single degree of freedom
 NEW_PROP_TAG(ElementBoundaryTypes); //!< Stores the boundary types on an element
@@ -73,6 +74,9 @@ NEW_PROP_TAG(PrimaryVariables); //!< A vector of primary variables within a sub-
 NEW_PROP_TAG(SolutionVector); //!< Vector containing all primary variable vector of the grid
 NEW_PROP_TAG(ElementSolutionVector); //!< A vector of primary variables within a sub-control volume
 
+// TODO GridVariables
+NEW_PROP_TAG(GridVariables); //!< Doc me
+
 NEW_PROP_TAG(EnableGlobalVolumeVariablesCache); //!< If disabled, the volume variables are not stored (reduces memory, but is slower)
 NEW_PROP_TAG(VolumeVariables);  //!< The secondary variables within a sub-control volume
 NEW_PROP_TAG(ElementVolumeVariables);  //!< The type for a local (element/stencil) container for the volume variables
diff --git a/dumux/nonlinear/newtoncontroller.hh b/dumux/nonlinear/newtoncontroller.hh
index a611e62a4d321898fcef76fc432322deed9c136e..a617f44e76fd5688204386c96d523c9705c228b8 100644
--- a/dumux/nonlinear/newtoncontroller.hh
+++ b/dumux/nonlinear/newtoncontroller.hh
@@ -167,7 +167,9 @@ public:
     /*!
      * \brief Constructor without convergence writer
      */
-    NewtonController(const Communicator& comm) : comm_(comm), endIterMsgStream_(std::ostringstream::out)
+    NewtonController(const Communicator& comm)
+    : comm_(comm)
+    , endIterMsgStream_(std::ostringstream::out)
     {
         enablePartialReassemble_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnablePartialReassemble);
         enableJacobianRecycling_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableJacobianRecycling);
@@ -196,12 +198,8 @@ public:
         numSteps_ = 0;
     }
 
-    /*!
-     * \brief Constructor with a given convergence writer
-     */
-    NewtonController(const Communicator& comm, ConvergenceWriter&& writer)
-    : NewtonController(comm), convergenceWriter_(std::move(writer))
-    {}
+    Communicator& communicator() const
+    { return comm_; }
 
     /*!
      * \brief Set the maximum acceptable difference of any primary variable
@@ -372,8 +370,8 @@ public:
             shift_ = max(shift_, shiftAtDof);
         }
 
-        if (comm().size() > 1)
-            shift_ = comm().max(shift_);
+        if (communicator().size() > 1)
+            shift_ = communicator().max(shift_);
     }
 
     /*!
@@ -406,8 +404,8 @@ public:
             if (numSteps_ == 0)
             {
                 Scalar norm2 = b.two_norm2();
-                if (comm().size() > 1)
-                    norm2 = comm().sum(norm2);
+                if (communicator().size() > 1)
+                    norm2 = communicator().sum(norm2);
 
                 using std::sqrt;
                 initialResidual_ = sqrt(norm2);
@@ -432,8 +430,8 @@ public:
 
             // make sure all processes converged
             int convergedRemote = converged;
-            if (comm().size() > 1)
-                convergedRemote = comm().min(converged);
+            if (communicator().size() > 1)
+                convergedRemote = communicator().min(converged);
 
             if (!converged) {
                 DUNE_THROW(NumericalProblem,
@@ -447,8 +445,8 @@ public:
         catch (Dune::MatrixBlockError e) {
             // make sure all processes converged
             int converged = 0;
-            if (comm().size() > 1)
-                converged = comm().min(converged);
+            if (communicator().size() > 1)
+                converged = communicator().min(converged);
 
             NumericalProblem p;
             std::string msg;
@@ -460,8 +458,8 @@ public:
         catch (const Dune::Exception &e) {
             // make sure all processes converged
             int converged = 0;
-            if (comm().size() > 1)
-                converged = comm().min(converged);
+            if (communicator().size() > 1)
+                converged = communicator().min(converged);
 
             NumericalProblem p;
             p.message(e.what());
@@ -495,7 +493,11 @@ public:
         if (enableShiftCriterion_)
             newtonUpdateShift(uLastIter, deltaU);
 
-        writeConvergence_(uLastIter, deltaU);
+        if (writeConvergence_)
+        {
+            convergenceWriter_->advanceIteration();
+            convergenceWriter_->write(uLastIter, deltaU);
+        }
 
         if (useLineSearch_)
         {
@@ -544,7 +546,7 @@ public:
         // classes directly as well?
         // -> The assembler has all the data w.r.t. the problem etc...
         // -> also, how do we call this?
-        assembler.updateVariables()
+        assembler.updateVariables();
 
         ++numSteps_;
 
@@ -628,7 +630,7 @@ public:
      * \brief Returns true if the Newton method ought to be chatty.
      */
     bool verbose() const
-    { return verbose_ && comm().rank() == 0; }
+    { return verbose_ && communicator().rank() == 0; }
 
 protected:
 
@@ -641,16 +643,6 @@ protected:
     const Implementation &asImp_() const
     { return *static_cast<const Implementation*>(this); }
 
-    void writeConvergence_(const SolutionVector &uLastIter,
-                           const SolutionVector &deltaU)
-    {
-        if (writeConvergence_)
-        {
-            convergenceWriter_->advanceIteration();
-            convergenceWriter_->write(uLastIter, deltaU);
-        }
-    }
-
     void lineSearchUpdate_(const JacobianAssembler& assembler,
                            SolutionVector &uCurrentIter,
                            const SolutionVector &uLastIter,
@@ -694,6 +686,7 @@ protected:
      * \param priVars1 The first vector of primary variables
      * \param priVars2 The second vector of primary variables
      */
+    template<class PrimaryVariables>
     Scalar relativeShiftAtDof_(const PrimaryVariables &priVars1,
                                const PrimaryVariables &priVars2)
     {
diff --git a/dumux/nonlinear/newtonmethod.hh b/dumux/nonlinear/newtonmethod.hh
index 0b142216c5f5613043ca94ad76eca74190f204c1..41e3fe14aff766121a8791b3273af33d316d8554 100644
--- a/dumux/nonlinear/newtonmethod.hh
+++ b/dumux/nonlinear/newtonmethod.hh
@@ -46,6 +46,9 @@ NEW_PROP_TAG(Scalar);
 NEW_PROP_TAG(NewtonController);
 NEW_PROP_TAG(SolutionVector);
 NEW_PROP_TAG(JacobianAssembler);
+NEW_PROP_TAG(JacobianMatrix);
+NEW_PROP_TAG(NewtonConvergenceWriter);
+NEW_PROP_TAG(WriteConvergence);
 }
 
 /*!
@@ -62,6 +65,7 @@ class NewtonMethod
     using NewtonController = typename GET_PROP_TYPE(TypeTag, NewtonController);
     using ConvergenceWriter =  typename GET_PROP_TYPE(TypeTag, NewtonConvergenceWriter);
     using JacobianAssembler = typename GET_PROP_TYPE(TypeTag, JacobianAssembler);
+    using JacobianMatrix = typename GET_PROP_TYPE(TypeTag, JacobianMatrix);
     using LinearSolver = typename GET_PROP_TYPE(TypeTag, LinearSolver);
 
 public:
@@ -69,18 +73,8 @@ public:
                  std::shared_ptr<LinearSolver> linearSolver)
     : jacobianAssembler_(jacobianAssembler)
     , linearSolver_(linearSolver)
-    , matrix_ = std::make_shared<JacobianMatrix>()
-    , residual_ = std::make_shared<SolutionVector>()
     {
-        // construct the newton controller with or without convergence writer
-        if (GET_PARAM_FROM_GROUP(TypeTag, bool, Newton, WriteConvergence))
-        {
-            newtonController_ = std::make_unique<NewtonController>(assembler().gridView().comm(),
-                                                                   NewtonConvergenceWriter(gridView, assembler().numDofs()));
-        }
-        else
-            newtonController_ = std::make_unique<NewtonController>(assembler().gridView().comm());
-
+        newtonController_ = std::make_unique<NewtonController>(assembler().gridView().comm());
         // set the linear system (matrix & residual) in the assembler
         assembler().setLinearSystem(matrix(), residual());
     }
@@ -95,9 +89,9 @@ public:
             return execute_();
         }
         catch (const NumericalProblem &e) {
-            if (ctl.verbose())
+            if (controller().verbose())
                 std::cout << "Newton: Caught exception: \"" << e.what() << "\"\n";
-            ctl.newtonFail();
+            controller().newtonFail();
             return false;
         }
     }
@@ -144,7 +138,7 @@ private:
             if (controller().newtonNumSteps() > 0)
                 uLastIter = uCurrentIter;
 
-            if (ctl.verbose()) {
+            if (controller().verbose()) {
                 std::cout << "Assemble: r(x^k) = dS/dt + div F - q;   M = grad r";
                 std::cout.flush();
             }
@@ -167,7 +161,7 @@ private:
             // http://en.wikipedia.org/wiki/ANSI_escape_code
             const char clearRemainingLine[] = { 0x1b, '[', 'K', 0 };
 
-            if (ctl.verbose()) {
+            if (controller().verbose()) {
                 std::cout << "\rSolve: M deltax^k = r";
                 std::cout << clearRemainingLine;
                 std::cout.flush();
@@ -180,15 +174,15 @@ private:
             deltaU = 0;
             // ask the controller to solve the linearized system
             controller().solveLinearSystem(linearSolver(),
-                                           jacobianAsm.matrix(),
+                                           matrix(),
                                            deltaU,
-                                           jacobianAsm.residual());
+                                           residual());
             solveTimer.stop();
 
             ///////////////
             // update
             ///////////////
-            if (ctl.verbose()) {
+            if (controller().verbose()) {
                 std::cout << "\rUpdate: x^(k+1) = x^k - deltax^k";
                 std::cout << clearRemainingLine;
                 std::cout.flush();
@@ -197,17 +191,17 @@ private:
             updateTimer.start();
             // update the current solution (i.e. uOld) with the delta
             // (i.e. u). The result is stored in u
-            ctl.newtonUpdate(assembler(), uCurrentIter, uLastIter, deltaU);
+            controller().newtonUpdate(assembler(), uCurrentIter, uLastIter, deltaU);
             updateTimer.stop();
 
             // tell the controller that we're done with this iteration
-            ctl.newtonEndStep(assembler(), uCurrentIter, uLastIter);
+            controller().newtonEndStep(assembler(), uCurrentIter, uLastIter);
         }
 
         // tell the controller that we're done
-        ctl.newtonEnd();
+        controller().newtonEnd();
 
-        if (ctl.verbose()) {
+        if (controller().verbose()) {
             Scalar elapsedTot = assembleTimer.elapsed() + solveTimer.elapsed() + updateTimer.elapsed();
             std::cout << "Assemble/solve/update time: "
                       <<  assembleTimer.elapsed() << "(" << 100*assembleTimer.elapsed()/elapsedTot << "%)/"
@@ -216,12 +210,12 @@ private:
                       << "\n";
         }
 
-        if (!ctl.newtonConverged()) {
-            ctl.newtonFail();
+        if (!controller().newtonConverged()) {
+            controller().newtonFail();
             return false;
         }
 
-        ctl.newtonSucceed();
+        controller().newtonSucceed();
         return true;
     }
 
diff --git a/dumux/porousmediumflow/immiscible/localresidual.hh b/dumux/porousmediumflow/immiscible/localresidual.hh
index c8f4361b3d4dba4d9de8804dc9fdc4676a6cd444..2365cefbddd2898d87695582d62c678f34eebba6 100644
--- a/dumux/porousmediumflow/immiscible/localresidual.hh
+++ b/dumux/porousmediumflow/immiscible/localresidual.hh
@@ -36,10 +36,9 @@ namespace Dumux
 template<class TypeTag>
 class ImmiscibleLocalResidual : public GET_PROP_TYPE(TypeTag, BaseLocalResidual)
 {
-    typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation;
-
     using ParentType = typename GET_PROP_TYPE(TypeTag, BaseLocalResidual);
     using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
     using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
     using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
     using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
@@ -69,7 +68,8 @@ public:
      * \note The volVars can be different to allow computing
      *       the implicit euler time derivative here
      */
-    PrimaryVariables computeStorage(const SubControlVolume& scv,
+    PrimaryVariables computeStorage(const Problem& problem,
+                                    const SubControlVolume& scv,
                                     const VolumeVariables& volVars) const
     {
         // partial time derivative of the phase mass
@@ -96,14 +96,15 @@ public:
      * \brief Evaluate the mass flux over a face of a sub control volume
      * \param scvf The sub control volume face to compute the flux on
      */
-    PrimaryVariables computeFlux(const Element& element,
+    PrimaryVariables computeFlux(const Problem& problem,
+                                 const Element& element,
                                  const FVElementGeometry& fvGeometry,
                                  const ElementVolumeVariables& elemVolVars,
                                  const SubControlVolumeFace& scvf,
                                  const ElementFluxVariablesCache& elemFluxVarsCache) const
     {
         FluxVariables fluxVars;
-        fluxVars.init(this->problem(), element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
+        fluxVars.init(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
 
         PrimaryVariables flux;
         for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
@@ -124,15 +125,8 @@ public:
 
         return flux;
     }
-
-private:
-    Implementation *asImp_()
-    { return static_cast<Implementation *> (this); }
-
-    const Implementation *asImp_() const
-    { return static_cast<const Implementation *> (this); }
 };
 
-}
+} // end namespace Dumux
 
 #endif
diff --git a/test/discretization/cellcentered/tpfa/test_tpfafvgeometry.cc b/test/discretization/cellcentered/tpfa/test_tpfafvgeometry.cc
index 349b045b476f4feb39cfa0b428306367b0dc1b3c..ca43301d6f6050ba6ff2be7a7ad35618024d1c25 100644
--- a/test/discretization/cellcentered/tpfa/test_tpfafvgeometry.cc
+++ b/test/discretization/cellcentered/tpfa/test_tpfafvgeometry.cc
@@ -36,27 +36,6 @@
 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_; }
-
-    template<class Element, class Intersection>
-    bool isInteriorBoundary(const Element& e, const Intersection& i) const
-    { return false; }
-
-    std::vector<unsigned int> getAdditionalDofDependencies(unsigned int index) const
-    { return std::vector<unsigned int>(); }
-private:
-    ElementMapper mapper_;
-};
-
 namespace Properties
 {
 NEW_TYPE_TAG(TestFVGeometry, INHERITS_FROM(CCTpfaModel));
diff --git a/test/porousmediumflow/1p/implicit/CMakeLists.txt b/test/porousmediumflow/1p/implicit/CMakeLists.txt
index 0997c152fe295579c19a28b42039a1834026ccb6..9713f6fd8116c8652db833919a15e9ea2630f87a 100644
--- a/test/porousmediumflow/1p/implicit/CMakeLists.txt
+++ b/test/porousmediumflow/1p/implicit/CMakeLists.txt
@@ -1,4 +1,5 @@
 add_subdirectory(pointsources)
+add_subdirectory(incompressible)
 
 add_input_file_links()
 add_gstat_file_links()
diff --git a/test/porousmediumflow/1p/implicit/incompressible/CMakeLists.txt b/test/porousmediumflow/1p/implicit/incompressible/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..4f3ee5b2806725005411a3ce4bf0b6fceea476fb
--- /dev/null
+++ b/test/porousmediumflow/1p/implicit/incompressible/CMakeLists.txt
@@ -0,0 +1,5 @@
+dune_symlink_to_source_files(FILES "test_1pincompressible.input")
+
+# incompressible
+add_dumux_test(test_1pincompressible test_1pincompressible test_1pincompressible.cc
+               ${CMAKE_CURRENT_BINARY_DIR}/test_1pincompressible)
diff --git a/test/porousmediumflow/1p/implicit/incompressible/properties.hh b/test/porousmediumflow/1p/implicit/incompressible/properties.hh
new file mode 100644
index 0000000000000000000000000000000000000000..c9b2584d2b2a49e4986ac78e4b5be00cd1df8262
--- /dev/null
+++ b/test/porousmediumflow/1p/implicit/incompressible/properties.hh
@@ -0,0 +1,75 @@
+// -*- 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 properties for the incompressible test
+ */
+#ifndef DUMUX_INCOMPRESSIBLE_ONEP_TEST_PROPERTIES_HH
+#define DUMUX_INCOMPRESSIBLE_ONEP_TEST_PROPERTIES_HH
+
+#include <dumux/implicit/cellcentered/tpfa/properties.hh>
+#include <dumux/discretization/cellcentered/tpfa/fvgridgeometry.hh>
+#include <dumux/porousmediumflow/1p/implicit/propertydefaults.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_; }
+
+    template<class Element, class Intersection>
+    bool isInteriorBoundary(const Element& e, const Intersection& i) const
+    { return false; }
+
+    std::vector<unsigned int> getAdditionalDofDependencies(unsigned int index) const
+    { return std::vector<unsigned int>(); }
+private:
+    ElementMapper mapper_;
+};
+
+namespace Properties
+{
+
+NEW_PROP_TAG(EnableFVGridGeometryCache);
+NEW_PROP_TAG(FVGridGeometry);
+
+NEW_TYPE_TAG(IncompressibleTestProblem, INHERITS_FROM(OneP, CCTpfaModel));
+
+// Set the grid type
+SET_TYPE_PROP(IncompressibleTestProblem, Grid, Dune::YaspGrid<2>);
+
+// Set the finite volume grid geometry
+SET_TYPE_PROP(IncompressibleTestProblem, FVGridGeometry, CCTpfaFVGridGeometry<TypeTag, false>);
+
+// Set the problem type
+SET_TYPE_PROP(IncompressibleTestProblem, Problem, Dumux::MockProblem<TypeTag>);
+
+} // end namespace Properties
+
+} // end namespace Dumux
+
+#endif
diff --git a/test/porousmediumflow/1p/implicit/incompressible/test_1pincompressible.cc b/test/porousmediumflow/1p/implicit/incompressible/test_1pincompressible.cc
new file mode 100644
index 0000000000000000000000000000000000000000..daaf557e3cff1c3fc2fcc255f91baa695ac63d41
--- /dev/null
+++ b/test/porousmediumflow/1p/implicit/incompressible/test_1pincompressible.cc
@@ -0,0 +1,126 @@
+// -*- 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 the one-phase CC model
+ */
+#include <config.h>
+
+#include <ctime>
+#include <iostream>
+
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/grid/io/file/dgfparser/dgfexception.hh>
+
+#include <dumux/common/propertysystem.hh>
+#include <dumux/common/parameters.hh>
+#include <dumux/common/valgrind.hh>
+#include <dumux/common/dumuxmessage.hh>
+#include <dumux/common/defaultusagemessage.hh>
+#include <dumux/common/parameterparser.hh>
+
+#include "properties.hh"
+//#include "problem.hh"
+
+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_; }
+
+    template<class Element, class Intersection>
+    bool isInteriorBoundary(const Element& e, const Intersection& i) const
+    { return false; }
+
+    std::vector<unsigned int> getAdditionalDofDependencies(unsigned int index) const
+    { return std::vector<unsigned int>(); }
+private:
+    ElementMapper mapper_;
+};
+
+int main(int argc, char** argv)
+{
+    using namespace Dumux;
+
+    using TypeTag = TTAG(IncompressibleTestProblem);
+
+    // some aliases for better readability
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using GridCreator = typename GET_PROP_TYPE(TypeTag, GridCreator);
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    // using TimeManager = typename GET_PROP_TYPE(TypeTag, TimeManager);
+    using ParameterTree = typename GET_PROP(TypeTag, ParameterTree);
+
+    // initialize MPI, finalize is done automatically on exit
+    const auto& mpiHelper = Dune::MPIHelper::instance(argc, argv);
+
+    // print dumux start message
+    if (mpiHelper.rank() == 0)
+        DumuxMessage::print(/*firstCall=*/true);
+
+    ////////////////////////////////////////////////////////////
+    // parse the command line arguments and input file
+    ////////////////////////////////////////////////////////////
+
+    // parse command line arguments
+    ParameterParser::parseCommandLineArguments(argc, argv, ParameterTree::tree());
+
+    // parse the input file into the parameter tree
+    // check first if the user provided an input file through the command line, if not use the default
+    const auto parameterFileName = ParameterTree::tree().hasKey("ParameterFile") ? GET_RUNTIME_PARAM(TypeTag, std::string, ParameterFile) : "";
+    ParameterParser::parseInputFile(argc, argv, ParameterTree::tree(), parameterFileName);
+
+    //////////////////////////////////////////////////////////////////////
+    // try to create a grid (from the given grid file or the input file)
+    /////////////////////////////////////////////////////////////////////
+
+    try { GridCreator::makeGrid(); }
+    catch (...) {
+        std::cout << "\n\t -> Creation of the grid failed! <- \n\n";
+        throw;
+    }
+    GridCreator::loadBalance();
+
+    // we compute on the leaf grid view
+    const auto& leafGridView = GridCreator::grid().leafGridView();
+
+    // create the finite volume grid geometry
+    using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
+    auto fvGridGeometry = std::make_shared<FVGridGeometry>(leafGridView);
+    fvGridGeometry->update();
+
+    // do some testing
+    for (const auto& element : elements(leafGridView))
+    {
+        auto fvGeometry = localView(*fvGridGeometry);
+        fvGeometry.bind(element);
+        for (const auto& scv : scvs(fvGeometry))
+            std::cout << scv.dofPosition() << " ";
+        std::cout << std::endl;
+    }
+
+    return 0;
+
+} // end main
diff --git a/test/porousmediumflow/1p/implicit/incompressible/test_1pincompressible.input b/test/porousmediumflow/1p/implicit/incompressible/test_1pincompressible.input
new file mode 100644
index 0000000000000000000000000000000000000000..bd21b5f555c67b6d7cf4624e7e8af6f29dc663aa
--- /dev/null
+++ b/test/porousmediumflow/1p/implicit/incompressible/test_1pincompressible.input
@@ -0,0 +1,19 @@
+[TimeManager]
+DtInitial = 1 # [s]
+TEnd = 1 # [s]
+
+[Grid]
+LowerLeft = 0 0
+UpperRight = 1 1
+Cells = 10 10
+
+[Problem]
+Name = 1ptestcc # name passed to the output routines
+
+[SpatialParams]
+LensLowerLeft = 0.2 0.2
+LensUpperRight = 0.8 0.8
+
+Permeability = 1e-10 # [m^2]
+PermeabilityLens = 1e-12 # [m^2]
+