From 916f27c94860ef1efa4e1b4f5fe67bf6ec62a4c9 Mon Sep 17 00:00:00 2001
From: Andreas Lauser <and@poware.org>
Date: Fri, 16 Dec 2011 13:23:35 +0000
Subject: [PATCH] add a flash constraint solver based on non-linear
 complementarity functions

also add a test

git-svn-id: svn://svn.iws.uni-stuttgart.de/DUMUX/dumux/trunk@7068 2fb0f335-1f38-0410-981e-8018bf24f1b0
---
 configure.ac                                  |   1 +
 dumux/boxmodels/MpNc/MpNcvolumevariables.hh   |  43 +-
 .../compositionfromfugacities.hh              |  10 +-
 .../computefromreferencephase.hh              |   6 +
 .../misciblemultiphasecomposition.hh          |   8 +-
 .../MpNcconstraintsolvers/ncpflash.hh         | 662 ++++++++++++++++++
 .../MpNcfluidsystems/h2on2fluidsystem.hh      |  15 +-
 .../MpNcfluidsystems/nullparametercache.hh    |  12 -
 .../MpNcfluidsystems/parametercachebase.hh    |  36 +-
 test/material/Makefile.am                     |   2 +-
 test/material/ncpflash/Makefile.am            |   5 +
 test/material/ncpflash/test_ncpflash.cc       | 294 ++++++++
 12 files changed, 1058 insertions(+), 36 deletions(-)
 create mode 100644 dumux/material/MpNcconstraintsolvers/ncpflash.hh
 create mode 100644 test/material/ncpflash/Makefile.am
 create mode 100644 test/material/ncpflash/test_ncpflash.cc

diff --git a/configure.ac b/configure.ac
index 3f08f975a4..e7decf83d7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -84,6 +84,7 @@ AC_CONFIG_FILES([dumux.pc
     test/decoupled/2p2c/Makefile
     test/material/Makefile
     test/material/tabulation/Makefile
+    test/material/ncpflash/Makefile
     tutorial/Makefile
 ])
 
diff --git a/dumux/boxmodels/MpNc/MpNcvolumevariables.hh b/dumux/boxmodels/MpNc/MpNcvolumevariables.hh
index 163225029b..4afe21e577 100644
--- a/dumux/boxmodels/MpNc/MpNcvolumevariables.hh
+++ b/dumux/boxmodels/MpNc/MpNcvolumevariables.hh
@@ -35,6 +35,7 @@
 #include "MpNcvolumevariablesia.hh"
 
 #include <dumux/boxmodels/common/boxvolumevariables.hh>
+#include <dumux/material/MpNcconstraintsolvers/ncpflash.hh>
 
 namespace Dumux
 {
@@ -240,8 +241,48 @@ public:
 				  elemGeom,
 				  scvIdx);
         IAVolumeVariables::checkDefined();
-
         checkDefined();
+
+
+#warning "HACK for testing the NCP flash calculation!"
+#if 0
+        FluidState foo;
+        foo.assign(fluidState_);
+        
+        typedef Dumux::NcpFlash<Scalar, FluidSystem> NcpFlash;
+        typedef typename NcpFlash::ComponentVector ComponentVector;
+        ComponentVector globalMolarities(0.0);
+        for (int compIdx = 0; compIdx < numComponents; ++compIdx)
+            for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+                globalMolarities[compIdx] += 
+                    fluidState_.saturation(phaseIdx)
+                    * fluidState_.molarity(phaseIdx, compIdx);
+
+        NcpFlash::guessInitial(foo, paramCache, globalMolarities);
+        NcpFlash::template solve<MaterialLaw>(foo, paramCache, materialParams, globalMolarities);
+        
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+            if (foo.pressure(phaseIdx) == fluidState_.pressure(phaseIdx))
+                continue;
+            Scalar error = 1 - fluidState_.pressure(phaseIdx)/foo.pressure(phaseIdx);
+            if (std::abs(error) > 1e-6) {
+                std::cout << "pressure error phase " << phaseIdx << ": " << foo.pressure(phaseIdx) << " vs " << fluidState_.pressure(phaseIdx) << " error=" << 1 - fluidState_.pressure(phaseIdx)/foo.pressure(phaseIdx) << "\n";
+                std::cout << "x_0: " << fluidState_.moleFraction(0, 0) << " vs " << foo.moleFraction(0, 0) << "\n";
+                std::cout << "x_1: " << fluidState_.moleFraction(0, 1) << " vs " << foo.moleFraction(0, 1) << "\n";
+            }
+        };
+
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+            if (foo.saturation(phaseIdx) == fluidState_.saturation(phaseIdx))
+                continue;
+
+            Scalar error = 1 - (1 + fluidState_.saturation(phaseIdx))/(1 + foo.saturation(phaseIdx));
+            if (std::abs(error) > 1e-6)
+                std::cout << "saturation error phase " << phaseIdx << ": " << foo.saturation(phaseIdx) << " vs " << fluidState_.saturation(phaseIdx) << " error=" << 1 - fluidState_.saturation(phaseIdx)/foo.saturation(phaseIdx) << "\n";
+        };
+        
+        //exit(1);
+#endif
     }
 
     /*!
diff --git a/dumux/material/MpNcconstraintsolvers/compositionfromfugacities.hh b/dumux/material/MpNcconstraintsolvers/compositionfromfugacities.hh
index 79cf8f60ed..e236eacba5 100644
--- a/dumux/material/MpNcconstraintsolvers/compositionfromfugacities.hh
+++ b/dumux/material/MpNcconstraintsolvers/compositionfromfugacities.hh
@@ -26,7 +26,11 @@
 #ifndef DUMUX_COMPOSITION_FROM_FUGACITIES_HH
 #define DUMUX_COMPOSITION_FROM_FUGACITIES_HH
 
+#include <dune/common/fvector.hh>
+#include <dune/common/fmatrix.hh>
+
 #include <dumux/common/exceptions.hh>
+#include <dumux/common/valgrind.hh>
 
 namespace Dumux {
 
@@ -237,7 +241,7 @@ protected:
             // deviate the mole fraction of the i-th component
             Scalar x_i = fluidState.moleFraction(phaseIdx, i);
             fluidState.setMoleFraction(phaseIdx, i, x_i + eps);
-            paramCache.updatePhaseSingleMoleFraction(fluidState, phaseIdx, i);
+            paramCache.updateSingleMoleFraction(fluidState, phaseIdx, i);
 
             // compute new defect and derivative for all component
             // fugacities
@@ -262,7 +266,7 @@ protected:
 
             // reset composition to original value
             fluidState.setMoleFraction(phaseIdx, i, x_i);
-            paramCache.updatePhaseSingleMoleFraction(fluidState, phaseIdx, i);
+            paramCache.updateSingleMoleFraction(fluidState, phaseIdx, i);
 
             // end forward differences
             ////////
@@ -320,7 +324,7 @@ protected:
                 //sumMoleFrac += std::abs(newx);
             }
 
-            paramCache.updatePhaseComposition(fluidState, phaseIdx);
+            paramCache.updateComposition(fluidState, phaseIdx);
 
             /*
             // if the sum of the mole fractions gets 0, we take the
diff --git a/dumux/material/MpNcconstraintsolvers/computefromreferencephase.hh b/dumux/material/MpNcconstraintsolvers/computefromreferencephase.hh
index f251dc06c0..1848ea40f2 100644
--- a/dumux/material/MpNcconstraintsolvers/computefromreferencephase.hh
+++ b/dumux/material/MpNcconstraintsolvers/computefromreferencephase.hh
@@ -32,6 +32,12 @@
 
 #include <dumux/material/MpNcconstraintsolvers/compositionfromfugacities.hh>
 
+#include <dune/common/fvector.hh>
+#include <dune/common/fmatrix.hh>
+
+#include <dumux/common/exceptions.hh>
+#include <dumux/common/valgrind.hh>
+
 namespace Dumux {
 
 /*!
diff --git a/dumux/material/MpNcconstraintsolvers/misciblemultiphasecomposition.hh b/dumux/material/MpNcconstraintsolvers/misciblemultiphasecomposition.hh
index d7db5a5512..a75ec2fb92 100644
--- a/dumux/material/MpNcconstraintsolvers/misciblemultiphasecomposition.hh
+++ b/dumux/material/MpNcconstraintsolvers/misciblemultiphasecomposition.hh
@@ -27,6 +27,12 @@
 #ifndef DUMUX_MISCIBLE_MULTIPHASE_COMPOSITION_HH
 #define DUMUX_MISCIBLE_MULTIPHASE_COMPOSITION_HH
 
+#include <dune/common/fvector.hh>
+#include <dune/common/fmatrix.hh>
+
+#include <dumux/common/exceptions.hh>
+#include <dumux/common/valgrind.hh>
+
 namespace Dumux {
 /*!
  * \brief Computes the composition of all phases of a N-phase,
@@ -167,7 +173,7 @@ public:
                 int rowIdx = phaseIdx*numComponents + compIdx;
                 fluidState.setMoleFraction(phaseIdx, compIdx, x[rowIdx]);
             }
-            paramCache.updatePhaseComposition(fluidState, phaseIdx);
+            paramCache.updateComposition(fluidState, phaseIdx);
         
             Scalar value = FluidSystem::density(fluidState, paramCache, phaseIdx);
             fluidState.setDensity(phaseIdx, value);
diff --git a/dumux/material/MpNcconstraintsolvers/ncpflash.hh b/dumux/material/MpNcconstraintsolvers/ncpflash.hh
new file mode 100644
index 0000000000..89827025c1
--- /dev/null
+++ b/dumux/material/MpNcconstraintsolvers/ncpflash.hh
@@ -0,0 +1,662 @@
+/*****************************************************************************
+ *   Copyright (C) 2011 by Andreas Lauser                                    *
+ *   Institute of Hydraulic Engineering                                      *
+ *   University of Stuttgart, Germany                                        *
+ *   email: <givenname>.<name>@iws.uni-stuttgart.de                          *
+ *                                                                           *
+ *   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 Determines the phase compositions, pressures and saturations
+ *        given the total mass of all components.
+ */
+#ifndef DUMUX_NCP_FLASH_HH
+#define DUMUX_NCP_FLASH_HH
+
+#include <dune/common/fvector.hh>
+#include <dune/common/fmatrix.hh>
+
+#include <dumux/common/exceptions.hh>
+#include <dumux/common/valgrind.hh>
+
+namespace Dumux {
+
+/*!
+ * \brief Determines the phase compositions, pressures and saturations
+ *        given the total mass of all components.
+ */
+template <class Scalar, class FluidSystem>
+class NcpFlash
+{
+    enum { numPhases = FluidSystem::numPhases };
+    enum { numComponents = FluidSystem::numComponents };
+
+    typedef typename FluidSystem::ParameterCache ParameterCache;
+
+    // In a M-phase, N-component context, we have the following
+    // unknowns:
+    //
+    // - M pressures
+    // - M saturations
+    // - M*N mole fractions
+    //
+    // This sums up to M*(N + 2). On the equations side of things,
+    // we have:
+    //
+    // - (M - 1)*N equation stemming from the fact that the
+    //   fugacity of any component is the same in all phases
+    // - 1 equation from the closure condition of all saturations
+    //   (they sum up to 1)
+    // - M - 1 constraints from the capillary pressures
+    //   (-> p_\beta = p_\alpha + p_c\alpha,\beta)
+    // - N constraints from the fact that the total mass of each
+    //   component is given (-> sum_\alpha rhoMolar_\alpha *
+    //   x_\alpha^\kappa = const)
+    // - M model constraints. Here we use the NCP constraints
+    //   (-> 0 = min{S_\alpha, 1 - \sum_\kappa x_\alpha^\kappa})
+    //
+    // this also sums up to M*(N + 2).
+    //
+    // We use the following catches: Capillary pressures are taken
+    // into accout expicitly, so that only the pressure of the first
+    // phase is solved implicitly, also the closure condition for the
+    // saturations is taken into account explicitly, which means, that
+    // we don't need to implicitly solve for the last
+    // saturation. These two measures reduce the number of unknowns to
+    // M*(N + 1), namely:
+    //
+    // - 1 pressure
+    // - M - 1 saturations
+    // - M*N mole fractions
+    static constexpr int numEq = numPhases*(numComponents + 1);
+
+    typedef Dune::FieldMatrix<Scalar, numEq, numEq> Matrix;
+    typedef Dune::FieldVector<Scalar, numEq> Vector;
+
+public:
+    typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
+
+    /*!
+     * \brief Guess initial values for all quantities.
+     */
+    template <class FluidState>
+    static void guessInitial(FluidState &fluidState,
+                             ParameterCache &paramCache,
+                             const ComponentVector &globalMolarities)
+    {
+        // the sum of all molarities
+        Scalar sumMoles = 0;
+        for (int compIdx = 0; compIdx < numComponents; ++compIdx)
+            sumMoles += globalMolarities[compIdx];
+
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
+            // composition
+            for (int compIdx = 0; compIdx < numComponents; ++ compIdx)
+                fluidState.setMoleFraction(phaseIdx,
+                                           compIdx,
+                                           globalMolarities[compIdx]/sumMoles);
+            
+            // pressure. use atmospheric pressure as initial guess
+            fluidState.setPressure(phaseIdx, 2e5);
+
+            // saturation. assume all fluids to be equally distributed
+            fluidState.setSaturation(phaseIdx, 1.0/numPhases);
+        }
+        
+        // set the fugacity coefficients of all components in all phases
+        paramCache.updateAll(fluidState);
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
+            for (int compIdx = 0; compIdx < numComponents; ++ compIdx) {
+                Scalar phi = FluidSystem::fugacityCoefficient(fluidState, paramCache, phaseIdx, compIdx);
+                fluidState.setFugacityCoefficient(phaseIdx, compIdx, phi);
+            }
+        }
+    };
+
+    /*!
+     * \brief Calculates the chemical equilibrium from the component
+     *        fugacities in a phase.
+     *
+     * The phase's fugacities must already be set.
+     */
+    template <class MaterialLaw, class FluidState>
+    static void solve(FluidState &fluidState,
+                      ParameterCache &paramCache,
+                      const typename MaterialLaw::Params &matParams,
+                      const ComponentVector &globalMolarities)
+    {
+        Dune::FMatrixPrecision<Scalar>::set_singular_limit(1e-25);
+
+        /////////////////////////
+        // Newton method
+        /////////////////////////
+
+        // Jacobian matrix
+        Matrix J;
+        // solution, i.e. phase composition
+        Vector deltaX;
+        // right hand side
+        Vector b;
+
+        Valgrind::SetUndefined(J);
+        Valgrind::SetUndefined(deltaX);
+        Valgrind::SetUndefined(b);
+               
+        // make the fluid state consistent with the fluid system.
+        completeFluidState_<MaterialLaw>(fluidState,
+                                         paramCache,
+                                         matParams);
+
+        /*
+        std::cout << "--------------------\n";
+        std::cout << "globalMolarities: ";
+        for (int compIdx = 0; compIdx < numComponents; ++ compIdx)
+            std::cout << globalMolarities[compIdx] << " ";
+        std::cout << "\n";
+        */
+
+        const int nMax = 50; // <- maximum number of newton iterations
+        for (int nIdx = 0; nIdx < nMax; ++nIdx) {
+            // calculate Jacobian matrix and right hand side
+            linearize_<MaterialLaw>(J, b, fluidState, paramCache, matParams, globalMolarities);
+            Valgrind::CheckDefined(J);
+            Valgrind::CheckDefined(b);
+          
+            // Solve J*x = b
+            deltaX = 0;
+
+            try { J.solve(deltaX, b); }
+            catch (Dune::FMatrixError e)
+            { 
+                /*
+                std::cout << "error: " << e << "\n";
+                std::cout << "b: " << b << "\n";
+                */
+                
+                throw Dumux::NumericalProblem(e.what());
+            }
+            Valgrind::CheckDefined(deltaX);
+
+            /*
+            printFluidState_(fluidState);
+            std::cout << "J:\n";
+            for (int i = 0; i < numEq; ++i) {
+                for (int j = 0; j < numEq; ++j) {
+                    std::ostringstream os;
+                    os << J[i][j];
+                        
+                    std::string s(os.str());
+                    do {
+                        s += " ";
+                    } while (s.size() < 20);
+                    std::cout << s;
+                }
+                std::cout << "\n";
+            };
+
+            std::cout << "deltaX: " << deltaX << "\n";
+            std::cout << "---------------\n";
+            */
+
+            // update the fluid quantities.
+            Scalar relError = update_<MaterialLaw>(fluidState, paramCache, matParams, deltaX);
+            
+            if (relError < 1e-9)
+                return;
+        }
+
+        /*
+        printFluidState_(fluidState);
+        std::cout << "globalMolarities: ";
+        for (int compIdx = 0; compIdx < numComponents; ++ compIdx)
+            std::cout << globalMolarities[compIdx] << " ";
+        std::cout << "\n";
+        */
+
+        DUNE_THROW(NumericalProblem,
+                   "Flash calculation failed."
+                   " {c_alpha^kappa} = {" << globalMolarities << "}, T = " 
+                   << fluidState.temperature(/*phaseIdx=*/0));
+    };
+
+
+protected:
+    template <class FluidState>
+    static void printFluidState_(const FluidState &fs)
+    {
+        std::cout << "saturations: ";
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+            std::cout << fs.saturation(phaseIdx) << " ";
+        std::cout << "\n";
+        
+        std::cout << "pressures: ";
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+            std::cout << fs.pressure(phaseIdx) << " ";
+        std::cout << "\n";
+
+        std::cout << "densities: ";
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+            std::cout << fs.density(phaseIdx) << " ";
+        std::cout << "\n";
+
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+            std::cout << "composition " << FluidSystem::phaseName(phaseIdx) << "Phase: ";
+            for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+                std::cout << fs.moleFraction(phaseIdx, compIdx) << " ";
+            }
+            std::cout << "\n";
+        }
+
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+            std::cout << "fugacities " << FluidSystem::phaseName(phaseIdx) << "Phase: ";
+            for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+                std::cout << fs.fugacity(phaseIdx, compIdx) << " ";
+            }
+            std::cout << "\n";
+        }
+
+        std::cout << "global component molarities: ";
+        for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+            Scalar sum = 0;
+            for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+                sum += fs.saturation(phaseIdx)*fs.molarity(phaseIdx, compIdx);
+            }
+            std::cout << sum << " ";
+        }
+        std::cout << "\n";
+    }
+
+    template <class MaterialLaw, class FluidState>
+    static void linearize_(Matrix &J,
+                           Vector &b,
+                           FluidState &fluidState,
+                           ParameterCache &paramCache,
+                           const typename MaterialLaw::Params &matParams,
+                           const ComponentVector &globalMolarities)
+    {
+        FluidState origFluidState(fluidState);
+        ParameterCache origParamCache(paramCache);
+        
+        Vector tmp;
+
+        // reset jacobian
+        J = 0;
+
+        Valgrind::SetUndefined(b);
+        calculateDefect_(b, fluidState, fluidState, globalMolarities);
+        Valgrind::CheckDefined(b);
+
+        // assemble jacobian matrix
+        for (int pvIdx = 0; pvIdx < numEq; ++ pvIdx) {
+            ////////
+            // approximately calculate partial derivatives of the
+            // fugacity defect of all components in regard to the mole
+            // fraction of the i-th component. This is done via
+            // forward differences
+
+            // deviate the mole fraction of the i-th component
+            Scalar x_i = getQuantity_(fluidState, pvIdx);
+            const Scalar eps = 1e-8/quantityWeight_(fluidState, pvIdx);
+            setQuantity_<MaterialLaw>(fluidState, paramCache, matParams, pvIdx, x_i + eps);
+            assert(getQuantity_(fluidState, pvIdx) == x_i + eps);
+            
+            // compute derivative of the defect
+            calculateDefect_(tmp, origFluidState, fluidState, globalMolarities);
+            tmp -= b;
+            tmp /= eps;
+
+            // store derivative in jacobian matrix
+            for (int eqIdx = 0; eqIdx < numEq; ++eqIdx)
+                J[eqIdx][pvIdx] = tmp[eqIdx];
+
+            // fluid state and parameter cache to their original values
+            fluidState = origFluidState;
+            paramCache = origParamCache;
+
+            // end forward differences
+            ////////
+        }
+    }
+
+    template <class FluidState>
+    static void calculateDefect_(Vector &b,
+                                 const FluidState &fluidStateEval,
+                                 const FluidState &fluidState,
+                                 const ComponentVector &globalMolarities)
+    {
+        int eqIdx = 0;
+
+        // fugacity of any component must be equal in all phases
+        for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+            for (int phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx) {
+                b[eqIdx] = 
+                    fluidState.fugacity(/*phaseIdx=*/0, compIdx) - 
+                    fluidState.fugacity(phaseIdx, compIdx);
+                ++eqIdx;
+            }
+        }
+        
+        assert(eqIdx == numComponents*(numPhases - 1));
+        
+        // the fact saturations must sum up to 1 is included explicitly!
+        
+        // capillary pressures are explicitly included!
+        
+        // global molarities are given
+        for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+            b[eqIdx] = 0.0;
+            for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+                b[eqIdx] += 
+                    fluidState.saturation(phaseIdx)
+                    * fluidState.molarity(phaseIdx, compIdx);
+            }
+            
+            b[eqIdx] -= globalMolarities[compIdx];
+            ++eqIdx;
+        }
+        
+        // model assumptions (-> non-linear complementarity functions)
+        // must be adhered
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+            Scalar sumMoleFracEval = 0.0;
+            for (int compIdx = 0; compIdx < numComponents; ++compIdx)
+                sumMoleFracEval += fluidStateEval.moleFraction(phaseIdx, compIdx);
+
+            if (1.0 - sumMoleFracEval > fluidStateEval.saturation(phaseIdx)) {
+                b[eqIdx] = fluidState.saturation(phaseIdx);
+            }
+            else {
+                Scalar sumMoleFrac = 0.0;
+                for (int compIdx = 0; compIdx < numComponents; ++compIdx)
+                    sumMoleFrac += fluidState.moleFraction(phaseIdx, compIdx);
+                b[eqIdx] = 1.0 - sumMoleFrac;
+            }
+
+            ++eqIdx;
+        }
+    }
+
+    template <class MaterialLaw, class FluidState>
+    static Scalar update_(FluidState &fluidState,
+                          ParameterCache &paramCache,
+                          const typename MaterialLaw::Params &matParams,
+                          const Vector &deltaX)
+    {
+        Scalar relError = 0;
+        for (int pvIdx = 0; pvIdx < numEq; ++ pvIdx) {
+            Scalar tmp = getQuantity_(fluidState, pvIdx);
+            Scalar delta = deltaX[pvIdx];
+                
+            relError = std::max(relError, std::abs(delta)*quantityWeight_(fluidState, pvIdx));
+          
+            if (isSaturationIdx_(pvIdx)) {
+                // dampen to at most 20% change in saturation per
+                // iteration
+                delta = std::min(0.2, std::max(-0.2, delta));
+            }
+            else if (isMoleFracIdx_(pvIdx)) {
+                // dampen to at most 15% change in mole fraction per
+                // iteration
+                delta = std::min(0.15, std::max(-0.15, delta));
+            }
+            else if (isPressureIdx_(pvIdx)) {
+                // dampen to at most 15% change in pressure per
+                // iteration
+                delta = std::min(0.15*fluidState.pressure(0), std::max(-0.15*fluidState.pressure(0), delta));
+            };
+            
+            setQuantityRaw_(fluidState, pvIdx, tmp - delta);
+        }
+
+        // make sure all saturations, pressures and mole fractions are non-negative
+        Scalar sumSat = 0;
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+            Scalar value = fluidState.saturation(phaseIdx);
+            if (value < -0.05) {
+                value = -0.05;
+                fluidState.setSaturation(phaseIdx, value);
+            }
+            sumSat += value;
+
+            value = fluidState.pressure(phaseIdx);
+            if (value < 0)
+                fluidState.setPressure(phaseIdx, 0.0);
+
+            for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+                value = fluidState.moleFraction(phaseIdx, compIdx);
+                if (value < 0)
+                    fluidState.setMoleFraction(phaseIdx, compIdx, 0.0);
+            }
+        };
+
+        // last saturation
+        if (sumSat > 1.05) {
+            for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+                Scalar value = fluidState.saturation(phaseIdx)/(0.95*sumSat);
+                fluidState.setSaturation(phaseIdx, value);
+            };                
+        };
+        
+        completeFluidState_<MaterialLaw>(fluidState, paramCache, matParams);
+
+        return relError;
+    }
+
+    template <class MaterialLaw, class FluidState>
+    static void completeFluidState_(FluidState &fluidState,
+                                    ParameterCache &paramCache,
+                                    const typename MaterialLaw::Params &matParams)
+    {
+        // calculate the saturation of the last phase as a function of
+        // the other saturations
+        Scalar sumSat = 0.0;
+        for (int phaseIdx = 0; phaseIdx < numPhases - 1; ++phaseIdx)
+            sumSat += fluidState.saturation(phaseIdx);
+        fluidState.setSaturation(/*phaseIdx=*/numPhases - 1, 1.0 - sumSat);
+        
+        // update the pressures using the material law (saturations
+        // and first pressure are already set because it is implicitly
+        // solved for.)
+        ComponentVector pC;
+        MaterialLaw::capillaryPressures(pC, matParams, fluidState);
+        for (int phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx)
+            fluidState.setPressure(phaseIdx, 
+                                   fluidState.pressure(0)
+                                   + (pC[phaseIdx] - pC[0]));
+
+        // update the parameter cache
+        paramCache.updateAll(fluidState, /*except=*/ParameterCache::Temperature);
+
+        // update all densities and fugacity coefficients
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) {
+            Scalar rho = FluidSystem::density(fluidState, paramCache, phaseIdx);
+            fluidState.setDensity(phaseIdx, rho);
+            
+            for (int compIdx = 0; compIdx < numComponents; ++ compIdx) {
+                Scalar phi = FluidSystem::fugacityCoefficient( fluidState, paramCache, phaseIdx, compIdx);
+                fluidState.setFugacityCoefficient(phaseIdx, compIdx, phi);
+            }
+        }
+    }
+
+    static bool isPressureIdx_(int pvIdx)
+    { return pvIdx == 0; }
+
+    static bool isSaturationIdx_(int pvIdx)
+    { return 1 <= pvIdx && pvIdx < numPhases; }
+
+    static bool isMoleFracIdx_(int pvIdx)
+    { return numPhases <= pvIdx && pvIdx < numPhases + numPhases*numComponents; }
+
+    // retrieves a quantity from the fluid state
+    template <class FluidState>
+    static Scalar getQuantity_(const FluidState &fs, int pvIdx)
+    {
+        assert(pvIdx < numEq);
+
+        // first pressure
+        if (pvIdx < 1) {
+            int phaseIdx = 0;
+            return fs.pressure(phaseIdx);
+        }
+        // first M - 1 saturations
+        else if (pvIdx < numPhases) {
+            int phaseIdx = pvIdx - 1;
+            return fs.saturation(phaseIdx);
+        }
+        // mole fractions
+        else // if (pvIdx < numPhases + numPhases*numComponents) 
+        {
+            int phaseIdx = (pvIdx - numPhases)/numComponents;
+            int compIdx = (pvIdx - numPhases)%numComponents;
+            return fs.moleFraction(phaseIdx, compIdx);
+        }
+    };
+
+    // set a quantity in the fluid state
+    template <class MaterialLaw, class FluidState>
+    static void setQuantity_(FluidState &fs,
+                             ParameterCache &paramCache,
+                             const typename MaterialLaw::Params &matParams,
+                             int pvIdx,
+                             Scalar value)
+    {
+        assert(0 <= pvIdx && pvIdx < numEq);
+
+        if (pvIdx < 1) { // <- first pressure
+            Scalar delta = value - fs.pressure(0);
+
+            // set all pressures. here we assume that the capillary
+            // pressure does not depend on absolute pressure.
+            for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx)
+                fs.setPressure(phaseIdx, fs.pressure(phaseIdx) + delta);
+            paramCache.updateAllPressures(fs);
+
+            // update all densities and fugacity coefficients
+            for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+                Scalar rho = FluidSystem::density(fs, paramCache, phaseIdx);
+                fs.setDensity(phaseIdx, rho);
+                
+                for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+                    Scalar phi = FluidSystem::fugacityCoefficient(fs, paramCache, phaseIdx, compIdx);
+                    fs.setFugacityCoefficient(phaseIdx, compIdx, phi);
+                }
+            }
+        }
+        else if (pvIdx < numPhases) { // <- first M - 1 saturations
+            Scalar delta = value - fs.saturation(/*phaseIdx=*/pvIdx - 1);
+            fs.setSaturation(/*phaseIdx=*/pvIdx - 1, value);
+
+            // set last saturation (-> minus the change of the
+            // satuation of the other phase)
+            fs.setSaturation(/*phaseIdx=*/numPhases - 1, 
+                             fs.saturation(numPhases - 1) - delta);
+
+            // update all fluid pressures using the capillary pressure
+            // law
+            ComponentVector pC;
+            MaterialLaw::capillaryPressures(pC, matParams, fs);
+            for (int phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx)
+                fs.setPressure(phaseIdx, 
+                               fs.pressure(0)
+                               + (pC[phaseIdx] - pC[0]));
+            paramCache.updateAllPressures(fs);
+
+            // update all densities and fugacity coefficients
+            for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+                Scalar rho = FluidSystem::density(fs, paramCache, phaseIdx);
+                fs.setDensity(phaseIdx, rho);
+                
+                for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+                    Scalar phi = FluidSystem::fugacityCoefficient(fs, paramCache, phaseIdx, compIdx);
+                    fs.setFugacityCoefficient(phaseIdx, compIdx, phi);
+                }
+            }
+        }
+        else if (pvIdx < numPhases + numPhases*numComponents) // <- mole fractions
+        {
+            int phaseIdx = (pvIdx - numPhases)/numComponents;
+            int compIdx = (pvIdx - numPhases)%numComponents;
+
+            fs.setMoleFraction(phaseIdx, compIdx, value);
+            paramCache.updateSingleMoleFraction(fs, phaseIdx, compIdx);
+
+            // update the density of the phase
+            Scalar rho = FluidSystem::density(fs, paramCache, phaseIdx);
+            fs.setDensity(phaseIdx, rho);
+
+            // if the phase's fugacity coefficients are composition
+            // dependent, update them as well.
+            if (!FluidSystem::isIdealMixture(phaseIdx)) {
+                for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+                    Scalar phi = FluidSystem::fugacityCoefficient(fs, paramCache, phaseIdx, compIdx);
+                    fs.setFugacityCoefficient(phaseIdx, compIdx, phi);
+                }
+            }
+        }
+        else {
+            assert(false);
+        }
+
+        // make the fluid state consistent with the fluid system.
+        completeFluidState_<MaterialLaw>(fs,
+                                         paramCache,
+                                         matParams);
+    };
+
+    // set a quantity in the fluid state
+    template <class FluidState>
+    static void setQuantityRaw_(FluidState &fs, int pvIdx, Scalar value)
+    {
+        assert(pvIdx < numEq);
+        
+        // first pressure
+        if (pvIdx < 1) {
+            int phaseIdx = 0;
+            fs.setPressure(phaseIdx, value);
+        }
+        // first M - 1 saturations
+        else if (pvIdx < numPhases) {
+            int phaseIdx = pvIdx - 1;
+            fs.setSaturation(phaseIdx, value);
+        }
+        // mole fractions
+        else // if (pvIdx < numPhases + numPhases*numComponents) 
+        {
+            int phaseIdx = (pvIdx - numPhases)/numComponents;
+            int compIdx = (pvIdx - numPhases)%numComponents;
+            fs.setMoleFraction(phaseIdx, compIdx, value);
+        }
+    };
+
+    template <class FluidState>
+    static Scalar quantityWeight_(const FluidState &fs, int pvIdx)
+    {
+        // first pressure
+        if (pvIdx < 1)
+            return 1.0/1e5;
+        // first M - 1 saturations
+        else if (pvIdx < numPhases)
+            return 1.0;
+        // mole fractions
+        else // if (pvIdx < numPhases + numPhases*numComponents) 
+            return 1.0;
+    };
+};
+
+} // end namespace Dumux
+
+#endif
diff --git a/dumux/material/MpNcfluidsystems/h2on2fluidsystem.hh b/dumux/material/MpNcfluidsystems/h2on2fluidsystem.hh
index d06a8abe36..a7ae7d4439 100644
--- a/dumux/material/MpNcfluidsystems/h2on2fluidsystem.hh
+++ b/dumux/material/MpNcfluidsystems/h2on2fluidsystem.hh
@@ -291,11 +291,11 @@ public:
 
         Scalar T = fluidState.temperature(phaseIdx);
         Scalar p = fluidState.pressure(phaseIdx);
-
-        if (phaseIdx == lPhaseIdx)
-            // assume pure water where one water molecule gets
-            // replaced by one nitrogen molecule
+        
+        if (phaseIdx == lPhaseIdx) {
+            // assume pure water
             return H2O::liquidDensity(T, p);
+        }
 
         // for the gas phase assume an ideal gas
         return
@@ -470,8 +470,7 @@ public:
         Valgrind::CheckDefined(p);
         if (phaseIdx == lPhaseIdx) {
             // TODO: correct way to deal with the solutes???
-            return
-                H2O::liquidEnthalpy(T, p) ;
+            return H2O::liquidEnthalpy(T, p);
         }
         else {
             // assume ideal gas
@@ -503,7 +502,7 @@ public:
 //        Scalar p = fluidState.pressure(phaseIdx);
 //        Scalar T = fluidState.temperature(phaseIdx);
 //        Scalar x = fluidState.moleFrac(phaseIdx,compIdx);
-#warning: so far rough estimates from wikipedia
+//#warning: so far rough estimates from wikipedia
         if (phaseIdx == lPhaseIdx)
             return  0.6;   // conductivity of water[W / (m K ) ]
 
@@ -524,7 +523,7 @@ public:
                                int phaseIdx)
     {
 //        http://en.wikipedia.org/wiki/Heat_capacity
-#warning: so far rough estimates from wikipedia
+//#warning: so far rough estimates from wikipedia
 //      TODO heatCapacity is a function of composition.
 //        Scalar p = fluidState.pressure(phaseIdx);
 //        Scalar T = fluidState.temperature(phaseIdx);
diff --git a/dumux/material/MpNcfluidsystems/nullparametercache.hh b/dumux/material/MpNcfluidsystems/nullparametercache.hh
index 7efe8a584c..7952aa5b9a 100644
--- a/dumux/material/MpNcfluidsystems/nullparametercache.hh
+++ b/dumux/material/MpNcfluidsystems/nullparametercache.hh
@@ -37,18 +37,6 @@ class NullParameterCache : public ParameterCacheBase<NullParameterCache>
 public:
     NullParameterCache()
     {};
-
-    template <class FluidState>
-    void updateAll(const FluidState &fs)
-    {
-    };
-
-    /*!
-     * \brief Update all cached parameters of a specific fluid phase
-     */
-    template <class FluidState>
-    void updatePhase(const FluidState &fs, int phaseIdx)
-    {};
 };
 
 } // end namepace
diff --git a/dumux/material/MpNcfluidsystems/parametercachebase.hh b/dumux/material/MpNcfluidsystems/parametercachebase.hh
index 1c381b4f41..2914ade4e1 100644
--- a/dumux/material/MpNcfluidsystems/parametercachebase.hh
+++ b/dumux/material/MpNcfluidsystems/parametercachebase.hh
@@ -34,21 +34,37 @@ template <class Implementation>
 class ParameterCacheBase
 {
 public:
+    enum ExceptQuantities {
+        None = 0,
+        Temperature = 1, 
+        Pressure = 2,
+        Composition = 2,       
+    };
+    
     ParameterCacheBase()
     {};
 
     template <class FluidState>
-    void updateAll(const FluidState &fs)
+    void updateAll(const FluidState &fs, int exceptQuantities = None)
     {
         for (int phaseIdx = 0; phaseIdx < FluidState::numPhases; ++phaseIdx)
             updatePhase(fs, phaseIdx);
     };
 
+
+    template <class FluidState>
+    void updateAllPressures(const FluidState &fs)
+    {
+        for (int phaseIdx = 0; phaseIdx < FluidState::numPhases; ++phaseIdx)
+            updatePhase(fs, phaseIdx);
+    };
+
+
     /*!
      * \brief Update all cached parameters of a specific fluid phase
      */
     template <class FluidState>
-    void updatePhase(const FluidState &fs, int phaseIdx)
+    void updatePhase(const FluidState &fs, int phaseIdx, int exceptQuantities = None)
     {};
 
     /*!
@@ -59,8 +75,8 @@ public:
      * changed between two update*() calls. If more changed, call
      * updatePhase()!
      */
-    template <class FluidState> void
-    updatePhaseTemperature(const FluidState &fs, int phaseIdx)
+    template <class FluidState> 
+    void updateTemperature(const FluidState &fs, int phaseIdx)
     {
         asImp_().updatePhase(fs, phaseIdx);
     };
@@ -74,7 +90,7 @@ public:
      * updatePhase()!
      */
     template <class FluidState>
-    void updatePhasePressure(const FluidState &fs, int phaseIdx)
+    void updateSinglePressure(const FluidState &fs, int phaseIdx)
     {
         asImp_().updatePhase(fs, phaseIdx);
     };
@@ -88,7 +104,7 @@ public:
      * calls. If more changed, call updatePhase()!
      */
     template <class FluidState>
-    void updatePhaseComposition(const FluidState &fs, int phaseIdx)
+    void updateComposition(const FluidState &fs, int phaseIdx)
     {
         asImp_().updatePhase(fs, phaseIdx);
     };
@@ -103,11 +119,11 @@ public:
      * updatePhase()!
      */
     template <class FluidState>
-    void updatePhaseSingleMoleFraction(const FluidState &fs,
-                                       int phaseIdx,
-                                       int compIdx)
+    void updateSingleMoleFraction(const FluidState &fs,
+                                  int phaseIdx,
+                                  int compIdx)
     {
-        asImp_().updatePhaseComposition(fs, phaseIdx);
+        asImp_().updateComposition(fs, phaseIdx);
     };
 
 private:
diff --git a/test/material/Makefile.am b/test/material/Makefile.am
index e01d18a4d7..17f3316dcc 100644
--- a/test/material/Makefile.am
+++ b/test/material/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = tabulation .
+SUBDIRS = tabulation ncpflash
 
 include $(top_srcdir)/am/global-rules
 
diff --git a/test/material/ncpflash/Makefile.am b/test/material/ncpflash/Makefile.am
new file mode 100644
index 0000000000..3c18c7f283
--- /dev/null
+++ b/test/material/ncpflash/Makefile.am
@@ -0,0 +1,5 @@
+check_PROGRAMS = test_ncpflash
+
+test_ncpflash_SOURCES = test_ncpflash.cc
+
+include $(top_srcdir)/am/global-rules
diff --git a/test/material/ncpflash/test_ncpflash.cc b/test/material/ncpflash/test_ncpflash.cc
new file mode 100644
index 0000000000..20fb52f37b
--- /dev/null
+++ b/test/material/ncpflash/test_ncpflash.cc
@@ -0,0 +1,294 @@
+/*****************************************************************************
+ *   Copyright (C) 2011 by Andreas Lauser                                    *
+ *   Institute of Hydraulic Engineering                                      *
+ *   University of Stuttgart, Germany                                        *
+ *   email: <givenname>.<name>@iws.uni-stuttgart.de                          *
+ *                                                                           *
+ *   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 is a program to test the flash calculation which uses
+ *        non-linear complementarity problems (NCP)
+ *
+ * A flash calculation determines the pressures, saturations and
+ * composition of all phases given the total mass (or, as in this case
+ * the total number of moles) in a given amount of pore space.
+ */
+#include "config.h"
+
+#include <dumux/material/MpNcconstraintsolvers/misciblemultiphasecomposition.hh>
+#include <dumux/material/MpNcconstraintsolvers/computefromreferencephase.hh>
+#include <dumux/material/MpNcconstraintsolvers/ncpflash.hh>
+
+#include <dumux/material/MpNcfluidstates/compositionalfluidstate.hh>
+
+#include <dumux/material/MpNcfluidsystems/h2on2fluidsystem.hh>
+
+#include <dumux/material/fluidmatrixinteractions/Mp/Mplinearmaterial.hh>
+#include <dumux/material/fluidmatrixinteractions/Mp/2padapter.hh>
+#include <dumux/material/fluidmatrixinteractions/2p/linearmaterial.hh>
+#include <dumux/material/fluidmatrixinteractions/2p/regularizedlinearmaterial.hh>
+#include <dumux/material/fluidmatrixinteractions/2p/regularizedbrookscorey.hh>
+#include <dumux/material/fluidmatrixinteractions/2p/efftoabslaw.hh>
+
+template <class Scalar, class FluidState>
+void checkSame(const FluidState &fsRef, const FluidState &fsFlash)
+{
+    enum { numPhases = FluidState::numPhases };
+    enum { numComponents = FluidState::numComponents };
+
+    for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+        Scalar error;
+
+        // check the pressures
+        error = 1 - fsRef.pressure(phaseIdx)/fsFlash.pressure(phaseIdx);
+        if (std::abs(error) > 1e-6) {
+            std::cout << "pressure error phase " << phaseIdx << ": "
+                      << fsFlash.pressure(phaseIdx)  << " flash vs "
+                      << fsRef.pressure(phaseIdx) << " reference"
+                      << " error=" << error << "\n";
+        }
+
+        // check the saturations
+        error = fsRef.saturation(phaseIdx) - fsFlash.saturation(phaseIdx);
+        if (std::abs(error) > 1e-6)
+            std::cout << "saturation error phase " << phaseIdx << ": " 
+                      << fsFlash.saturation(phaseIdx) << " flash vs "
+                      << fsRef.saturation(phaseIdx) << " reference"
+                      << " error=" << error << "\n";
+
+        // check the compositions
+        for (int compIdx = 0; compIdx < numComponents; ++ compIdx) {
+            error = fsRef.moleFraction(phaseIdx, compIdx) - fsFlash.moleFraction(phaseIdx, compIdx);
+            if (std::abs(error) > 1e-6)
+                std::cout << "composition error phase " << phaseIdx << ", component " << compIdx << ": " 
+                          << fsFlash.moleFraction(phaseIdx, compIdx) << " flash vs "
+                          << fsRef.moleFraction(phaseIdx, compIdx) << " reference"
+                          << " error=" << error << "\n";
+        };
+    }
+}
+
+template <class Scalar, class FluidSystem, class MaterialLaw, class FluidState>
+void checkNcpFlash(const FluidState &fsRef, 
+                   typename MaterialLaw::Params &matParams)
+{
+    enum { numPhases = FluidSystem::numPhases };
+    enum { numComponents = FluidSystem::numComponents };
+    typedef Dune::FieldVector<Scalar, numComponents> ComponentVector;
+
+    // calculate the total amount of stuff in the reference fluid
+    // phase
+    ComponentVector globalMolarities(0.0);
+    for (int compIdx = 0; compIdx < numComponents; ++compIdx) {
+        for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) {
+            globalMolarities[compIdx] +=
+                fsRef.saturation(phaseIdx)*fsRef.molarity(phaseIdx, compIdx);
+        }
+    }
+
+    // initialize the fluid state for the flash calculation
+    typedef Dumux::NcpFlash<Scalar, FluidSystem> NcpFlash;
+    FluidState fsFlash;
+
+    fsFlash.setTemperature(fsRef.temperature(/*phaseIdx=*/0));
+
+    // run the flash calculation
+    typename FluidSystem::ParameterCache paramCache;
+    NcpFlash::guessInitial(fsFlash, paramCache, globalMolarities);
+    NcpFlash::template solve<MaterialLaw>(fsFlash, paramCache, matParams, globalMolarities);
+
+    // compare the "flashed" fluid state with the reference one
+    checkSame<Scalar>(fsRef, fsFlash);
+};
+
+
+template <class Scalar, class FluidSystem, class MaterialLaw, class FluidState>
+void completeReferenceFluidState(FluidState &fs, 
+                                 typename MaterialLaw::Params &matParams,
+                                 int refPhaseIdx)
+{
+    enum { numPhases = FluidSystem::numPhases };
+
+    typedef Dumux::ComputeFromReferencePhase<Scalar, FluidSystem> ComputeFromReferencePhase;
+    typedef Dune::FieldVector<Scalar, numPhases> PhaseVector;
+    
+    int otherPhaseIdx = 1 - refPhaseIdx;
+
+    // calculate the other saturation
+    fs.setSaturation(otherPhaseIdx, 1.0 - fs.saturation(refPhaseIdx));
+
+    // calulate the capillary pressure
+    PhaseVector pC;
+    MaterialLaw::capillaryPressures(pC, matParams, fs);
+    fs.setPressure(otherPhaseIdx, 
+                   fs.pressure(refPhaseIdx)
+                   + (pC[otherPhaseIdx] - pC[refPhaseIdx]));
+    
+    // make the fluid state consistent with local thermodynamic
+    // equilibrium
+    typename FluidSystem::ParameterCache paramCache;
+    ComputeFromReferencePhase::solve(fs,
+                                     paramCache, 
+                                     refPhaseIdx,
+                                     /*setViscosity=*/false,
+                                     /*setEnthalpy=*/false);
+}
+
+
+int main()
+{
+    typedef double Scalar;
+    typedef Dumux::H2ON2FluidSystem<Scalar> FluidSystem;
+    typedef Dumux::CompositionalFluidState<Scalar, FluidSystem> CompositionalFluidState;
+
+    enum { numPhases = FluidSystem::numPhases };
+    enum { numComponents = FluidSystem::numComponents };
+    enum { lPhaseIdx = FluidSystem::lPhaseIdx };
+    enum { gPhaseIdx = FluidSystem::gPhaseIdx };
+
+    enum { H2OIdx = FluidSystem::H2OIdx };
+    enum { N2Idx = FluidSystem::N2Idx };
+
+    typedef Dumux::RegularizedBrooksCorey<Scalar> EffMaterialLaw;
+    typedef Dumux::EffToAbsLaw<EffMaterialLaw> TwoPMaterialLaw;
+    typedef Dumux::TwoPAdapter<lPhaseIdx, TwoPMaterialLaw> MaterialLaw;
+    typedef MaterialLaw::Params MaterialLawParams;
+
+    Scalar T = 273.15 + 25;
+    
+    // initialize the tables of the fluid system
+    Scalar Tmin = T - 1.0;
+    Scalar Tmax = T + 1.0;
+    int nT = 3;
+    
+    Scalar pmin = 0.75 * 1e5;
+    Scalar pmax = 1.25 * 2e5;
+    int np = 100;
+
+    FluidSystem::init(Tmin, Tmax, nT, pmin, pmax, np);
+
+    // set the parameters for the capillary pressure law
+    MaterialLawParams matParams;
+    matParams.setSwr(0.0);
+    matParams.setSnr(0.0);
+    matParams.setPe(0);
+    matParams.setLambda(2.0);
+
+    CompositionalFluidState fsRef;
+    
+    // create an fluid state which is consistent
+
+    // set the fluid temperatures
+    fsRef.setTemperature(T);
+    
+    ////////////////
+    // only liquid
+    ////////////////
+
+    // set liquid saturation
+    fsRef.setSaturation(lPhaseIdx, 1.0);
+    
+    // set pressure of the liquid phase
+    fsRef.setPressure(lPhaseIdx, 2e5);
+    
+    // set the liquid composition to pure water
+    fsRef.setMoleFraction(lPhaseIdx, N2Idx, 0.0);
+    fsRef.setMoleFraction(lPhaseIdx, H2OIdx, 1.0);
+    
+    // "complete" the fluid state
+    completeReferenceFluidState<Scalar, FluidSystem, MaterialLaw>(fsRef, matParams, lPhaseIdx);
+
+    // check the flash calculation
+    checkNcpFlash<Scalar, FluidSystem, MaterialLaw>(fsRef, matParams);
+
+    ////////////////
+    // only gas
+    ////////////////
+
+    // set gas saturation
+    fsRef.setSaturation(gPhaseIdx, 1.0);
+    
+    // set pressure of the gas phase
+    fsRef.setPressure(gPhaseIdx, 1e6);
+    
+    // set the gas composition to 99.9% nitrogen and 0.1% water
+    fsRef.setMoleFraction(gPhaseIdx, N2Idx, 0.999);
+    fsRef.setMoleFraction(gPhaseIdx, H2OIdx, 0.001);
+    
+    // "complete" the fluid state
+    completeReferenceFluidState<Scalar, FluidSystem, MaterialLaw>(fsRef, matParams, gPhaseIdx);
+
+    // check the flash calculation
+    checkNcpFlash<Scalar, FluidSystem, MaterialLaw>(fsRef, matParams);
+
+    ////////////////
+    // both pgases gas
+    ////////////////
+
+    // set saturations
+    fsRef.setSaturation(lPhaseIdx, 0.5);
+    fsRef.setSaturation(gPhaseIdx, 0.5);
+    
+    // set pressures
+    fsRef.setPressure(lPhaseIdx, 1e6);
+    fsRef.setPressure(gPhaseIdx, 1e6);
+       
+    FluidSystem::ParameterCache paramCache;
+    typedef Dumux::MiscibleMultiPhaseComposition<Scalar, FluidSystem> MiscibleMultiPhaseComposition;
+    MiscibleMultiPhaseComposition::solve(fsRef, paramCache,
+                                         /*setViscosity=*/false,
+                                         /*setEnthalpy=*/false);
+
+    // check the flash calculation
+    checkNcpFlash<Scalar, FluidSystem, MaterialLaw>(fsRef, matParams);
+
+    ////////////////
+    // with capillary pressure
+    ////////////////
+
+    MaterialLawParams matParams2;
+    matParams2.setSwr(0.0);
+    matParams2.setSnr(0.0);
+    matParams2.setPe(1e3);
+    matParams2.setLambda(2.0);
+
+    // set gas saturation
+    fsRef.setSaturation(gPhaseIdx, 0.5);
+    fsRef.setSaturation(lPhaseIdx, 0.5);
+    
+    // set pressure of the liquid phase
+    fsRef.setPressure(lPhaseIdx, 1e6);
+
+    // calulate the capillary pressure
+    typedef Dune::FieldVector<Scalar, numPhases> PhaseVector;
+    PhaseVector pC;
+    MaterialLaw::capillaryPressures(pC, matParams2, fsRef);
+    fsRef.setPressure(gPhaseIdx, 
+                      fsRef.pressure(lPhaseIdx)
+                      + (pC[gPhaseIdx] - pC[lPhaseIdx]));
+    
+    typedef Dumux::MiscibleMultiPhaseComposition<Scalar, FluidSystem> MiscibleMultiPhaseComposition;
+    MiscibleMultiPhaseComposition::solve(fsRef, paramCache,
+                                         /*setViscosity=*/false,
+                                         /*setEnthalpy=*/false);
+
+
+    // check the flash calculation
+    checkNcpFlash<Scalar, FluidSystem, MaterialLaw>(fsRef, matParams2);
+
+    return 0;
+}
-- 
GitLab