diff --git a/dumux/implicit/box/localjacobian.hh b/dumux/implicit/box/localjacobian.hh
index 7ce07c5560c2bfed6ee187336c2dd7f7c8cefbb3..14041d5f88cf53376bed8a39596b63e0b0a6ee0f 100644
--- a/dumux/implicit/box/localjacobian.hh
+++ b/dumux/implicit/box/localjacobian.hh
@@ -18,10 +18,10 @@
  *****************************************************************************/
 /*!
  * \file
- * \brief Caculates the Jacobian of the local residual for fully-implicit models
+ * \brief Caculates the Jacobian of the local residual for fully-implicit box models
  */
-#ifndef DUMUX_IMPLICIT_LOCAL_JACOBIAN_HH
-#define DUMUX_IMPLICIT_LOCAL_JACOBIAN_HH
+#ifndef DUMUX_IMPLICIT_BOX_LOCAL_JACOBIAN_HH
+#define DUMUX_IMPLICIT_BOX_LOCAL_JACOBIAN_HH
 
 #include <dune/istl/io.hh>
 #include <dune/istl/matrix.hh>
@@ -82,18 +82,16 @@ class BoxLocalJacobian : public ImplicitLocalJacobian<TypeTag>
         dim = GridView::dimension,
     };
 
+    typedef typename GET_PROP_TYPE(TypeTag, JacobianMatrix) JacobianMatrix;
+    typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
     typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry;
     typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume;
     typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper;
     typedef typename GET_PROP_TYPE(TypeTag, ElementSolutionVector) ElementSolutionVector;
     typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
-
     typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables;
     typedef typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes) ElementBoundaryTypes;
-
     typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
-    typedef Dune::FieldMatrix<Scalar, numEq, numEq> MatrixBlock;
-    typedef Dune::Matrix<MatrixBlock> LocalBlockMatrix;
 
 public:
     BoxLocalJacobian()
@@ -101,62 +99,56 @@ public:
         numericDifferenceMethod_ = GET_PARAM_FROM_GROUP(TypeTag, int, Implicit, NumericDifferenceMethod);
     }
 
-
     /*!
      * \brief Assemble an element's local Jacobian matrix of the
      *        defect.
      *
      * \param element The DUNE Codim<0> entity which we look at.
      */
-    void assemble(const Element& element, JacobianMatrix& matrix)
+    void assemble(const Element& element, JacobianMatrix& matrix, SolutionVector& residual)
     {
-        // set the current grid element and update the element's
-        // finite volume geometry
-        elemPtr_ = &element;
-        reset_();
+        // prepare the volvars/fvGeometries for the case when caching is disabled
+        this->model_().fvGeometries_().bind(element);
+        this->model_().curVolVars_().bind(element);
+        this->model_().prevVolVars_().bindElement(element);
+        this->model_().fluxVariablesCache_().bind(element);
 
-        bcTypes_.update(problem_(), element, fvElemGeom_());
+        // the finite volume element geometry
+        const auto& fvGeometry = this->model_().fvGeometries(element);
 
-        // calculate the local residual
+        // the element boundary types
+        bcTypes_.update(this->problem_(), element, fvGeometry);
+
+        // calculate the actual element residual
         this->localResidual().eval(element, bcTypes_);
         this->residual_ = this->localResidual().residual();
 
-        this->model_().updatePVWeights(fvElemGeom_());
-
-        // get stencil informations
-        const auto& elementStencil = this->model_().stencils(element).elementStencil();
+        this->model_().updatePVWeights(fvGeometry);
 
-        // calculate derivatives for the dofs inside the element
-        ElementSolutionVector partialDeriv(numRows);
-        for (auto&& scv : fvElemGeom_().scvs())
+        // calculation of the derivatives
+        for (const auto& scv : fvGeometry.scvs())
         {
+            // dof index and corresponding actual pri vars
+            const auto dofIdx = scv.dofIndex();
+            const auto localScvIdx = scv.indexInElement();
+            VolumeVariables origVolVars(this->model_().curVolVars(scv));
+
+            // add precalculated residual for this scv into the global container
+            residual[dofIdx] += this->residual_[localScvIdx];
+
+            // calculate derivatives w.r.t to the privars at the dof at hand
             for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
             {
-                asImp_().evalPartialDerivative_(partialDeriv, element, scv, pvIdx);
+                evalPartialDerivative_(matrix, element, scv, pvIdx);
 
-                // update the local stiffness matrix with the current partial derivatives
-                for (auto&& scvJ : fvElemGeom_().scvs())
-                    this->updateGlobalJacobian_(matrix, scv.dofIndex(), scvJ.dofIndex(), pvIdx, partialDeriv[scvJ.indexInElement()]);
+                // restore the original state of the scv's volume variables
+                this->model_().curVolVars_(scv) = origVolVars;
             }
-        }
 
-        // TODO: calculate derivatives in the case of an extended source stencil
-        // const auto& extendedSourceStencil = model_().stencils(element).extendedSourceStencil();
-        // for (auto&& globalJ : extendedSourceStencil)
-        // {
-        //     for (int pvIdx = 0; pvIdx < numEq; pvIdx++)
-        //         {
-        //             evalPartialDerivativeSource_(partialDeriv, globalJ, pvIdx, fluxVarIndices);
-
-        //             // update the local stiffness matrix with the partial derivatives
-        //             updateLocalJacobian_(j, pvIdx, partialDeriv);
-        //         }
-               // ++j;
-        // }
-
-        // for cellcentered methods, calculate the derivatives w.r.t cells in stencil
+            // TODO: what if we have an extended source stencil????
+        }
     }
-
+protected:
     /*!
      * \brief Compute the partial derivatives to a primary variable at
      *        an degree of freedom.
@@ -193,6 +185,7 @@ public:
      *
      * \param partialDeriv The vector storing the partial derivatives of all
      *              equations
+     * \param storageDeriv the mass matrix contributions
      * \param col The block column index of the degree of freedom
      *            for which the partial derivative is calculated.
      *            Box: a sub-control volume index.
@@ -200,19 +193,19 @@ public:
      * \param pvIdx The index of the primary variable
      *              for which the partial derivative is calculated
      */
-    void evalPartialDerivative_(ElementSolutionVector &partialDeriv,
+    void evalPartialDerivative_(JacobianMatrix& matrix,
                                 const Element& element,
-                                const SubControlVolume &scv,
+                                const SubControlVolume& scv,
                                 const int pvIdx)
     {
-        auto dofIdxGlobal = scv.dofIndex();
+        auto dofIdx = scv.dofIndex();
 
-        PrimaryVariables priVars(model_().curSol()[dofIdxGlobal]);
-        VolumeVariables origVolVars(model_().curVolVars(scv));
-
-        Scalar eps = asImp_().numericEpsilon(scv, pvIdx);
+        ElementSolutionVector partialDeriv(element.subEntities(dim));
+        PrimaryVariables priVars(this->model_().curSol()[dofIdx]);
+        Scalar eps = this->numericEpsilon(scv, pvIdx);
         Scalar delta = 0;
 
+        // calculate the residual with the forward deflected primary variables
         if (numericDifferenceMethod_ >= 0)
         {
             // we are not using backward differences, i.e. we need to
@@ -222,21 +215,21 @@ public:
             priVars[pvIdx] += eps;
             delta += eps;
 
-            // update the volume variables
-            model_().curVolVars_(scv).update(priVars, problem_(), element, scv);
+            // update the volume variables connected to the dof
+            this->model_().curVolVars_(scv).update(priVars, this->problem_(), element, scv);
 
-            // calculate the residual with the deflected primary variables
-            localResidual().eval(element, bcTypes_);
+            // calculate the deflected residual
+            this->localResidual().eval(element, bcTypes_);
 
-            // store the residual and the storage term
-            partialDeriv = localResidual().residual();
+            // store the residual
+            partialDeriv = this->localResidual().residual();
         }
         else
         {
             // we are using backward differences, i.e. we don't need
             // to calculate f(x + \epsilon) and we can recycle the
             // (already calculated) residual f(x)
-            partialDeriv = residual_;
+            partialDeriv = this->residual_;
         }
 
         if (numericDifferenceMethod_ <= 0)
@@ -248,45 +241,38 @@ public:
             priVars[pvIdx] -= delta + eps;
             delta += eps;
 
-            // update the volume variables
-            model_().curVolVars_(scv).update(priVars, problem_(), element, scv);
+            // update the volume variables connected to the dof
+            this->model_().curVolVars_(scv).update(priVars, this->problem_(), element, scv);
 
-            // calculate the residual with the deflected primary variables
-            localResidual().eval(element, bcTypes_);
+            // calculate the deflected residual
+            this->localResidual().eval(element, bcTypes_);
 
             // subtract the residual from the derivative storage
-            partialDeriv -= localResidual().residual();
+            partialDeriv -= this->localResidual().residual();
         }
         else
         {
             // we are using forward differences, i.e. we don't need to
             // calculate f(x - \epsilon) and we can recycle the
             // (already calculated) residual f(x)
-            partialDeriv -= residual_;
+            partialDeriv -= this->residual_;
         }
 
         // divide difference in residuals by the magnitude of the
         // deflections between the two function evaluation
         partialDeriv /= delta;
 
-        // restore the original state of the scv's volume variables
-        model_().curVolVars_(scv) = origVolVars;
-
-#if HAVE_VALGRIND
-        for (unsigned i = 0; i < partialDeriv.size(); ++i)
-            Valgrind::CheckDefined(partialDeriv[i]);
-#endif
+        // update the global stiffness matrix with the current partial derivatives
+        const auto& fvGeometry = this->model_().fvGeometries(element);
+        for (const auto& scvJ : fvGeometry.scvs())
+            this->updateGlobalJacobian_(matrix, scvJ.dofIndex(), dofIdx, pvIdx, partialDeriv[scvJ.indexInElement()]);
     }
 
-    const FVElementGeometry& fvElemGeom_() const
-    {
-        return model_().fvGeometries(eIdxGlobal_);
-    }
-
-    IndexType eIdxGlobal_;
-    ElementBoundaryTypes bcTypes_;
+private:
 
     int numericDifferenceMethod_;
+
+    ElementBoundaryTypes bcTypes_;
 };
 }
 
diff --git a/dumux/implicit/box/localresidual.hh b/dumux/implicit/box/localresidual.hh
index 1eacceb3b1711de1024d04f5ab68b0717caa6627..a43ee2c14a495d4c7a3686f813f31d855ec440a9 100644
--- a/dumux/implicit/box/localresidual.hh
+++ b/dumux/implicit/box/localresidual.hh
@@ -55,14 +55,10 @@ class BoxLocalResidual : public ImplicitLocalResidual<TypeTag>
     };
 
     typedef typename GridView::template Codim<0>::Entity Element;
-
-    typedef typename GridView::Grid::ctype CoordScalar;
-    typedef typename Dune::ReferenceElements<CoordScalar, dim> ReferenceElements;
-    typedef typename Dune::ReferenceElement<CoordScalar, dim> ReferenceElement;
-
-    typedef typename GET_PROP_TYPE(TypeTag, VertexMapper) VertexMapper;
     typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
     typedef typename GET_PROP_TYPE(TypeTag, BoundaryTypes) BoundaryTypes;
+    typedef typename GET_PROP_TYPE(TypeTag, SubControlVolume) SubControlVolume;
+    typedef typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace) SubControlVolumeFace;
 
     // copying the local residual class is not a good idea
     BoxLocalResidual(const BoxLocalResidual &);
@@ -72,116 +68,86 @@ public:
     { }
 
 protected:
+
+    void evalFluxes_()
+    {
+        // calculate the mass flux over the scv faces and subtract
+        const auto& fvGeometry = this->fvGeometry_();
+        for (const auto& scvf : fvGeometry.scvfs())
+        {
+            if (!scvf.boundary())
+            {
+                auto flux = this->asImp_().computeFlux(scvf);
+                const auto& insideScv = this->model_().fvGeometries().subControlVolume(scvf.insideScvIdx());
+                const auto& outsideScv = this->model_().fvGeometries().subControlVolume(scvf.outsideScvIdx());
+
+                this->residual_[insideScv.indexInElement()] += flux;
+                this->residual_[outsideScv.indexInElement()] -= flux;
+            }
+        }
+    }
+
     /*!
      * \brief Set the values of the Dirichlet boundary control volumes
      *        of the current element.
      */
-    void evalDirichlet_()
+    void evalDirichlet_(const SubControlVolume& scv, const BoundaryTypes& bcTypes)
     {
-        PrimaryVariables dirichletValues(0);
-        for (int scvIdx = 0; scvIdx < this->fvGeometry_().numScv; ++scvIdx) {
-            const BoundaryTypes &bcTypes = this->bcTypes_(scvIdx);
-
-            if (bcTypes.hasDirichlet()) {
-                // ask the problem for the dirichlet values
-                Valgrind::SetUndefined(dirichletValues);
-                this->asImp_().problem_().dirichlet(dirichletValues, this->element_().template subEntity<dim>(scvIdx));
+        PrimaryVariables dirichletValues = this->asImp_().problem_().dirichlet(this->element_(), scv);
 
-                // set the dirichlet conditions
-                for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) {
-                    if (bcTypes.isDirichlet(eqIdx)) {
-                        int pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
-                        assert(0 <= pvIdx && pvIdx < numEq);
-                        Valgrind::CheckDefined(dirichletValues[pvIdx]);
+        // set the dirichlet conditions
+        for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+        {
+            if (bcTypes.isDirichlet(eqIdx))
+            {
+                int pvIdx = bcTypes.eqToDirichletIndex(eqIdx);
+                assert(0 <= pvIdx && pvIdx < numEq);
+                Valgrind::CheckDefined(dirichletValues[pvIdx]);
 
-                        this->residual_[scvIdx][eqIdx] =
-                                this->curPriVar_(scvIdx, pvIdx) - dirichletValues[pvIdx];
+                // get the primary variables
+                const auto& priVars = this->model_().curVolVars(scv).priVars();
 
-                        this->storageTerm_[scvIdx][eqIdx] = 0.0;
-                    }
-                }
+                this->residual_[scv.indexInElement()][eqIdx] = priVars[pvIdx] - dirichletValues[pvIdx];
             }
         }
     }
 
     /*!
-     * \brief Add all Neumann and outflow boundary conditions to the local
-     *        residual.
+     * \brief Add all fluxes resulting from Neumann and outflow boundary conditions to the local residual.
      */
-    void evalBoundaryFluxes_()
+    void evalBoundaryFluxes_(const SubControlVolumeFace &scvf, const SubControlVolume& insideScv, const BoundaryTypes& bcTypes)
     {
-        Dune::GeometryType geoType = this->element_().geometry().type();
-        const ReferenceElement &refElement = ReferenceElements::general(geoType);
 
-        for (const auto& intersection : intersections(this->gridView_(), this->element_()))
-        {
-            // handle only faces on the boundary
-            if (intersection.boundary()) {
-                // Assemble the boundary for all vertices of the current
-                // face
-                int fIdx = intersection.indexInInside();
-                int numFaceVerts = refElement.size(fIdx, 1, dim);
-                for (int faceVertexIdx = 0;
-                    faceVertexIdx < numFaceVerts;
-                    ++faceVertexIdx)
-                {
-                    int scvIdx = refElement.subEntity(fIdx,
-                                                        1,
-                                                        faceVertexIdx,
-                                                        dim);
-
-                    int boundaryFaceIdx =
-                        this->fvGeometry_().boundaryFaceIndex(fIdx, faceVertexIdx);
+        // evaluate the Neumann conditions at the boundary face
+        if (bcTypes.hasNeumann())
+            this->residual_[insideScv.indexInElement()] += this->asImp_().evalNeumannSegment_(scvf, insideScv, bcTypes);
 
-                    // add the residual of all vertices of the boundary
-                    // segment
-                    this->asImp_().evalNeumannSegment_(&intersection,
-                                                       scvIdx,
-                                                       boundaryFaceIdx);
-                    // evaluate the outflow conditions at the boundary face
-                    this->asImp_().evalOutflowSegment_(&intersection,
-                                                       scvIdx,
-                                                       boundaryFaceIdx);
-                }
-            }
-        }
+        // TODO: evaluate the outflow conditions at the boundary face
+        //if (bcTypes.hasOutflow())
+        //    flux += this->asImp_().evalOutflowSegment_(&intersection, bcTypes);
     }
 
     /*!
-     * \brief Add Neumann boundary conditions for a single sub-control
-     *        volume face to the local residual.
+     * \brief Add Neumann boundary conditions for a single scv face
      */
-    template <class IntersectionIterator>
-    void evalNeumannSegment_(const IntersectionIterator &isIt,
-                             const int scvIdx,
-                             const int boundaryFaceIdx)
+    PrimaryVariables evalNeumannSegment_(const SubControlVolumeFace &scvf,
+                                         const SubControlVolume& insideScv,
+                                         const BoundaryTypes &bcTypes)
     {
         // temporary vector to store the neumann boundary fluxes
-        PrimaryVariables neumannFlux(0.0);
-        const BoundaryTypes &bcTypes = this->bcTypes_(scvIdx);
+        PrimaryVariables flux(0);
 
-        // deal with neumann boundaries
-        if (bcTypes.hasNeumann()) {
-            Valgrind::SetUndefined(neumannFlux);
-            this->problem_().solDependentNeumann(neumannFlux,
-                                          this->element_(),
-                                          this->fvGeometry_(),
-                                          *isIt,
-                                          scvIdx,
-                                          boundaryFaceIdx,
-                                          this->curVolVars_());
-            neumannFlux *=
-                this->fvGeometry_().boundaryFace[boundaryFaceIdx].area
-                * this->curVolVars_(scvIdx).extrusionFactor();
-            Valgrind::CheckDefined(neumannFlux);
+        auto neumannFluxes = this->problem_().neumann(this->element_(), scvf);
 
-            // set the neumann conditions
-            for (int eqIdx = 0; eqIdx < numEq; ++eqIdx) {
-                if (!bcTypes.isNeumann(eqIdx))
-                    continue;
-                this->residual_[scvIdx][eqIdx] += neumannFlux[eqIdx];
-            }
-        }
+        // multiply neumann fluxes with the area and the extrusion factor
+        neumannFluxes *= scvf.area()*this->problem_().model().curVolVars(insideScv).extrusionFactor();
+
+        // add fluxes to the temporary vector
+        for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+            if (bcTypes.isNeumann(eqIdx))
+                flux[eqIdx] += neumannFluxes[eqIdx];
+
+        return flux;
     }
 
     /*!
@@ -192,77 +158,59 @@ protected:
     * \param scvIdx The index of the considered face of the sub-control volume
     * \param boundaryFaceIdx The index of the considered boundary face of the sub control volume
     */
-    template <class IntersectionIterator>
-    void evalOutflowSegment_(const IntersectionIterator &isIt,
-                            const int scvIdx,
-                            const int boundaryFaceIdx)
+    // template <class IntersectionIterator>
+    // void evalOutflowSegment_(const IntersectionIterator &isIt,
+    //                         const int scvIdx,
+    //                         const int boundaryFaceIdx)
+    // {
+    //     const BoundaryTypes &bcTypes = this->bcTypes_(scvIdx);
+    //     // deal with outflow boundaries
+    //     if (bcTypes.hasOutflow())
+    //     {
+    //         //calculate outflow fluxes
+    //         PrimaryVariables values(0.0);
+    //         this->asImp_().computeFlux(values, boundaryFaceIdx, true);
+    //         Valgrind::CheckDefined(values);
+
+    //         for (int equationIdx = 0; equationIdx < numEq; ++equationIdx)
+    //         {
+    //             if (!bcTypes.isOutflow(equationIdx) )
+    //                 continue;
+    //             // deduce outflow
+    //             this->residual_[scvIdx][equationIdx] += values[equationIdx];
+    //         }
+    //     }
+    // }
+
+    void evalBoundary_()
     {
-        const BoundaryTypes &bcTypes = this->bcTypes_(scvIdx);
-        // deal with outflow boundaries
-        if (bcTypes.hasOutflow())
+        const auto& fvGeometry = this->fvGeometry_();
+        if (this->bcTypes_().hasNeumann() || this->bcTypes_().hasOutflow())
         {
-            //calculate outflow fluxes
-            PrimaryVariables values(0.0);
-            this->asImp_().computeFlux(values, boundaryFaceIdx, true);
-            values *= this->curVolVars_(scvIdx).extrusionFactor();
-            Valgrind::CheckDefined(values);
 
-            for (int equationIdx = 0; equationIdx < numEq; ++equationIdx)
+            for (const auto& scvf : fvGeometry.scvfs())
             {
-                if (!bcTypes.isOutflow(equationIdx) )
-                    continue;
-                // deduce outflow
-                this->residual_[scvIdx][equationIdx] += values[equationIdx];
+                if (scvf.boundary())
+                {
+                    const auto& scv = this->problem_().model().fvGeometries().subControlVolume(scvf.insideScvIdx());
+                    this->asImp_().evalBoundaryFluxes_(scvf, scv, this->bcTypes_(scv.indexInElement()));
+                }
             }
         }
-    }
 
-    /*!
-     * \brief Add the flux terms to the local residual of all
-     *        sub-control volumes of the current element.
-     */
-    void evalFluxes_()
-    {
-        // calculate the mass flux over the faces and subtract
-        // it from the local rates
-        for (int scvfIdx = 0; scvfIdx < this->fvGeometry_().numScvf; scvfIdx++)
+        // additionally treat mixed D/N conditions in a strong sense
+        if (this->bcTypes_().hasDirichlet())
         {
-            int i = this->fvGeometry_().subContVolFace[scvfIdx].i;
-            int j = this->fvGeometry_().subContVolFace[scvfIdx].j;
-
-            PrimaryVariables flux;
-
-            Valgrind::SetUndefined(flux);
-            this->asImp_().computeFlux(flux, scvfIdx);
-            Valgrind::CheckDefined(flux);
-
-            Scalar extrusionFactor =
-                (this->curVolVars_(i).extrusionFactor()
-                 + this->curVolVars_(j).extrusionFactor())
-                / 2;
-            flux *= extrusionFactor;
+            for (const auto& scv : fvGeometry.scvs())
+            {
+                BoundaryTypes bcTypes = this->bcTypes_(scv.indexInElement());
+                if (!bcTypes.hasDirichlet())
+                    continue;
 
-            // The balance equation for a finite volume is:
-            //
-            // dStorage/dt = Flux + Source
-            //
-            // where the 'Flux' and the 'Source' terms represent the
-            // mass per second which _ENTER_ the finite
-            // volume. Re-arranging this, we get
-            //
-            // dStorage/dt - Source - Flux = 0
-            //
-            // Since the flux calculated by computeFlux() goes _OUT_
-            // of sub-control volume i and _INTO_ sub-control volume
-            // j, we need to add the flux to finite volume i and
-            // subtract it from finite volume j
-            this->residual_[i] += flux;
-            this->residual_[j] -= flux;
+                this->asImp_().evalDirichlet_(scv, bcTypes);
+            }
         }
     }
-
-    const VertexMapper &vertexMapper_() const
-    { return this->problem_().vertexMapper(); }
 };
 
 }