From a5f0c430b342c5ac38d4704dca9e4e1001800d03 Mon Sep 17 00:00:00 2001 From: Holger Class <holger.class@iws.uni-stuttgart.de> Date: Tue, 31 Jan 2012 14:50:17 +0000 Subject: [PATCH] fluidsystem required by some tests git-svn-id: svn://svn.iws.uni-stuttgart.de/DUMUX/dumux/trunk@7582 2fb0f335-1f38-0410-981e-8018bf24f1b0 --- .../fluidsystems/h2oairxylenefluidsystem.hh | 493 ++++++++++++++++++ 1 file changed, 493 insertions(+) create mode 100644 dumux/material/fluidsystems/h2oairxylenefluidsystem.hh diff --git a/dumux/material/fluidsystems/h2oairxylenefluidsystem.hh b/dumux/material/fluidsystems/h2oairxylenefluidsystem.hh new file mode 100644 index 0000000000..e577c2b560 --- /dev/null +++ b/dumux/material/fluidsystems/h2oairxylenefluidsystem.hh @@ -0,0 +1,493 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/***************************************************************************** + * Copyright (C) 2011 by Holger Class * + * Copyright (C) 2009-2010 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 A fluid system with water, gas and NAPL as phases and + * \f$H_2O\f$ and \f$Air\f$ and \f$NAPL (contaminant)\f$ as components. + */ +#ifndef DUMUX_H2O_AIR_XYLENE_FLUID_SYSTEM_HH +#define DUMUX_H2O_AIR_XYLENE_FLUID_SYSTEM_HH + +#include <dumux/material/idealgas.hh> +#include <dumux/material/components/air.hh> +#include <dumux/material/components/h2o.hh> +#include <dumux/material/components/xylene.hh> +#include <dumux/material/components/tabulatedcomponent.hh> + +#include <dumux/material/binarycoefficients/h2o_air.hh> +#include <dumux/material/binarycoefficients/h2o_xylene.hh> +#include <dumux/material/binarycoefficients/air_xylene.hh> + +#include <dumux/material/fluidsystems/basefluidsystem.hh> + +namespace Dumux +{ +namespace FluidSystems +{ + +/*! + * \brief A compositional fluid with water and molecular nitrogen as + * components in both, the liquid and the gas phase. + */ +template <class Scalar> +class H2OAirXylene + : public BaseFluidSystem<Scalar, H2OAirXylene<Scalar> > +{ + typedef H2OAirXylene<Scalar> ThisType; + typedef BaseFluidSystem<Scalar, ThisType> Base; + +public: + typedef Dumux::H2O<Scalar> H2O; + typedef Dumux::Xylene<Scalar> NAPL; + typedef Dumux::Air<Scalar> Air; + + static const int numPhases = 3; + static const int numComponents = 3; + + static const int wPhaseIdx = 0; // index of the water phase + static const int nPhaseIdx = 1; // index of the NAPL phase + static const int gPhaseIdx = 2; // index of the gas phase + + static const int H2OIdx = 0; + static const int NAPLIdx = 1; + static const int airIdx = 2; + + static void init() + { } + + /*! + * \brief Return whether a phase is liquid + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isLiquid(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + return phaseIdx != gPhaseIdx; + } + + static bool isIdealGas(int phaseIdx) + { return phaseIdx == gPhaseIdx && H2O::gasIsIdeal() && Air::gasIsIdeal() && NAPL::gasIsIdeal(); } + + /*! + * \brief Returns true if and only if a fluid phase is assumed to + * be an ideal mixture. + * + * We define an ideal mixture as a fluid phase where the fugacity + * coefficients of all components times the pressure of the phase + * are indepent on the fluid composition. This assumtion is true + * if Henry's law and Rault's law apply. If you are unsure what + * this function should return, it is safe to return false. The + * only damage done will be (slightly) increased computation times + * in some cases. + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isIdealMixture(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + // we assume Henry's and Rault's laws for the water phase and + // and no interaction between gas molecules of different + // components, so all phases are ideal mixtures! + return true; + } + + /*! + * \brief Returns true if and only if a fluid phase is assumed to + * be compressible. + * + * Compressible means that the partial derivative of the density + * to the fluid pressure is always larger than zero. + * + * \param phaseIdx The index of the fluid phase to consider + */ + static bool isCompressible(int phaseIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + // gases are always compressible + if (phaseIdx == gPhaseIdx) + return true; + else if (phaseIdx == wPhaseIdx) + // the water component decides for the water phase... + return H2O::liquidIsCompressible(); + + // the NAPL component decides for the napl phase... + return NAPL::liquidIsCompressible(); + } + + /*! + * \brief Return the human readable name of a phase (used in indices) + */ + static const char *phaseName(int phaseIdx) + { + switch (phaseIdx) { + case wPhaseIdx: return "w"; + case nPhaseIdx: return "n"; + case gPhaseIdx: return "g";; + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + /*! + * \brief Return the human readable name of a component (used in indices) + */ + static const char *componentName(int compIdx) + { + switch (compIdx) { + case H2OIdx: return H2O::name(); + case airIdx: return Air::name(); + case NAPLIdx: return NAPL::name(); + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << compIdx); + } + + /*! + * \brief Return the molar mass of a component in [kg/mol]. + */ + static Scalar molarMass(int compIdx) + { + switch (compIdx) { + case H2OIdx: return H2O::molarMass(); + case airIdx: return Air::molarMass(); + case NAPLIdx: return NAPL::molarMass(); + }; + DUNE_THROW(Dune::InvalidStateException, "Invalid component index " << compIdx); + } + + /*! + * \brief Given all mole fractions in a phase, return the phase + * density [kg/m^3]. + */ + using Base::density; + template <class FluidState> + static Scalar density(const FluidState &fluidState, int phaseIdx) + { + if (phaseIdx == wPhaseIdx) { + // See: Ochs 2008 + // \todo: proper citation + Scalar rholH2O = H2O::liquidDensity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + Scalar clH2O = rholH2O/H2O::molarMass(); + + // this assumes each dissolved molecule displaces exactly one + // water molecule in the liquid + return + clH2O*(H2O::molarMass()*fluidState.moleFraction(wPhaseIdx, H2OIdx) + + + Air::molarMass()*fluidState.moleFraction(wPhaseIdx, airIdx) + + + NAPL::molarMass()*fluidState.moleFraction(wPhaseIdx, NAPLIdx)); + } + else if (phaseIdx == nPhaseIdx) { + // assume pure NAPL for the NAPL phase + Scalar pressure = NAPL::liquidIsCompressible()?fluidState.pressure(phaseIdx):1e100; + return NAPL::liquidDensity(fluidState.temperature(phaseIdx), pressure); + } + + assert (phaseIdx == gPhaseIdx); + Scalar pH2O = + fluidState.moleFraction(gPhaseIdx, H2OIdx) * + fluidState.pressure(gPhaseIdx); + Scalar pAir = + fluidState.moleFraction(gPhaseIdx, airIdx) * + fluidState.pressure(gPhaseIdx); + Scalar pNAPL = + fluidState.moleFraction(gPhaseIdx, NAPLIdx) * + fluidState.pressure(gPhaseIdx); + return + H2O::gasDensity(fluidState.temperature(phaseIdx), pH2O) + + Air::gasDensity(fluidState.temperature(phaseIdx), pAir) + + NAPL::gasDensity(fluidState.temperature(phaseIdx), pNAPL); + } + + /*! + * \brief Return the viscosity of a phase. + */ + using Base::viscosity; + template <class FluidState> + static Scalar viscosity(const FluidState &fluidState, + int phaseIdx) + { + if (phaseIdx == wPhaseIdx) { + // assume pure water viscosity + return H2O::liquidViscosity(fluidState.temperature(phaseIdx), + fluidState.pressure(phaseIdx)); + } + else if (phaseIdx == nPhaseIdx) { + // assume pure NAPL viscosity + return NAPL::liquidViscosity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + + assert (phaseIdx == gPhaseIdx); + + /* Wilke method. See: + * + * See: R. Reid, et al.: The Properties of Gases and Liquids, + * 4th edition, McGraw-Hill, 1987, 407-410 + * 5th edition, McGraw-Hill, 20001, p. 9.21/22 + * + * in this case, we use a simplified version in order to avoid + * computationally costly evaluation of sqrt and pow functions and + * divisions + * -- compare e.g. with Promo Class p. 32/33 + */ + Scalar muResult; + const Scalar mu[numComponents] = { + H2O::gasViscosity(fluidState.temperature(phaseIdx), H2O::vaporPressure(fluidState.temperature(phaseIdx))), + Air::simpleGasViscosity(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)), + NAPL::gasViscosity(fluidState.temperature(phaseIdx), NAPL::vaporPressure(fluidState.temperature(phaseIdx))) + }; + // molar masses + const Scalar M[numComponents] = { + H2O::molarMass(), + Air::molarMass(), + NAPL::molarMass() + }; + + Scalar muAW = mu[airIdx]*fluidState.moleFraction(gPhaseIdx, airIdx) + + mu[H2OIdx]*fluidState.moleFraction(gPhaseIdx, H2OIdx) + / (fluidState.moleFraction(gPhaseIdx, airIdx) + + fluidState.moleFraction(gPhaseIdx, H2OIdx)); + Scalar xAW = fluidState.moleFraction(gPhaseIdx, airIdx) + + fluidState.moleFraction(gPhaseIdx, H2OIdx); + + Scalar MAW = (fluidState.moleFraction(gPhaseIdx, airIdx)*Air::molarMass() + + fluidState.moleFraction(gPhaseIdx, H2OIdx)*H2O::molarMass()) + / xAW; + + /* TODO, please check phiCAW for the Xylene case here */ + + + Scalar phiCAW = 0.3; // simplification for this particular system + /* actually like this + * Scalar phiCAW = std::pow(1.+std::sqrt(mu[NAPLIdx]/muAW)*std::pow(MAW/M[NAPLIdx],0.25),2) + * / std::sqrt(8.*(1.+M[NAPLIdx]/MAW)); + */ + Scalar phiAWC = phiCAW * muAW*M[NAPLIdx]/(mu[NAPLIdx]*MAW); + + muResult = (xAW*muAW)/(xAW+fluidState.moleFraction(gPhaseIdx, NAPLIdx)*phiAWC) + + (fluidState.moleFraction(gPhaseIdx, NAPLIdx) * mu[NAPLIdx]) + / (fluidState.moleFraction(gPhaseIdx, NAPLIdx) + xAW*phiCAW); + return muResult; + } + + + /*! + * \brief Given all mole fractions, return the diffusion + * coefficent of a component in a phase. + */ + using Base::diffusionCoefficient; + template <class FluidState> + static Scalar diffusionCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIdx) + { + Scalar diffCont; + + if (phaseIdx==gPhaseIdx) { + Scalar diffAC = Dumux::BinaryCoeff::Air_Xylene::gasDiffCoeff(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + Scalar diffWC = Dumux::BinaryCoeff::H2O_Xylene::gasDiffCoeff(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + Scalar diffAW = Dumux::BinaryCoeff::H2O_Air::gasDiffCoeff(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + + const Scalar xga = fluidState.moleFraction(gPhaseIdx, airIdx); + const Scalar xgw = fluidState.moleFraction(gPhaseIdx, H2OIdx); + const Scalar xgc = fluidState.moleFraction(gPhaseIdx, NAPLIdx); + + if (compIdx==NAPLIdx) return (1.- xgw)/(xga/diffAW + xgc/diffWC); + else if (compIdx==H2OIdx) return (1.- xgc)/(xgw/diffWC + xga/diffAC); + else if (compIdx==airIdx) DUNE_THROW(Dune::InvalidStateException, + "Diffusivity of air in the gas phase " + "is constraint by sum of diffusive fluxes = 0 !\n"); + } else if (phaseIdx==wPhaseIdx){ + Scalar diffACl = 1.e-9; // BinaryCoeff::Air_Xylene::liquidDiffCoeff(temperature, pressure); + Scalar diffWCl = 1.e-9; // BinaryCoeff::H2O_Xylene::liquidDiffCoeff(temperature, pressure); + Scalar diffAWl = 1.e-9; // BinaryCoeff::H2O_Air::liquidDiffCoeff(temperature, pressure); + + Scalar xwa = fluidState.moleFraction(wPhaseIdx, airIdx); + Scalar xww = fluidState.moleFraction(wPhaseIdx, H2OIdx); + Scalar xwc = fluidState.moleFraction(wPhaseIdx, NAPLIdx); + + switch (compIdx) { + case NAPLIdx: + diffCont = (1.- xww)/(xwa/diffAWl + xwc/diffWCl); + return diffCont; + case airIdx: + diffCont = (1.- xwc)/(xww/diffWCl + xwa/diffACl); + return diffCont; + case H2OIdx: + DUNE_THROW(Dune::InvalidStateException, + "Diffusivity of water in the water phase " + "is constraint by sum of diffusive fluxes = 0 !\n"); + }; + } else if (phaseIdx==nPhaseIdx) { + + DUNE_THROW(Dune::InvalidStateException, + "Diffusion coefficients of " + "substances in liquid phase are undefined!\n"); + } + return 0; + } + + using Base::binaryDiffusionCoefficient; + template <class FluidState> + static Scalar binaryDiffusionCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIIdx, + int compJIdx) + { + DUNE_THROW(Dune::NotImplemented, "FluidSystems::H2OAirXylene::binaryDiffusionCoefficient()"); + } + + /*! + * \brief Returns the fugacity coefficient [-] of a component in a + * phase. + * + * In this case, things are actually pretty simple. We have an ideal + * solution. Thus, the fugacity coefficient is 1 in the gas phase + * (fugacity equals the partial pressure of the component in the gas phase + * respectively in the liquid phases it is the inverse of the + * Henry coefficients scaled by pressure + */ + using Base::fugacityCoefficient; + template <class FluidState> + static Scalar fugacityCoefficient(const FluidState &fluidState, + int phaseIdx, + int compIdx) + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + assert(0 <= compIdx && compIdx < numComponents); + + Scalar T = fluidState.temperature(phaseIdx); + Scalar p = fluidState.pressure(phaseIdx); + + if (phaseIdx == wPhaseIdx) { + if (compIdx == H2OIdx) + return H2O::vaporPressure(T)/p; + else if (compIdx == airIdx) + return Dumux::BinaryCoeff::H2O_Air::henry(T)/p; + else if (compIdx == NAPLIdx) + return Dumux::BinaryCoeff::H2O_Xylene::henry(T)/p; + } + + // for the NAPL phase, we assume currently that nothing is + // dissolved. this means that the affinity of the NAPL + // component to the NAPL phase is much higher than for the + // other components, i.e. the fugacity cofficient is much + // smaller. + if (phaseIdx == nPhaseIdx) { + Scalar phiNapl = NAPL::vaporPressure(T)/p; + if (compIdx == NAPLIdx) + return phiNapl; + else if (compIdx == airIdx) + return 1e6*phiNapl; + else if (compIdx == H2OIdx) + return 1e6*phiNapl; + } + + // for the gas phase, assume an ideal gas when it comes to + // fugacity (-> fugacity == partial pressure) + assert(phaseIdx == gPhaseIdx); + return 1.0; + } + + + /*! + * \brief Given all mole fractions in a phase, return the specific + * phase enthalpy [J/kg]. + */ + /*! + * \todo This system neglects the contribution of gas-molecules in the liquid phase. + * This contribution is probably not big. Somebody would have to find out the enthalpy of solution for this system. ... + */ + using Base::enthalpy; + template <class FluidState> + static Scalar enthalpy(const FluidState &fluidState, + int phaseIdx) + { + if (phaseIdx == wPhaseIdx) { + return H2O::liquidEnthalpy(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + else if (phaseIdx == nPhaseIdx) { + return NAPL::liquidEnthalpy(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); + } + else if (phaseIdx == gPhaseIdx) { // gas phase enthalpy depends strongly on composition + Scalar hgc = NAPL::gasEnthalpy(fluidState.temperature(phaseIdx), + fluidState.pressure(phaseIdx)); + Scalar hgw = H2O::gasEnthalpy(fluidState.temperature(phaseIdx), + fluidState.pressure(phaseIdx)); + Scalar hga = Air::gasEnthalpy(fluidState.temperature(phaseIdx), fluidState.pressure(phaseIdx)); // pressure is only a dummy here (not dependent on pressure, just temperature) + + Scalar result = 0; + result += hgw * fluidState.massFraction(gPhaseIdx, H2OIdx); + result += hga * fluidState.massFraction(gPhaseIdx, airIdx); + result += hgc * fluidState.massFraction(gPhaseIdx, NAPLIdx); + + return result; + } + DUNE_THROW(Dune::InvalidStateException, "Invalid phase index " << phaseIdx); + } + + using Base::heatCapacity; + template <class FluidState> + static Scalar heatCapacity(const FluidState &fluidState, + int phaseIdx) + { + DUNE_THROW(Dune::NotImplemented, "FluidSystems::H2OAirXylene::heatCapacity()"); + } + + using Base::thermalConductivity; + template <class FluidState> + static Scalar thermalConductivity(const FluidState &fluidState, + int phaseIdx) + { + DUNE_THROW(Dune::NotImplemented, "FluidSystems::H2OAirXylene::thermalConductivity()"); + } + +private: + static Scalar waterPhaseDensity_(Scalar T, Scalar pw, Scalar xww, Scalar xwa, Scalar xwc) + { + Scalar rholH2O = H2O::liquidDensity(T, pw); + Scalar clH2O = rholH2O/H2O::molarMass(); + + // this assumes each dissolved molecule displaces exactly one + // water molecule in the liquid + return + clH2O*(xww*H2O::molarMass() + xwa*Air::molarMass() + xwc*NAPL::molarMass()); + } + + static Scalar gasPhaseDensity_(Scalar T, Scalar pg, Scalar xgw, Scalar xga, Scalar xgc) + { + return H2O::gasDensity(T, pg*xgw) + Air::gasDensity(T, pg*xga) + NAPL::gasDensity(T, pg*xgc); + }; + + static Scalar NAPLPhaseDensity_(Scalar T, Scalar pn) + { + return + NAPL::liquidDensity(T, pn); + } + +}; +} // end namespace FluidSystems +} // end namespace Dumux + +#endif -- GitLab