diff --git a/dumux/implicit/cellcentered/elementvolumevariables.hh b/dumux/implicit/cellcentered/elementvolumevariables.hh
index dfa3ae46af0d1c5a494e19ad34832b689d3a13e2..c09efacc7cfa010884b16827877f1629683f2bdc 100644
--- a/dumux/implicit/cellcentered/elementvolumevariables.hh
+++ b/dumux/implicit/cellcentered/elementvolumevariables.hh
@@ -34,12 +34,13 @@ namespace Dumux
  *        volume variables object for each of the element's vertices
  */
 template<class TypeTag>
-class CCElementVolumeVariables : public std::vector<typename GET_PROP_TYPE(TypeTag, VolumeVariables) >
+class CCElementVolumeVariables
 {
     typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
     typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry;
     typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
     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, BoundaryTypes) BoundaryTypes;
 
@@ -55,35 +56,21 @@ public:
      * \param fvGeometry The finite volume geometry of the element
      * \param oldSol Tells whether the model's previous or current solution should be used.
      */
-    void update(const Problem &problem,
+    void update(Problem &problem,
                 const Element &element,
                 const FVElementGeometry &fvGeometry,
                 bool oldSol)
     {
-        const SolutionVector &globalSol =
-            oldSol?
-            problem.model().prevSol():
-            problem.model().curSol();
+        oldSol_ = oldSol;
+        problem_ = &problem;
 
         int numNeighbors = fvGeometry.numNeighbors;
-        this->resize(numNeighbors);
+        stencil_.resize(numNeighbors);
 
         for (int i = 0; i < numNeighbors; i++)
         {
             const Element& neighbor = fvGeometry.neighbors[i];
-
-            const PrimaryVariables &solI
-                    = globalSol[problem.elementMapper().index(neighbor)];
-
-            FVElementGeometry neighborFVGeom;
-            neighborFVGeom.updateInner(neighbor);
-
-            (*this)[i].update(solI,
-                              problem,
-                              neighbor,
-                              neighborFVGeom,
-                              /*scvIdx=*/0,
-                              oldSol);
+            stencil_[i] = problem.elementMapper().index(neighbor);
         }
 
         // only treat boundary if current solution is evaluated
@@ -96,40 +83,69 @@ public:
                 || elemBCTypes.hasNeumann()
                 || elemBCTypes.hasOutflow())
             {
-                this->resize(numNeighbors + element.subEntities(1));
+                ghostVolVars_ = std::vector<VolumeVariables>(element.subEntities(1));
+                isDirichlet_ = std::vector<bool>(element.subEntities(1), false);
 
                 // add volume variables for the boundary faces
                 for (const auto& intersection : intersections(problem.gridView(), element))
                 {
-                    if (intersection.boundary())
+                    if (!intersection.boundary())
+                        continue;
+
+                    BoundaryTypes bcTypes;
+                    problem.boundaryTypes(bcTypes, intersection);
+
+                    int fIdx = intersection.indexInInside();
+                    if (bcTypes.hasDirichlet())
                     {
-                        BoundaryTypes bcTypes;
-                        problem.boundaryTypes(bcTypes, intersection);
-
-                        int fIdx = intersection.indexInInside();
-                        int indexInVariables = numNeighbors + fIdx;
-
-                        if (bcTypes.hasDirichlet())
-                        {
-                            PrimaryVariables dirichletValues;
-                            problem.dirichlet(dirichletValues, intersection);
-
-                            (*this)[indexInVariables].update(dirichletValues,
-                                                            problem,
-                                                            element,
-                                                            fvGeometry,
-                                                            /*scvIdx=*/0,
-                                                            oldSol);
-                        }
-                        else
-                        {
-                            (*this)[indexInVariables] = (*this)[0];
-                        }
+                        PrimaryVariables dirichletValues;
+                        problem.dirichlet(dirichletValues, intersection);
+
+                        ghostVolVars_[fIdx].update(dirichletValues,
+                                                    problem,
+                                                    element,
+                                                    fvGeometry,
+                                                    /*scvIdx=*/0,
+                                                    oldSol);
+                        isDirichlet_[fIdx] = true;
                     }
                 }
             }
         }
     }
+
+    const VolumeVariables& operator [](const unsigned int i) const
+    {
+        if (i >= stencil_.size())
+        {
+            assert(!oldSol_); // old boundary volVars don't exist
+            if (isDirichlet_[i - stencil_.size()]) // ghost volVars only exist for Dirichlet boundaries
+                return ghostVolVars_[i - stencil_.size()];
+            else
+                return problem_->model().volVars(stencil_[0]);
+        }
+        else
+        {
+            if(!oldSol_)
+                return problem_->model().volVars(stencil_[i]);
+            else
+                return problem_->model().prevVolVars(stencil_[i]);
+        }
+    }
+
+    VolumeVariables& operator [](const unsigned int i)
+    {
+        assert(!oldSol_); // old volVars should never be modified
+        assert(i < stencil_.size()); // boundary volVars should not be modified
+        return problem_->model().volVars(stencil_[i]);
+    }
+
+private:
+    bool oldSol_ = false;
+    std::vector<unsigned int> stencil_;
+    std::vector<VolumeVariables> ghostVolVars_;
+    std::vector<bool> isDirichlet_;
+    Problem* problem_;
 };
 
 } // namespace Dumux
diff --git a/dumux/implicit/localjacobian.hh b/dumux/implicit/localjacobian.hh
index 4ba53f954b9386f13cfb224e592c6182307612d6..b5d27dc017023ed930f8f7f8daf77d236c9f5f30 100644
--- a/dumux/implicit/localjacobian.hh
+++ b/dumux/implicit/localjacobian.hh
@@ -23,6 +23,7 @@
 #ifndef DUMUX_IMPLICIT_LOCAL_JACOBIAN_HH
 #define DUMUX_IMPLICIT_LOCAL_JACOBIAN_HH
 
+#include <dune/istl/io.hh>
 #include <dune/istl/matrix.hh>
 
 #include <dumux/common/math.hh>
@@ -145,32 +146,31 @@ public:
         // set the current grid element and update the element's
         // finite volume geometry
         elemPtr_ = &element;
-        fvElemGeom_.update(gridView_(), element);
         reset_();
 
-        bcTypes_.update(problem_(), element_(), fvElemGeom_);
+        bcTypes_.update(problem_(), element_(), fvElemGeom_());
 
         // set the hints for the volume variables
-        model_().setHints(element, prevVolVars_, curVolVars_);
+        // model_().setHints(element, prevVolVars_, curVolVars_);
 
         // update the secondary variables for the element at the last
         // and the current time levels
         prevVolVars_.update(problem_(),
                             element_(),
-                            fvElemGeom_,
+                            fvElemGeom_(),
                             true /* isOldSol? */);
 
         curVolVars_.update(problem_(),
                            element_(),
-                           fvElemGeom_,
+                           fvElemGeom_(),
                            false /* isOldSol? */);
 
         // update the hints of the model
-        model_().updateCurHints(element, curVolVars_);
+        // model_().updateCurHints(element, curVolVars_);
 
         // calculate the local residual
         localResidual().eval(element_(),
-                             fvElemGeom_,
+                             fvElemGeom_(),
                              prevVolVars_,
                              curVolVars_,
                              bcTypes_);
@@ -183,7 +183,7 @@ public:
         int numRows, numCols;
         if (isBox)
         {
-            numRows = numCols = fvElemGeom_.numScv;
+            numRows = numCols = fvElemGeom_().numScv;
             // resize for hanging nodes or lower dimensional grids
             if(numRows > 1<<dim || numCols > 1<<dim)
                 A_.setSize(numRows, numCols);
@@ -191,7 +191,7 @@ public:
         else
         {
             numRows = 1;
-            numCols = fvElemGeom_.numNeighbors;
+            numCols = fvElemGeom_().numNeighbors;
             // resize for hanging nodes or lower dimensional grids
             if(numCols > 2*dim + 1)
                 A_.setSize(numRows, numCols);
@@ -309,6 +309,15 @@ protected:
         return *problemPtr_;
     }
 
+    /*!
+     * \brief Returns a reference to the problem.
+     */
+    Problem &problem_()
+    {
+        Valgrind::CheckDefined(problemPtr_);
+        return *problemPtr_;
+    }
+
     /*!
      * \brief Returns a reference to the grid view.
      */
@@ -413,15 +422,17 @@ protected:
         }
         else
         {
-            neighbor = fvElemGeom_.neighbors[col];
+            neighbor = fvElemGeom_().neighbors[col];
             neighborFVGeom.updateInner(neighbor);
             dofIdxGlobal = problemPtr_->elementMapper().index(neighbor);
         }
 
-        PrimaryVariables priVars(model_().curSol()[dofIdxGlobal]);
-        VolumeVariables origVolVars(curVolVars_[col]);
+        auto priVars = model_().curSol()[dofIdxGlobal];
+        // std::cout << "Copy old volVars: " << std::endl;
+        auto origVolVars = curVolVars_[col];
+        // std::cout << "...end copy old volVars." << std::endl;
 
-        curVolVars_[col].setEvalPoint(&origVolVars);
+        // curVolVars_[col].setEvalPoint(&origVolVars);
         Scalar eps = asImp_().numericEpsilon(col, pvIdx);
         Scalar delta = 0;
 
@@ -434,11 +445,12 @@ protected:
             delta += eps;
 
             // calculate the residual
+            // std::cout << "Compute forward-deflected residual: " << std::endl;
             if (isBox)
                 curVolVars_[col].update(priVars,
                                         problem_(),
                                         element_(),
-                                        fvElemGeom_,
+                                        fvElemGeom_(),
                                         col,
                                         false);
             else
@@ -450,10 +462,11 @@ protected:
                                         false);
 
             localResidual().eval(element_(),
-                                 fvElemGeom_,
+                                 fvElemGeom_(),
                                  prevVolVars_,
                                  curVolVars_,
                                  bcTypes_);
+            // std::cout << "...end compute forward-deflected residual." << std::endl;
 
             // store the residual and the storage term
             partialDeriv = localResidual().residual();
@@ -479,11 +492,12 @@ protected:
             delta += eps;
 
             // calculate residual again
+            // std::cout << "Compute backward-deflected residual: " << std::endl;
             if (isBox)
                 curVolVars_[col].update(priVars,
                                         problem_(),
                                         element_(),
-                                        fvElemGeom_,
+                                        fvElemGeom_(),
                                         col,
                                         false);
             else
@@ -495,10 +509,11 @@ protected:
                                         false);
 
             localResidual().eval(element_(),
-                                 fvElemGeom_,
+                                 fvElemGeom_(),
                                  prevVolVars_,
                                  curVolVars_,
                                  bcTypes_);
+            // std::cout << "...end compute backward-deflected residual." << std::endl;
             partialDeriv -= localResidual().residual();
             if (isBox || col == 0)
                 storageDeriv -= localResidual().storageTerm()[col];
@@ -518,7 +533,9 @@ protected:
         storageDeriv /= delta;
 
         // restore the original state of the element's volume variables
+        // std::cout << "Restore to orgininal volVars: " << std::endl;
         curVolVars_[col] = origVolVars;
+        // std::cout << "...end Restore to orgininal volVars." << std::endl << std::endl;
 
 #if HAVE_VALGRIND
         for (unsigned i = 0; i < partialDeriv.size(); ++i)
@@ -544,7 +561,7 @@ protected:
             }
         }
 
-        for (int i = 0; i < fvElemGeom_.numScv; i++)
+        for (int i = 0; i < fvElemGeom_().numScv; i++)
         {
             // Green vertices are not to be changed!
             if (!isBox || jacAsm_().vertexColor(element_(), i) != Green) {
@@ -558,11 +575,19 @@ protected:
                 }
             }
         }
+
+        // std::cout << std::endl << std::endl;
+        // Dune::printmatrix(std::cout, A_, "THE LOCAL JACOBIAN MATRIX", "");
+        // std::cout << std::endl << std::endl;
+
     }
 
-    const Element *elemPtr_;
-    FVElementGeometry fvElemGeom_;
+    const FVElementGeometry& fvElemGeom_() const
+    {
+        return model_().fvGeometries(problem_().elementMapper().index(element_()));
+    }
 
+    const Element *elemPtr_;
     ElementBoundaryTypes bcTypes_;
 
     // The problem we would like to solve
diff --git a/dumux/implicit/localresidual.hh b/dumux/implicit/localresidual.hh
index f48ca6355b1b4600f224a8bd43b80789c9f5cc70..98d9f3fe991ac6d6815476a298a3e7cc7b29aee4 100644
--- a/dumux/implicit/localresidual.hh
+++ b/dumux/implicit/localresidual.hh
@@ -85,14 +85,11 @@ public:
      */
     void eval(const Element &element)
     {
-        FVElementGeometry fvGeometry;
-
-        fvGeometry.update(gridView_(), element);
-        fvElemGeomPtr_ = &fvGeometry;
+        fvElemGeomPtr_ = &model_().fvGeometries(model_().elementMapper().index(element));
 
         ElementVolumeVariables volVarsPrev, volVarsCur;
         // update the hints
-        model_().setHints(element, volVarsPrev, volVarsCur);
+        // model_().setHints(element, volVarsPrev, volVarsCur);
 
         volVarsPrev.update(problem_(),
                            element,
@@ -121,10 +118,7 @@ public:
     void evalStorage(const Element &element)
     {
         elemPtr_ = &element;
-
-        FVElementGeometry fvGeometry;
-        fvGeometry.update(gridView_(), element);
-        fvElemGeomPtr_ = &fvGeometry;
+        fvElemGeomPtr_ = &model_().fvGeometries(model_().elementMapper().index(element));
 
         ElementBoundaryTypes bcTypes;
         bcTypes.update(problem_(), element, fvGeometry_());
@@ -136,7 +130,7 @@ public:
         ElementVolumeVariables volVars;
 
         // update the hints
-        model_().setHints(element, volVars);
+        // model_().setHints(element, volVars);
 
         // calculate volume current variables
         volVars.update(problem_(), element, fvGeometry_(), false);
@@ -157,10 +151,7 @@ public:
                     const ElementVolumeVariables &curVolVars)
     {
         elemPtr_ = &element;
-
-        FVElementGeometry fvGeometry;
-        fvGeometry.update(gridView_(), element);
-        fvElemGeomPtr_ = &fvGeometry;
+        fvElemGeomPtr_ = &model_().fvGeometries(model_().elementMapper().index(element));
 
         ElementBoundaryTypes bcTypes;
         bcTypes.update(problem_(), element, fvGeometry_());
@@ -424,6 +415,12 @@ protected:
     const Problem &problem_() const
     { return *problemPtr_; }
 
+    /*!
+     * \brief Returns a reference to the problem.
+     */
+    Problem &problem_()
+    { return *problemPtr_; }
+
     /*!
      * \brief Returns a reference to the model.
      */
diff --git a/dumux/implicit/model.hh b/dumux/implicit/model.hh
index 40b2d0cec6d2da4667bc65d77c0171a0e4789c3e..f1de5b9228972818167c9bced1c2ca24c0b2b2f6 100644
--- a/dumux/implicit/model.hh
+++ b/dumux/implicit/model.hh
@@ -84,7 +84,8 @@ public:
     ImplicitModel()
     : problemPtr_(0)
     {
-        enableHints_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableHints);
+        // enableHints_ = GET_PARAM_FROM_GROUP(TypeTag, bool, Implicit, EnableHints);
+        // std::cout << enableHints_ << std::endl;
     }
 
     /*!
@@ -101,7 +102,8 @@ public:
 
         int numDofs = asImp_().numDofs();
         uCur_.resize(numDofs);
-        uPrev_.resize(numDofs);
+        volVars_.resize(numDofs);
+        fvGeometries_.resize(numDofs);
         if (isBox)
             boxVolume_.resize(numDofs);
 
@@ -111,89 +113,102 @@ public:
 
         asImp_().applyInitialSolution_();
 
-        // resize the hint vectors
-        if (isBox && enableHints_) {
-            int numVertices = gridView_().size(dim);
-            curHints_.resize(numVertices);
-            prevHints_.resize(numVertices);
-            hintsUsable_.resize(numVertices);
-            std::fill(hintsUsable_.begin(),
-                      hintsUsable_.end(),
-                      false);
+        // update the volVars with the initial solution
+        for (const auto& element : elements(gridView_()))
+        {
+            int dofIdxGlobal = elementMapper().index(element);
+            volVars_[dofIdxGlobal].update(uCur_[dofIdxGlobal],
+                                               this->problem_(),
+                                               element,
+                                               fvGeometries_[dofIdxGlobal],
+                                               0,
+                                               false);
         }
 
+        // // resize the hint vectors
+        // if (isBox && enableHints_) {
+        //     int numVertices = gridView_().size(dim);
+        //     curHints_.resize(numVertices);
+        //     prevHints_.resize(numVertices);
+        //     hintsUsable_.resize(numVertices);
+        //     std::fill(hintsUsable_.begin(),
+        //               hintsUsable_.end(),
+        //               false);
+        // }
+
         // also set the solution of the "previous" time step to the
         // initial solution.
         uPrev_ = uCur_;
+        prevVolVars_ = volVars_;
     }
 
-    void setHints(const Element &element,
-                  ElementVolumeVariables &prevVolVars,
-                  ElementVolumeVariables &curVolVars) const
-    {
-        if (!isBox || !enableHints_)
-            return;
-
-        int n = element.subEntities(dim);
-        prevVolVars.resize(n);
-        curVolVars.resize(n);
-        for (int i = 0; i < n; ++i)
-        {
-            int vIdxGlobal = vertexMapper().subIndex(element, i, dim);
-
-            if (!hintsUsable_[vIdxGlobal]) {
-                curVolVars[i].setHint(NULL);
-                prevVolVars[i].setHint(NULL);
-            }
-            else {
-                curVolVars[i].setHint(&curHints_[vIdxGlobal]);
-                prevVolVars[i].setHint(&prevHints_[vIdxGlobal]);
-            }
-        }
-    }
-
-    void setHints(const Element &element,
-                  ElementVolumeVariables &curVolVars) const
-    {
-        if (!isBox || !enableHints_)
-            return;
-
-        int n = element.subEntities(dim);
-        curVolVars.resize(n);
-        for (int i = 0; i < n; ++i)
-        {
-            int vIdxGlobal = vertexMapper().subIndex(element, i, dim);
-
-            if (!hintsUsable_[vIdxGlobal])
-                curVolVars[i].setHint(NULL);
-            else
-                curVolVars[i].setHint(&curHints_[vIdxGlobal]);
-        }
-    }
-
-    void updatePrevHints()
-    {
-        if (!isBox || !enableHints_)
-            return;
-
-        prevHints_ = curHints_;
-    }
-
-    void updateCurHints(const Element &element,
-                        const ElementVolumeVariables &elemVolVars) const
-    {
-        if (!isBox || !enableHints_)
-            return;
-
-        for (unsigned int i = 0; i < elemVolVars.size(); ++i)
-        {
-            int vIdxGlobal = vertexMapper().subIndex(element, i, dim);
-            curHints_[vIdxGlobal] = elemVolVars[i];
-            if (!hintsUsable_[vIdxGlobal])
-                prevHints_[vIdxGlobal] = elemVolVars[i];
-            hintsUsable_[vIdxGlobal] = true;
-        }
-    }
+    // void setHints(const Element &element,
+    //               ElementVolumeVariables &prevVolVars,
+    //               ElementVolumeVariables &curVolVars) const
+    // {
+    //     if (!isBox || !enableHints_)
+    //         return;
+
+    //     int n = element.subEntities(dim);
+    //     prevVolVars_.resize(n);
+    //     curVolVars_.resize(n);
+    //     for (int i = 0; i < n; ++i)
+    //     {
+    //         int vIdxGlobal = vertexMapper().subIndex(element, i, dim);
+
+    //         if (!hintsUsable_[vIdxGlobal]) {
+    //             curVolVars[i].setHint(NULL);
+    //             prevVolVars[i].setHint(NULL);
+    //         }
+    //         else {
+    //             curVolVars[i].setHint(&curHints_[vIdxGlobal]);
+    //             prevVolVars[i].setHint(&prevHints_[vIdxGlobal]);
+    //         }
+    //     }
+    // }
+
+    // void setHints(const Element &element,
+    //               ElementVolumeVariables &curVolVars) const
+    // {
+    //     if (!isBox || !enableHints_)
+    //         return;
+
+    //     int n = element.subEntities(dim);
+    //     curVolVars.resize(n);
+    //     for (int i = 0; i < n; ++i)
+    //     {
+    //         int vIdxGlobal = vertexMapper().subIndex(element, i, dim);
+
+    //         if (!hintsUsable_[vIdxGlobal])
+    //             curVolVars[i].setHint(NULL);
+    //         else
+    //             curVolVars[i].setHint(&curHints_[vIdxGlobal]);
+    //     }
+    // }
+
+    // void updatePrevHints()
+    // {
+    //     if (!isBox || !enableHints_)
+    //         return;
+
+    //     prevHints_ = curHints_;
+    // }
+
+    // void updateCurHints(const Element &element,
+    //                     const ElementVolumeVariables &elemVolVars) const
+    // {
+    //     if (!isBox || !enableHints_)
+    //         return;
+
+    //     for (unsigned int i = 0; i < elemVolVars.size(); ++i)
+    //     {
+    //         int vIdxGlobal = vertexMapper().subIndex(element, i, dim);
+    //         curHints_[vIdxGlobal] = elemVolVars[i];
+    //         if (!hintsUsable_[vIdxGlobal])
+    //             prevHints_[vIdxGlobal] = elemVolVars[i];
+    //         hintsUsable_[vIdxGlobal] = true;
+    //     }
+    // }
 
 
     /*!
@@ -456,6 +471,7 @@ public:
         if(GET_PROP_VALUE(TypeTag, AdaptiveGrid) && problem_().gridAdapt().wasAdapted())
         {
             uPrev_ = uCur_;
+            prevVolVars_ = volVars_;
 
             updateBoundaryIndices_();
 
@@ -466,17 +482,19 @@ public:
 
             jacAsm_->init(problem_());
 
-            // resize the hint vectors
-            if (isBox && enableHints_) {
-                int numVertices = gridView_().size(dim);
-                curHints_.resize(numVertices);
-                prevHints_.resize(numVertices);
-                hintsUsable_.resize(numVertices);
-                std::fill(hintsUsable_.begin(),
-                          hintsUsable_.end(),
-                          false);
-            }
+            // // resize the hint vectors
+            // if (isBox && enableHints_) {
+            //     int numVertices = gridView_().size(dim);
+            //     curHints_.resize(numVertices);
+            //     prevHints_.resize(numVertices);
+            //     hintsUsable_.resize(numVertices);
+            //     std::fill(hintsUsable_.begin(),
+            //               hintsUsable_.end(),
+            //               false);
+            // }
+
         }
+
     }
 
 
@@ -488,6 +506,21 @@ public:
     void updateSuccessful()
     { }
 
+    void updateVolVars()
+    {
+        // update the volVars with the computed solution
+        for (const auto& element : Dune::elements(gridView_()))
+        {
+                int dofIdxGlobal = dofMapper().subIndex(element, 0, dofCodim);
+                this->volVars(dofIdxGlobal).update(curSol()[dofIdxGlobal],
+                                                   this->problem_(),
+                                                   element,
+                                                   fvGeometries_[dofIdxGlobal],
+                                                   0,
+                                                   false);
+        }
+    }
+
     /*!
      * \brief Called by the update() method if it was
      *        unsuccessful. This is primarily a hook which the actual
@@ -499,8 +532,9 @@ public:
         // previous time step so that we can start the next
         // update at a physically meaningful solution.
         uCur_ = uPrev_;
-        if (isBox)
-            curHints_ = prevHints_;
+        volVars_ = prevVolVars_;
+        // if (isBox)
+        //     curHints_ = prevHints_;
 
         jacAsm_->reassembleAll();
     }
@@ -516,10 +550,12 @@ public:
     {
         // make the current solution the previous one.
         uPrev_ = uCur_;
-        if (isBox)
-            prevHints_ = curHints_;
+        prevVolVars_ = volVars_;
+
+        // if (isBox)
+        //     prevHints_ = curHints_;
 
-        updatePrevHints();
+        // updatePrevHints();
     }
 
     /*!
@@ -846,6 +882,25 @@ public:
         VolumeVariables::completeFluidState(priVars, problem, element,
                                             fvGeometry, scvIdx, fluidState);
     }
+
+    const VolumeVariables& volVars(unsigned int dofIdxGlobal) const
+    { return volVars_[dofIdxGlobal]; }
+
+    VolumeVariables& volVars(unsigned int dofIdxGlobal)
+    { return volVars_[dofIdxGlobal]; }
+
+    const VolumeVariables& prevVolVars(unsigned int dofIdxGlobal) const
+    { return prevVolVars_[dofIdxGlobal]; }
+
+    VolumeVariables& prevVolVars(unsigned int dofIdxGlobal)
+    { return prevVolVars_[dofIdxGlobal]; }
+
+    const FVElementGeometry& fvGeometries(unsigned int dofIdxGlobal) const
+    { return fvGeometries_[dofIdxGlobal]; }
+
+    FVElementGeometry& fvGeometries(unsigned int dofIdxGlobal)
+    { return fvGeometries_[dofIdxGlobal]; }
+
 protected:
     /*!
      * \brief A reference to the problem on which the model is applied.
@@ -882,14 +937,13 @@ protected:
         uCur_ = Scalar(0.0);
         boxVolume_ = Scalar(0.0);
 
-        FVElementGeometry fvGeometry;
-
         // iterate through leaf grid and evaluate initial
         // condition at the center of each sub control volume
         for (const auto& element : elements(gridView_())) {
             // deal with the current element
-            fvGeometry.update(gridView_(), element);
-
+            int eIdx = elementMapper().index(element);
+            fvGeometries_[eIdx].update(gridView_(), element);
+            const auto& fvGeometry = fvGeometries_[eIdx];
             // loop over all element vertices, i.e. sub control volumes
             for (int scvIdx = 0; scvIdx < fvGeometry.numScv; scvIdx++)
             {
@@ -991,9 +1045,9 @@ protected:
 
     // the hint cache for the previous and the current volume
     // variables
-    mutable std::vector<bool> hintsUsable_;
-    mutable std::vector<VolumeVariables> curHints_;
-    mutable std::vector<VolumeVariables> prevHints_;
+    // mutable std::vector<bool> hintsUsable_;
+    // mutable std::vector<VolumeVariables> curHints_;
+    // mutable std::vector<VolumeVariables> prevHints_;
 
     // the problem we want to solve. defines the constitutive
     // relations, matxerial laws, etc.
@@ -1008,6 +1062,10 @@ protected:
     // the set of all indices of vertices on the boundary
     std::vector<bool> boundaryIndices_;
 
+    std::vector<VolumeVariables> volVars_;
+    std::vector<VolumeVariables> prevVolVars_;
+    std::vector<FVElementGeometry> fvGeometries_;
+
     // cur is the current iterative solution, prev the converged
     // solution of the previous time step
     SolutionVector uCur_;
@@ -1027,7 +1085,7 @@ private:
     const Implementation &asImp_() const
     { return *static_cast<const Implementation*>(this); }
 
-    bool enableHints_;
+    // bool enableHints_;
 };
 } // end namespace Dumux
 
diff --git a/dumux/implicit/volumevariables.hh b/dumux/implicit/volumevariables.hh
index 99789c2f7689071fe47bc0c37d343cc4b95650f7..d16e258963238472dd8004b6c1203019297f37d0 100644
--- a/dumux/implicit/volumevariables.hh
+++ b/dumux/implicit/volumevariables.hh
@@ -85,20 +85,20 @@ public:
         Valgrind::CheckDefined(evalPoint_);
     }
 
-    /*!
-     * \brief Returns the evaluation point used by the local jacobian.
-     *
-     * The evaluation point is only used by semi-smooth models.
-     */
-    const Implementation &evalPoint() const
-    { return (evalPoint_ == 0)?asImp_():*evalPoint_; }
-
-    /*!
-     * \brief Set the volume variables which should be used as initial
-     *        conditions for complex calculations.
-     */
-    void setHint(const Implementation *hint)
-    {}
+    // /*!
+    //  * \brief Returns the evaluation point used by the local jacobian.
+    //  *
+    //  * The evaluation point is only used by semi-smooth models.
+    //  */
+    // const Implementation &evalPoint() const
+    // { return (evalPoint_ == 0)?asImp_():*evalPoint_; }
+
+    // /*!
+    //  * \brief Set the volume variables which should be used as initial
+    //  *        conditions for complex calculations.
+    //  */
+    // void setHint(const Implementation *hint)
+    // {}
 
     /*!
      * \brief Update all quantities for a given control volume
diff --git a/dumux/nonlinear/newtoncontroller.hh b/dumux/nonlinear/newtoncontroller.hh
index 6f43f1b0fd2e456615b91efcbb107172158930d7..e4186aabea3005a0e0fe4c9e67383370ae892809 100644
--- a/dumux/nonlinear/newtoncontroller.hh
+++ b/dumux/nonlinear/newtoncontroller.hh
@@ -471,6 +471,8 @@ public:
             }
         }
 
+        this->model_().updateVolVars();
+
     }
 
     /*!
diff --git a/dumux/porousmediumflow/2p/implicit/model.hh b/dumux/porousmediumflow/2p/implicit/model.hh
index 5ea13e75476ec0f22cba24a769cf7ff2e334f09d..2af79e8a4697a0feadbcbb03df6e551a494ff1c4 100644
--- a/dumux/porousmediumflow/2p/implicit/model.hh
+++ b/dumux/porousmediumflow/2p/implicit/model.hh
@@ -155,19 +155,33 @@ public:
 
             for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx)
             {
-                int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim);
-
-                (*pw)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(wPhaseIdx);
-                (*pn)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(nPhaseIdx);
-                (*pc)[dofIdxGlobal] = elemVolVars[scvIdx].capillaryPressure();
-                (*sw)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(wPhaseIdx);
-                (*sn)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(nPhaseIdx);
-                (*rhoW)[dofIdxGlobal] = elemVolVars[scvIdx].density(wPhaseIdx);
-                (*rhoN)[dofIdxGlobal] = elemVolVars[scvIdx].density(nPhaseIdx);
-                (*mobW)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(wPhaseIdx);
-                (*mobN)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(nPhaseIdx);
-                (*poro)[dofIdxGlobal] = elemVolVars[scvIdx].porosity();
-                (*Te)[dofIdxGlobal] = elemVolVars[scvIdx].temperature();
+                int eIdx = this->elementMapper().index(element);
+
+                (*rank)[eIdx] = this->gridView_().comm().rank();
+
+                const auto& fvGeometry = this->fvGeometries(eIdx);
+                ElementVolumeVariables elemVolVars;
+                elemVolVars.update(this->problem_(),
+                                   element,
+                                   fvGeometry,
+                                   false /* oldSol? */);
+
+                for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx)
+                {
+                    int dofIdxGlobal = this->dofMapper().subIndex(element, scvIdx, dofCodim);
+
+                    (*pw)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(wPhaseIdx);
+                    (*pn)[dofIdxGlobal] = elemVolVars[scvIdx].pressure(nPhaseIdx);
+                    (*pc)[dofIdxGlobal] = elemVolVars[scvIdx].capillaryPressure();
+                    (*sw)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(wPhaseIdx);
+                    (*sn)[dofIdxGlobal] = elemVolVars[scvIdx].saturation(nPhaseIdx);
+                    (*rhoW)[dofIdxGlobal] = elemVolVars[scvIdx].density(wPhaseIdx);
+                    (*rhoN)[dofIdxGlobal] = elemVolVars[scvIdx].density(nPhaseIdx);
+                    (*mobW)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(wPhaseIdx);
+                    (*mobN)[dofIdxGlobal] = elemVolVars[scvIdx].mobility(nPhaseIdx);
+                    (*poro)[dofIdxGlobal] = elemVolVars[scvIdx].porosity();
+                    (*Te)[dofIdxGlobal] = elemVolVars[scvIdx].temperature();
+                }
             }
 
             // velocity output