diff --git a/dumux/common/properties.hh b/dumux/common/properties.hh
index def2fb54f87c219d8170bc2d5fe24a0b489c3980..95dbf79f5aef913114207e9686bae63fce6f134d 100644
--- a/dumux/common/properties.hh
+++ b/dumux/common/properties.hh
@@ -174,6 +174,11 @@ NEW_PROP_TAG(SetMoleFractionsForWettingPhase);     //!< Set the mole fraction in
 //////////////////////////////////////////////////////////////
 NEW_PROP_TAG(EnableWaterDiffusionInAir); //!< Property for turning Richards into extended Richards
 
+//////////////////////////////////////////////////////////////
+// Additional properties used by the 3pwateroil model:
+//////////////////////////////////////////////////////////////
+NEW_PROP_TAG(OnlyGasPhaseCanDisappear); //!< reduces the phasestates to threePhases and wnPhaseOnly
+
 /////////////////////////////////////////////////////////////
 // Properties used by the staggered-grid discretization method
 /////////////////////////////////////////////////////////////
diff --git a/dumux/porousmediumflow/3pwateroil/fluxvariables.hh b/dumux/porousmediumflow/3pwateroil/fluxvariables.hh
deleted file mode 100644
index 96a6bd3df740cc2c8007d0feaa2a5685f61fc0ca..0000000000000000000000000000000000000000
--- a/dumux/porousmediumflow/3pwateroil/fluxvariables.hh
+++ /dev/null
@@ -1,302 +0,0 @@
-// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-// vi: set et ts=4 sw=4 sts=4:
-/*****************************************************************************
- *   See the file COPYING for full copying permissions.                      *
- *                                                                           *
- *   This program is free software: you can redistribute it and/or modify    *
- *   it under the terms of the GNU General Public License as published by    *
- *   the Free Software Foundation, either version 2 of the License, or       *
- *   (at your option) any later version.                                     *
- *                                                                           *
- *   This program is distributed in the hope that it will be useful,         *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
- *   GNU General Public License for more details.                            *
- *                                                                           *
- *   You should have received a copy of the GNU General Public License       *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
- *****************************************************************************/
-/*!
- * \file
- * \brief   This file contains the data which is required to calculate
- *          all fluxes of components over a face of a finite volume for
- *          the three-phase, two-component model.
- */
-#ifndef DUMUX_3P2CNI_FLUX_VARIABLES_HH
-#define DUMUX_3P2CNI_FLUX_VARIABLES_HH
-
-#include <dumux/common/math.hh>
-#include <dumux/common/spline.hh>
-
-#include "properties.hh"
-
-namespace Dumux
-{
-
-/*!
- * \ingroup ThreePWaterOilModel
- * \ingroup ImplicitFluxVariables
- * \brief This template class contains the data which is required to
- *        calculate all fluxes of components over a face of a finite
- *        volume for the three-phase, two-component model.
- *
- * This means pressure and concentration gradients, phase densities at
- * the integration point, etc.
- */
-template <class TypeTag>
-class ThreePWaterOilFluxVariables : public GET_PROP_TYPE(TypeTag, BaseFluxVariables)
-{
-    friend typename GET_PROP_TYPE(TypeTag, BaseFluxVariables); // be friends with base class
-    using BaseFluxVariables = typename GET_PROP_TYPE(TypeTag, BaseFluxVariables);
-    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-
-    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
-    using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
-    using EffectiveDiffusivityModel = typename GET_PROP_TYPE(TypeTag, EffectiveDiffusivityModel);
-
-    using Element = typename GridView::template Codim<0>::Entity;
-    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
-
-    enum {
-        dim = GridView::dimension,
-        dimWorld = GridView::dimensionworld,
-        numPhases = GET_PROP_VALUE(TypeTag, NumPhases),
-        numComponents = GET_PROP_VALUE(TypeTag, NumComponents)
-    };
-
-    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
-    using SpatialParams = typename GET_PROP_TYPE(TypeTag, SpatialParams);
-    using SCVFace = typename FVElementGeometry::SubControlVolumeFace;
-
-    using DimVector = Dune::FieldVector<Scalar, dim>;
-    using DimMatrix = Dune::FieldMatrix<Scalar, dim, dim>;
-
-    using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
-    enum {
-        wPhaseIdx = Indices::wPhaseIdx,
-        nPhaseIdx = Indices::nPhaseIdx,
-        gPhaseIdx = Indices::gPhaseIdx,
-
-        wCompIdx = Indices::wCompIdx,
-        nCompIdx = Indices::nCompIdx,
-    };
-
-public:
-    /*!
-     * \brief Compute / update the flux variables
-     *
-     * \param problem The problem
-     * \param element The finite element
-     * \param fvGeometry The finite-volume geometry
-     * \param fIdx The local index of the SCV (sub-control-volume) face
-     * \param elemVolVars The volume variables of the current element
-     * \param onBoundary A boolean variable to specify whether the flux variables
-     * are calculated for interior SCV faces or boundary faces, default=false
-     */
-    void update(const Problem &problem,
-                const Element &element,
-                const FVElementGeometry &fvGeometry,
-                const int fIdx,
-                const ElementVolumeVariables &elemVolVars,
-                const bool onBoundary = false)
-    {
-        BaseFluxVariables::update(problem, element, fvGeometry, fIdx, elemVolVars, onBoundary);
-        calculatePorousDiffCoeff_(problem, element, elemVolVars);
-    }
-
-private:
-    void calculateGradients_(const Problem &problem,
-                             const Element &element,
-                             const ElementVolumeVariables &elemVolVars)
-    {
-        // initialize to zero
-        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
-            density_[phaseIdx] = Scalar(0);
-            molarDensity_[phaseIdx] = Scalar(0);
-            massFractionCompWGrad_[phaseIdx] = Scalar(0);
-            massFractionCompNGrad_[phaseIdx] = Scalar(0);
-            moleFractionCompWGrad_[phaseIdx] = Scalar(0);
-            moleFractionCompNGrad_[phaseIdx] = Scalar(0);
-        }
-
-        BaseFluxVariables::calculateGradients_(problem, element, elemVolVars);
-
-        // calculate gradients
-        DimVector tmp(0.0);
-        for (int idx = 0; idx < this->face().numFap; idx++) // loop over adjacent vertices
-        {
-            // FE gradient at vertex idx
-            const DimVector &feGrad = this->face().grad[idx];
-
-            // index for the element volume variables
-            int volVarsIdx = this->face().fapIndices[idx];
-
-            // the concentration gradient of the components
-            // component in the phases
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().massFraction(wPhaseIdx, wCompIdx);
-            massFractionCompWGrad_[wPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().massFraction(nPhaseIdx, wCompIdx);
-            massFractionCompWGrad_[nPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().massFraction(gPhaseIdx, wCompIdx);
-            massFractionCompWGrad_[gPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().massFraction(wPhaseIdx, nCompIdx);
-            massFractionCompNGrad_[wPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().massFraction(nPhaseIdx, nCompIdx);
-            massFractionCompNGrad_[nPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().massFraction(gPhaseIdx, nCompIdx);
-            massFractionCompNGrad_[gPhaseIdx] += tmp;
-
-            // the molar concentration gradients of the components
-            // in the phases
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().moleFraction(wPhaseIdx, wCompIdx);
-            moleFractionCompWGrad_[wPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().moleFraction(nPhaseIdx, wCompIdx);
-            moleFractionCompWGrad_[nPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().moleFraction(gPhaseIdx, wCompIdx);
-            moleFractionCompWGrad_[gPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().moleFraction(wPhaseIdx, nCompIdx);
-            moleFractionCompNGrad_[wPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().moleFraction(nPhaseIdx, nCompIdx);
-            moleFractionCompNGrad_[nPhaseIdx] += tmp;
-
-            tmp = feGrad;
-            tmp *= elemVolVars[volVarsIdx].fluidState().moleFraction(gPhaseIdx, nCompIdx);
-            moleFractionCompNGrad_[gPhaseIdx] += tmp;
-
-        }
-        // calculate temperature gradient using finite element
-        // gradients
-        DimVector temperatureGrad(0);
-        for (int idx = 0; idx < this->face().numFap; idx++)
-        {
-            tmp = this->face().grad[idx];
-
-            // index for the element volume variables
-            int volVarsIdx = this->face().fapIndices[idx];
-
-            tmp *= elemVolVars[volVarsIdx].temperature();
-            temperatureGrad += tmp;
-        }
-    }
-
-    void calculatePorousDiffCoeff_(const Problem &problem,
-                                   const Element &element,
-                                   const ElementVolumeVariables &elemVolVars)
-    {
-
-        const VolumeVariables &volVarsI = elemVolVars[this->face().i];
-        const VolumeVariables &volVarsJ = elemVolVars[this->face().j];
-
-        // the effective diffusion coefficients at vertex i and j
-        Scalar diffCoeffI;
-        Scalar diffCoeffJ;
-
-
-        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
-        {
-            // make sure to calculate only diffusion coefficients
-            // for phases which exist in both finite volumes
-            /* \todo take care: This should be discussed once again
-             * as long as a meaningful value can be found for the required mole fraction
-             * diffusion should work even without this one here */
-            if (volVarsI.saturation(phaseIdx) <= 0 ||
-                volVarsJ.saturation(phaseIdx) <= 0)
-            {
-                porousDiffCoeff_[phaseIdx] = 0.0;
-            }
-            else
-            {
-
-                diffCoeffI = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsI.porosity(),
-                                                                             volVarsI.saturation(phaseIdx),
-                                                                             volVarsI.diffCoeff(phaseIdx));
-
-                diffCoeffJ = EffectiveDiffusivityModel::effectiveDiffusivity(volVarsJ.porosity(),
-                                                                             volVarsJ.saturation(phaseIdx),
-                                                                             volVarsJ.diffCoeff(phaseIdx));
-
-                porousDiffCoeff_[phaseIdx] = harmonicMean(diffCoeffI, diffCoeffJ);
-            }
-        }
-    }
-
-public:
-    /*!
-     * \brief The binary diffusion coefficient for each fluid phase.
-     *
-     *   \param phaseIdx The phase index
-     */
-    DUNE_DEPRECATED_MSG("porousDiffCoeff() is deprecated. Use porousDiffCoeff(phaseIdx) instead.")
-    Dune::FieldVector<Scalar, numPhases> porousDiffCoeff() const
-    { return porousDiffCoeff_; };
-
-    /*!
-     * \brief The binary diffusion coefficient for each fluid phase.
-     *
-     *   \param phaseIdx The phase index
-     */
-    Scalar porousDiffCoeff(int phaseIdx) const
-    { return porousDiffCoeff_[phaseIdx];}
-
-    /*!
-     * \brief Return density \f$\mathrm{[kg/m^3]}\f$ of a phase.
-     */
-    Scalar density(int phaseIdx) const
-    { return density_[phaseIdx]; }
-
-    /*!
-     * \brief Return molar density \f$\mathrm{[mol/m^3]}\f$ of a phase.
-     */
-    Scalar molarDensity(int phaseIdx) const
-    { return molarDensity_[phaseIdx]; }
-
-    const DimVector &massFractionCompWGrad(int phaseIdx) const
-    {return massFractionCompWGrad_[phaseIdx];}
-
-    const DimVector &massFractionCompNGrad(int phaseIdx) const
-    { return massFractionCompNGrad_[phaseIdx]; };
-
-    const DimVector &moleFractionCompWGrad(int phaseIdx) const
-    { return moleFractionCompWGrad_[phaseIdx]; };
-
-    const DimVector &moleFractionCompNGrad(int phaseIdx) const
-    { return moleFractionCompNGrad_[phaseIdx]; };
-
-protected:
-    // gradients
-    DimVector massFractionCompWGrad_[numPhases];
-    DimVector massFractionCompNGrad_[numPhases];
-    DimVector moleFractionCompWGrad_[numPhases];
-    DimVector moleFractionCompNGrad_[numPhases];
-
-    // density of each face at the integration point
-    Scalar density_[numPhases], molarDensity_[numPhases];
-
-    // the diffusivity matrix for the porous medium
-    Dune::FieldVector<Scalar, numPhases> porousDiffCoeff_;
-};
-
-} // end namespace Dumux
-
-#endif
diff --git a/dumux/porousmediumflow/3pwateroil/indices.hh b/dumux/porousmediumflow/3pwateroil/indices.hh
index 3ac1b47ae70dc74cf6cc166d2580e5b3d3d97159..52541a3205ba01e39c131a2ab268d5f5bb7dea36 100644
--- a/dumux/porousmediumflow/3pwateroil/indices.hh
+++ b/dumux/porousmediumflow/3pwateroil/indices.hh
@@ -18,19 +18,18 @@
  *****************************************************************************/
 /*!
  * \file
+ * \ingroup ThreePWaterOilModel
  * \brief Defines the indices required for the 3p2cni model.
  */
 #ifndef DUMUX_3P2CNI_INDICES_HH
 #define DUMUX_3P2CNI_INDICES_HH
 
-#include "properties.hh"
-
+#include <dumux/common/properties.hh>
 namespace Dumux
 {
 
 /*!
  * \ingroup ThreePWaterOilModel
- * \ingroup ImplicitIndices
  * \brief The indices for the isothermal 3p2cni model.
  *
  * \tparam formulation The formulation, only pgSwSn
diff --git a/dumux/porousmediumflow/3pwateroil/localresidual.hh b/dumux/porousmediumflow/3pwateroil/localresidual.hh
index 8aeea475c83e558acdfa18599aa31ffdad3b7ed9..4bb312fd7890e2431b25ff0b0980ad98afafdd59 100644
--- a/dumux/porousmediumflow/3pwateroil/localresidual.hh
+++ b/dumux/porousmediumflow/3pwateroil/localresidual.hh
@@ -18,38 +18,47 @@
  *****************************************************************************/
 /*!
  * \file
- *
+ * \ingroup ThreePWaterOilModel
  * \brief Element-wise calculation of the Jacobian matrix for problems
  *        using the three-phase three-component fully implicit model.
  */
 #ifndef DUMUX_3P2CNI_LOCAL_RESIDUAL_HH
 #define DUMUX_3P2CNI_LOCAL_RESIDUAL_HH
 
-#include "properties.hh"
+#include <dumux/common/properties.hh>
 #include <dumux/porousmediumflow/3p3c/localresidual.hh>
 
 namespace Dumux
 {
 /*!
  * \ingroup ThreePWaterOilModel
- * \ingroup ImplicitLocalResidual
- * \brief Element-wise calculation of the Jacobian matrix for problems
- *        using the three-phase three-component fully implicit model.
+ * \brief Element-wise calculation of the local residual for problems
+ *        using the ThreePWaterOil fully implicit model.
  *
- * This class is used to fill the gaps in BoxLocalResidual for the 3P2C flow.
+ * This class is used to fill the gaps in the CompositionalLocalResidual for the 3PWaterOil flow.
  */
 template<class TypeTag>
 class ThreePWaterOilLocalResidual: public ThreePThreeCLocalResidual<TypeTag>
 {
 protected:
+    using ParentType = ThreePThreeCLocalResidual<TypeTag>;
     using Implementation = typename GET_PROP_TYPE(TypeTag, LocalResidual);
-
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
     using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
     using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
+    using ResidualVector = typename GET_PROP_TYPE(TypeTag, NumEqVector);
+    using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables);
+    using ElementFluxVariablesCache = typename GET_PROP_TYPE(TypeTag, ElementFluxVariablesCache);
     using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
-
+    using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
     using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
-    using ElementBoundaryTypes = typename GET_PROP_TYPE(TypeTag, ElementBoundaryTypes);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using Element = typename GridView::template Codim<0>::Entity;
+    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
+    using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
+    using EnergyLocalResidual = typename GET_PROP_TYPE(TypeTag, EnergyLocalResidual);
 
 
     enum {
@@ -67,127 +76,128 @@ protected:
         nCompIdx = Indices::nCompIdx,
     };
 
-    using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
-    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
-    using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables);
-
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-    using Element = typename GridView::template Codim<0>::Entity;
-
     //! property that defines whether mole or mass fractions are used
     static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles);
 public:
+    using ParentType::ParentType;
 
     /*!
-     * \brief Evaluate the storage term of the current solution in a
-     *        single phase.
+     * \brief Evaluate the amount of all conservation quantities
+     *        (e.g. phase mass) within a sub-control volume.
      *
-     * \param element The element
-     * \param phaseIdx The index of the fluid phase
+     * The result should be averaged over the volume (e.g. phase mass
+     * inside a sub control volume divided by the volume)
+     *
+     *  \param storage The mass of the component within the sub-control volume
+     *  \param scvIdx The SCV (sub-control-volume) index
+     *  \param usePrevSol Evaluate function with solution of current or previous time step
      */
-    void evalPhaseStorage(const Element &element, const int phaseIdx)
+     ResidualVector computeStorage(const Problem& problem,
+                                  const SubControlVolume& scv,
+                                  const VolumeVariables& volVars) const
     {
-        FVElementGeometry fvGeometry;
-        fvGeometry.update(this->gridView_(), element);
-        ElementBoundaryTypes bcTypes;
-        bcTypes.update(this->problem_(), element, fvGeometry);
-        ElementVolumeVariables elemVolVars;
-        elemVolVars.update(this->problem_(), element, fvGeometry, false);
-
-        this->storageTerm_.resize(fvGeometry.numScv);
-        this->storageTerm_ = 0;
-
-        this->elemPtr_ = &element;
-        this->fvElemGeomPtr_ = &fvGeometry;
-        this->bcTypesPtr_ = &bcTypes;
-        this->prevVolVarsPtr_ = 0;
-        this->curVolVarsPtr_ = &elemVolVars;
-        evalPhaseStorage_(phaseIdx);
+        ResidualVector storage(0.0);
+
+        const auto massOrMoleDensity = [](const auto& volVars, const int phaseIdx)
+        { return useMoles ? volVars.molarDensity(phaseIdx) : volVars.density(phaseIdx); };
+
+        const auto massOrMoleFraction= [](const auto& volVars, const int phaseIdx, const int compIdx)
+        { return useMoles ? volVars.moleFraction(phaseIdx, compIdx) : volVars.massFraction(phaseIdx, compIdx); };
+
+        // compute storage term of all components within all phases
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+        {
+            for (int compIdx = 0; compIdx < numComponents; ++compIdx)
+            {
+                    int eqIdx = (compIdx == wCompIdx) ? conti0EqIdx : conti1EqIdx;
+                    storage[eqIdx] += volVars.porosity()
+                                      * volVars.saturation(phaseIdx)
+                                      * massOrMoleDensity(volVars, phaseIdx)
+                                      * massOrMoleFraction(volVars, phaseIdx, compIdx);
+            }
+
+            //! The energy storage in the fluid phase with index phaseIdx
+            EnergyLocalResidual::fluidPhaseStorage(storage, scv, volVars, phaseIdx);
+        }
+
+        //! The energy storage in the solid matrix
+        EnergyLocalResidual::solidPhaseStorage(storage, scv, volVars);
+
+        return storage;
     }
 
-    /*!
-     * \brief Adds the diffusive mass flux of all components over
-     *        a face of a subcontrol volume.
+     /*!
+     * \brief Evaluates the total flux of all conservation quantities
+     *        over a face of a sub-control volume.
      *
-     * \param flux The diffusive flux over the sub-control-volume face for each component
-     * \param fluxVars The flux variables at the current SCV
+     * \param flux The flux over the SCV (sub-control-volume) face for each component
+     * \param fIdx The index of the SCV face
+     * \param onBoundary A boolean variable to specify whether the flux variables
+     *        are calculated for interior SCV faces or boundary faces, default=false
      */
-
-    void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const
+    ResidualVector computeFlux(const Problem& problem,
+                               const Element& element,
+                               const FVElementGeometry& fvGeometry,
+                               const ElementVolumeVariables& elemVolVars,
+                               const SubControlVolumeFace& scvf,
+                               const ElementFluxVariablesCache& elemFluxVarsCache) const
     {
-        // TODO: reference!?  Dune::FieldMatrix<Scalar, numPhases, numComponents> averagedPorousDiffCoeffMatrix = fluxVars.porousDiffCoeff();
-        // add diffusive flux of gas component in liquid phase
-        Scalar tmp;
-        tmp = - fluxVars.porousDiffCoeff(wPhaseIdx) * fluxVars.molarDensity(wPhaseIdx);
-        tmp *= (fluxVars.moleFractionCompNGrad(wPhaseIdx) * fluxVars.face().normal);
-        Scalar jNW = tmp;
+        FluxVariables fluxVars;
+        fluxVars.init(problem, element, fvGeometry, elemVolVars, scvf, elemFluxVarsCache);
+
+        // get upwind weights into local scope
+        ResidualVector flux(0.0);
+
+        const auto massOrMoleDensity = [](const auto& volVars, const int phaseIdx)
+        { return useMoles ? volVars.molarDensity(phaseIdx) : volVars.density(phaseIdx); };
+
+        const auto massOrMoleFraction= [](const auto& volVars, const int phaseIdx, const int compIdx)
+        { return useMoles ? volVars.moleFraction(phaseIdx, compIdx) : volVars.massFraction(phaseIdx, compIdx); };
 
-        Scalar jWW = -jNW;
+        // advective fluxes
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+        {
+            for (int compIdx = 0; compIdx < numComponents; ++compIdx)
+            {
+                 const auto upwindTerm = [&massOrMoleDensity, &massOrMoleFraction, phaseIdx, compIdx] (const auto& volVars)
+                { return massOrMoleDensity(volVars, phaseIdx)*massOrMoleFraction(volVars, phaseIdx, compIdx)*volVars.mobility(phaseIdx); };
+
+                // get equation index
+                auto eqIdx = conti0EqIdx + compIdx;
+                flux[eqIdx] += fluxVars.advectiveFlux(phaseIdx, upwindTerm);
+            }
+
+            //! Add advective phase energy fluxes. For isothermal model the contribution is zero.
+            EnergyLocalResidual::heatConvectionFlux(flux, fluxVars, phaseIdx);
+        }
 
-        tmp = - fluxVars.porousDiffCoeff(gPhaseIdx) * fluxVars.molarDensity(gPhaseIdx);
-        tmp *= (fluxVars.moleFractionCompWGrad(gPhaseIdx) * fluxVars.face().normal);
-        Scalar jWG = tmp;
+        //! Add diffusive energy fluxes. For isothermal model the contribution is zero.
+        EnergyLocalResidual::heatConductionFlux(flux, fluxVars);
 
-        Scalar jNG = -jWG;
+        const auto diffusionFluxesWPhase = fluxVars.molecularDiffusionFlux(wPhaseIdx);
 
-        tmp = - fluxVars.porousDiffCoeff(nPhaseIdx) * fluxVars.molarDensity(nPhaseIdx);
-        tmp *= (fluxVars.moleFractionCompWGrad(nPhaseIdx) * fluxVars.face().normal);
-        Scalar jWN = tmp;
+        // diffusive fluxes
+        Scalar jNW =  diffusionFluxesWPhase[nCompIdx];
+        Scalar jWW = -(jNW);
 
+        const auto diffusionFluxesGPhase = fluxVars.molecularDiffusionFlux(gPhaseIdx);
+
+        Scalar jWG = diffusionFluxesGPhase[wCompIdx];
+        Scalar jNG = -(jWG);
+
+        const auto diffusionFluxesNPhase = fluxVars.molecularDiffusionFlux(nPhaseIdx);
+        // At the moment we do not consider diffusion in the NAPL phase
+        Scalar jWN = diffusionFluxesNPhase[wCompIdx];
         Scalar jNN = -jWN;
 
         flux[conti0EqIdx] += jWW+jWG+jWN;
         flux[conti1EqIdx] += jNW+jNG+jNN;
-    }
 
-protected:
-    void evalPhaseStorage_(const int phaseIdx)
-    {
-        if(!useMoles) //mass-fraction formulation
-        {
-            // evaluate the storage terms of a single phase
-            for (int i=0; i < this->fvGeometry_().numScv; i++) {
-                PrimaryVariables &storage = this->storageTerm_[i];
-                const ElementVolumeVariables &elemVolVars = this->curVolVars_();
-                const VolumeVariables &volVars = elemVolVars[i];
-
-                // compute storage term of all components within all phases
-                storage = 0;
-                for (int compIdx = 0; compIdx < numComponents; ++compIdx)
-                {
-                    int eqIdx = (compIdx == wCompIdx) ? conti0EqIdx : conti1EqIdx;
-                    storage[eqIdx] += volVars.density(phaseIdx)
-                        * volVars.saturation(phaseIdx)
-                        * volVars.fluidState().massFraction(phaseIdx, compIdx);
-                }
+        return flux;
+    }
 
-                storage *= volVars.porosity();
-                storage *= this->fvGeometry_().subContVol[i].volume;
-            }
-        }
-        else //mole-fraction formulation
-        {
-            // evaluate the storage terms of a single phase
-            for (int i=0; i < this->fvGeometry_().numScv; i++) {
-                PrimaryVariables &storage = this->storageTerm_[i];
-                const ElementVolumeVariables &elemVolVars = this->curVolVars_();
-                const VolumeVariables &volVars = elemVolVars[i];
-
-                // compute storage term of all components within all phases
-                storage = 0;
-                for (int compIdx = 0; compIdx < numComponents; ++compIdx)
-                {
-                    int eqIdx = (compIdx == wCompIdx) ? conti0EqIdx : conti1EqIdx;
-                    storage[eqIdx] += volVars.molarDensity(phaseIdx)
-                        * volVars.saturation(phaseIdx)
-                        * volVars.fluidState().moleFraction(phaseIdx, compIdx);
-                }
 
-                storage *= volVars.porosity();
-                storage *= this->fvGeometry_().subContVol[i].volume;
-            }
-        }
-    }
+protected:
     Implementation *asImp_()
     {
         return static_cast<Implementation *> (this);
diff --git a/dumux/porousmediumflow/3pwateroil/model.hh b/dumux/porousmediumflow/3pwateroil/model.hh
index bbde1e52f266d3772bfda8bbac406dd9dfe93ad0..0506938e8876fecf6420394cbc39591a04281179 100644
--- a/dumux/porousmediumflow/3pwateroil/model.hh
+++ b/dumux/porousmediumflow/3pwateroil/model.hh
@@ -18,23 +18,11 @@
  *****************************************************************************/
 /*!
  * \file
- *
+ * \ingroup ThreePWaterOilModel
  * \brief Adaption of the fully implicit scheme to the three-phase three-component flow model.
  *
  * The model is designed for simulating three fluid phases with water, gas, and
  * a liquid contaminant (NAPL - non-aqueous phase liquid)
- */
-#ifndef DUMUX_3PWATEROIL_MODEL_HH
-#define DUMUX_3PWATEROIL_MODEL_HH
-
-#include "properties.hh"
-
-namespace Dumux
-{
-/*!
- * \ingroup ThreePWaterOilModel
- * \brief Adaption of the fully implicit scheme to the three-phase two-component flow model.
- *
  * This model implements three-phase two-component flow of three fluid phases
  * \f$\alpha \in \{ water, gas, NAPL \}\f$ each composed of up to two components
  * \f$\kappa \in \{ water, contaminant \}\f$. The standard multiphase Darcy
@@ -79,996 +67,161 @@ namespace Dumux
  *  <li> ... to be completed ... </li>
  * </ul>
  */
-template<class TypeTag>
-class ThreePWaterOilModel: public GET_PROP_TYPE(TypeTag, BaseModel)
-{
-    using ParentType = typename GET_PROP_TYPE(TypeTag, BaseModel);
-
-    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
-    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-
-    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
-    using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
-    using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
-    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
-    using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
-    using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
-
-    enum {
-        dim = GridView::dimension,
-        dimWorld = GridView::dimensionworld,
-
-        numPhases = GET_PROP_VALUE(TypeTag, NumPhases),
-        numComponents = GET_PROP_VALUE(TypeTag, NumComponents),
-
-        pressureIdx = Indices::pressureIdx,
-        switch1Idx = Indices::switch1Idx,
-        switch2Idx = Indices::switch2Idx,
-
-
-        wPhaseIdx = Indices::wPhaseIdx,
-        nPhaseIdx = Indices::nPhaseIdx,
-        gPhaseIdx = Indices::gPhaseIdx,
-
-        wCompIdx = Indices::wCompIdx,
-        nCompIdx = Indices::nCompIdx,
-
-        threePhases = Indices::threePhases,
-        wPhaseOnly  = Indices::wPhaseOnly,
-        gnPhaseOnly = Indices::gnPhaseOnly,
-        wnPhaseOnly = Indices::wnPhaseOnly,
-        gPhaseOnly  = Indices::gPhaseOnly,
-        wgPhaseOnly = Indices::wgPhaseOnly
-
-    };
-
-
-    using Vertex = typename GridView::template Codim<dim>::Entity;
-    using Element = typename GridView::template Codim<0>::Entity;
-
-    using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
-
-    static const bool useMoles = GET_PROP_VALUE(TypeTag, UseMoles);
-
-
-    enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) };
-    enum { dofCodim = isBox ? dim : 0 };
-
-public:
-    /*!
-     * \brief Initialize the static data with the initial solution.
-     *
-     * \param problem The problem to be solved
-     */
-    void init(Problem &problem)
-    {
-        ParentType::init(problem);
-
-        staticDat_.resize(this->numDofs());
-
-        setSwitched_(false);
-
-        if (isBox)
-        {
-            for (const auto& vertex : vertices(this->gridView_()))
-            {
-                int globalIdx = this->dofMapper().index(vertex);
-                const GlobalPosition &globalPos = vertex.geometry().corner(0);
-
-                // initialize phase presence
-                staticDat_[globalIdx].phasePresence
-                    = this->problem_().initialPhasePresence(vertex, globalIdx,
-                                                        globalPos);
-                staticDat_[globalIdx].wasSwitched = false;
-
-                staticDat_[globalIdx].oldPhasePresence
-                    = staticDat_[globalIdx].phasePresence;
-            }
-        }
-        else
-        {
-            for (const auto& element : elements(this->gridView_()))
-            {
-                int globalIdx = this->dofMapper().index(element);
-                const GlobalPosition &globalPos = element.geometry().center();
-
-                // initialize phase presence
-                staticDat_[globalIdx].phasePresence
-                    = this->problem_().initialPhasePresence(*this->gridView_().template begin<dim> (),
-                                                            globalIdx, globalPos);
-                staticDat_[globalIdx].wasSwitched = false;
-
-                staticDat_[globalIdx].oldPhasePresence
-                    = staticDat_[globalIdx].phasePresence;
-            }
-        }
-    }
-
-    /*!
-     * \brief Compute the total storage inside one phase of all
-     *        conservation quantities.
-     *
-     * \param storage Contains the storage of each component for one phase
-     * \param phaseIdx The phase index
-     */
-    void globalPhaseStorage(PrimaryVariables &storage, const int phaseIdx)
-    {
-        storage = 0;
-
-        for (const auto& element : elements(this->gridView_(), Dune::Partitions::interior))
-        {
-            this->localResidual().evalPhaseStorage(element, phaseIdx);
-
-            for (unsigned int i = 0; i < this->localResidual().storageTerm().size(); ++i)
-                storage += this->localResidual().storageTerm()[i];
-        }
-        if (this->gridView_().comm().size() > 1)
-            storage = this->gridView_().comm().sum(storage);
-    }
-
-
-    /*!
-     * \brief Called by the update() method if applying the newton
-     *         method was unsuccessful.
-     */
-    void updateFailed()
-    {
-        ParentType::updateFailed();
-
-        setSwitched_(false);
-        resetPhasePresence_();
-    };
-
-    /*!
-     * \brief Called by the problem if a time integration was
-     *        successful, post processing of the solution is done and the
-     *        result has been written to disk.
-     *
-     * This should prepare the model for the next time integration.
-     */
-    void advanceTimeLevel()
-    {
-        ParentType::advanceTimeLevel();
-
-        // update the phase state
-        updateOldPhasePresence_();
-        setSwitched_(false);
-    }
-
-    /*!
-     * \brief Return true if the primary variables were switched for
-     *        at least one vertex after the last timestep.
-     */
-    bool switched() const
-    {
-        return switchFlag_;
-    }
-
-    /*!
-     * \brief Returns the phase presence of the current or the old solution of a degree of freedom.
-     *
-     * \param globalIdx The global index of the degree of freedom
-     * \param oldSol Evaluate function with solution of current or previous time step
-     */
-    int phasePresence(int globalIdx, bool oldSol) const
-    {
-        return
-            oldSol
-            ? staticDat_[globalIdx].oldPhasePresence
-            : staticDat_[globalIdx].phasePresence;
-    }
-
-    /*!
-     * \brief Append all quantities of interest which can be derived
-     *        from the solution of the current time step to the VTK
-     *        writer.
-     *
-     * \param sol The solution vector
-     * \param writer The writer for multi-file VTK datasets
-     */
-    template<class MultiWriter>
-    void addOutputVtkFields(const SolutionVector &sol,
-                            MultiWriter &writer)
-    {
-        using ScalarField = Dune::BlockVector< Dune::FieldVector<double, 1> >;
-        using VectorField = Dune::BlockVector<Dune::FieldVector<double, dim> >;
-
-        // get the number of degrees of freedom
-        unsigned numDofs = this->numDofs();
-
-        // create the required scalar fields
-        ScalarField *saturation[numPhases];
-        ScalarField *pressure[numPhases];
-        ScalarField *density[numPhases];
-
-        ScalarField *mobility[numPhases];
-        ScalarField *viscosity[numPhases];
-
-
-        for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
-            saturation[phaseIdx] = writer.allocateManagedBuffer(numDofs);
-            pressure[phaseIdx] = writer.allocateManagedBuffer(numDofs);
-            density[phaseIdx] = writer.allocateManagedBuffer(numDofs);
-
-            mobility[phaseIdx] = writer.allocateManagedBuffer(numDofs);
-            viscosity[phaseIdx] = writer.allocateManagedBuffer(numDofs);
-        }
-
-        ScalarField *phasePresence = writer.allocateManagedBuffer (numDofs);
-        ScalarField *moleFraction[numPhases][numComponents];
-        for (int i = 0; i < numPhases; ++i)
-            for (int j = 0; j < numComponents; ++j)
-                moleFraction[i][j] = writer.allocateManagedBuffer (numDofs);
-        ScalarField *temperature = writer.allocateManagedBuffer (numDofs);
-        ScalarField *poro = writer.allocateManagedBuffer(numDofs);
-        ScalarField *perm = writer.allocateManagedBuffer(numDofs);
-        VectorField *velocityN = writer.template allocateManagedBuffer<double, dim>(numDofs);
-        VectorField *velocityW = writer.template allocateManagedBuffer<double, dim>(numDofs);
-        VectorField *velocityG = writer.template allocateManagedBuffer<double, dim>(numDofs);
-        ImplicitVelocityOutput<TypeTag> velocityOutput(this->problem_());
-
-        if (velocityOutput.enableOutput()) // check if velocity output is demanded
-        {
-            // initialize velocity fields
-            for (unsigned int i = 0; i < numDofs; ++i)
-            {
-                (*velocityN)[i] = Scalar(0);
-                (*velocityW)[i] = Scalar(0);
-                (*velocityG)[i] = Scalar(0);
-            }
-        }
-
-        unsigned numElements = this->gridView_().size(0);
-        ScalarField *rank = writer.allocateManagedBuffer (numElements);
-
-        for (const auto& element : elements(this->gridView_(), Dune::Partitions::interior))
-        {
-            int idx = this->problem_().elementMapper().index(element);
-            (*rank)[idx] = this->gridView_().comm().rank();
-
-            FVElementGeometry fvGeometry;
-            fvGeometry.update(this->gridView_(), element);
-
-
-            ElementVolumeVariables elemVolVars;
-            elemVolVars.update(this->problem_(),
-                               element,
-                               fvGeometry,
-                               false /* oldSol? */);
-
-            for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx)
-            {
-                int globalIdx = this->dofMapper().subIndex(element, scvIdx, dofCodim);
-
-                for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
-                    (*saturation[phaseIdx])[globalIdx] = elemVolVars[scvIdx].fluidState().saturation(phaseIdx);
-                    (*pressure[phaseIdx])[globalIdx] = elemVolVars[scvIdx].fluidState().pressure(phaseIdx);
-                    (*density[phaseIdx])[globalIdx] = elemVolVars[scvIdx].fluidState().density(phaseIdx);
-
-                    (*mobility[phaseIdx])[globalIdx] = elemVolVars[scvIdx].mobility(phaseIdx);
-                    (*viscosity[phaseIdx])[globalIdx] = elemVolVars[scvIdx].fluidState().viscosity(phaseIdx);
-                }
-
-                for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
-                    for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
-                        (*moleFraction[phaseIdx][compIdx])[globalIdx] =
-                            elemVolVars[scvIdx].fluidState().moleFraction(phaseIdx,
-                                                              compIdx);
-
-                        Valgrind::CheckDefined((*moleFraction[phaseIdx][compIdx])[globalIdx]);
-                    }
-                }
-
-                (*poro)[globalIdx] = elemVolVars[scvIdx].porosity();
-                (*perm)[globalIdx] = elemVolVars[scvIdx].permeability();
-                (*temperature)[globalIdx] = elemVolVars[scvIdx].temperature();
-                (*phasePresence)[globalIdx] = staticDat_[globalIdx].phasePresence;
-            }
-
-            // velocity output
-            velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, element, wPhaseIdx);
-            velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, nPhaseIdx);
-            velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, element, gPhaseIdx);
-
-        }
-
-        writer.attachDofData(*saturation[wPhaseIdx], "sw", isBox);
-        writer.attachDofData(*saturation[nPhaseIdx], "sn", isBox);
-        writer.attachDofData(*saturation[gPhaseIdx], "sg", isBox);
-        writer.attachDofData(*pressure[wPhaseIdx], "pw", isBox);
-        writer.attachDofData(*pressure[nPhaseIdx], "pn", isBox);
-        writer.attachDofData(*pressure[gPhaseIdx], "pg", isBox);
-        writer.attachDofData(*density[wPhaseIdx], "rhow", isBox);
-        writer.attachDofData(*density[nPhaseIdx], "rhon", isBox);
-        writer.attachDofData(*density[gPhaseIdx], "rhog", isBox);
-
-        writer.attachDofData(*mobility[wPhaseIdx], "MobW", isBox);
-        writer.attachDofData(*mobility[nPhaseIdx], "MobN", isBox);
-        writer.attachDofData(*mobility[gPhaseIdx], "MobG", isBox);
-
-        writer.attachDofData(*viscosity[wPhaseIdx], "ViscosW", isBox);
-        writer.attachDofData(*viscosity[nPhaseIdx], "ViscosN", isBox);
-        writer.attachDofData(*viscosity[gPhaseIdx], "ViscosG", isBox);
-        for (int i = 0; i < numPhases; ++i)
-        {
-            for (int j = 0; j < numComponents; ++j)
-            {
-                std::ostringstream oss;
-                oss << "x^"
-                    << FluidSystem::phaseName(i)
-                    << "_"
-                    << FluidSystem::componentName(j);
-                writer.attachDofData(*moleFraction[i][j], oss.str().c_str(), isBox);
-            }
-        }
-        writer.attachDofData(*poro, "porosity", isBox);
-        writer.attachDofData(*perm, "permeability", isBox);
-        writer.attachDofData(*temperature, "temperature", isBox);
-        writer.attachDofData(*phasePresence, "phase presence", isBox);
-
-        if (velocityOutput.enableOutput()) // check if velocity output is demanded
-        {
-            writer.attachDofData(*velocityW,  "velocityW", isBox, dim);
-            writer.attachDofData(*velocityN,  "velocityN", isBox, dim);
-            writer.attachDofData(*velocityG,  "velocityG", isBox, dim);
-        }
-
-        writer.attachCellData(*rank, "process rank");
-    }
-
-    /*!
-     * \brief Write the current solution to a restart file.
-     *
-     * \param outStream The output stream of one entity for the restart file
-     * \param entity The entity, either a vertex or an element
-     */
-    template<class Entity>
-    void serializeEntity(std::ostream &outStream, const Entity &entity)
-    {
-        // write primary variables
-        ParentType::serializeEntity(outStream, entity);
-
-        int globalIdx = this->dofMapper().index(entity);
-        if (!outStream.good())
-            DUNE_THROW(Dune::IOError, "Could not serialize entity " << globalIdx);
-
-        outStream << staticDat_[globalIdx].phasePresence << " ";
-    }
-
-    /*!
-     * \brief Reads the current solution from a restart file.
-     *
-     * \param inStream The input stream of one entity from the restart file
-     * \param entity The entity, either a vertex or an element
-     */
-    template<class Entity>
-    void deserializeEntity(std::istream &inStream, const Entity &entity)
-    {
-        // read primary variables
-        ParentType::deserializeEntity(inStream, entity);
-
-        // read phase presence
-        int globalIdx = this->dofMapper().index(entity);
-        if (!inStream.good())
-            DUNE_THROW(Dune::IOError,
-                       "Could not deserialize entity " << globalIdx);
-
-        inStream >> staticDat_[globalIdx].phasePresence;
-        staticDat_[globalIdx].oldPhasePresence
-            = staticDat_[globalIdx].phasePresence;
-
-    }
-
-    /*!
-     * \brief Update the static data of all vertices in the grid.
-     *
-     * \param curGlobalSol The current global solution
-     * \param oldGlobalSol The previous global solution
-     */
-    void updateStaticData(SolutionVector &curGlobalSol,
-                          const SolutionVector &oldGlobalSol)
-    {
-        bool wasSwitched = false;
-
-        bool useSimpleModel = GET_PROP_VALUE(TypeTag, UseSimpleModel);
-
-        for (unsigned i = 0; i < staticDat_.size(); ++i)
-            staticDat_[i].visited = false;
-
-        FVElementGeometry fvGeometry;
-        static VolumeVariables volVars;
-        for (const auto& element : elements(this->gridView_()))
-        {
-            fvGeometry.update(this->gridView_(), element);
-            for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx)
-            {
-                int globalIdx = this->dofMapper().subIndex(element, scvIdx, dofCodim);
-
-                if (staticDat_[globalIdx].visited)
-                    continue;
-
-                staticDat_[globalIdx].visited = true;
-                volVars.update(curGlobalSol[globalIdx],
-                               this->problem_(),
-                               element,
-                               fvGeometry,
-                               scvIdx,
-                               false);
-                const GlobalPosition &globalPos = fvGeometry.subContVol[scvIdx].global;
-
-                if(useSimpleModel)
-                {
-                    if (primaryVarSwitchSimple_(curGlobalSol,
-                                          volVars,
-                                          globalIdx,
-                                          globalPos))
-                    {
-                        this->jacobianAssembler().markDofRed(globalIdx);
-                        wasSwitched = true;
-                    }
-                }
-                else
-                {
-                    if (primaryVarSwitch_(curGlobalSol,
-                                          volVars,
-                                          globalIdx,
-                                          globalPos))
-                    {
-                        this->jacobianAssembler().markDofRed(globalIdx);
-                        wasSwitched = true;
-                    }
-                }
-            }
-        }
-
-        // make sure that if there was a variable switch in an
-        // other partition we will also set the switch flag
-        // for our partition.
-        if (this->gridView_().comm().size() > 1)
-            wasSwitched = this->gridView_().comm().max(wasSwitched);
-
-        setSwitched_(wasSwitched);
-    }
-
-protected:
-    /*!
-     * \brief Data which is attached to each vertex and is not only
-     *        stored locally.
-     */
-    struct StaticVars
-    {
-        int phasePresence;
-        bool wasSwitched;
-
-        int oldPhasePresence;
-        bool visited;
-    };
-
-    /*!
-     * \brief Reset the current phase presence of all vertices to the old one.
-     *
-     * This is done after an update failed.
-     */
-    void resetPhasePresence_()
-    {
-        for (unsigned int i = 0; i < this->numDofs(); ++i)
-        {
-            staticDat_[i].phasePresence
-                = staticDat_[i].oldPhasePresence;
-            staticDat_[i].wasSwitched = false;
-        }
-    }
-
-    /*!
-     * \brief Set the old phase of all verts state to the current one.
-     */
-    void updateOldPhasePresence_()
-    {
-        for (unsigned int i = 0; i < this->numDofs(); ++i)
-        {
-            staticDat_[i].oldPhasePresence
-                = staticDat_[i].phasePresence;
-            staticDat_[i].wasSwitched = false;
-        }
-    }
-
-    /*!
-     * \brief Set whether there was a primary variable switch after in
-     *        the last timestep.
-     */
-    void setSwitched_(bool yesno)
-    {
-        switchFlag_ = yesno;
-    }
-
-    //  perform variable switch at a vertex; Returns true if a
-    //  variable switch was performed.
-    bool primaryVarSwitch_(SolutionVector &globalSol,
-                           const VolumeVariables &volVars,
-                           int globalIdx,
-                           const GlobalPosition &globalPos)
-    {
-        // evaluate primary variable switch
-        bool wouldSwitch = false;
-        int phasePresence = staticDat_[globalIdx].phasePresence;
-        int newPhasePresence = phasePresence;
-
-        // check if a primary var switch is necessary
-        if (phasePresence == threePhases)
-        {
-            Scalar Smin = 0;
-            if (staticDat_[globalIdx].wasSwitched)
-                Smin = -0.01;
-
-            if (volVars.saturation(gPhaseIdx) <= Smin)
-            {
-                wouldSwitch = true;
-                // gas phase disappears
-                std::cout << "Gas phase disappears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", sg: "
-                          << volVars.saturation(gPhaseIdx) << std::endl;
-                newPhasePresence = wnPhaseOnly;
-
-                globalSol[globalIdx][pressureIdx] = volVars.fluidState().pressure(wPhaseIdx);
-                globalSol[globalIdx][switch1Idx] = volVars.fluidState().temperature();
-            }
-            else if (volVars.saturation(wPhaseIdx) <= Smin)
-            {
-                wouldSwitch = true;
-                // water phase disappears
-                std::cout << "Water phase disappears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", sw: "
-                          << volVars.saturation(wPhaseIdx) << std::endl;
-                newPhasePresence = gnPhaseOnly;
-
-                globalSol[globalIdx][switch1Idx] = volVars.fluidState().saturation(nPhaseIdx);
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(nPhaseIdx, wCompIdx);
-            }
-            else if (volVars.saturation(nPhaseIdx) <= Smin)
-            {
-                wouldSwitch = true;
-                // NAPL phase disappears
-                std::cout << "NAPL phase disappears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", sn: "
-                          << volVars.saturation(nPhaseIdx) << std::endl;
-                newPhasePresence = wgPhaseOnly;
-
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
-            }
-        }
-        else if (phasePresence == wPhaseOnly)
-        {
-            bool gasFlag = 0;
-            bool nonwettingFlag = 0;
-            // calculate fractions of the partial pressures in the
-            // hypothetical gas phase
-            Scalar xwg = volVars.fluidState().moleFraction(gPhaseIdx, wCompIdx);
-            Scalar xng = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
-
-            Scalar xgMax = 1.0;
-            if (xwg + xng > xgMax)
-                wouldSwitch = true;
-            if (staticDat_[globalIdx].wasSwitched)
-                xgMax *= 1.02;
-
-            // if the sum of the mole fractions would be larger than
-            // 100%, gas phase appears
-            if (xwg + xng > xgMax)
-            {
-                // gas phase appears
-                std::cout << "gas phase appears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", xwg + xng: "
-                          << xwg + xng << std::endl;
-                gasFlag = 1;
-            }
-
-            // calculate fractions in the hypothetical NAPL phase
-            Scalar xnn = volVars.fluidState().moleFraction(nPhaseIdx, nCompIdx);
-            /* take care:
-               for xnn in case wPhaseOnly we compute xnn=henry_mesitylene*x1w,
-               where a hypothetical gas pressure is assumed for the Henry
-               x0n is set to NULL  (all NAPL phase is dirty)
-               x2n is set to NULL  (all NAPL phase is dirty)
-            */
-
-            Scalar xnMax = 1.0;
-            if (xnn > xnMax)
-                wouldSwitch = true;
-            if (staticDat_[globalIdx].wasSwitched)
-                xnMax *= 1.02;
-
-            // if the sum of the hypothetical mole fractions would be larger than
-            // 100%, NAPL phase appears
-            if (xnn > xnMax)
-            {
-                // NAPL phase appears
-                std::cout << "NAPL phase appears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", xnn: "
-                          << xnn << std::endl;
-                nonwettingFlag = 1;
-            }
-
-            if ((gasFlag == 1) && (nonwettingFlag == 0))
-            {
-                newPhasePresence = wgPhaseOnly;
-                globalSol[globalIdx][switch1Idx] = 0.9999;
-                globalSol[globalIdx][pressureIdx] = volVars.fluidState().pressure(gPhaseIdx);
-            }
-            else if ((gasFlag == 1) && (nonwettingFlag == 1))
-            {
-                newPhasePresence = threePhases;
-                globalSol[globalIdx][pressureIdx] = volVars.fluidState().pressure(gPhaseIdx);
-                globalSol[globalIdx][switch1Idx] = 0.999;
-            }
-            else if ((gasFlag == 0) && (nonwettingFlag == 1))
-            {
-                newPhasePresence = wnPhaseOnly;
-                globalSol[globalIdx][switch2Idx] = 0.0001;
-            }
-        }
-        else if (phasePresence == gnPhaseOnly)
-        {
-            bool nonwettingFlag = 0;
-            bool wettingFlag = 0;
-
-            Scalar Smin = 0.0;
-            if (staticDat_[globalIdx].wasSwitched)
-                Smin = -0.01;
-
-            if (volVars.saturation(nPhaseIdx) <= Smin)
-            {
-                wouldSwitch = true;
-                // NAPL phase disappears
-                std::cout << "NAPL phase disappears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", sn: "
-                          << volVars.saturation(nPhaseIdx) << std::endl;
-                nonwettingFlag = 1;
-            }
 
+#ifndef DUMUX_3PWATEROIL_MODEL_HH
+#define DUMUX_3PWATEROIL_MODEL_HH
 
-            // calculate fractions of the hypothetical water phase
-            Scalar xww = volVars.fluidState().moleFraction(wPhaseIdx, wCompIdx);
-            /*
-              take care:, xww, if no water is present, then take xww=xwg*pg/pwsat .
-              If this is larger than 1, then water appears
-            */
-            Scalar xwMax = 1.0;
-            if (xww > xwMax)
-                wouldSwitch = true;
-            if (staticDat_[globalIdx].wasSwitched)
-                xwMax *= 1.02;
+#include <dumux/common/properties.hh>
 
-            // if the sum of the mole fractions would be larger than
-            // 100%, water phase appears
-            if (xww > xwMax)
-            {
-                // water phase appears
-                std::cout << "water phase appears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", xww=xwg*pg/pwsat : "
-                          << xww << std::endl;
-                wettingFlag = 1;
-            }
+#include <dumux/material/spatialparams/fv.hh>
+#include <dumux/material/fluidmatrixinteractions/3p/thermalconductivitysomerton3p.hh>
+#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh>
 
-            if ((wettingFlag == 1) && (nonwettingFlag == 0))
-            {
-                newPhasePresence = threePhases;
-                globalSol[globalIdx][switch1Idx] = 0.0001;
-                globalSol[globalIdx][switch2Idx] = volVars.saturation(nPhaseIdx);
-            }
-            else if ((wettingFlag == 1) && (nonwettingFlag == 1))
-            {
-                newPhasePresence = wgPhaseOnly;
-                globalSol[globalIdx][switch1Idx] = 0.0001;
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
-            }
-            else if ((wettingFlag == 0) && (nonwettingFlag == 1))
-            {
-                newPhasePresence = gPhaseOnly;
-                globalSol[globalIdx][switch1Idx] = volVars.fluidState().temperature();
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
-            }
-        }
-        else if (phasePresence == wnPhaseOnly)
-        {
-            bool nonwettingFlag = 0;
-            bool gasFlag = 0;
+#include <dumux/porousmediumflow/properties.hh>
+#include <dumux/porousmediumflow/nonisothermal/model.hh>
+#include <dumux/porousmediumflow/compositional/switchableprimaryvariables.hh>
 
-            Scalar Smin = 0.0;
-            if (staticDat_[globalIdx].wasSwitched)
-                Smin = -0.01;
+#include "indices.hh"
+#include "model.hh"
+#include "volumevariables.hh"
+#include "localresidual.hh"
+#include "primaryvariableswitch.hh"
+#include "vtkoutputfields.hh"
 
-            if (volVars.saturation(nPhaseIdx) <= Smin)
-            {
-                wouldSwitch = true;
-                // NAPL phase disappears
-                std::cout << "NAPL phase disappears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", sn: "
-                          << volVars.saturation(nPhaseIdx) << std::endl;
-                nonwettingFlag = 1;
-            }
+namespace Dumux
+{
+/*!
+ * \ingroup ThreePWaterOilModel
+ * \brief Adaption of the fully implicit scheme to the three-phase two-component flow model.
+ *
+ */
+namespace Properties {
 
-            // calculate fractions of the partial pressures in the
-            // hypothetical gas phase
-            Scalar xwg = volVars.fluidState().moleFraction(gPhaseIdx, wCompIdx);
-            Scalar xng = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
+NEW_TYPE_TAG(ThreePWaterOilNI, INHERITS_FROM(PorousMediumFlow, NonIsothermal));
 
-            Scalar xgMax = 1.0;
-            if (xwg + xng > xgMax)
-                wouldSwitch = true;
-            if (staticDat_[globalIdx].wasSwitched)
-                xgMax *= 1.02;
+//////////////////////////////////////////////////////////////////
+// Property values
+//////////////////////////////////////////////////////////////////
 
-            // if the sum of the mole fractions would be larger than
-            // 100%, gas phase appears
-            if (xwg + xng > xgMax)
-            {
-                // gas phase appears
-                std::cout << "gas phase appears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", xwg + xng: "
-                          << xwg + xng << std::endl;
-                gasFlag = 1;
-            }
+/*!
+ * \brief Set the property for the number of components.
+ *
+ * We just forward the number from the fluid system and use an static
+ * assert to make sure it is 2.
+ */
+SET_PROP(ThreePWaterOilNI, NumComponents)
+{
+ private:
+    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
 
-            if ((gasFlag == 1) && (nonwettingFlag == 0))
-            {
-                newPhasePresence = threePhases;
-                globalSol[globalIdx][pressureIdx] = volVars.pressure(gPhaseIdx);
-                globalSol[globalIdx][switch1Idx] = volVars.saturation(wPhaseIdx);
-            }
-            else if ((gasFlag == 1) && (nonwettingFlag == 1))
-            {
-                newPhasePresence = wgPhaseOnly;
-                globalSol[globalIdx][pressureIdx] = volVars.pressure(gPhaseIdx);
-                globalSol[globalIdx][switch1Idx] = volVars.temperature();
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
-            }
-            else if ((gasFlag == 0) && (nonwettingFlag == 1))
-            {
-                newPhasePresence = wPhaseOnly;
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
-            }
-        }
-        else if (phasePresence == gPhaseOnly)
-        {
-            bool nonwettingFlag = 0;
-            bool wettingFlag = 0;
+ public:
+    static const int value = FluidSystem::numComponents;
 
-            // calculate fractions in the hypothetical NAPL phase
-            Scalar xnn = volVars.fluidState().moleFraction(nPhaseIdx, nCompIdx);
-            /*
-              take care:, xnn, if no NAPL phase is there, take xnn=xng*pg/pcsat
-              if this is larger than 1, then NAPL appears
-            */
+    static_assert(value == 2,
+                  "Only fluid systems with 2 components are supported by the 3p2cni model!");
+};
 
-            Scalar xnMax = 1.0;
-            if (xnn > xnMax)
-                wouldSwitch = true;
-            if (staticDat_[globalIdx].wasSwitched)
-                xnMax *= 1.02;
+/*!
+ * \brief Set the property for the number of fluid phases.
+ *
+ * We just forward the number from the fluid system and use an static
+ * assert to make sure it is 2.
+ */
+SET_PROP(ThreePWaterOilNI, NumPhases)
+{
+ private:
+    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
 
-            // if the sum of the hypothetical mole fraction would be larger than
-            // 100%, NAPL phase appears
-            if (xnn > xnMax)
-            {
-                // NAPL phase appears
-                std::cout << "NAPL phase appears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", xnn: "
-                          << xnn << std::endl;
-                nonwettingFlag = 1;
-            }
-            // calculate fractions of the hypothetical water phase
-            Scalar xww = volVars.fluidState().moleFraction(wPhaseIdx, wCompIdx);
-            /*
-              take care:, xww, if no water is present, then take xww=xwg*pg/pwsat .
-              If this is larger than 1, then water appears
-            */
-            Scalar xwMax = 1.0;
-            if (xww > xwMax)
-                wouldSwitch = true;
-            if (staticDat_[globalIdx].wasSwitched)
-                xwMax *= 1.02;
+ public:
+    static const int value = FluidSystem::numPhases;
+    static_assert(value == 3,
+                  "Only fluid systems with 3 phases are supported by the 3p2cni model!");
+};
 
-            // if the sum of the mole fractions would be larger than
-            // 100%, gas phase appears
-            if (xww > xwMax)
-            {
-                // water phase appears
-                std::cout << "water phase appears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", xww=xwg*pg/pwsat : "
-                          << xww << std::endl;
-                wettingFlag = 1;
-            }
-            if ((wettingFlag == 1) && (nonwettingFlag == 0))
-            {
-                newPhasePresence = wgPhaseOnly;
-                globalSol[globalIdx][switch1Idx] = 0.0001;
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
-            }
-            else if ((wettingFlag == 1) && (nonwettingFlag == 1))
-            {
-                newPhasePresence = threePhases;
-                globalSol[globalIdx][switch1Idx] = 0.0001;
-                globalSol[globalIdx][switch2Idx] = 0.0001;
-            }
-            else if ((wettingFlag == 0) && (nonwettingFlag == 1))
-            {
-                newPhasePresence = gnPhaseOnly;
-                globalSol[globalIdx][switch2Idx]
-                    = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
-            }
-        }
-        else if (phasePresence == wgPhaseOnly)
-        {
-            bool nonwettingFlag = 0;
-            bool gasFlag = 0;
-            bool wettingFlag = 0;
+/*!
+ * \brief The fluid state which is used by the volume variables to
+ *        store the thermodynamic state. This should be chosen
+ *        appropriately for the model ((non-)isothermal, equilibrium, ...).
+ *        This can be done in the problem.
+ */
+SET_PROP(ThreePWaterOilNI, FluidState){
+    private:
+        using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+        using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
+    public:
+        using type = CompositionalFluidState<Scalar, FluidSystem>;
+};
 
-            // get the fractions in the hypothetical NAPL phase
-            Scalar xnn = volVars.fluidState().moleFraction(nPhaseIdx, nCompIdx);
+//! The local residual function of the conservation equations
+SET_TYPE_PROP(ThreePWaterOilNI, LocalResidual, ThreePWaterOilLocalResidual<TypeTag>);
 
-            // take care: if the NAPL phase is not present, take
-            // xnn=xng*pg/pcsat if this is larger than 1, then NAPL
-            // appears
-            Scalar xnMax = 1.0;
-            if (xnn > xnMax)
-                wouldSwitch = true;
-            if (staticDat_[globalIdx].wasSwitched)
-                xnMax *= 1.02;
+//! Set as default that no component mass balance is replaced by the total mass balance
+SET_INT_PROP(ThreePWaterOilNI, ReplaceCompEqIdx, GET_PROP_VALUE(TypeTag, NumComponents));
 
-            // if the sum of the hypothetical mole fraction would be larger than
-            // 100%, NAPL phase appears
-            if (xnn > xnMax)
-            {
-                // NAPL phase appears
-                std::cout << "NAPL phase appears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", xnn: "
-                          << xnn << std::endl;
-                nonwettingFlag = 1;
-            }
+//! Enable advection
+SET_BOOL_PROP(ThreePWaterOilNI, EnableAdvection, true);
 
-            Scalar Smin = -1.e-6;
-            if (staticDat_[globalIdx].wasSwitched)
-                Smin = -0.01;
+//! disable molecular diffusion for the 3p model
+SET_BOOL_PROP(ThreePWaterOilNI, EnableMolecularDiffusion, true);
 
-            if (volVars.saturation(gPhaseIdx) <= Smin)
-            {
-                wouldSwitch = true;
-                // gas phase disappears
-                std::cout << "Gas phase disappears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", sg: "
-                          << volVars.saturation(gPhaseIdx) << std::endl;
-                gasFlag = 1;
-            }
+//! Isothermal model by default
+SET_BOOL_PROP(ThreePWaterOilNI, EnableEnergyBalance, true);
 
-            Smin = 0.0;
-            if (staticDat_[globalIdx].wasSwitched)
-                Smin = -0.01;
+//! The primary variable switch for the 3p3c model
+SET_TYPE_PROP(ThreePWaterOilNI, PrimaryVariableSwitch, ThreePWaterOilPrimaryVariableSwitch<TypeTag>);
 
-            if (volVars.saturation(wPhaseIdx) <= Smin)
-            {
-                wouldSwitch = true;
-                // gas phase disappears
-                std::cout << "Water phase disappears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", sw: "
-                          << volVars.saturation(wPhaseIdx) << std::endl;
-                wettingFlag = 1;
-            }
+//! The primary variables vector for the 3p3c model
+SET_TYPE_PROP(ThreePWaterOilNI, PrimaryVariables, SwitchablePrimaryVariables<TypeTag, int>);
 
-            if ((gasFlag == 0) && (nonwettingFlag == 1) && (wettingFlag == 1))
-            {
-                newPhasePresence = gnPhaseOnly;
-                globalSol[globalIdx][switch1Idx] = 0.0001;
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(nPhaseIdx, wCompIdx);
-;
-            }
-            else if ((gasFlag == 0) && (nonwettingFlag == 1) && (wettingFlag == 0))
-            {
-                newPhasePresence = threePhases;
-                globalSol[globalIdx][switch2Idx] = 0.0001;
-            }
-            else if ((gasFlag == 1) && (nonwettingFlag == 0) && (wettingFlag == 0))
-            {
-                newPhasePresence = wPhaseOnly;
-                globalSol[globalIdx][pressureIdx] = volVars.fluidState().pressure(wPhaseIdx);
-                globalSol[globalIdx][switch1Idx] = volVars.fluidState().temperature();
-                globalSol[globalIdx][switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
-            }
-            else if ((gasFlag == 0) && (nonwettingFlag == 0) && (wettingFlag == 1))
-            {
-                newPhasePresence = gPhaseOnly;
-                globalSol[globalIdx][switch1Idx]
-                    = volVars.fluidState().temperature();
-                globalSol[globalIdx][switch2Idx]
-                    = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
-            }
-        }
+//! Determines whether a constraint solver should be used explicitly
+SET_BOOL_PROP(ThreePWaterOilNI, OnlyGasPhaseCanDisappear, true);
 
-        staticDat_[globalIdx].phasePresence = newPhasePresence;
-        staticDat_[globalIdx].wasSwitched = wouldSwitch;
-        return phasePresence != newPhasePresence;
-    }
+//! the VolumeVariables property
+SET_TYPE_PROP(ThreePWaterOilNI, VolumeVariables, ThreePWaterOilVolumeVariables<TypeTag>);
 
-    //  perform variable switch at a vertex; Returns true if a
-    //  variable switch was performed.
-    // Note that this one is the simplified version with only two phase states
-    bool primaryVarSwitchSimple_(SolutionVector &globalSol,
-                           const VolumeVariables &volVars,
-                           int globalIdx,
-                           const GlobalPosition &globalPos)
-    {
-        // evaluate primary variable switch
-        bool wouldSwitch = false;
-        int phasePresence = staticDat_[globalIdx].phasePresence;
-        int newPhasePresence = phasePresence;
+//! The spatial parameters to be employed.
+//! Use FVSpatialParams by default.
+SET_TYPE_PROP(ThreePWaterOilNI, SpatialParams, FVSpatialParams<TypeTag>);
 
-        // check if a primary var switch is necessary
-        if (phasePresence == threePhases)
-        {
-            Scalar Smin = 0;
-            if (staticDat_[globalIdx].wasSwitched)
-                Smin = -0.01;
+//! Use the model after Millington (1961) for the effective diffusivity
+SET_TYPE_PROP(ThreePWaterOilNI, EffectiveDiffusivityModel,
+             DiffusivityMillingtonQuirk<typename GET_PROP_TYPE(TypeTag, Scalar)>);
 
-            if (volVars.saturation(gPhaseIdx) <= Smin)
-            {
-                wouldSwitch = true;
-                // gas phase disappears
-                std::cout << "Gas phase disappears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", sg: "
-                          << volVars.saturation(gPhaseIdx) << std::endl;
-                newPhasePresence = wnPhaseOnly;
+// disable velocity output by default
 
-                globalSol[globalIdx][pressureIdx] = volVars.fluidState().pressure(wPhaseIdx);
-                globalSol[globalIdx][switch1Idx] = volVars.fluidState().temperature();
-            }
-        }
-        else if (phasePresence == wnPhaseOnly)
-        {
-            bool gasFlag = 0;
+SET_BOOL_PROP(ThreePWaterOilNI, UseMoles, true); //!< Define that mole fractions are used in the balance equations per default
 
-            // calculate fractions of the partial pressures in the
-            // hypothetical gas phase
-            Scalar xwg = volVars.fluidState().moleFraction(gPhaseIdx, wCompIdx);
-            Scalar xng = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
+//! Somerton is used as default model to compute the effective thermal heat conductivity
+SET_PROP(ThreePWaterOilNI, ThermalConductivityModel)
+{
+private:
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
+public:
+    using type = ThermalConductivitySomerton<Scalar, Indices>;
+};
 
-            Scalar xgMax = 1.0;
-            if (xwg + xng > xgMax)
-                wouldSwitch = true;
-            if (staticDat_[globalIdx].wasSwitched)
-                xgMax *= 1.02;
 
-            // if the sum of the mole fractions would be larger than
-            // 100%, gas phase appears
-            if (xwg + xng > xgMax)
-            {
-                // gas phase appears
-                std::cout << "gas phase appears at vertex " << globalIdx
-                          << ", coordinates: " << globalPos << ", xwg + xng: "
-                          << xwg + xng << std::endl;
-                gasFlag = 1;
-            }
+//////////////////////////////////////////////////////////////////
+// Property values for isothermal model required for the general non-isothermal model
+//////////////////////////////////////////////////////////////////
 
-            if (gasFlag == 1)
-            {
-                newPhasePresence = threePhases;
-                globalSol[globalIdx][pressureIdx] = volVars.pressure(gPhaseIdx);
-                globalSol[globalIdx][switch1Idx] = volVars.saturation(wPhaseIdx);
-            }
-        }
+//set isothermal output fields
+SET_TYPE_PROP(ThreePWaterOilNI, IsothermalVtkOutputFields, ThreePWaterOilVtkOutputFields<TypeTag>);
 
-        staticDat_[globalIdx].phasePresence = newPhasePresence;
-        staticDat_[globalIdx].wasSwitched = wouldSwitch;
-        return phasePresence != newPhasePresence;
-    }
+//set isothermal Indices
+SET_PROP(ThreePWaterOilNI, IsothermalIndices)
+{
 
-    // parameters given in constructor
-    std::vector<StaticVars> staticDat_;
-    bool switchFlag_;
+public:
+    using type = ThreePWaterOilIndices<TypeTag, /*PVOffset=*/0>;
 };
 
+//set isothermal NumEq
+SET_INT_PROP(ThreePWaterOilNI, IsothermalNumEq, 2);
+
 }
 
-#include "propertydefaults.hh"
+ }
 
 #endif
diff --git a/dumux/porousmediumflow/3pwateroil/newtoncontroller.hh b/dumux/porousmediumflow/3pwateroil/newtoncontroller.hh
deleted file mode 100644
index 419cf1d45b404d4cbd84c53ae4ac8691fcb444db..0000000000000000000000000000000000000000
--- a/dumux/porousmediumflow/3pwateroil/newtoncontroller.hh
+++ /dev/null
@@ -1,85 +0,0 @@
-// -*- 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 A 3p2cni specific controller for the newton solver.
- *
- * This controller 'knows' what a 'physically meaningful' solution is
- * which allows the newton method to abort quicker if the solution is
- * way out of bounds.
- */
-#ifndef DUMUX_3P2CNI_NEWTON_CONTROLLER_HH
-#define DUMUX_3P2CNI_NEWTON_CONTROLLER_HH
-
-#include <dumux/nonlinear/newtoncontroller.hh>
-
-#include "properties.hh"
-
-namespace Dumux {
-/*!
- * \ingroup ThreePWaterOilModel
- * \brief A 3p2cni specific controller for the newton solver.
- *
- * This controller 'knows' what a 'physically meaningful' solution is
- * which allows the newton method to abort quicker if the solution is
- * way out of bounds.
- */
-template <class TypeTag>
-class ThreePWaterOilNewtonController : public NewtonController<TypeTag>
-{
-    using ParentType = NewtonController<TypeTag>;
-    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
-    using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
-
-public:
-    ThreePWaterOilNewtonController(const Problem &problem)
-        : ParentType(problem)
-    {};
-
-
-    /*!
-     * \brief Called after each Newton update
-     *
-     * \param uCurrentIter The current global solution vector
-     * \param uLastIter The previous global solution vector
-     */
-    void newtonEndStep(SolutionVector &uCurrentIter,
-                       const SolutionVector &uLastIter)
-    {
-        // call the method of the base class
-        this->method().model().updateStaticData(uCurrentIter, uLastIter);
-        ParentType::newtonEndStep(uCurrentIter, uLastIter);
-    }
-
-
-    /*!
-     * \brief Returns true if the current solution can be considered to
-     *        be accurate enough
-     */
-    bool newtonConverged()
-    {
-        if (this->method().model().switched())
-            return false;
-
-        return ParentType::newtonConverged();
-    };
-};
-}
-
-#endif
diff --git a/dumux/porousmediumflow/3pwateroil/primaryvariableswitch.hh b/dumux/porousmediumflow/3pwateroil/primaryvariableswitch.hh
new file mode 100644
index 0000000000000000000000000000000000000000..35c945abefb71c7a6d05ca6f7a334d1679dd5d87
--- /dev/null
+++ b/dumux/porousmediumflow/3pwateroil/primaryvariableswitch.hh
@@ -0,0 +1,549 @@
+// -*- 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
+ * \ingroup ThreePWaterOilModel
+ * \brief The primary variable switch for the 3p3c model
+ */
+#ifndef DUMUX_3P3C_PRIMARY_VARIABLE_SWITCH_HH
+#define DUMUX_3P3C_PRIMARY_VARIABLE_SWITCH_HH
+
+#include <dumux/porousmediumflow/compositional/primaryvariableswitch.hh>
+
+namespace Dumux
+{
+/*!
+ * \ingroup ThreePWaterOilModel
+ * \brief The primary variable switch controlling the phase presence state variable
+ */
+template<class TypeTag>
+class ThreePWaterOilPrimaryVariableSwitch : public Dumux::PrimaryVariableSwitch<TypeTag>
+{
+    friend typename Dumux::PrimaryVariableSwitch<TypeTag>;
+    using ParentType = Dumux::PrimaryVariableSwitch<TypeTag>;
+
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using IndexType = typename GridView::IndexSet::IndexType;
+    using GlobalPosition = Dune::FieldVector<Scalar, GridView::dimensionworld>;
+
+    using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
+    using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
+    using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
+
+    enum {
+        switch1Idx = Indices::switch1Idx,
+        switch2Idx = Indices::switch2Idx,
+        pressureIdx = Indices::pressureIdx,
+
+        wPhaseIdx = Indices::wPhaseIdx,
+        nPhaseIdx = Indices::nPhaseIdx,
+        gPhaseIdx = Indices::gPhaseIdx,
+
+        wCompIdx = Indices::wCompIdx,
+        nCompIdx = Indices::nCompIdx,
+        gCompIdx = Indices::gCompIdx,
+
+        threePhases = Indices::threePhases,
+        wPhaseOnly  = Indices::wPhaseOnly,
+        gnPhaseOnly = Indices::gnPhaseOnly,
+        wnPhaseOnly = Indices::wnPhaseOnly,
+        gPhaseOnly  = Indices::gPhaseOnly,
+        wgPhaseOnly = Indices::wgPhaseOnly
+    };
+
+public:
+    using ParentType::ParentType;
+
+protected:
+
+    // perform variable switch at a degree of freedom location
+    bool update_(PrimaryVariables& priVars,
+                 const VolumeVariables& volVars,
+                 IndexType dofIdxGlobal,
+                 const GlobalPosition& globalPos)
+    {
+        // evaluate primary variable switch
+        bool wouldSwitch = false;
+        auto phasePresence = priVars.state();
+        int newPhasePresence = phasePresence;
+
+        bool onlyGasPhaseCanDisappear = GET_PROP_VALUE(TypeTag, OnlyGasPhaseCanDisappear);
+
+        if(onlyGasPhaseCanDisappear)
+        {
+            // check if a primary var switch is necessary
+            if (phasePresence == threePhases)
+            {
+                Scalar Smin = 0;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    Smin = -0.01;
+
+                if (volVars.saturation(gPhaseIdx) <= Smin)
+                {
+                    wouldSwitch = true;
+                    // gas phase disappears
+                    std::cout << "Gas phase disappears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", sg: "
+                            << volVars.saturation(gPhaseIdx) << std::endl;
+                    newPhasePresence = wnPhaseOnly;
+
+                    priVars[pressureIdx] = volVars.fluidState().pressure(wPhaseIdx);
+                    priVars[switch1Idx] = volVars.fluidState().temperature();
+                }
+            }
+            else if (phasePresence == wnPhaseOnly)
+            {
+                bool gasFlag = 0;
+
+                // calculate fractions of the partial pressures in the
+                // hypothetical gas phase
+                Scalar xwg = volVars.fluidState().moleFraction(gPhaseIdx, wCompIdx);
+                Scalar xng = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
+
+                Scalar xgMax = 1.0;
+                if (xwg + xng > xgMax)
+                    wouldSwitch = true;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    xgMax *= 1.02;
+
+                // if the sum of the mole fractions would be larger than
+                // 100%, gas phase appears
+                if (xwg + xng > xgMax)
+                {
+                    // gas phase appears
+                    std::cout << "gas phase appears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", xwg + xng: "
+                            << xwg + xng << std::endl;
+                    gasFlag = 1;
+                }
+
+                if (gasFlag == 1)
+                {
+                    newPhasePresence = threePhases;
+                    priVars[pressureIdx] = volVars.pressure(gPhaseIdx);
+                    priVars[switch1Idx] = volVars.saturation(wPhaseIdx);
+                }
+            }
+        }
+
+        else
+        {
+            // check if a primary var switch is necessary
+            if (phasePresence == threePhases)
+            {
+                Scalar Smin = 0;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    Smin = -0.01;
+
+                if (volVars.saturation(gPhaseIdx) <= Smin)
+                {
+                    wouldSwitch = true;
+                    // gas phase disappears
+                    std::cout << "Gas phase disappears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", sg: "
+                            << volVars.saturation(gPhaseIdx) << std::endl;
+                    newPhasePresence = wnPhaseOnly;
+
+                    priVars[pressureIdx] = volVars.fluidState().pressure(wPhaseIdx);
+                    priVars[switch1Idx] = volVars.fluidState().temperature();
+                }
+                else if (volVars.saturation(wPhaseIdx) <= Smin)
+                {
+                    wouldSwitch = true;
+                    // water phase disappears
+                    std::cout << "Water phase disappears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", sw: "
+                            << volVars.saturation(wPhaseIdx) << std::endl;
+                    newPhasePresence = gnPhaseOnly;
+
+                    priVars[switch1Idx] = volVars.fluidState().saturation(nPhaseIdx);
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(nPhaseIdx, wCompIdx);
+                }
+                else if (volVars.saturation(nPhaseIdx) <= Smin)
+                {
+                    wouldSwitch = true;
+                    // NAPL phase disappears
+                    std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", sn: "
+                            << volVars.saturation(nPhaseIdx) << std::endl;
+                    newPhasePresence = wgPhaseOnly;
+
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
+                }
+            }
+            else if (phasePresence == wPhaseOnly)
+            {
+                bool gasFlag = 0;
+                bool nonwettingFlag = 0;
+                // calculate fractions of the partial pressures in the
+                // hypothetical gas phase
+                Scalar xwg = volVars.fluidState().moleFraction(gPhaseIdx, wCompIdx);
+                Scalar xng = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
+
+                Scalar xgMax = 1.0;
+                if (xwg + xng > xgMax)
+                    wouldSwitch = true;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    xgMax *= 1.02;
+
+                // if the sum of the mole fractions would be larger than
+                // 100%, gas phase appears
+                if (xwg + xng > xgMax)
+                {
+                    // gas phase appears
+                    std::cout << "gas phase appears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", xwg + xng: "
+                            << xwg + xng << std::endl;
+                    gasFlag = 1;
+                }
+
+                // calculate fractions in the hypothetical NAPL phase
+                Scalar xnn = volVars.fluidState().moleFraction(nPhaseIdx, nCompIdx);
+                /* take care:
+                for xnn in case wPhaseOnly we compute xnn=henry_mesitylene*x1w,
+                where a hypothetical gas pressure is assumed for the Henry
+                x0n is set to NULL  (all NAPL phase is dirty)
+                x2n is set to NULL  (all NAPL phase is dirty)
+                */
+
+                Scalar xnMax = 1.0;
+                if (xnn > xnMax)
+                    wouldSwitch = true;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    xnMax *= 1.02;
+
+                // if the sum of the hypothetical mole fractions would be larger than
+                // 100%, NAPL phase appears
+                if (xnn > xnMax)
+                {
+                    // NAPL phase appears
+                    std::cout << "NAPL phase appears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", xnn: "
+                            << xnn << std::endl;
+                    nonwettingFlag = 1;
+                }
+
+                if ((gasFlag == 1) && (nonwettingFlag == 0))
+                {
+                    newPhasePresence = wgPhaseOnly;
+                    priVars[switch1Idx] = 0.9999;
+                    priVars[pressureIdx] = volVars.fluidState().pressure(gPhaseIdx);
+                }
+                else if ((gasFlag == 1) && (nonwettingFlag == 1))
+                {
+                    newPhasePresence = threePhases;
+                    priVars[pressureIdx] = volVars.fluidState().pressure(gPhaseIdx);
+                    priVars[switch1Idx] = 0.999;
+                }
+                else if ((gasFlag == 0) && (nonwettingFlag == 1))
+                {
+                    newPhasePresence = wnPhaseOnly;
+                    priVars[switch2Idx] = 0.0001;
+                }
+            }
+            else if (phasePresence == gnPhaseOnly)
+            {
+                bool nonwettingFlag = 0;
+                bool wettingFlag = 0;
+
+                Scalar Smin = 0.0;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    Smin = -0.01;
+
+                if (volVars.saturation(nPhaseIdx) <= Smin)
+                {
+                    wouldSwitch = true;
+                    // NAPL phase disappears
+                    std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", sn: "
+                            << volVars.saturation(nPhaseIdx) << std::endl;
+                    nonwettingFlag = 1;
+                }
+
+
+                // calculate fractions of the hypothetical water phase
+                Scalar xww = volVars.fluidState().moleFraction(wPhaseIdx, wCompIdx);
+                /*
+                take care:, xww, if no water is present, then take xww=xwg*pg/pwsat .
+                If this is larger than 1, then water appears
+                */
+                Scalar xwMax = 1.0;
+                if (xww > xwMax)
+                    wouldSwitch = true;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    xwMax *= 1.02;
+
+                // if the sum of the mole fractions would be larger than
+                // 100%, water phase appears
+                if (xww > xwMax)
+                {
+                    // water phase appears
+                    std::cout << "water phase appears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", xww=xwg*pg/pwsat : "
+                            << xww << std::endl;
+                    wettingFlag = 1;
+                }
+
+                if ((wettingFlag == 1) && (nonwettingFlag == 0))
+                {
+                    newPhasePresence = threePhases;
+                    priVars[switch1Idx] = 0.0001;
+                    priVars[switch2Idx] = volVars.saturation(nPhaseIdx);
+                }
+                else if ((wettingFlag == 1) && (nonwettingFlag == 1))
+                {
+                    newPhasePresence = wgPhaseOnly;
+                    priVars[switch1Idx] = 0.0001;
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
+                }
+                else if ((wettingFlag == 0) && (nonwettingFlag == 1))
+                {
+                    newPhasePresence = gPhaseOnly;
+                    priVars[switch1Idx] = volVars.fluidState().temperature();
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
+                }
+            }
+            else if (phasePresence == wnPhaseOnly)
+            {
+                bool nonwettingFlag = 0;
+                bool gasFlag = 0;
+
+                Scalar Smin = 0.0;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    Smin = -0.01;
+
+                if (volVars.saturation(nPhaseIdx) <= Smin)
+                {
+                    wouldSwitch = true;
+                    // NAPL phase disappears
+                    std::cout << "NAPL phase disappears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", sn: "
+                            << volVars.saturation(nPhaseIdx) << std::endl;
+                    nonwettingFlag = 1;
+                }
+
+                // calculate fractions of the partial pressures in the
+                // hypothetical gas phase
+                Scalar xwg = volVars.fluidState().moleFraction(gPhaseIdx, wCompIdx);
+                Scalar xng = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
+
+                Scalar xgMax = 1.0;
+                if (xwg + xng > xgMax)
+                    wouldSwitch = true;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    xgMax *= 1.02;
+
+                // if the sum of the mole fractions would be larger than
+                // 100%, gas phase appears
+                if (xwg + xng > xgMax)
+                {
+                    // gas phase appears
+                    std::cout << "gas phase appears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", xwg + xng: "
+                            << xwg + xng << std::endl;
+                    gasFlag = 1;
+                }
+
+                if ((gasFlag == 1) && (nonwettingFlag == 0))
+                {
+                    newPhasePresence = threePhases;
+                    priVars[pressureIdx] = volVars.pressure(gPhaseIdx);
+                    priVars[switch1Idx] = volVars.saturation(wPhaseIdx);
+                }
+                else if ((gasFlag == 1) && (nonwettingFlag == 1))
+                {
+                    newPhasePresence = wgPhaseOnly;
+                    priVars[pressureIdx] = volVars.pressure(gPhaseIdx);
+                    priVars[switch1Idx] = volVars.temperature();
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
+                }
+                else if ((gasFlag == 0) && (nonwettingFlag == 1))
+                {
+                    newPhasePresence = wPhaseOnly;
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
+                }
+            }
+            else if (phasePresence == gPhaseOnly)
+            {
+                bool nonwettingFlag = 0;
+                bool wettingFlag = 0;
+
+                // calculate fractions in the hypothetical NAPL phase
+                Scalar xnn = volVars.fluidState().moleFraction(nPhaseIdx, nCompIdx);
+                /*
+                take care:, xnn, if no NAPL phase is there, take xnn=xng*pg/pcsat
+                if this is larger than 1, then NAPL appears
+                */
+
+                Scalar xnMax = 1.0;
+                if (xnn > xnMax)
+                    wouldSwitch = true;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    xnMax *= 1.02;
+
+                // if the sum of the hypothetical mole fraction would be larger than
+                // 100%, NAPL phase appears
+                if (xnn > xnMax)
+                {
+                    // NAPL phase appears
+                    std::cout << "NAPL phase appears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", xnn: "
+                            << xnn << std::endl;
+                    nonwettingFlag = 1;
+                }
+                // calculate fractions of the hypothetical water phase
+                Scalar xww = volVars.fluidState().moleFraction(wPhaseIdx, wCompIdx);
+                /*
+                take care:, xww, if no water is present, then take xww=xwg*pg/pwsat .
+                If this is larger than 1, then water appears
+                */
+                Scalar xwMax = 1.0;
+                if (xww > xwMax)
+                    wouldSwitch = true;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    xwMax *= 1.02;
+
+                // if the sum of the mole fractions would be larger than
+                // 100%, gas phase appears
+                if (xww > xwMax)
+                {
+                    // water phase appears
+                    std::cout << "water phase appears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", xww=xwg*pg/pwsat : "
+                            << xww << std::endl;
+                    wettingFlag = 1;
+                }
+                if ((wettingFlag == 1) && (nonwettingFlag == 0))
+                {
+                    newPhasePresence = wgPhaseOnly;
+                    priVars[switch1Idx] = 0.0001;
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
+                }
+                else if ((wettingFlag == 1) && (nonwettingFlag == 1))
+                {
+                    newPhasePresence = threePhases;
+                    priVars[switch1Idx] = 0.0001;
+                    priVars[switch2Idx] = 0.0001;
+                }
+                else if ((wettingFlag == 0) && (nonwettingFlag == 1))
+                {
+                    newPhasePresence = gnPhaseOnly;
+                    priVars[switch2Idx]
+                        = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
+                }
+            }
+            else if (phasePresence == wgPhaseOnly)
+            {
+                bool nonwettingFlag = 0;
+                bool gasFlag = 0;
+                bool wettingFlag = 0;
+
+                // get the fractions in the hypothetical NAPL phase
+                Scalar xnn = volVars.fluidState().moleFraction(nPhaseIdx, nCompIdx);
+
+                // take care: if the NAPL phase is not present, take
+                // xnn=xng*pg/pcsat if this is larger than 1, then NAPL
+                // appears
+                Scalar xnMax = 1.0;
+                if (xnn > xnMax)
+                    wouldSwitch = true;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    xnMax *= 1.02;
+
+                // if the sum of the hypothetical mole fraction would be larger than
+                // 100%, NAPL phase appears
+                if (xnn > xnMax)
+                {
+                    // NAPL phase appears
+                    std::cout << "NAPL phase appears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", xnn: "
+                            << xnn << std::endl;
+                    nonwettingFlag = 1;
+                }
+
+                Scalar Smin = -1.e-6;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    Smin = -0.01;
+
+                if (volVars.saturation(gPhaseIdx) <= Smin)
+                {
+                    wouldSwitch = true;
+                    // gas phase disappears
+                    std::cout << "Gas phase disappears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", sg: "
+                            << volVars.saturation(gPhaseIdx) << std::endl;
+                    gasFlag = 1;
+                }
+
+                Smin = 0.0;
+                if (this->wasSwitched_[dofIdxGlobal])
+                    Smin = -0.01;
+
+                if (volVars.saturation(wPhaseIdx) <= Smin)
+                {
+                    wouldSwitch = true;
+                    // gas phase disappears
+                    std::cout << "Water phase disappears at vertex " << dofIdxGlobal
+                            << ", coordinates: " << globalPos << ", sw: "
+                            << volVars.saturation(wPhaseIdx) << std::endl;
+                    wettingFlag = 1;
+                }
+
+                if ((gasFlag == 0) && (nonwettingFlag == 1) && (wettingFlag == 1))
+                {
+                    newPhasePresence = gnPhaseOnly;
+                    priVars[switch1Idx] = 0.0001;
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(nPhaseIdx, wCompIdx);
+    ;
+                }
+                else if ((gasFlag == 0) && (nonwettingFlag == 1) && (wettingFlag == 0))
+                {
+                    newPhasePresence = threePhases;
+                    priVars[switch2Idx] = 0.0001;
+                }
+                else if ((gasFlag == 1) && (nonwettingFlag == 0) && (wettingFlag == 0))
+                {
+                    newPhasePresence = wPhaseOnly;
+                    priVars[pressureIdx] = volVars.fluidState().pressure(wPhaseIdx);
+                    priVars[switch1Idx] = volVars.fluidState().temperature();
+                    priVars[switch2Idx] = volVars.fluidState().moleFraction(wPhaseIdx, nCompIdx);
+                }
+                else if ((gasFlag == 0) && (nonwettingFlag == 0) && (wettingFlag == 1))
+                {
+                    newPhasePresence = gPhaseOnly;
+                    priVars[switch1Idx]
+                        = volVars.fluidState().temperature();
+                    priVars[switch2Idx]
+                        = volVars.fluidState().moleFraction(gPhaseIdx, nCompIdx);
+                }
+            }
+        }
+
+
+        priVars.setState(newPhasePresence);
+        this->wasSwitched_[dofIdxGlobal] = wouldSwitch;
+        return phasePresence != newPhasePresence;
+    }
+
+};
+
+} // end namespace dumux
+
+#endif
diff --git a/dumux/porousmediumflow/3pwateroil/properties.hh b/dumux/porousmediumflow/3pwateroil/properties.hh
deleted file mode 100644
index 2ba4bc7e387fe273caae02915fc2701e5396d8ed..0000000000000000000000000000000000000000
--- a/dumux/porousmediumflow/3pwateroil/properties.hh
+++ /dev/null
@@ -1,75 +0,0 @@
-// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-// vi: set et ts=4 sw=4 sts=4:
-/*****************************************************************************
- *   See the file COPYING for full copying permissions.                      *
- *                                                                           *
- *   This program is free software: you can redistribute it and/or modify    *
- *   it under the terms of the GNU General Public License as published by    *
- *   the Free Software Foundation, either version 2 of the License, or       *
- *   (at your option) any later version.                                     *
- *                                                                           *
- *   This program is distributed in the hope that it will be useful,         *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
- *   GNU General Public License for more details.                            *
- *                                                                           *
- *   You should have received a copy of the GNU General Public License       *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
- *****************************************************************************/
-/*!
- * \ingroup ThreePWaterOilModel
- */
-/*!
- * \file
- *
- * \brief Defines the properties required for the three-phase two-component
- *        fully implicit model. This model requires the use of the non-isothermal
- *        extension found in dumux/implicit/nonisothermal
- */
-#ifndef DUMUX_3P2CNI_PROPERTIES_HH
-#define DUMUX_3P2CNI_PROPERTIES_HH
-
-#include <dumux/implicit/box/properties.hh>
-#include <dumux/implicit/cellcentered/properties.hh>
-#include <dumux/porousmediumflow/nonisothermal/model.hh>
-
-namespace Dumux
-{
-
-namespace Properties
-{
-//////////////////////////////////////////////////////////////////
-// Type tags
-//////////////////////////////////////////////////////////////////
-NEW_TYPE_TAG(ThreePWaterOilNI, INHERITS_FROM(NonIsothermal));
-NEW_TYPE_TAG(BoxThreePWaterOilNI, INHERITS_FROM(BoxModel, ThreePWaterOilNI));
-NEW_TYPE_TAG(CCThreePWaterOilNI, INHERITS_FROM(CCModel, ThreePWaterOilNI));
-
-//////////////////////////////////////////////////////////////////
-// Property tags
-//////////////////////////////////////////////////////////////////
-
-NEW_PROP_TAG(NumPhases);   //!< Number of fluid phases in the system
-NEW_PROP_TAG(NumComponents); //!< Number of fluid components in the system
-NEW_PROP_TAG(Indices); //!< Enumerations for the model
-NEW_PROP_TAG(SpatialParams); //!< The type of the spatial parameters
-NEW_PROP_TAG(FluidSystem); //!< Type of the multi-component relations
-
-NEW_PROP_TAG(MaterialLaw);   //!< The material law which ought to be used (extracted from the spatial parameters)
-
-NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem
-
-NEW_PROP_TAG(UseMoles); //!< Defines whether mole (true) or mass (false) fractions are used
-
-NEW_PROP_TAG(UseMassOutput); //!< Defines whether mole or mass are used for phaseStorage output
-NEW_PROP_TAG(EffectiveDiffusivityModel); //!< The employed model for the computation of the effective diffusivity
-
-NEW_PROP_TAG(ImplicitMassUpwindWeight); //!< The value of the upwind parameter for the mobility
-NEW_PROP_TAG(ImplicitMobilityUpwindWeight); //!< Weight for the upwind mobility in the velocity calculation
-NEW_PROP_TAG(UseSimpleModel); //!< Determines whether a simple model with only two phase states (wng) and (wn) should be used
-NEW_PROP_TAG(BaseFluxVariables); //!< The base flux variables
-NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient
-}
-}
-
-#endif
diff --git a/dumux/porousmediumflow/3pwateroil/propertydefaults.hh b/dumux/porousmediumflow/3pwateroil/propertydefaults.hh
deleted file mode 100644
index 3de1dacb7653b8b5e4d6e584050f5d7525acac6a..0000000000000000000000000000000000000000
--- a/dumux/porousmediumflow/3pwateroil/propertydefaults.hh
+++ /dev/null
@@ -1,172 +0,0 @@
-// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
-// vi: set et ts=4 sw=4 sts=4:
-/*****************************************************************************
- *   See the file COPYING for full copying permissions.                      *
- *                                                                           *
- *   This program is free software: you can redistribute it and/or modify    *
- *   it under the terms of the GNU General Public License as published by    *
- *   the Free Software Foundation, either version 2 of the License, or       *
- *   (at your option) any later version.                                     *
- *                                                                           *
- *   This program is distributed in the hope that it will be useful,         *
- *   but WITHOUT ANY WARRANTY; without even the implied warranty of          *
- *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the            *
- *   GNU General Public License for more details.                            *
- *                                                                           *
- *   You should have received a copy of the GNU General Public License       *
- *   along with this program.  If not, see <http://www.gnu.org/licenses/>.   *
- *****************************************************************************/
-/*!
- * \ingroup ThreePWaterOilModel
- */
-/*!
- * \file
- *
- * \brief Defines default values for most properties required by the
- *        3p2cni fully implicit model.
- */
-#ifndef DUMUX_3P2CNI_PROPERTY_DEFAULTS_HH
-#define DUMUX_3P2CNI_PROPERTY_DEFAULTS_HH
-
-#include <dumux/porousmediumflow/implicit/darcyfluxvariables.hh>
-#include <dumux/material/spatialparams/fv.hh>
-#include <dumux/material/fluidmatrixinteractions/3p/thermalconductivitysomerton3p.hh>
-#include <dumux/porousmediumflow/nonisothermal/model.hh>
-#include <dumux/material/fluidmatrixinteractions/diffusivitymillingtonquirk.hh>
-
-#include "indices.hh"
-#include "model.hh"
-#include "fluxvariables.hh"
-#include "volumevariables.hh"
-#include "properties.hh"
-#include "newtoncontroller.hh"
-#include "localresidual.hh"
-
-namespace Dumux
-{
-
-namespace Properties {
-//////////////////////////////////////////////////////////////////
-// Property values
-//////////////////////////////////////////////////////////////////
-
-/*!
- * \brief Set the property for the number of components.
- *
- * We just forward the number from the fluid system and use an static
- * assert to make sure it is 2.
- */
-SET_PROP(ThreePWaterOilNI, NumComponents)
-{
- private:
-    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
-
- public:
-    static const int value = FluidSystem::numComponents;
-
-    static_assert(value == 2,
-                  "Only fluid systems with 2 components are supported by the 3p2cni model!");
-};
-
-/*!
- * \brief Set the property for the number of fluid phases.
- *
- * We just forward the number from the fluid system and use an static
- * assert to make sure it is 2.
- */
-SET_PROP(ThreePWaterOilNI, NumPhases)
-{
- private:
-    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
-
- public:
-    static const int value = FluidSystem::numPhases;
-    static_assert(value == 3,
-                  "Only fluid systems with 3 phases are supported by the 3p2cni model!");
-};
-
-//! Use the 3p2cni specific newton controller for the 3p2cni model
-SET_TYPE_PROP(ThreePWaterOilNI, NewtonController, ThreePWaterOilNewtonController<TypeTag>);
-
-//! define the base flux variables to realize Darcy flow
-SET_TYPE_PROP(ThreePWaterOilNI, BaseFluxVariables, ImplicitDarcyFluxVariables<TypeTag>);
-
-//! the upwind factor for the mobility.
-SET_SCALAR_PROP(ThreePWaterOilNI, ImplicitMassUpwindWeight, 1.0);
-
-//! set default mobility upwind weight to 1.0, i.e. fully upwind
-SET_SCALAR_PROP(ThreePWaterOilNI, ImplicitMobilityUpwindWeight, 1.0);
-
-//! Determines whether a constraint solver should be used explicitly
-SET_BOOL_PROP(ThreePWaterOilNI, UseSimpleModel, true);
-
-//! The spatial parameters to be employed.
-//! Use FVSpatialParams by default.
-SET_TYPE_PROP(ThreePWaterOilNI, SpatialParams, FVSpatialParams<TypeTag>);
-
-//! Use the model after Millington (1961) for the effective diffusivity
-SET_TYPE_PROP(ThreePWaterOilNI, EffectiveDiffusivityModel,
-             DiffusivityMillingtonQuirk<typename GET_PROP_TYPE(TypeTag, Scalar)>);
-
-// disable velocity output by default
-
-// enable gravity by default
-SET_BOOL_PROP(ThreePWaterOilNI, ProblemEnableGravity, true);
-
-SET_BOOL_PROP(ThreePWaterOilNI, UseMoles, true); //!< Define that mole fractions are used in the balance equations per default
-
-
-
-//! default value for the forchheimer coefficient
-// Source: Ward, J.C. 1964 Turbulent flow in porous media. ASCE J. Hydraul. Div 90.
-//        Actually the Forchheimer coefficient is also a function of the dimensions of the
-//        porous medium. Taking it as a constant is only a first approximation
-//        (Nield, Bejan, Convection in porous media, 2006, p. 10)
-SET_SCALAR_PROP(ThreePWaterOilNI, SpatialParamsForchCoeff, 0.55);
-
-
-//! Somerton is used as default model to compute the effective thermal heat conductivity
-SET_PROP(ThreePWaterOilNI, ThermalConductivityModel)
-{
-private:
-    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
-public:
-    using type = ThermalConductivitySomerton<Scalar, Indices>;
-};
-
-//! temperature is already written by the isothermal model
-SET_BOOL_PROP(ThreePWaterOilNI, NiOutputLevel, 0);
-
-//////////////////////////////////////////////////////////////////
-// Property values for isothermal model required for the general non-isothermal model
-//////////////////////////////////////////////////////////////////
-
-// set isothermal Model
-SET_TYPE_PROP(ThreePWaterOilNI, IsothermalModel, ThreePWaterOilModel<TypeTag>);
-
-// set isothermal FluxVariables
-SET_TYPE_PROP(ThreePWaterOilNI, IsothermalFluxVariables, ThreePWaterOilFluxVariables<TypeTag>);
-
-//set isothermal VolumeVariables
-SET_TYPE_PROP(ThreePWaterOilNI, IsothermalVolumeVariables, ThreePWaterOilVolumeVariables<TypeTag>);
-
-//set isothermal LocalResidual
-SET_TYPE_PROP(ThreePWaterOilNI, IsothermalLocalResidual, ThreePWaterOilLocalResidual<TypeTag>);
-
-//set isothermal Indices
-SET_PROP(ThreePWaterOilNI, IsothermalIndices)
-{
-
-public:
-    using type = ThreePWaterOilIndices<TypeTag, /*PVOffset=*/0>;
-};
-
-//set isothermal NumEq
-SET_INT_PROP(ThreePWaterOilNI, IsothermalNumEq, 2);
-
-}
-
-}
-
-#endif
diff --git a/dumux/porousmediumflow/3pwateroil/volumevariables.hh b/dumux/porousmediumflow/3pwateroil/volumevariables.hh
index d87d3eb8a95b1761c6b7cd6f739f05305099c729..b48f932adac6f620bc183cd8e034424e689e4c9d 100644
--- a/dumux/porousmediumflow/3pwateroil/volumevariables.hh
+++ b/dumux/porousmediumflow/3pwateroil/volumevariables.hh
@@ -18,57 +18,54 @@
  *****************************************************************************/
 /*!
  * \file
- *
+ * \ingroup ThreePWaterOilModel
  * \brief Contains the quantities which are constant within a
  *        finite volume in the three-phase, two-component model.
  */
 #ifndef DUMUX_3P2CNI_VOLUME_VARIABLES_HH
 #define DUMUX_3P2CNI_VOLUME_VARIABLES_HH
 
-#include <dumux/implicit/model.hh>
 #include <dumux/common/math.hh>
 
 #include <dune/common/parallel/collectivecommunication.hh>
 #include <vector>
 #include <iostream>
 
+#include <dumux/porousmediumflow/volumevariables.hh>
+
 #include <dumux/material/constants.hh>
 #include <dumux/material/fluidstates/compositional.hh>
 #include <dumux/material/constraintsolvers/computefromreferencephase.hh>
 #include <dumux/material/constraintsolvers/misciblemultiphasecomposition.hh>
-
 #include <dune/common/deprecated.hh>
 
-#include "properties.hh"
-
 namespace Dumux
 {
 
 /*!
  * \ingroup ThreePWaterOilModel
  * \brief Contains the quantities which are are constant within a
- *        finite volume in the two-phase, two-component model.
+ *        finite volume in the three-phase, two-component model.
  */
 template <class TypeTag>
-class ThreePWaterOilVolumeVariables : public ImplicitVolumeVariables<TypeTag>
+class ThreePWaterOilVolumeVariables : public PorousMediumFlowVolumeVariables<TypeTag>
 {
-    using ParentType = ImplicitVolumeVariables<TypeTag>;
+    using ParentType = PorousMediumFlowVolumeVariables<TypeTag>;
     using Implementation = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
 
     using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
     using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
-    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
-    using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
-    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
+    using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
     using MaterialLaw = typename GET_PROP_TYPE(TypeTag, MaterialLaw);
-    using MaterialLawParams = typename GET_PROP_TYPE(TypeTag, MaterialLaw)::Params;
+    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
+    using SpatialParams = typename GET_PROP_TYPE(TypeTag, SpatialParams);
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
+    using ElementSolutionVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector);
 
     // constraint solvers
     using MiscibleMultiPhaseComposition = Dumux::MiscibleMultiPhaseComposition<Scalar, FluidSystem>;
     using ComputeFromReferencePhase = Dumux::ComputeFromReferencePhase<Scalar, FluidSystem>;
-
-    using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
     enum {
         dim = GridView::dimension,
 
@@ -77,6 +74,7 @@ class ThreePWaterOilVolumeVariables : public ImplicitVolumeVariables<TypeTag>
 
         wCompIdx = Indices::wCompIdx,
         nCompIdx = Indices::nCompIdx,
+        gCompIdx = Indices::gCompIdx,
 
         wPhaseIdx = Indices::wPhaseIdx,
         gPhaseIdx = Indices::gPhaseIdx,
@@ -101,42 +99,33 @@ class ThreePWaterOilVolumeVariables : public ImplicitVolumeVariables<TypeTag>
 
     static const Scalar R; // universial gas constant
 
-    enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) };
+     enum { isBox = GET_PROP_VALUE(TypeTag, DiscretizationMethod) == DiscretizationMethods::Box };
     enum { dofCodim = isBox ? dim : 0 };
 
 public:
     //! The type of the object returned by the fluidState() method
-    using FluidState = Dumux::CompositionalFluidState<Scalar, FluidSystem>;
+    using FluidState = typename GET_PROP_TYPE(TypeTag, FluidState);
+    using ParentType::enthalpy;
 
 
     /*!
      * \copydoc ImplicitVolumeVariables::update
      */
-    void update(const PrimaryVariables &priVars,
+    void update(const ElementSolutionVector &elemSol,
                 const Problem &problem,
                 const Element &element,
-                const FVElementGeometry &fvGeometry,
-                const int scvIdx,
-                bool isOldSol)
+                const SubControlVolume& scv)
     {
-        ParentType::update(priVars,
-                           problem,
-                           element,
-                           fvGeometry,
-                           scvIdx,
-                           isOldSol);
+        ParentType::update(elemSol, problem, element, scv);
+        const auto& priVars = ParentType::extractDofPriVars(elemSol, scv);
+        const auto phasePresence = priVars.state();
 
-        bool useSimpleModel = GET_PROP_VALUE(TypeTag, UseSimpleModel);
+        bool onlyGasPhaseCanDisappear = GET_PROP_VALUE(TypeTag, OnlyGasPhaseCanDisappear);
 
         // capillary pressure parameters
-        const MaterialLawParams &materialParams =
-            problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx);
+        const auto& materialParams = problem.spatialParams().materialLawParams(element, scv, elemSol);
 
-        int globalIdx = problem.model().dofMapper().subIndex(element, scvIdx, dofCodim);
-
-        int phasePresence = problem.model().phasePresence(globalIdx, isOldSol);
-
-        if(!useSimpleModel)
+        if(!onlyGasPhaseCanDisappear)
         {
             /* first the saturations */
             if (phasePresence == threePhases)
@@ -650,8 +639,7 @@ public:
                 fluidState_.setDensity(gPhaseIdx, rhoG);
                 fluidState_.setDensity(nPhaseIdx, rhoN);
             }
-            else
-                assert(false); // unhandled phase state
+            else DUNE_THROW(Dune::InvalidStateException, "phasePresence: " << phasePresence << " is invalid.");
             }
 
         for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
@@ -678,37 +666,27 @@ public:
          *            for the porous media happens at another place!
          */
 
-        // diffusivity coefficients
         diffusionCoefficient_[gPhaseIdx] = FluidSystem::diffusionCoefficient(fluidState_, gPhaseIdx);
-
         diffusionCoefficient_[wPhaseIdx] = FluidSystem::diffusionCoefficient(fluidState_, wPhaseIdx);
-
         /* no diffusion in NAPL phase considered  at the moment, dummy values */
         diffusionCoefficient_[nPhaseIdx] = 1.e-10;
 
-        Valgrind::CheckDefined(diffusionCoefficient_);
 
         // porosity
-        porosity_ = problem.spatialParams().porosity(element,
-                                                         fvGeometry,
-                                                         scvIdx);
+        porosity_ = problem.spatialParams().porosity(element, scv, elemSol);
         Valgrind::CheckDefined(porosity_);
 
         // permeability
-        permeability_ = problem.spatialParams().intrinsicPermeability(element,
-                                                                          fvGeometry,
-                                                                          scvIdx);
+        permeability_ =  problem.spatialParams().permeability(element, scv, elemSol);
         Valgrind::CheckDefined(permeability_);
 
+//         fluidState_.setTemperature(temp_);
         // the enthalpies (internal energies are directly calculated in the fluidstate
         for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
             Scalar h = FluidSystem::enthalpy(fluidState_, phaseIdx);
             fluidState_.setEnthalpy(phaseIdx, h);
-        }
 
-
-        // energy related quantities not contained in the fluid state
-        asImp_().updateEnergy_(priVars, problem, element, fvGeometry, scvIdx, isOldSol);
+        }
     }
 
     /*!
@@ -790,9 +768,10 @@ public:
      * \param phaseIdx The phase index
      */
     Scalar mobility(const int phaseIdx) const
-    {
-        return mobility_[phaseIdx];
-    }
+    { return mobility_[phaseIdx]; }
+
+    Scalar viscosity(const int phaseIdx) const
+    { return fluidState_.viscosity(phaseIdx); }
 
     /*!
      * \brief Returns the effective capillary pressure within the control volume.
@@ -815,17 +794,19 @@ public:
     /*!
      * \brief Returns the diffusivity coefficient matrix
      */
-    DUNE_DEPRECATED_MSG("diffusionCoefficient() is deprecated. Use diffCoeff(int phaseIdx) instead.")
+    DUNE_DEPRECATED_MSG("diffusionCoefficient() is deprecated. Use diffusionCoefficient(int phaseIdx) instead.")
     Dune::FieldVector<Scalar, numPhases> diffusionCoefficient() const
     {
         return diffusionCoefficient_;
     }
 
     /*!
-     * \brief Returns the diffusivity coefficient
+     * \brief Returns the diffusion coeffiecient
      */
-    Scalar diffCoeff(int phaseIdx) const
-    { return diffusionCoefficient_[phaseIdx]; }
+    Scalar diffusionCoefficient(int phaseIdx, int compIdx) const
+    {
+        return diffusionCoefficient_[phaseIdx];
+    }
 
     /*!
      * \brief Returns the adsorption information
@@ -853,17 +834,6 @@ public:
 
 protected:
 
-    /*!
-     * \brief Called by update() to compute the energy related quantities
-     */
-    void updateEnergy_(const PrimaryVariables &priVars,
-                       const Problem &problem,
-                       const Element &element,
-                       const FVElementGeometry &fvGeometry,
-                       const int scvIdx,
-                       bool isOldSol)
-    { }
-
     Scalar sw_, sg_, sn_, pg_, pw_, pn_, temp_;
 
     Scalar moleFrac_[numPhases][numComponents];
@@ -879,6 +849,8 @@ protected:
     FluidState fluidState_;
 
 private:
+    std::array<std::array<Scalar, numComponents-1>, numPhases> diffCoefficient_;
+
     Implementation &asImp_()
     { return *static_cast<Implementation*>(this); }
 
diff --git a/dumux/porousmediumflow/3pwateroil/vtkoutputfields.hh b/dumux/porousmediumflow/3pwateroil/vtkoutputfields.hh
new file mode 100644
index 0000000000000000000000000000000000000000..079e1dce9292a8ae047dae1f3c6540a8f63304fd
--- /dev/null
+++ b/dumux/porousmediumflow/3pwateroil/vtkoutputfields.hh
@@ -0,0 +1,82 @@
+// -*- 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
+ * \ingroup ThreePWaterOilModel
+ * \brief Adds vtk output fields specific to the twop model
+ */
+#ifndef DUMUX_THREEPWATEROIL_VTK_OUTPUT_FIELDS_HH
+#define DUMUX_THREEPWATEROIL_VTK_OUTPUT_FIELDS_HH
+
+#include <dumux/common/properties.hh>
+
+namespace Dumux
+{
+
+/*!
+ * \ingroup ThreePWaterOilModel
+ * \brief Adds vtk output fields specific to the three-phase three-component model
+ */
+template<class TypeTag>
+class ThreePWaterOilVtkOutputFields
+{
+    using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
+    using VolumeVariables = typename GET_PROP_TYPE(TypeTag, VolumeVariables);
+    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
+
+    enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases),
+           numComponents = GET_PROP_VALUE(TypeTag, NumComponents)
+         };
+public:
+    template <class VtkOutputModule>
+    static void init(VtkOutputModule& vtk)
+    {
+        // register standardized vtk output fields
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.saturation(Indices::wPhaseIdx); }, "sw");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.saturation(Indices::nPhaseIdx); },"sn");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.saturation(Indices::gPhaseIdx); },"sg");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.pressure(Indices::wPhaseIdx); },"pw");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.pressure(Indices::nPhaseIdx); },"pn");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.pressure(Indices::gPhaseIdx); },"pg");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.density(Indices::wPhaseIdx); },"rhow");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.density(Indices::nPhaseIdx); },"rhon");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.density(Indices::gPhaseIdx); },"rhog");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return
+        v.mobility(Indices::wPhaseIdx); },"MobW");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.mobility(Indices::nPhaseIdx); },"MobN");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.mobility(Indices::gPhaseIdx); },"MobG");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return
+        v.viscosity(Indices::wPhaseIdx); },"ViscosW");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.viscosity(Indices::nPhaseIdx); },"ViscosN");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.viscosity(Indices::gPhaseIdx); },"ViscosG");
+
+        for (int i = 0; i < numPhases; ++i)
+            for (int j = 0; j < numComponents; ++j)
+                vtk.addVolumeVariable([i,j](const VolumeVariables& v){ return v.moleFraction(i,j); },
+                                      "x^" + FluidSystem::phaseName(i) + "_" +  FluidSystem::componentName(j));
+
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.porosity(); },"porosity");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.priVars().state(); },"phase presence");
+        vtk.addVolumeVariable( [](const VolumeVariables& v){ return v.permeability(); },"permeability");
+    }
+};
+
+} // end namespace Dumux
+
+#endif
diff --git a/test/porousmediumflow/3pwateroil/implicit/3pwateroilsagdproblem.hh b/test/porousmediumflow/3pwateroil/implicit/3pwateroilsagdproblem.hh
index 7ff97306dbb0acf66da383c7b1833da95256b589..ec746506441ef4beec445b9af567f51bf78d64db 100644
--- a/test/porousmediumflow/3pwateroil/implicit/3pwateroilsagdproblem.hh
+++ b/test/porousmediumflow/3pwateroil/implicit/3pwateroilsagdproblem.hh
@@ -24,8 +24,9 @@
 #ifndef DUMUX_SAGDPROBLEM_HH
 #define DUMUX_SAGDPROBLEM_HH
 
-#include <dumux/porousmediumflow/implicit/problem.hh>
+#include <dumux/porousmediumflow/problem.hh>
 
+#include <dumux/discretization/box/properties.hh>
 #include <dumux/porousmediumflow/3pwateroil/model.hh>
 #include <dumux/material/fluidsystems/h2oheavyoilfluidsystem.hh>
 #include "3pwateroilsagdspatialparams.hh"
@@ -56,19 +57,9 @@ SET_TYPE_PROP(SagdProblem,
               FluidSystem,
               Dumux::FluidSystems::H2OHeavyOil<typename GET_PROP_TYPE(TypeTag, Scalar)>);
 
+SET_BOOL_PROP(SagdProblem, OnlyGasPhaseCanDisappear, true);
 
-// Enable gravity
-SET_BOOL_PROP(SagdProblem, ProblemEnableGravity, true);
-
-// Use forward differences instead of central differences
-SET_INT_PROP(SagdProblem, ImplicitNumericDifferenceMethod, +1);
-
-// Write newton convergence
-SET_BOOL_PROP(SagdProblem, NewtonWriteConvergence, false);
-
-SET_BOOL_PROP(SagdProblem, UseSimpleModel, true);
-
-SET_BOOL_PROP(SagdProblem, UseMoles, false);
+SET_BOOL_PROP(SagdProblem, UseMoles, true);
 }
 
 
@@ -81,15 +72,13 @@ SET_BOOL_PROP(SagdProblem, UseMoles, false);
  *
  *  */
 template <class TypeTag >
-class SagdProblem : public ImplicitPorousMediaProblem<TypeTag>
+class SagdProblem : public PorousMediumFlowProblem<TypeTag>
 {
-    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using ParentType = PorousMediumFlowProblem<TypeTag>;
     using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
-    using Grid = typename GridView::Grid;
-
-    using ParentType = ImplicitPorousMediaProblem<TypeTag>;
-
-    // copy some indices for convenience
+    using FVGridGeometry = typename GET_PROP_TYPE(TypeTag, FVGridGeometry);
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
     using Indices = typename GET_PROP_TYPE(TypeTag, Indices);
     enum {
         pressureIdx = Indices::pressureIdx,
@@ -97,6 +86,7 @@ class SagdProblem : public ImplicitPorousMediaProblem<TypeTag>
         switch2Idx = Indices::switch2Idx,
 
         energyEqIdx = Indices::energyEqIdx,
+        temperatureIdx = Indices::temperatureIdx,
 
         // phase and component indices
         wPhaseIdx = Indices::wPhaseIdx,
@@ -111,30 +101,21 @@ class SagdProblem : public ImplicitPorousMediaProblem<TypeTag>
         wgPhaseOnly = Indices::wgPhaseOnly,
         threePhases = Indices::threePhases,
 
-        //contiWEqIdx = Indices::contiWEqIdx,
-        //contiNEqIdx = Indices::contiNEqIdx,
         // Grid and world dimension
         dim = GridView::dimension,
         dimWorld = GridView::dimensionworld
     };
 
-
     using PrimaryVariables = typename GET_PROP_TYPE(TypeTag, PrimaryVariables);
+    using NeumannFluxes = typename GET_PROP_TYPE(TypeTag, NumEqVector);
+    using Sources = typename GET_PROP_TYPE(TypeTag, NumEqVector);
+    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
     using BoundaryTypes = typename GET_PROP_TYPE(TypeTag, BoundaryTypes);
-    using TimeManager = typename GET_PROP_TYPE(TypeTag, TimeManager);
-
     using Element = typename GridView::template Codim<0>::Entity;
-    using Vertex = typename GridView::template Codim<dim>::Entity;
-    using Intersection = typename GridView::Intersection;
-
     using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
-    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
-    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
-
+    using SubControlVolumeFace = typename GET_PROP_TYPE(TypeTag, SubControlVolumeFace);
     using GlobalPosition = Dune::FieldVector<Scalar, dimWorld>;
 
-    enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) };
-
 public:
 
     /*!
@@ -144,8 +125,8 @@ public:
      * \param gridView The grid view
      */
 
-    SagdProblem(TimeManager &timeManager, const GridView &gridView)
-        : ParentType(timeManager, gridView), pOut_(4e6)
+    SagdProblem(std::shared_ptr<const FVGridGeometry> fvGridGeometry)
+    : ParentType(fvGridGeometry), pOut_(4e6)
     {
 
         maxDepth_ = 400.0; // [m]
@@ -153,72 +134,9 @@ public:
         totalMassProducedOil_ =0;
         totalMassProducedWater_ =0;
 
-        this->timeManager().startNextEpisode(86400);
-
-        name_ = GET_RUNTIME_PARAM(TypeTag, std::string, Problem.Name);
+        name_ = getParam<std::string>("Problem.Name");
     }
 
-    bool shouldWriteRestartFile() const
-    {
-        return 0;
-    }
-
-
-    /*!
-     * \brief Called directly after the time integration.
-     */
-    void postTimeStep()
-    {
-        double time = this->timeManager().time();
-        double dt = this->timeManager().timeStepSize();
-
-        // Calculate storage terms
-        PrimaryVariables storage;
-        this->model().globalStorage(storage);
-
-        // Write mass balance information for rank 0
-        if (this->gridView().comm().rank() == 0)
-        {
-            std::cout<<"Storage: " << storage << "Time: " << time+dt << std::endl;
-            massBalance.open ("massBalance.txt", std::ios::out | std::ios::app );
-                        massBalance << "         Storage       " << storage
-                                    << "         Time           " << time+dt
-                                    << std::endl;
-                        massBalance.close();
-
-        }
-
-            // Calculate storage terms
-        PrimaryVariables storageW, storageN;
-        //Dune::FieldVector<Scalar, 2> flux(0.0);
-        this->model().globalPhaseStorage(storageW, wPhaseIdx);
-        this->model().globalPhaseStorage(storageN, nPhaseIdx);
-
-        //mass of Oil
-        const Scalar newMassProducedOil_ = massProducedOil_;
-        std::cout<<" newMassProducedOil_ : "<< newMassProducedOil_ << " Time: " << time+dt << std::endl;
-
-        totalMassProducedOil_ += newMassProducedOil_;
-        std::cout<<" totalMassProducedOil_ : "<< totalMassProducedOil_ << " Time: " << time+dt << std::endl;
-        //mass of Water
-        const Scalar newMassProducedWater_ = massProducedWater_;
-        //std::cout<<" newMassProducedWater_ : "<< newMassProducedWater_ << " Time: " << time+dt << std::endl;
-
-        totalMassProducedWater_ += newMassProducedWater_;
-        //std::cout<<" totalMassProducedWater_ : "<< totalMassProducedWater_ << " Time: " << time+dt << std::endl;
-
-
-        const int timeStepIndex = this->timeManager().timeStepIndex();
-
-        if (timeStepIndex == 0 ||
-            timeStepIndex % 100 == 0 ||   //after every 1000000 secs
-            this->timeManager().episodeWillBeFinished() ||
-            this->timeManager().willBeFinished())
-        {
-            std::cout<<" totalMassProducedOil_ : "<< totalMassProducedOil_ << " Time: " << time+dt << std::endl;
-            std::cout<<" totalMassProducedWater_ : "<< totalMassProducedWater_ << " Time: " << time+dt << std::endl;
-        }
-    }
 
     void episodeEnd()
     {
@@ -241,13 +159,6 @@ public:
     const std::string name() const
     { return name_; }
 
-
-    void sourceAtPos(PrimaryVariables &values,
-                     const GlobalPosition &globalPos) const
-    {
-        values = 0.0;
-    }
-
     // \}
 
     /*!
@@ -262,9 +173,9 @@ public:
      * \param bcTypes The boundary types for the conservation equations
      * \param globalPos The position for which the bc type should be evaluated
      */
-   void boundaryTypesAtPos(BoundaryTypes &bcTypes,
-            const GlobalPosition &globalPos) const
+    BoundaryTypes boundaryTypesAtPos(const GlobalPosition &globalPos) const
     {
+        BoundaryTypes bcTypes;
         // on bottom
         if (globalPos[1] <  eps_)
             bcTypes.setAllNeumann();
@@ -280,6 +191,7 @@ public:
         // on Left
         else
             bcTypes.setAllNeumann();
+        return bcTypes;
     }
 
     /*!
@@ -291,9 +203,9 @@ public:
      *
      * For this method, the \a values parameter stores primary variables.
      */
-    void dirichletAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const
+    PrimaryVariables dirichletAtPos(const GlobalPosition &globalPos) const
     {
-        initial_(values, globalPos);
+       return initial_(globalPos);
     }
 
     /*!
@@ -311,22 +223,14 @@ public:
      * For this method, the \a values parameter stores the mass flux
      * in normal direction of each phase. Negative values mean influx.
      */
-    void solDependentNeumann(PrimaryVariables &values,
-                      const Element &element,
-                      const FVElementGeometry &fvGeometry,
-                      const Intersection &is,
-                      const int scvIdx,
-                      const int boundaryFaceIdx,
-                      const ElementVolumeVariables &elemVolVars) const
+    NeumannFluxes neumann(const Element& element,
+                          const FVElementGeometry& fvGeometry,
+                          const ElementVolumeVariables& elemVolVars,
+                          const SubControlVolumeFace& scvf) const
     {
-        values = 0;
-
-        GlobalPosition globalPos;
-        if (isBox)
-           globalPos = element.geometry().corner(scvIdx);
-        else
-           globalPos = is.geometry().center();
+        NeumannFluxes values(0.0);
 
+         const auto& globalPos = scvf.ipGlobal();
         // negative values for injection at injection well
         if (globalPos[1] > 8.5 - eps_ && globalPos[1] < 9.5 + eps_)
         {
@@ -337,17 +241,17 @@ public:
         else if (globalPos[1] > 2.5 - eps_ && globalPos[1] < 3.5 + eps_) // production well
         {
 
-            const Scalar elemPressW = elemVolVars[scvIdx].pressure(wPhaseIdx);            //Pressures
-            const Scalar elemPressN = elemVolVars[scvIdx].pressure(nPhaseIdx);
+            const Scalar elemPressW = elemVolVars[scvf.insideScvIdx()].pressure(wPhaseIdx);            //Pressures
+            const Scalar elemPressN = elemVolVars[scvf.insideScvIdx()].pressure(nPhaseIdx);
 
-            const Scalar densityW = elemVolVars[scvIdx].fluidState().density(wPhaseIdx);  //Densities
-            const Scalar densityN = elemVolVars[scvIdx].fluidState().density(nPhaseIdx);
+            const Scalar densityW = elemVolVars[scvf.insideScvIdx()].fluidState().density(wPhaseIdx);  //Densities
+            const Scalar densityN = elemVolVars[scvf.insideScvIdx()].fluidState().density(nPhaseIdx);
 
-            const Scalar elemMobW = elemVolVars[scvIdx].mobility(wPhaseIdx);      //Mobilities
-            const Scalar elemMobN = elemVolVars[scvIdx].mobility(nPhaseIdx);
+            const Scalar elemMobW = elemVolVars[scvf.insideScvIdx()].mobility(wPhaseIdx);      //Mobilities
+            const Scalar elemMobN = elemVolVars[scvf.insideScvIdx()].mobility(nPhaseIdx);
 
-            const Scalar enthW = elemVolVars[scvIdx].enthalpy(wPhaseIdx);      //Enthalpies
-            const Scalar enthN = elemVolVars[scvIdx].enthalpy(nPhaseIdx);
+            const Scalar enthW = elemVolVars[scvf.insideScvIdx()].enthalpy(wPhaseIdx);      //Enthalpies
+            const Scalar enthN = elemVolVars[scvf.insideScvIdx()].enthalpy(nPhaseIdx);
 
             const Scalar wellRadius = 0.50 * 0.3048; // 0.50 ft as specified by SPE9
 
@@ -368,7 +272,7 @@ public:
             // qE = qW*0.018*enthW + qN*enthN*0.350;
 
             //with cooling: see Diplomarbeit Stefan Roll, Sept. 2015
-            Scalar wT = elemVolVars[scvIdx].temperature(); // well temperature
+            Scalar wT = elemVolVars[scvf.insideScvIdx()].temperature(); // well temperature
             if ( wT > 495. )
             {
               qE = qW*0.018*enthW + qN*enthN*0.350 + (wT-495.)*5000.; // ~3x injected enthalpy
@@ -384,6 +288,7 @@ public:
             massProducedOil_ = qN;
             massProducedWater_ = qW;
         }
+        return values;
     }
 
     // \}
@@ -402,36 +307,24 @@ public:
      * For this method, the \a values parameter stores primary
      * variables.
      */
-    void initialAtPos(PrimaryVariables &values, const GlobalPosition &globalPos) const
-    {
-        initial_(values, globalPos);
-    }
-
-    /*!
-     * \brief Return the initial phase state inside a control volume.
-     *
-     * \param vert The vertex
-     * \param globalIdx The index of the global vertex
-     * \param globalPos The global position
-     */
-    int initialPhasePresence(const Vertex &vert,
-                             int &globalIdx,
-                             const GlobalPosition &globalPos) const
+     PrimaryVariables initialAtPos(const GlobalPosition &globalPos) const
     {
-        return wnPhaseOnly;
+        return initial_(globalPos);
     }
 
 private:
     // internal method for the initial condition (reused for the
     // dirichlet conditions!)
-    void initial_(PrimaryVariables &values,
-                  const GlobalPosition &globalPos) const
+    PrimaryVariables initial_(const GlobalPosition &globalPos) const
     {
+        PrimaryVariables values(0.0);
+        values.setState(Indices::wnPhaseOnly);
         Scalar densityW = 1000.0;
         values[pressureIdx] = 101300.0 + (maxDepth_ - globalPos[1])*densityW*9.81;
 
         values[switch1Idx] = 295.13;   // temperature
         values[switch2Idx] = 0.3;   //NAPL saturation
+        return values;
     }
 
     Scalar maxDepth_;
diff --git a/test/porousmediumflow/3pwateroil/implicit/3pwateroilsagdspatialparams.hh b/test/porousmediumflow/3pwateroil/implicit/3pwateroilsagdspatialparams.hh
index d253b4c9229e2030d2c92b14e9a4d014c985e974..1a217f300d5895d59952dc5d553796602bee8740 100644
--- a/test/porousmediumflow/3pwateroil/implicit/3pwateroilsagdspatialparams.hh
+++ b/test/porousmediumflow/3pwateroil/implicit/3pwateroilsagdspatialparams.hh
@@ -74,11 +74,15 @@ template<class TypeTag>
 class SagdSpatialParams : public FVSpatialParams<TypeTag>
 {
     using ParentType = FVSpatialParams<TypeTag>;
-
     using Grid = typename GET_PROP_TYPE(TypeTag, Grid);
-    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
     using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
-    using CoordScalar = typename Grid::ctype;
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    using GridView = typename GET_PROP_TYPE(TypeTag, GridView);
+    using MaterialLaw = typename GET_PROP_TYPE(TypeTag, MaterialLaw);
+    using MaterialLawParams = typename MaterialLaw::Params;
+    using FluidSystem = typename GET_PROP_TYPE(TypeTag, FluidSystem);
+    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+    using SubControlVolume = typename GET_PROP_TYPE(TypeTag, SubControlVolume);
     enum {
         dim=GridView::dimension,
         dimWorld=GridView::dimensionworld
@@ -90,30 +94,21 @@ class SagdSpatialParams : public FVSpatialParams<TypeTag>
         nPhaseIdx = Indices::nPhaseIdx
     };
 
-    using GlobalPosition = Dune::FieldVector<CoordScalar, dimWorld>;
-    using DimVector = Dune::FieldVector<CoordScalar, dimWorld>;
-
-
-    using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
-
-    using FluxVariables = typename GET_PROP_TYPE(TypeTag, FluxVariables);
-    using ElementVolumeVariables = typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables);
-
-    using FVElementGeometry = typename GET_PROP_TYPE(TypeTag, FVElementGeometry);
+    using CoordScalar = typename Grid::ctype;
+    using GlobalPosition = Dune::FieldVector<CoordScalar,dimWorld>;
     using Element = typename GridView::template Codim<0>::Entity;
-
+    using ElementSolutionVector = typename GET_PROP_TYPE(TypeTag, ElementSolutionVector);
 
 public:
-    using MaterialLaw = typename GET_PROP_TYPE(TypeTag, MaterialLaw);
-    using MaterialLawParams = typename MaterialLaw::Params;
+    using PermeabilityType = Scalar;
 
     /*!
      * \brief The constructor
      *
      * \param gridView The grid view
      */
-    SagdSpatialParams(const GridView &gridView)
-        : ParentType(gridView), eps_(1e-6)
+    SagdSpatialParams(const Problem& problem)
+    : ParentType(problem), eps_(1e-6)
     {
         layerBottom_ = 35.0;
 
@@ -152,60 +147,69 @@ public:
         fineMaterialParams_.setKrRegardsSnr(false);
     }
 
-    ~SagdSpatialParams()
-    {}
+    /*!
+     * \brief Function for defining the (intrinsic) permeability \f$[m^2]\f$
+     * \note  It is possibly solution dependent.
+     *
+     * \param element The current element
+     * \param scv The sub-control volume inside the element.
+     * \param elemSol The solution at the dofs connected to the element.
+     * \return permeability
+     */
+    PermeabilityType permeability(const Element& element,
+                                  const SubControlVolume& scv,
+                                  const ElementSolutionVector& elemSol) const
+    {  return permeabilityAtPos(scv.dofPosition());}
 
     /*!
-     * \brief Apply the intrinsic permeability tensor to a pressure
-     *        potential gradient.
+     * \brief Returns the intrinsic permeability tensor \f$[m^2]\f$
      *
-     * \param element The current finite element
-     * \param fvElemGeom The current finite volume geometry of the element
-     * \param scvIdx The index of the sub-control volume
+     * \param globalPos The global position
      */
-    const Scalar intrinsicPermeability(const Element &element,
-                                       const FVElementGeometry &fvElemGeom,
-                                       int scvIdx) const
+    PermeabilityType permeabilityAtPos(const GlobalPosition& globalPos) const
     {
-        const GlobalPosition &pos = fvElemGeom.subContVol[scvIdx].global;
-        if (isFineMaterial_(pos))
+        if (isFineMaterial_(globalPos))
             return fineK_;
         return coarseK_;
     }
 
     /*!
-     * \brief Define the porosity \f$[-]\f$ of the spatial parameters
+     * \brief Returns the porosity \f$[-]\f$
      *
-     * \param element The finite element
-     * \param fvGeometry The finite volume geometry
-     * \param scvIdx The local index of the sub-control volume where
-     *                    the porosity needs to be defined
+     * \param globalPos The global position
      */
-    Scalar porosity(const Element &element,
-                    const FVElementGeometry &fvGeometry,
-                    const int scvIdx) const
+    Scalar porosityAtPos(const GlobalPosition& globalPos) const
     {
-        const GlobalPosition &pos = fvGeometry.subContVol[scvIdx].global;
-        if (isFineMaterial_(pos))
+        if (isFineMaterial_(globalPos))
             return finePorosity_;
         else
             return coarsePorosity_;
     }
 
+    /*!
+     * \brief Function for defining the parameters needed by constitutive relationships (kr-sw, pc-sw, etc.).
+     *
+     * \param element The current element
+     * \param scv The sub-control volume inside the element.
+     * \param elemSol The solution at the dofs connected to the element.
+     * \return the material parameters object
+     */
+    const MaterialLawParams& materialLawParams(const Element& element,
+                                               const SubControlVolume& scv,
+                                               const ElementSolutionVector& elemSol) const
+    {
+        return materialLawParamsAtPos(scv.dofPosition());
+    }
 
     /*!
-     * \brief return the parameter object for the Brooks-Corey material law which depends on the position
+     * \brief Returns the parameter object for the capillary-pressure/
+     *        saturation material law
      *
-     * \param element The current finite element
-     * \param fvGeometry The current finite volume geometry of the element
-     * \param scvIdx The index of the sub-control volume
+     * \param globalPos The global position
      */
-    const MaterialLawParams& materialLawParams(const Element &element,
-                                               const FVElementGeometry &fvGeometry,
-                                               const int scvIdx) const
+    const MaterialLawParams& materialLawParamsAtPos(const GlobalPosition& globalPos) const
     {
-        const GlobalPosition &pos = fvGeometry.subContVol[scvIdx].global;
-        if (isFineMaterial_(pos))
+        if (isFineMaterial_(globalPos))
             return fineMaterialParams_;
         else
             return coarseMaterialParams_;
@@ -220,12 +224,9 @@ public:
      * \param fvGeometry The finite volume geometry
      * \param scvIdx The local index of the sub-control volume
      */
-    Scalar solidHeatCapacity(const Element &element,
-                             const FVElementGeometry &fvGeometry,
-                             const int scvIdx) const
+    Scalar solidHeatCapacityAtPos(const GlobalPosition& globalPos) const
     {
-        const GlobalPosition &pos = fvGeometry.subContVol[scvIdx].global;
-        if (isFineMaterial_(pos))
+        if (isFineMaterial_(globalPos))
             return fineHeatCap_ ;
         else
             return coarseHeatCap_;
@@ -240,9 +241,7 @@ public:
      * \param fvGeometry The finite volume geometry
      * \param scvIdx The local index of the sub-control volume
      */
-    Scalar solidDensity(const Element &element,
-                        const FVElementGeometry &fvGeometry,
-                        const int scvIdx) const
+    Scalar solidDensityAtPos(const GlobalPosition& globalPos) const
     {
         return 2650; // density of sand [kg/m^3]
     }
@@ -255,9 +254,7 @@ public:
      * \param scvIdx The local index of the sub-control volume where
      *                    the heat capacity needs to be defined
      */
-    Scalar solidThermalConductivity(const Element &element,
-                                    const FVElementGeometry &fvGeometry,
-                                    const int scvIdx) const
+    Scalar solidThermalConductivityAtPos(const GlobalPosition& globalPos) const
     {
         return lambdaSolid_;
     }
diff --git a/test/porousmediumflow/3pwateroil/implicit/CMakeLists.txt b/test/porousmediumflow/3pwateroil/implicit/CMakeLists.txt
index b0428e98ea7e02a51fb186faaf2262a2e8ceaf2e..f902e222a3cbd0a145eab5d0d81da4add741f612 100644
--- a/test/porousmediumflow/3pwateroil/implicit/CMakeLists.txt
+++ b/test/porousmediumflow/3pwateroil/implicit/CMakeLists.txt
@@ -1,13 +1,13 @@
 add_input_file_links()
 
-dune_add_test(
-  NAME test_box3pwateroil
-  SOURCES test_box3pwateroil.cc
-  COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py
-  CMD_ARGS --script fuzzy
-           --files ${CMAKE_SOURCE_DIR}/test/references/3pwateroilbox-reference.vtu
+dune_add_test(NAME test_box3pwateroil
+              SOURCES test_box3pwateroil.cc
+              COMPILE_DEFINITIONS TYPETAG=ThreePWaterOilSagdBoxProblem
+              COMMAND ${CMAKE_SOURCE_DIR}/bin/testing/runtest.py
+                CMD_ARGS --script fuzzy
+            --files ${CMAKE_SOURCE_DIR}/test/references/3pwateroilbox-reference.vtu
                    ${CMAKE_CURRENT_BINARY_DIR}/sagd-00011.vtu
-           --command "${CMAKE_CURRENT_BINARY_DIR}/test_box3pwateroil"
+            --command "${CMAKE_CURRENT_BINARY_DIR}/test_box3pwateroil"
   )
 
 #install sources
diff --git a/test/porousmediumflow/3pwateroil/implicit/test_box3pwateroil.cc b/test/porousmediumflow/3pwateroil/implicit/test_box3pwateroil.cc
index 9d42852d6a2d3d20d6e3291231d7212f3879f435..ef46ef7d475312fb4aa98379c44a422ea3e5b7fd 100644
--- a/test/porousmediumflow/3pwateroil/implicit/test_box3pwateroil.cc
+++ b/test/porousmediumflow/3pwateroil/implicit/test_box3pwateroil.cc
@@ -18,19 +18,41 @@
  *****************************************************************************/
 /*!
  * \file
- *
- * \brief test for the 3p3cni box model
+ * \ingroup OnePTests
+ * \brief Test for the three-phase three-component box model
  */
-#include "config.h"
-#include "3pwateroilsagdproblem.hh"
-#include <dumux/common/start.hh>
+#include <config.h>
+#include <ctime>
+#include <iostream>
+
+#include <dune/common/parallel/mpihelper.hh>
+#include <dune/common/timer.hh>
+#include <dune/grid/io/file/dgfparser/dgfexception.hh>
+#include <dune/grid/io/file/vtk.hh>
+
+#include <dumux/common/properties.hh>
+#include <dumux/common/parameters.hh>
+#include <dumux/common/dumuxmessage.hh>
+#include <dumux/common/defaultusagemessage.hh>
+#include <dumux/common/timeloop.hh>
+
+#include <dumux/linear/amgbackend.hh>
+#include <dumux/nonlinear/newtonmethod.hh>
+#include <dumux/porousmediumflow/compositional/privarswitchnewtoncontroller.hh>
 
+#include <dumux/assembly/fvassembler.hh>
+#include <dumux/assembly/diffmethod.hh>
+
+#include <dumux/discretization/methods.hh>
+
+#include <dumux/io/vtkoutputmodule.hh>
+
+#include "3pwateroilsagdproblem.hh"
 
 /*!
  * \brief Provides an interface for customizing error messages associated with
  *        reading in parameters.
- *
- * \param progName  The name of the program, that was tried to be started.
+ * \ingroup OnePTests
  * \param errorMsg  The error message that was issued by the start function.
  *                  Comprises the thing that went wrong and a general help message.
  */
@@ -42,21 +64,188 @@ void usage(const char *progName, const std::string &errorMsg)
                     errorMessageOut += " [options]\n";
                     errorMessageOut += errorMsg;
                     errorMessageOut += "\n\nThe list of mandatory options for this program is:\n"
-                                        "\t-TimeManager.TEnd      End of the simulation [s] \n"
-                                        "\t-TimeManager.DtInitial Initial timestep size [s] \n"
-                                        "\t-Grid.File             Name of the file containing the grid \n"
-                                        "\t                       definition in DGF format\n";
+                                        "\t-TimeManager.TEnd              End of the simulation [s] \n"
+                                        "\t-TimeManager.DtInitial         Initial timestep size [s] \n"
+                                        "\t-Grid.File                     Name of the file containing the grid \n"
+                                        "\t                               definition in DGF format\n";
 
         std::cout << errorMessageOut
                   << "\n";
     }
 }
 
-int main(int argc, char** argv)
+int main(int argc, char** argv) try
 {
 
-    using ProblemTypeTag = TTAG(ThreePWaterOilSagdBoxProblem);
-    return Dumux::start<ProblemTypeTag>(argc, argv, usage);
+    using namespace Dumux;
+
+    // define the type tag for this problem
+    using TypeTag = TTAG(TYPETAG);
+
+    ////////////////////////////////////////////////////////////
+    ////////////////////////////////////////////////////////////
+
+    // 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 command line arguments and input file
+    Parameters::init(argc, argv, usage);
+
+    // try to create a grid (from the given grid file or the input file)
+    using GridCreator = typename GET_PROP_TYPE(TypeTag, GridCreator);
+    GridCreator::makeGrid();
+    GridCreator::loadBalance();
+
+    ////////////////////////////////////////////////////////////
+    // run instationary non-linear problem on this grid
+    ////////////////////////////////////////////////////////////
+
+    // 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();
+
+    // the problem (initial and boundary conditions)
+    using Problem = typename GET_PROP_TYPE(TypeTag, Problem);
+    auto problem = std::make_shared<Problem>(fvGridGeometry);
+
+    // the solution vector
+    using SolutionVector = typename GET_PROP_TYPE(TypeTag, SolutionVector);
+    SolutionVector x(fvGridGeometry->numDofs());
+    problem->applyInitialSolution(x);
+    auto xOld = x;
+
+    // the grid variables
+    using GridVariables = typename GET_PROP_TYPE(TypeTag, GridVariables);
+    auto gridVariables = std::make_shared<GridVariables>(problem, fvGridGeometry);
+    gridVariables->init(x, xOld);
+
+    // get some time loop parameters
+    using Scalar = typename GET_PROP_TYPE(TypeTag, Scalar);
+    const auto tEnd = getParam<Scalar>("TimeLoop.TEnd");
+    const auto maxDivisions = getParam<int>("TimeLoop.MaxTimeStepDivisions");
+    const auto maxDt = getParam<Scalar>("TimeLoop.MaxTimeStepSize");
+    auto dt = getParam<Scalar>("TimeLoop.DtInitial");
+
+    // check if we are about to restart a previously interrupted simulation
+    Scalar restartTime = 0;
+    if (Parameters::getTree().hasKey("Restart") || Parameters::getTree().hasKey("TimeLoop.Restart"))
+        restartTime = getParam<Scalar>("TimeLoop.Restart");
+
+    // intialize the vtk output module
+    using VtkOutputFields = typename GET_PROP_TYPE(TypeTag, VtkOutputFields);
+    VtkOutputModule<TypeTag> vtkWriter(*problem, *fvGridGeometry, *gridVariables, x, problem->name());
+    VtkOutputFields::init(vtkWriter); //! Add model specific output fields
+    vtkWriter.write(0.0);
+
+    // instantiate time loop
+    auto timeLoop = std::make_shared<CheckPointTimeLoop<Scalar>>(restartTime, dt, tEnd);
+    timeLoop->setMaxTimeStepSize(maxDt);
+    timeLoop->setPeriodicCheckPoint(getParam<Scalar>("TimeLoop.EpisodeLength", std::numeric_limits<Scalar>::max()));
+
+    // the assembler with time loop for instationary problem
+    using Assembler = FVAssembler<TypeTag, DiffMethod::numeric>;
+    auto assembler = std::make_shared<Assembler>(problem, fvGridGeometry, gridVariables, timeLoop);
 
+    // the linear solver
+    using LinearSolver = Dumux::AMGBackend<TypeTag>;
+    auto linearSolver = std::make_shared<LinearSolver>(leafGridView, fvGridGeometry->dofMapper());
 
+    // the non-linear solver
+    using NewtonController = PriVarSwitchNewtonController<TypeTag>;
+    using NewtonMethod = Dumux::NewtonMethod<NewtonController, Assembler, LinearSolver>;
+    auto newtonController = std::make_shared<NewtonController>(leafGridView.comm(), timeLoop);
+    NewtonMethod nonLinearSolver(newtonController, assembler, linearSolver);
+
+    // time loop
+    timeLoop->start();
+    while (!timeLoop->finished())
+    {
+        // set previous solution for storage evaluations
+        assembler->setPreviousSolution(xOld);
+
+        // try solving the non-linear system
+        for (int i = 0; i < maxDivisions; ++i)
+        {
+            // linearize & solve
+            auto converged = nonLinearSolver.solve(x);
+
+            if (converged)
+                break;
+
+            if (!converged && i == maxDivisions-1)
+                DUNE_THROW(Dune::MathError,
+                            "Newton solver didn't converge after "
+                            << maxDivisions
+                            << " time-step divisions. dt="
+                            << timeLoop->timeStepSize()
+                            << ".\nThe solutions of the current and the previous time steps "
+                            << "have been saved to restart files.");
+        }
+
+        // make the new solution the old solution
+        xOld = x;
+        gridVariables->advanceTimeStep();
+
+        // advance to the time loop to the next step
+        timeLoop->advanceTimeStep();
+
+        // write vtk output
+        // if episode length was specificied output only at the end of episodes
+        if (!haveParam("TimeLoop.EpisodeLength") || timeLoop->isCheckPoint() || timeLoop->finished() || timeLoop->timeStepIndex() == 1)
+            vtkWriter.write(timeLoop->time());
+
+        // report statistics of this time step
+        timeLoop->reportTimeStep();
+
+        // set new dt as suggested by newton controller
+        timeLoop->setTimeStepSize(newtonController->suggestTimeStepSize(timeLoop->timeStepSize()));
+    }
+
+    timeLoop->finalize(leafGridView.comm());
+
+    ////////////////////////////////////////////////////////////
+    // finalize, print dumux message to say goodbye
+    ////////////////////////////////////////////////////////////
+
+    // print dumux end message
+    if (mpiHelper.rank() == 0)
+    {
+        Parameters::print();
+        DumuxMessage::print(/*firstCall=*/false);
+    }
+
+    return 0;
+
+}
+catch (Dumux::ParameterException &e)
+{
+    std::cerr << std::endl << e << " ---> Abort!" << std::endl;
+    return 1;
+}
+catch (Dune::DGFException & e)
+{
+    std::cerr << "DGF exception thrown (" << e <<
+                 "). Most likely, the DGF file name is wrong "
+                 "or the DGF file is corrupted, "
+                 "e.g. missing hash at end of file or wrong number (dimensions) of entries."
+                 << " ---> Abort!" << std::endl;
+    return 2;
+}
+catch (Dune::Exception &e)
+{
+    std::cerr << "Dune reported error: " << e << " ---> Abort!" << std::endl;
+    return 3;
+}
+catch (...)
+{
+    std::cerr << "Unknown exception thrown! ---> Abort!" << std::endl;
+    return 4;
 }
diff --git a/test/porousmediumflow/3pwateroil/implicit/test_box3pwateroil.input b/test/porousmediumflow/3pwateroil/implicit/test_box3pwateroil.input
index c0656001abb8d2619a893f5604149a952d14b1ac..d1f6789df9cd3161409a4af7bafd7152793e3097 100644
--- a/test/porousmediumflow/3pwateroil/implicit/test_box3pwateroil.input
+++ b/test/porousmediumflow/3pwateroil/implicit/test_box3pwateroil.input
@@ -1,4 +1,4 @@
-[TimeManager]
+[TimeLoop]
 DtInitial = 1800 # [s]
 TEnd = 60000 # [s]
 
@@ -13,6 +13,5 @@ Name = sagd # name passed to the output routines
 MaxTimeStepDivisions = 100
 
 [Newton]
-RelTolerance = 1e-02
 MaxSteps = 8
 WriteConvergence = 0