Files
opm-common/opm/material/components/H2O.hpp
2014-03-05 16:30:54 +01:00

941 lines
34 KiB
C++

/*
Copyright (C) 2009-2013 by Andreas Lauser
Copyright (C) 2010 by Jochen Fritz
This file is part of the Open Porous Media project (OPM).
OPM 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.
OPM 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 OPM. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file
* \copydoc Opm::H2O
*/
#ifndef OPM_H2O_HPP
#define OPM_H2O_HPP
#include <cmath>
#include <cassert>
#include <opm/material/IdealGas.hpp>
#include <opm/core/utility/Exceptions.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/material/Valgrind.hpp>
#include "Component.hpp"
#include "iapws/Common.hpp"
#include "iapws/Region1.hpp"
#include "iapws/Region2.hpp"
#include "iapws/Region4.hpp"
namespace Opm {
/*!
* \ingroup Components
*
* \brief Material properties of pure water \f$H_2O\f$.
*
* \tparam Scalar The type used for scalar values
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*/
template <class Scalar>
class H2O : public Component<Scalar, H2O<Scalar> >
{
typedef IAPWS::Common<Scalar> Common;
typedef IAPWS::Region1<Scalar> Region1;
typedef IAPWS::Region2<Scalar> Region2;
typedef IAPWS::Region4<Scalar> Region4;
static const Scalar Rs; // specific gas constant of water
public:
/*!
* \brief A human readable name for the water.
*/
static const char *name()
{ return "H2O"; }
/*!
* \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of water.
*/
static const Scalar molarMass()
{ return Common::molarMass; }
/*!
* \brief The acentric factor \f$\mathrm{[-]}\f$ of water.
*/
static const Scalar acentricFactor()
{ return Common::acentricFactor; }
/*!
* \brief Returns the critical temperature \f$\mathrm{[K]}\f$ of water
*/
static const Scalar criticalTemperature()
{ return Common::criticalTemperature; }
/*!
* \brief Returns the critical pressure \f$\mathrm{[Pa]}\f$ of water.
*/
static const Scalar criticalPressure()
{ return Common::criticalPressure; }
/*!
* \brief Returns the molar volume \f$\mathrm{[m^3/mol]}\f$ of water at the critical point
*/
static const Scalar criticalMolarVolume()
{ return Common::criticalMolarVolume; }
/*!
* \brief Returns the temperature \f$\mathrm{[K]}\f$ at water's triple point.
*/
static const Scalar tripleTemperature()
{ return Common::tripleTemperature; }
/*!
* \brief Returns the pressure \f$\mathrm{[Pa]}\f$ at water's triple point.
*/
static const Scalar triplePressure()
{ return Common::triplePressure; }
/*!
* \brief The vapor pressure in \f$\mathrm{[Pa]}\f$ of pure water
* at a given temperature.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param T Absolute temperature of the system in \f$\mathrm{[K]}\f$
*/
static Scalar vaporPressure(Scalar T)
{
if (T > criticalTemperature())
T = criticalTemperature();
if (T < tripleTemperature())
T = tripleTemperature();
return Region4::saturationPressure(T);
}
/*!
* \brief The vapor temperature in \f$\mathrm{[Ka]}\f$ of pure water
* at a given pressure.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar vaporTemperature(Scalar pressure)
{
if (pressure > criticalPressure())
pressure = criticalPressure();
if (pressure < triplePressure())
pressure = triplePressure();
return Region4::vaporTemperature(pressure);
}
/*!
* \brief Specific enthalpy of water steam \f$\mathrm{[J/kg]}\f$.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar gasEnthalpy(Scalar temperature,
Scalar pressure)
{
if (!Region2::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Enthalpy of steam is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
if (pressure < triplePressure() - 100) {
// We assume an ideal gas for low pressures to avoid the
// 0/0 for the gas enthalpy at very low pressures. The
// enthalpy of an ideal gas does not exhibit any
// dependence on pressure, so we can just return the
// specific enthalpy at the point of regularization, i.e.
// the triple pressure - 100Pa
return enthalpyRegion2_(temperature, triplePressure() - 100);
}
Scalar pv = vaporPressure(temperature);
if (pressure > pv) {
// the pressure is too high, in this case we use the slope
// of the enthalpy at the vapor pressure to regularize
Scalar dh_dp =
Rs*temperature*
Region2::tau(temperature)*
Region2::dpi_dp(pv)*
Region2::ddgamma_dtaudpi(temperature, pv);
return
enthalpyRegion2_(temperature, pv) +
(pressure - pv)*dh_dp;
};
return enthalpyRegion2_(temperature, pressure);
}
/*!
* \brief Specific enthalpy of liquid water \f$\mathrm{[J/kg]}\f$.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar liquidEnthalpy(Scalar temperature,
Scalar pressure)
{
if (!Region1::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Enthalpy of water is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
Scalar pv = vaporPressure(temperature);
if (pressure < pv) {
// the pressure is too low, in this case we use the slope
// of the enthalpy at the vapor pressure to regularize
Scalar dh_dp =
Rs * temperature*
Region1::tau(temperature)*
Region1::dpi_dp(pv)*
Region1::ddgamma_dtaudpi(temperature, pv);
return
enthalpyRegion1_(temperature, pv) +
(pressure - pv)*dh_dp;
};
return enthalpyRegion1_(temperature, pressure);
}
/*!
* \brief Specific isobaric heat capacity of water steam \f$\mathrm{[J/kg]}\f$.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar gasHeatCapacity(Scalar temperature,
Scalar pressure)
{
if (!Region2::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Heat capacity of steam is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
if (pressure < triplePressure() - 100) {
return heatCap_p_Region2_(temperature, triplePressure() - 100);
}
Scalar pv = vaporPressure(temperature);
if (pressure > pv) {
// the pressure is too high, in this case we use the heat
// cap at the vapor pressure to regularize
return
heatCap_p_Region2_(temperature, pv);
};
return heatCap_p_Region2_(temperature, pressure);
}
/*!
* \brief Specific isobaric heat capacity of liquid water \f$\mathrm{[J/kg]}\f$.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar liquidHeatCapacity(Scalar temperature,
Scalar pressure)
{
if (!Region1::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"heat Capacity of water is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
Scalar pv = vaporPressure(temperature);
if (pressure < pv) {
// the pressure is too low, in this case we use the heat cap at the vapor pressure to regularize
return
heatCap_p_Region1_(temperature, pv);
};
return heatCap_p_Region1_(temperature, pressure);
}
/*!
* \brief Specific internal energy of liquid water \f$\mathrm{[J/kg]}\f$.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar liquidInternalEnergy(Scalar temperature,
Scalar pressure)
{
if (!Region1::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Internal Energy of water is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
Scalar pv = vaporPressure(temperature);
if (pressure < pv) {
// the pressure is too low, in this case we use the slope
// of the internal energy at the vapor pressure to
// regularize
/*
// calculate the partial derivative of the internal energy
// to the pressure at the vapor pressure.
Scalar tau = Region1::tau(temperature);
Scalar dgamma_dpi = Region1::dgamma_dpi(temperature, pv);
Scalar ddgamma_dtaudpi = Region1::ddgamma_dtaudpi(temperature, pv);
Scalar ddgamma_ddpi = Region1::ddgamma_ddpi(temperature, pv);
Scalar pi = Region1::pi(pv);
Scalar dpi_dp = Region1::dpi_dp(pv);
Scalar du_dp =
Rs*temperature*
(tau*dpi_dp*ddgamma_dtaudpi + dpi_dp*dpi_dp*dgamma_dpi + pi*dpi_dp*ddgamma_ddpi);
*/
// use a straight line for extrapolation. use forward
// differences to calculate the partial derivative to the
// pressure at the vapor pressure
Scalar eps = 1e-7;
Scalar uv = internalEnergyRegion1_(temperature, pv);
Scalar uvPEps = internalEnergyRegion1_(temperature, pv + eps);
Scalar du_dp = (uvPEps - uv)/eps;
return uv + du_dp*(pressure - pv);
};
return internalEnergyRegion1_(temperature, pressure);
}
/*!
* \brief Specific internal energy of steam and water vapor \f$\mathrm{[J/kg]}\f$.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar gasInternalEnergy(Scalar temperature, Scalar pressure)
{
if (!Region2::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Internal Energy of steam is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
if (pressure < triplePressure() - 100) {
// We assume an ideal gas for low pressures to avoid the
// 0/0 for the internal energy of gas at very low
// pressures. The enthalpy of an ideal gas does not
// exhibit any dependence on pressure, so we can just
// return the specific enthalpy at the point of
// regularization, i.e. the triple pressure - 100Pa, and
// subtract the work required to change the volume for an
// ideal gas.
return
enthalpyRegion2_(temperature, triplePressure() - 100)
-
Rs*temperature; // = p*v for an ideal gas!
}
Scalar pv = vaporPressure(temperature);
if (pressure > pv) {
// the pressure is too high, in this case we use the slope
// of the internal energy at the vapor pressure to
// regularize
/*
// calculate the partial derivative of the internal energy
// to the pressure at the vapor pressure.
Scalar tau = Region2::tau(temperature);
Scalar dgamma_dpi = Region2::dgamma_dpi(temperature, pv);
Scalar ddgamma_dtaudpi = Region2::ddgamma_dtaudpi(temperature, pv);
Scalar ddgamma_ddpi = Region2::ddgamma_ddpi(temperature, pv);
Scalar pi = Region2::pi(pv);
Scalar dpi_dp = Region2::dpi_dp(pv);
Scalar du_dp =
Rs*temperature*
(tau*dpi_dp*ddgamma_dtaudpi + dpi_dp*dpi_dp*dgamma_dpi + pi*dpi_dp*ddgamma_ddpi);
// use a straight line for extrapolation
Scalar uv = internalEnergyRegion2_(temperature, pv);
return uv + du_dp*(pressure - pv);
*/
// use a straight line for extrapolation. use backward
// differences to calculate the partial derivative to the
// pressure at the vapor pressure
Scalar eps = 1e-7;
Scalar uv = internalEnergyRegion2_(temperature, pv);
Scalar uvMEps = internalEnergyRegion2_(temperature, pv - eps);
Scalar du_dp = (uv - uvMEps)/eps;
return uv + du_dp*(pressure - pv);
};
return internalEnergyRegion2_(temperature, pressure);
}
/*!
* \brief Specific isochoric heat capacity of liquid water \f$\mathrm{[J/m^3]}\f$.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar liquidHeatCapacityConstVolume(Scalar temperature,
Scalar pressure)
{
if (!Region1::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Heat capacity of water is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
Scalar pv = vaporPressure(temperature);
if (pressure < pv) {
// the pressure is too low, in this case we use the heat cap at the vapor pressure to regularize
return heatCap_v_Region1_(temperature, pv);
}
return heatCap_v_Region1_(temperature, pressure);
}
/*!
* \brief Specific isochoric heat capacity of steam and water vapor \f$\mathrm{[J/kg]}\f$.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar gasHeatCapacityConstVolume(Scalar temperature, Scalar pressure)
{
if (!Region2::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Heat capacity of steam is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
if (pressure < triplePressure() - 100) {
return
heatCap_v_Region2_(temperature, triplePressure() - 100);
}
Scalar pv = vaporPressure(temperature);
if (pressure > pv) {
return heatCap_v_Region2_(temperature, pv);
};
return heatCap_v_Region2_(temperature, pressure);
}
/*!
* \brief Returns true iff the gas phase is assumed to be compressible
*/
static bool gasIsCompressible()
{ return true; }
/*!
* \brief Returns true iff the liquid phase is assumed to be compressible
*/
static bool liquidIsCompressible()
{ return true; }
/*!
* \brief The density of steam in \f$\mathrm{[kg/m^3]}\f$ at a given pressure and temperature.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar gasDensity(Scalar temperature, Scalar pressure)
{
if (!Region2::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Density of steam is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
if (pressure < triplePressure() - 100) {
// We assume an ideal gas for low pressures to avoid the
// 0/0 for the internal energy and enthalpy.
Scalar rho0IAPWS = 1.0/volumeRegion2_(temperature,
triplePressure() - 100);
Scalar rho0Id = IdealGas<Scalar>::density(molarMass(),
temperature,
triplePressure() - 100);
return
rho0IAPWS/rho0Id *
IdealGas<Scalar>::density(molarMass(),
temperature,
pressure);
}
Scalar pv = vaporPressure(temperature);
if (pressure > pv) {
// the pressure is too high, in this case we use the slope
// of the density energy at the vapor pressure to
// regularize
// calculate the partial derivative of the specific volume
// to the pressure at the vapor pressure.
Scalar eps = pv*1e-8;
Scalar v0 = volumeRegion2_(temperature, pv);
Scalar v1 = volumeRegion2_(temperature, pv + eps);
Scalar dv_dp = (v1 - v0)/eps;
/*
Scalar pi = Region2::pi(pv);
Scalar dp_dpi = Region2::dp_dpi(pv);
Scalar dgamma_dpi = Region2::dgamma_dpi(temperature, pv);
Scalar ddgamma_ddpi = Region2::ddgamma_ddpi(temperature, pv);
Scalar RT = Rs*temperature;
Scalar dv_dp =
RT/(dp_dpi*pv)
*
(dgamma_dpi + pi*ddgamma_ddpi - v0*dp_dpi/RT);
*/
// calculate the partial derivative of the density to the
// pressure at vapor pressure
Scalar drho_dp = - 1/(v0*v0)*dv_dp;
// use a straight line for extrapolation
return 1.0/v0 + (pressure - pv)*drho_dp;
};
return 1.0/volumeRegion2_(temperature, pressure);
}
/*!
* \brief Returns true iff the gas phase is assumed to be ideal
*/
static bool gasIsIdeal()
{ return false; }
/*!
* \brief The pressure of steam in \f$\mathrm{[Pa]}\f$ at a given density and temperature.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param density Density in \f$\mathrm{[kg/m^3]}\f$
*/
static Scalar gasPressure(Scalar temperature, Scalar density)
{
Valgrind::CheckDefined(temperature);
Valgrind::CheckDefined(density);
// We use the newton method for this. For the initial value we
// assume steam to be an ideal gas
Scalar pressure = IdealGas<Scalar>::pressure(temperature, density/molarMass());
Scalar eps = pressure*1e-7;
Scalar deltaP = pressure*2;
Valgrind::CheckDefined(pressure);
Valgrind::CheckDefined(deltaP);
for (int i = 0; i < 5 && std::abs(pressure*1e-9) < std::abs(deltaP); ++i) {
Scalar f = gasDensity(temperature, pressure) - density;
Scalar df_dp;
df_dp = gasDensity(temperature, pressure + eps);
df_dp -= gasDensity(temperature, pressure - eps);
df_dp /= 2*eps;
deltaP = - f/df_dp;
pressure += deltaP;
Valgrind::CheckDefined(pressure);
Valgrind::CheckDefined(deltaP);
}
return pressure;
}
/*!
* \brief The density of pure water in \f$\mathrm{[kg/m^3]}\f$ at a given pressure and temperature.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar liquidDensity(Scalar temperature, Scalar pressure)
{
if (!Region1::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Density of water is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
// regularization
Scalar pv = vaporPressure(temperature);
if (pressure < pv) {
// the pressure is too low, in this case we use the slope
// of the density at the vapor pressure to regularize
// calculate the partial derivative of the specific volume
// to the pressure at the vapor pressure.
Scalar eps = pv*1e-8;
Scalar v0 = volumeRegion1_(temperature, pv);
Scalar v1 = volumeRegion1_(temperature, pv + eps);
Scalar dv_dp = (v1 - v0)/eps;
/*
Scalar v0 = volumeRegion1_(temperature, pv);
Scalar pi = Region1::pi(pv);
Scalar dp_dpi = Region1::dp_dpi(pv);
Scalar dgamma_dpi = Region1::dgamma_dpi(temperature, pv);
Scalar ddgamma_ddpi = Region1::ddgamma_ddpi(temperature, pv);
Scalar RT = Rs*temperature;
Scalar dv_dp =
RT/(dp_dpi*pv)
*
(dgamma_dpi + pi*ddgamma_ddpi - v0*dp_dpi/RT);
*/
// calculate the partial derivative of the density to the
// pressure at vapor pressure
Scalar drho_dp = - 1/(v0*v0)*dv_dp;
// use a straight line for extrapolation
return 1.0/v0 + (pressure - pv)*drho_dp;
};
return 1/volumeRegion1_(temperature, pressure);
}
/*!
* \brief The pressure of liquid water in \f$\mathrm{[Pa]}\f$ at a given density and
* temperature.
*
* See:
*
* IAPWS: "Revised Release on the IAPWS Industrial Formulation
* 1997 for the Thermodynamic Properties of Water and Steam",
* http://www.iapws.org/relguide/IF97-Rev.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param density Density of the fluid in \f$\mathrm{[kg/m^3]}\f$
*/
static Scalar liquidPressure(Scalar temperature, Scalar density)
{
// We use the newton method for this. For the initial value we
// assume the pressure to be 10% higher than the vapor
// pressure
Scalar pressure = 1.1*vaporPressure(temperature);
Scalar eps = pressure*1e-7;
Scalar deltaP = pressure*2;
for (int i = 0; i < 5 && std::abs(pressure*1e-9) < std::abs(deltaP); ++i) {
Scalar f = liquidDensity(temperature, pressure) - density;
Scalar df_dp;
df_dp = liquidDensity(temperature, pressure + eps);
df_dp -= liquidDensity(temperature, pressure - eps);
df_dp /= 2*eps;
deltaP = - f/df_dp;
pressure += deltaP;
}
return pressure;
}
/*!
* \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of steam.
*
* This method is only valid if pressure is below or at the vapor
* pressure of water.
*
* See:
*
* IAPWS: "Release on the IAPWS Formulation 2008 for the Viscosity
* of Ordinary Water Substance", http://www.iapws.org/relguide/visc.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar gasViscosity(Scalar temperature, Scalar pressure)
{
if (!Region2::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Viscosity of steam is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
}
Scalar rho = gasDensity(temperature, pressure);
return Common::viscosity(temperature, rho);
}
/*!
* \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of pure water.
*
* See:
*
* IAPWS: "Release on the IAPWS Formulation 2008 for the Viscosity
* of Ordinary Water Substance", http://www.iapws.org/relguide/visc.pdf
*
* \param temperature Absolute temperature of the fluid in \f$\mathrm{[K]}\f$
* \param pressure Phase pressure in \f$\mathrm{[Pa]}\f$
*/
static Scalar liquidViscosity(Scalar temperature, Scalar pressure)
{
if (!Region1::isValid(temperature, pressure))
{
OPM_THROW(NumericalProblem,
"Viscosity of water is only implemented for temperatures below 623.15K and "
"pressures below 100MPa. (T = " << temperature << ", p=" << pressure);
};
Scalar rho = liquidDensity(temperature, pressure);
return Common::viscosity(temperature, rho);
}
/*!
* \brief Thermal conductivity \f$\mathrm{[[W/(m K)]}\f$ of water (IAPWS) .
*
* Implementation taken from:
* freesteam - IAPWS-IF97 steam tables library
* Copyright (C) 2004-2009 John Pye
*
* Appendix B: Recommended Interpolating equation for Industrial Use
* see http://www.iapws.org/relguide/thcond.pdf
*
* \param temperature Absolute temperature in K
* \param pressure Phase pressure of the phase in Pa
*/
static Scalar liquidThermalConductivity(Scalar temperature, Scalar pressure)
{
Scalar rho = liquidDensity(temperature, pressure);
return Common::thermalConductivityIAPWS(temperature, rho);
}
/*!
* \brief Thermal conductivity \f$\mathrm{[[W/(m K)]}\f$ of water (IAPWS) .
*
* Implementation taken from:
* freesteam - IAPWS-IF97 steam tables library
* Copyright (C) 2004-2009 John Pye
*
* Appendix B: Recommended Interpolating equation for Industrial Use
* see http://www.iapws.org/relguide/thcond.pdf
*
* \param temperature Absolute temperature in K
* \param pressure Phase pressure of the phase in Pa
*/
static Scalar gasThermalConductivity(Scalar temperature, Scalar pressure)
{
Scalar rho = gasDensity(temperature, pressure);
return Common::thermalConductivityIAPWS(temperature, rho);
}
private:
// the unregularized specific enthalpy for liquid water
static Scalar enthalpyRegion1_(Scalar temperature, Scalar pressure)
{
return
Region1::tau(temperature) *
Region1::dgamma_dtau(temperature, pressure) *
Rs*temperature;
}
// the unregularized specific isobaric heat capacity
static Scalar heatCap_p_Region1_(Scalar temperature, Scalar pressure)
{
return
- std::pow(Region1::tau(temperature), 2 ) *
Region1::ddgamma_ddtau(temperature, pressure) *
Rs;
}
// the unregularized specific isochoric heat capacity
static Scalar heatCap_v_Region1_(Scalar temperature, Scalar pressure)
{
double tau = Region1::tau(temperature);
double num = Region1::dgamma_dpi(temperature, pressure) - tau * Region1::ddgamma_dtaudpi(temperature, pressure);
double diff = std::pow(num, 2) / Region1::ddgamma_ddpi(temperature, pressure);
return
- std::pow(tau, 2 ) *
Region1::ddgamma_ddtau(temperature, pressure) * Rs +
diff;
}
// the unregularized specific internal energy for liquid water
static Scalar internalEnergyRegion1_(Scalar temperature, Scalar pressure)
{
return
Rs * temperature *
( Region1::tau(temperature)*Region1::dgamma_dtau(temperature, pressure) -
Region1::pi(pressure)*Region1::dgamma_dpi(temperature, pressure));
}
// the unregularized specific volume for liquid water
static Scalar volumeRegion1_(Scalar temperature, Scalar pressure)
{
return
Region1::pi(pressure)*
Region1::dgamma_dpi(temperature, pressure) *
Rs * temperature / pressure;
}
// the unregularized specific enthalpy for steam
static Scalar enthalpyRegion2_(Scalar temperature, Scalar pressure)
{
return
Region2::tau(temperature) *
Region2::dgamma_dtau(temperature, pressure) *
Rs*temperature;
}
// the unregularized specific internal energy for steam
static Scalar internalEnergyRegion2_(Scalar temperature, Scalar pressure)
{
return
Rs * temperature *
( Region2::tau(temperature)*Region2::dgamma_dtau(temperature, pressure) -
Region2::pi(pressure)*Region2::dgamma_dpi(temperature, pressure));
}
// the unregularized specific isobaric heat capacity
static Scalar heatCap_p_Region2_(Scalar temperature, Scalar pressure)
{
return
- std::pow(Region2::tau(temperature), 2 ) *
Region2::ddgamma_ddtau(temperature, pressure) *
Rs;
}
// the unregularized specific isochoric heat capacity
static Scalar heatCap_v_Region2_(Scalar temperature, Scalar pressure)
{
double tau = Region2::tau(temperature);
double pi = Region2::pi(pressure);
double num = 1 + pi * Region2::dgamma_dpi(temperature, pressure) + tau * pi * Region2::ddgamma_dtaudpi(temperature, pressure);
double diff = num * num / (1 - pi * pi * Region2::ddgamma_ddpi(temperature, pressure));
return
- std::pow(tau, 2 ) *
Region2::ddgamma_ddtau(temperature, pressure) * Rs
- diff;
}
// the unregularized specific volume for steam
static Scalar volumeRegion2_(Scalar temperature, Scalar pressure)
{
return
Region2::pi(pressure)*
Region2::dgamma_dpi(temperature, pressure) *
Rs * temperature / pressure;
}
}; // end class
template <class Scalar>
const Scalar H2O<Scalar>::Rs = Common::Rs;
} // namespace Opm
#endif