From 3769ec5ef5b8236536d0cde8616179b49a2085a9 Mon Sep 17 00:00:00 2001
From: Holger Class <holger.class@iws.uni-stuttgart.de>
Date: Mon, 26 Aug 2013 11:27:47 +0000
Subject: [PATCH] the 3p module is new to Dumux

git-svn-id: svn://svn.iws.uni-stuttgart.de/DUMUX/dumux/trunk@11262 2fb0f335-1f38-0410-981e-8018bf24f1b0
---
 dumux/implicit/3p/3pindices.hh          |  69 ++++++
 dumux/implicit/3p/3plocalresidual.hh    | 207 ++++++++++++++++
 dumux/implicit/3p/3pmodel.hh            | 275 ++++++++++++++++++++++
 dumux/implicit/3p/3pproperties.hh       |  69 ++++++
 dumux/implicit/3p/3ppropertydefaults.hh | 122 ++++++++++
 dumux/implicit/3p/3pvolumevariables.hh  | 299 ++++++++++++++++++++++++
 dumux/implicit/3p/Makefile.am           |   4 +
 7 files changed, 1045 insertions(+)
 create mode 100644 dumux/implicit/3p/3pindices.hh
 create mode 100644 dumux/implicit/3p/3plocalresidual.hh
 create mode 100644 dumux/implicit/3p/3pmodel.hh
 create mode 100644 dumux/implicit/3p/3pproperties.hh
 create mode 100644 dumux/implicit/3p/3ppropertydefaults.hh
 create mode 100644 dumux/implicit/3p/3pvolumevariables.hh
 create mode 100644 dumux/implicit/3p/Makefile.am

diff --git a/dumux/implicit/3p/3pindices.hh b/dumux/implicit/3p/3pindices.hh
new file mode 100644
index 0000000000..3b052b84e0
--- /dev/null
+++ b/dumux/implicit/3p/3pindices.hh
@@ -0,0 +1,69 @@
+// -*- 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 Defines the indices required for the 3p model.
+ */
+#ifndef DUMUX_3P_INDICES_HH
+#define DUMUX_3P_INDICES_HH
+
+#include "3pproperties.hh"
+
+namespace Dumux
+{
+
+/*!
+ * \ingroup ThreePModel
+ * \ingroup ImplicitIndices
+ * \brief The indices for the isothermal 3p model.
+ *
+ * \tparam formulation The formulation, only pgSwSn
+ * \tparam PVOffset The first index in a primary variable vector.
+ */
+template <class TypeTag, int PVOffset = 0>
+class ThreePIndices
+{
+    typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
+
+public:
+    // Phase indices
+    static const int wPhaseIdx = FluidSystem::wPhaseIdx; //!< index of the wetting liquid phase
+    static const int nPhaseIdx = FluidSystem::nPhaseIdx; //!< index of the nonwetting liquid phase
+    static const int gPhaseIdx = FluidSystem::gPhaseIdx; //!< index of the gas phase
+
+
+    // Primary variable indices
+    static const int pressureIdx = PVOffset + 0; //!< Index for gas phase pressure in a solution vector
+    static const int swIdx = PVOffset + 1; //!< Index of water (more wetting than the other liquid) saturation 
+    static const int snIdx = PVOffset + 2; //!< Index of (e.g.) NAPL saturation 
+
+
+    // equation indices
+    static const int conti0EqIdx = PVOffset    + wPhaseIdx; //!< Index of the mass conservation equation for the water component
+    static const int conti1EqIdx = conti0EqIdx + nPhaseIdx; //!< Index of the mass conservation equation for the contaminant component
+    static const int conti2EqIdx = conti0EqIdx + gPhaseIdx; //!< Index of the mass conservation equation for the air component
+
+    static const int contiWEqIdx = conti0EqIdx + wPhaseIdx; //!< index of the mass conservation equation for the water component
+    static const int contiNEqIdx = conti0EqIdx + nPhaseIdx; //!< index of the mass conservation equation for the contaminant component
+    static const int contiGEqIdx = conti0EqIdx + gPhaseIdx; //!< index of the mass conservation equation for the air component
+};
+
+}
+
+#endif
diff --git a/dumux/implicit/3p/3plocalresidual.hh b/dumux/implicit/3p/3plocalresidual.hh
new file mode 100644
index 0000000000..bb6d42324d
--- /dev/null
+++ b/dumux/implicit/3p/3plocalresidual.hh
@@ -0,0 +1,207 @@
+// -*- 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 Element-wise calculation of the Jacobian matrix for problems
+ *        using the three-phase fully implicit model.
+ */
+#ifndef DUMUX_3P_LOCAL_RESIDUAL_HH
+#define DUMUX_3P_LOCAL_RESIDUAL_HH
+
+#include "3pproperties.hh"
+
+namespace Dumux
+{
+/*!
+ * \ingroup ThreePModel
+ * \ingroup ImplicitLocalResidual
+ * \brief Element-wise calculation of the Jacobian matrix for problems
+ *        using the three-phase fully implicit model.
+ *
+ * This class is used to fill the gaps in BoxLocalResidual for the 3P flow.
+ */
+template<class TypeTag>
+class ThreePLocalResidual: public GET_PROP_TYPE(TypeTag, BaseLocalResidual)
+{
+protected:
+    typedef typename GET_PROP_TYPE(TypeTag, LocalResidual) Implementation;
+
+    typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
+    typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
+    typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
+
+    enum {
+        numPhases = GET_PROP_VALUE(TypeTag, NumPhases),
+
+        conti0EqIdx = Indices::conti0EqIdx,//!< Index of the mass conservation equation for the water component
+        conti1EqIdx = Indices::conti1EqIdx,//!< Index of the mass conservation equation for the contaminant component
+        conti2EqIdx = Indices::conti2EqIdx,//!< Index of the mass conservation equation for the gas component
+
+        wPhaseIdx = Indices::wPhaseIdx,
+        nPhaseIdx = Indices::nPhaseIdx,
+        gPhaseIdx = Indices::gPhaseIdx,
+    };
+
+    typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables;
+    typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables;
+    typedef typename GET_PROP_TYPE(TypeTag, FluxVariables) FluxVariables;
+
+public:
+    /*!
+     * \brief Evaluate the amount all conservation quantities
+     *        (e.g. phase mass) within a sub-control volume.
+     *
+     * 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 computeStorage(PrimaryVariables &storage, const int scvIdx, bool usePrevSol) const
+    {
+        // if flag usePrevSol is set, the solution from the previous
+        // time step is used, otherwise the current solution is
+        // used. The secondary variables are used accordingly.  This
+        // is required to compute the derivative of the storage term
+        // using the implicit euler method.
+        const ElementVolumeVariables &elemVolVars =
+            usePrevSol
+            ? this->prevVolVars_()
+            : this->curVolVars_();
+        const VolumeVariables &volVars = elemVolVars[scvIdx];
+
+        // compute storage term of all components within all phases
+        storage = 0;
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+        {
+            storage[conti0EqIdx + phaseIdx] +=
+                volVars.porosity()
+                * volVars.saturation(phaseIdx)
+                * volVars.density(phaseIdx);
+        }
+    }
+
+    /*!
+     * \brief Evaluates the total flux of all conservation quantities
+     *        over a face of a sub-control volume.
+     *
+     * \param flux The flux over the SCV (sub-control-volume) face for each component
+     * \param faceIdx 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 computeFlux(PrimaryVariables &flux, const int faceIdx, const bool onBoundary=false) const
+    {
+        FluxVariables fluxVars(this->problem_(),
+                           this->element_(),
+                           this->fvGeometry_(),
+                           faceIdx,
+                           this->curVolVars_(),
+                           onBoundary);
+
+        flux = 0;
+        asImp_()->computeAdvectiveFlux(flux, fluxVars);
+    }
+
+    /*!
+     * \brief Evaluates the advective mass flux of all components over
+     *        a face of a subcontrol volume.
+     *
+     * \param flux The advective flux over the sub-control-volume face for each component
+     * \param fluxVars The flux variables at the current SCV
+     */
+
+    void computeAdvectiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const
+    {
+        Scalar massUpwindWeight = GET_PARAM_FROM_GROUP(TypeTag, Scalar, Implicit, MassUpwindWeight);
+
+        ////////
+        // advective fluxes of all components in all phases
+        ////////
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+        {
+            // data attached to upstream and the downstream vertices
+            // of the current phase
+            const VolumeVariables &up = this->curVolVars_(fluxVars.upstreamIdx(phaseIdx));
+            const VolumeVariables &dn = this->curVolVars_(fluxVars.downstreamIdx(phaseIdx));
+
+            // add advective flux of current phase
+            // if alpha > 0 und alpha < 1 then both upstream and downstream
+            // nodes need their contribution
+            // if alpha == 1 (which is mostly the case) then, the downstream
+            // node is not evaluated
+            int eqIdx = conti0EqIdx + phaseIdx;
+            flux[eqIdx] += fluxVars.volumeFlux(phaseIdx)
+                * (massUpwindWeight
+                   * up.fluidState().density(phaseIdx)
+                   +
+                   (1.0 - massUpwindWeight)
+                   * dn.fluidState().density(phaseIdx));
+        }
+    }
+
+    /*!
+     * \brief Adds the diffusive flux to the flux vector over
+     *        the face of a sub-control volume.
+     *
+     * \param flux The diffusive flux over the sub-control-volume face for each phase
+     * \param fluxVars The flux variables at the current SCV
+     *
+     * It doesn't do anything in three-phase model but may be used by the
+     * non-isothermal three-phase models to calculate diffusive heat
+     * fluxes
+     */
+    void computeDiffusiveFlux(PrimaryVariables &flux, const FluxVariables &fluxVars) const
+    {
+        // diffusive fluxes
+        flux += 0.0;
+    }
+
+    /*!
+     * \brief Calculate the source term of the equation
+     *
+     * \param source The source/sink in the SCV for each phase
+     * \param scvIdx The index of the SCV
+     */
+    void computeSource(PrimaryVariables &source, const int scvIdx)
+    {
+        this->problem_().solDependentSource(source,
+                                     this->element_(),
+                                     this->fvGeometry_(),
+                                     scvIdx,
+                                     this->curVolVars_());
+    }
+
+protected:
+    Implementation *asImp_()
+    {
+        return static_cast<Implementation *> (this);
+    }
+
+    const Implementation *asImp_() const
+    {
+        return static_cast<const Implementation *> (this);
+    }
+};
+
+} // end namepace
+
+#endif
diff --git a/dumux/implicit/3p/3pmodel.hh b/dumux/implicit/3p/3pmodel.hh
new file mode 100644
index 0000000000..6a40722ad7
--- /dev/null
+++ b/dumux/implicit/3p/3pmodel.hh
@@ -0,0 +1,275 @@
+// -*- 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 Adaption of the fully implicit scheme to the three-phase 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_3P_MODEL_HH
+#define DUMUX_3P_MODEL_HH
+
+#include <dumux/implicit/common/implicitvelocityoutput.hh>
+#include "3pproperties.hh"
+
+namespace Dumux
+{
+/*!
+ * \ingroup ThreePModel
+ * \brief Adaption of the fully implicit scheme to the three-phase flow model.
+ *
+ * This model implements three-phase flow of three fluid phases
+ * \f$\alpha \in \{ water, gas, NAPL \}\f$ 
+ * The standard multiphase Darcy
+ * approach is used as the equation for the conservation of momentum.
+ *
+ * By inserting this into the equations for the conservation of the
+ * components, the well-known multiphase flow equation is obtained.
+ *
+ * All equations are discretized using a vertex-centered finite volume (box)
+ * or cell-centered finite volume scheme as spatial
+ * and the implicit Euler method as time discretization.
+ *
+ * The model uses commonly applied auxiliary conditions like
+ * \f$S_w + S_n + S_g = 1\f$ for the saturations. 
+ * Furthermore, the phase pressures are related to each other via
+ * capillary pressures between the fluid phases, which are functions of
+ * the saturation, e.g. according to the approach of Parker et al.
+ *
+ * The used primary variables are gas phase pressure, water saturation and
+ * NAPL saturation.
+ */
+template<class TypeTag>
+class ThreePModel: public GET_PROP_TYPE(TypeTag, BaseModel)
+{
+    typedef typename GET_PROP_TYPE(TypeTag, BaseModel) ParentType;
+
+    typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
+    typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
+    typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
+    typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
+
+    typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry;
+    typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
+    typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) VolumeVariables;
+    typedef typename GET_PROP_TYPE(TypeTag, ElementVolumeVariables) ElementVolumeVariables;
+    typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector;
+    typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
+
+    enum {
+        dim = GridView::dimension,
+        dimWorld = GridView::dimensionworld,
+
+        numPhases = GET_PROP_VALUE(TypeTag, NumPhases),
+
+        pressureIdx = Indices::pressureIdx,
+        swIdx = Indices::swIdx,
+        snIdx = Indices::snIdx,
+
+        wPhaseIdx = Indices::wPhaseIdx,
+        nPhaseIdx = Indices::nPhaseIdx,
+        gPhaseIdx = Indices::gPhaseIdx,
+    };
+
+
+    typedef typename GridView::template Codim<dim>::Entity Vertex;
+    typedef typename GridView::template Codim<0>::Entity Element;
+    typedef typename GridView::template Codim<0>::Iterator ElementIterator;
+    typedef typename GridView::template Codim<dim>::Iterator VertexIterator;
+
+    typedef Dune::FieldVector<Scalar, dimWorld> GlobalPosition;
+    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);
+
+        if (isBox)
+        {
+            VertexIterator vIt = this->gridView_().template begin<dim> ();
+            const VertexIterator &vEndIt = this->gridView_().template end<dim> ();
+            for (; vIt != vEndIt; ++vIt)
+            {
+                int globalIdx = this->dofMapper().map(*vIt);
+                const GlobalPosition &globalPos = vIt->geometry().corner(0);
+            }
+        }
+        else
+        {
+            ElementIterator eIt = this->gridView_().template begin<0> ();
+            const ElementIterator &eEndIt = this->gridView_().template end<0> ();
+            for (; eIt != eEndIt; ++eIt)
+            {
+                int globalIdx = this->dofMapper().map(*eIt);
+                const GlobalPosition &globalPos = eIt->geometry().center();
+            }
+        }
+    }
+
+    /*!
+     * \brief Called by the update() method if applying the newton
+     *         method was unsuccessful.
+     */
+    void updateFailed()
+    {
+        ParentType::updateFailed();
+    };
+
+    /*!
+     * \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();
+    }
+
+    /*!
+     * \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)
+    {
+        typedef Dune::BlockVector<Dune::FieldVector<double, 1> > ScalarField;
+        typedef Dune::BlockVector<Dune::FieldVector<double, dim> > VectorField;
+
+        // 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];
+
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
+            saturation[phaseIdx] = writer.allocateManagedBuffer(numDofs);
+            pressure[phaseIdx] = writer.allocateManagedBuffer(numDofs);
+            density[phaseIdx] = 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);
+
+        ElementIterator eIt = this->gridView_().template begin<0>();
+        ElementIterator eEndIt = this->gridView_().template end<0>();
+        for (; eIt != eEndIt; ++eIt)
+        {
+            int idx = this->problem_().elementMapper().map(*eIt);
+            (*rank)[idx] = this->gridView_().comm().rank();
+
+            FVElementGeometry fvGeometry;
+            fvGeometry.update(this->gridView_(), *eIt);
+
+
+            ElementVolumeVariables elemVolVars;
+            elemVolVars.update(this->problem_(),
+                               *eIt,
+                               fvGeometry,
+                               false /* oldSol? */);
+
+            for (int scvIdx = 0; scvIdx < fvGeometry.numScv; ++scvIdx)
+            {
+                int globalIdx = this->dofMapper().map(*eIt, 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);
+                }
+
+                (*poro)[globalIdx] = elemVolVars[scvIdx].porosity();
+                (*perm)[globalIdx] = elemVolVars[scvIdx].permeability();
+                (*temperature)[globalIdx] = elemVolVars[scvIdx].temperature();
+            }
+
+            // velocity output
+            velocityOutput.calculateVelocity(*velocityW, elemVolVars, fvGeometry, *eIt, wPhaseIdx);
+            velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, *eIt, nPhaseIdx);
+            velocityOutput.calculateVelocity(*velocityN, elemVolVars, fvGeometry, *eIt, 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(*poro, "porosity", isBox);
+        writer.attachDofData(*perm, "permeability", isBox);
+        writer.attachDofData(*temperature, "temperature", 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");
+    }
+
+};
+
+}
+
+#include "3ppropertydefaults.hh"
+
+#endif
diff --git a/dumux/implicit/3p/3pproperties.hh b/dumux/implicit/3p/3pproperties.hh
new file mode 100644
index 0000000000..f6b3949618
--- /dev/null
+++ b/dumux/implicit/3p/3pproperties.hh
@@ -0,0 +1,69 @@
+// -*- 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 ThreePModel
+ */
+/*!
+ * \file
+ *
+ * \brief Defines the properties required for the 3p fully implicit model.
+ */
+#ifndef DUMUX_3P_PROPERTIES_HH
+#define DUMUX_3P_PROPERTIES_HH
+
+#include <dumux/implicit/box/boxproperties.hh>
+#include <dumux/implicit/cellcentered/ccproperties.hh>
+
+namespace Dumux
+{
+
+namespace Properties
+{
+//////////////////////////////////////////////////////////////////
+// Type tags
+//////////////////////////////////////////////////////////////////
+
+//! The type tags for the implicit three-phase problems
+NEW_TYPE_TAG(ThreeP);
+NEW_TYPE_TAG(BoxThreeP, INHERITS_FROM(BoxModel, ThreeP));
+NEW_TYPE_TAG(CCThreeP, INHERITS_FROM(CCModel, ThreeP));
+
+//////////////////////////////////////////////////////////////////
+// Property tags
+//////////////////////////////////////////////////////////////////
+
+NEW_PROP_TAG(NumPhases);   //!< Number of fluid phases 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(FluidState); //!< the phases' state
+
+NEW_PROP_TAG(MaterialLaw);   //!< The material law which ought to be used (extracted from the spatial parameters)
+NEW_PROP_TAG(MaterialLawParams); //!< The parameters of the material law (extracted from the spatial parameters)
+
+NEW_PROP_TAG(ProblemEnableGravity); //!< Returns whether gravity is considered in the problem
+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(BaseFluxVariables); //! The base flux variables
+NEW_PROP_TAG(SpatialParamsForchCoeff); //!< Property for the forchheimer coefficient
+NEW_PROP_TAG(VtkAddVelocity); //!< Returns whether velocity vectors are written into the vtk output
+}
+}
+
+#endif
diff --git a/dumux/implicit/3p/3ppropertydefaults.hh b/dumux/implicit/3p/3ppropertydefaults.hh
new file mode 100644
index 0000000000..cd31aa893b
--- /dev/null
+++ b/dumux/implicit/3p/3ppropertydefaults.hh
@@ -0,0 +1,122 @@
+// -*- 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 ThreePModel
+ */
+/*!
+ * \file
+ *
+ * \brief Defines default values for most properties required by the
+ *        3p fully implicit model.
+ */
+#ifndef DUMUX_3P_PROPERTY_DEFAULTS_HH
+#define DUMUX_3P_PROPERTY_DEFAULTS_HH
+
+#include "3pindices.hh"
+
+#include "3pmodel.hh"
+#include "3pindices.hh"
+#include "3pvolumevariables.hh"
+#include "3pproperties.hh"
+#include "3plocalresidual.hh"
+
+#include <dumux/implicit/common/implicitdarcyfluxvariables.hh>
+#include <dumux/material/spatialparams/implicitspatialparams.hh>
+#include <dumux/material/fluidstates/immisciblefluidstate.hh>
+#include <dumux/implicit/common/implicitdarcyfluxvariables.hh>
+
+
+namespace Dumux
+{
+
+namespace Properties {
+//////////////////////////////////////////////////////////////////
+// Property values
+//////////////////////////////////////////////////////////////////
+
+/*!
+ * \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(ThreeP, NumPhases)
+{
+ private:
+    typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
+
+ public:
+    static const int value = FluidSystem::numPhases;
+    static_assert(value == 3,
+                  "Only fluid systems with 3 phases are supported by the 3p model!");
+};
+
+SET_INT_PROP(ThreeP, NumEq, 3); //!< set the number of equations to 2
+
+/*!
+ * \brief Set the property for the material parameters by extracting
+ *        it from the material law.
+ */
+SET_TYPE_PROP(ThreeP, MaterialLawParams, typename GET_PROP_TYPE(TypeTag, MaterialLaw)::Params);
+
+//! The local residual function of the conservation equations
+SET_TYPE_PROP(ThreeP, LocalResidual, ThreePLocalResidual<TypeTag>);
+
+//! the Model property
+SET_TYPE_PROP(ThreeP, Model, ThreePModel<TypeTag>);
+
+//! the VolumeVariables property
+SET_TYPE_PROP(ThreeP, VolumeVariables, ThreePVolumeVariables<TypeTag>);
+
+//! the FluxVariables property
+SET_TYPE_PROP(ThreeP, FluxVariables, ImplicitDarcyFluxVariables<TypeTag>);
+
+//! the upwind factor for the mobility.
+SET_SCALAR_PROP(ThreeP, ImplicitMassUpwindWeight, 1.0);
+
+//! set default mobility upwind weight to 1.0, i.e. fully upwind
+SET_SCALAR_PROP(ThreeP, ImplicitMobilityUpwindWeight, 1.0);
+
+//! The indices required by the isothermal 3p model
+SET_TYPE_PROP(ThreeP, Indices, ThreePIndices<TypeTag, /*PVOffset=*/0>);
+
+//! The spatial parameters to be employed. 
+//! Use ImplicitSpatialParams by default.
+SET_TYPE_PROP(ThreeP, SpatialParams, ImplicitSpatialParams<TypeTag>);
+
+SET_PROP(ThreeP, FluidState)
+{
+private:
+    typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
+    typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
+public:
+    typedef ImmiscibleFluidState<Scalar, FluidSystem> type;
+};
+
+// disable velocity output by default
+SET_BOOL_PROP(ThreeP, VtkAddVelocity, false);
+
+// enable gravity by default
+SET_BOOL_PROP(ThreeP, ProblemEnableGravity, true);
+
+}
+
+}
+
+#endif
diff --git a/dumux/implicit/3p/3pvolumevariables.hh b/dumux/implicit/3p/3pvolumevariables.hh
new file mode 100644
index 0000000000..6f4f0a7ba8
--- /dev/null
+++ b/dumux/implicit/3p/3pvolumevariables.hh
@@ -0,0 +1,299 @@
+// -*- 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 Contains the quantities which are constant within a
+ *        finite volume in the three-phase model.
+ */
+#ifndef DUMUX_3P_VOLUME_VARIABLES_HH
+#define DUMUX_3P_VOLUME_VARIABLES_HH
+
+#include <dumux/implicit/common/implicitmodel.hh>
+#include <dumux/common/math.hh>
+
+#include <dune/common/collectivecommunication.hh>
+#include <vector>
+#include <iostream>
+
+#include "3pproperties.hh"
+
+#include <dumux/material/constants.hh>
+#include <dumux/material/fluidstates/immisciblefluidstate.hh>
+
+namespace Dumux
+{
+
+/*!
+ * \ingroup ThreePModel
+ * \brief Contains the quantities which are are constant within a
+ *        finite volume in the two-phase, two-component model.
+ */
+template <class TypeTag>
+class ThreePVolumeVariables : public ImplicitVolumeVariables<TypeTag>
+{
+    typedef ImplicitVolumeVariables<TypeTag> ParentType;
+    typedef typename GET_PROP_TYPE(TypeTag, VolumeVariables) Implementation;
+
+    typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar;
+    typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView;
+    typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem;
+    typedef typename GET_PROP_TYPE(TypeTag, FVElementGeometry) FVElementGeometry;
+    typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables;
+    typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem;
+    typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw;
+    typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams;
+
+    typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices;
+    enum {
+        dim = GridView::dimension,
+
+        numPhases = GET_PROP_VALUE(TypeTag, NumPhases),
+
+        wPhaseIdx = Indices::wPhaseIdx,
+        gPhaseIdx = Indices::gPhaseIdx,
+        nPhaseIdx = Indices::nPhaseIdx,
+
+        swIdx = Indices::swIdx,
+        snIdx = Indices::snIdx,
+        pressureIdx = Indices::pressureIdx
+    };
+
+    static const Scalar R; // universal gas constant
+
+    typedef typename GridView::template Codim<0>::Entity Element;
+
+    enum { isBox = GET_PROP_VALUE(TypeTag, ImplicitIsBox) };
+    enum { dofCodim = isBox ? dim : 0 };
+
+public:
+    //! The type of the object returned by the fluidState() method
+    typedef Dumux::ImmiscibleFluidState<Scalar, FluidSystem> FluidState;
+
+
+    /*!
+     * \copydoc ImplicitVolumeVariables::update
+     */
+    void update(const PrimaryVariables &priVars,
+                const Problem &problem,
+                const Element &element,
+                const FVElementGeometry &fvGeometry,
+                const int scvIdx,
+                bool isOldSol)
+    {
+        ParentType::update(priVars,
+                           problem,
+                           element,
+                           fvGeometry,
+                           scvIdx,
+                           isOldSol);
+
+        // capillary pressure parameters
+        const MaterialLawParams &materialParams =
+            problem.spatialParams().materialLawParams(element, fvGeometry, scvIdx);
+
+        int globalIdx = problem.model().dofMapper().map(element, scvIdx, dofCodim);
+
+        Scalar temp = Implementation::temperature_(priVars, problem, element, fvGeometry, scvIdx);
+        fluidState_.setTemperature(temp);
+
+        sw_ = priVars[swIdx];
+        sn_ = priVars[snIdx];
+        sg_ = 1. - sw_ - sn_;
+
+        Valgrind::CheckDefined(sg_);
+
+        fluidState_.setSaturation(wPhaseIdx, sw_);
+        fluidState_.setSaturation(gPhaseIdx, sg_);
+        fluidState_.setSaturation(nPhaseIdx, sn_);
+
+        /* now the pressures */
+        pg_ = priVars[pressureIdx];
+
+        // calculate capillary pressures
+        Scalar pcgw = MaterialLaw::pcgw(materialParams, sw_);
+        Scalar pcnw = MaterialLaw::pcnw(materialParams, sw_);
+        Scalar pcgn = MaterialLaw::pcgn(materialParams, sw_ + sn_);
+
+        Scalar pcAlpha = MaterialLaw::pcAlpha(materialParams, sn_);
+        Scalar pcNW1 = 0.0; // TODO: this should be possible to assign in the problem file
+
+        pn_ = pg_- pcAlpha * pcgn - (1.-pcAlpha)*(pcgw - pcNW1);
+        pw_ = pn_ - pcAlpha * pcnw - (1.-pcAlpha)*pcNW1;
+
+        fluidState_.setPressure(wPhaseIdx, pw_);
+        fluidState_.setPressure(gPhaseIdx, pg_);
+        fluidState_.setPressure(nPhaseIdx, pn_);
+
+        Scalar rhoW = FluidSystem::density(fluidState_, wPhaseIdx);
+        Scalar rhoG = FluidSystem::density(fluidState_, gPhaseIdx);
+        Scalar rhoN = FluidSystem::density(fluidState_, nPhaseIdx);
+
+        fluidState_.setDensity(wPhaseIdx, rhoW);
+        fluidState_.setDensity(gPhaseIdx, rhoG);
+        fluidState_.setDensity(nPhaseIdx, rhoN);
+
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+            // Mobilities
+            const Scalar mu =
+                FluidSystem::viscosity(fluidState_,
+                                       phaseIdx);
+            fluidState_.setViscosity(phaseIdx,mu);
+
+            Scalar kr;
+            kr = MaterialLaw::kr(materialParams, phaseIdx,
+                                 fluidState_.saturation(wPhaseIdx),
+                                 fluidState_.saturation(nPhaseIdx),
+                                 fluidState_.saturation(gPhaseIdx));
+            mobility_[phaseIdx] = kr / mu;
+            Valgrind::CheckDefined(mobility_[phaseIdx]);
+        }
+
+        // porosity
+        porosity_ = problem.spatialParams().porosity(element,
+                                                         fvGeometry,
+                                                         scvIdx);
+        Valgrind::CheckDefined(porosity_);
+
+        // permeability
+        permeability_ = problem.spatialParams().intrinsicPermeability(element,
+                                                                          fvGeometry,
+                                                                          scvIdx);
+        Valgrind::CheckDefined(permeability_);
+
+        // energy related quantities not contained in the fluid state
+        asImp_().updateEnergy_(priVars, problem, element, fvGeometry, scvIdx, isOldSol);
+    }
+
+    /*!
+     * \brief Returns the phase state for the control-volume.
+     */
+    const FluidState &fluidState() const
+    { return fluidState_; }
+
+    /*!
+     * \brief Returns the effective saturation of a given phase within
+     *        the control volume.
+     *
+     * \param phaseIdx The phase index
+     */
+    Scalar saturation(const int phaseIdx) const
+    { return fluidState_.saturation(phaseIdx); }
+
+    /*!
+     * \brief Returns the mass density of a given phase within the
+     *        control volume.
+     *
+     * \param phaseIdx The phase index
+     */
+    Scalar density(const int phaseIdx) const
+    { return fluidState_.density(phaseIdx); }
+
+    /*!
+     * \brief Returns the effective pressure of a given phase within
+     *        the control volume.
+     *
+     * \param phaseIdx The phase index
+     */
+    Scalar pressure(const int phaseIdx) const
+    { return fluidState_.pressure(phaseIdx); }
+
+    /*!
+     * \brief Returns temperature inside the sub-control volume.
+     *
+     * Note that we assume thermodynamic equilibrium, i.e. the
+     * temperatures of the rock matrix and of all fluid phases are
+     * identical.
+     */
+    Scalar temperature() const
+    { return fluidState_.temperature(/*phaseIdx=*/0); }
+
+    /*!
+     * \brief Returns the effective mobility of a given phase within
+     *        the control volume.
+     *
+     * \param phaseIdx The phase index
+     */
+    Scalar mobility(const int phaseIdx) const
+    {
+        return mobility_[phaseIdx];
+    }
+
+    /*!
+     * \brief Returns the effective capillary pressure within the control volume.
+     */
+    Scalar capillaryPressure() const
+    { return fluidState_.capillaryPressure(); }
+
+    /*!
+     * \brief Returns the average porosity within the control volume.
+     */
+    Scalar porosity() const
+    { return porosity_; }
+
+    /*!
+     * \brief Returns the permeability within the control volume.
+     */
+    Scalar permeability() const
+    { return permeability_; }
+
+protected:
+
+    static Scalar temperature_(const PrimaryVariables &priVars,
+                               const Problem &problem,
+                               const Element &element,
+                               const FVElementGeometry &fvGeometry,
+                               const int scvIdx)
+    {
+        return problem.temperatureAtPos(fvGeometry.subContVol[scvIdx].global);
+    }
+
+    /*!
+     * \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_;
+
+    Scalar porosity_;        //!< Effective porosity within the control volume
+    Scalar permeability_;        //!< Effective porosity within the control volume
+    Scalar mobility_[numPhases];  //!< Effective mobility within the control volume
+    Scalar bulkDensTimesAdsorpCoeff_; //!< the basis for calculating adsorbed NAPL
+    FluidState fluidState_;
+
+private:
+    Implementation &asImp_()
+    { return *static_cast<Implementation*>(this); }
+
+    const Implementation &asImp_() const
+    { return *static_cast<const Implementation*>(this); }
+};
+
+template <class TypeTag>
+const typename ThreePVolumeVariables<TypeTag>::Scalar ThreePVolumeVariables<TypeTag>::R = Constants<typename GET_PROP_TYPE(TypeTag, Scalar)>::R;
+
+} // end namespace
+
+#endif
diff --git a/dumux/implicit/3p/Makefile.am b/dumux/implicit/3p/Makefile.am
new file mode 100644
index 0000000000..f50519766e
--- /dev/null
+++ b/dumux/implicit/3p/Makefile.am
@@ -0,0 +1,4 @@
+3pdir = $(includedir)/dumux/implicit/3p
+3p_HEADERS = *.hh
+
+include $(top_srcdir)/am/global-rules
-- 
GitLab