Files
opm-common/opm/material/components/TabulatedComponent.hpp
Andreas Lauser d55f213653 make it possible to nest function evaluation objects
IMO this is pretty cool because it allows to transparantly calculate
higher order derivatives. for example this enables to implement the
linearization stage of higher-order non-linear solvers without much
additional effort compared to just evaluating the function in
question. (essentially, such higher order non-linear solvers are based
on truncating the Taylor series not after the first term -- like for the
Newton scheme -- but later. That said, they require to solve linear
systems of equations which involve tensors of orders greater than 2,
so they are not really practical as far as I can see.)

A more practical motivation for this is to allow the constraint
solvers to be used in "nested mode", i.e., linearizing the system of
equations they need to solve using automatic differentiation, but
allowing the value objects which are passed to the constraint solvers
be function evaluations themselves. (E.g. the result of a flash
calculation can also include the derivatives with regard to the
primary variables of the flow model. Note that the individual
constraint solvers need to some patches to make this work.)
2016-04-17 11:42:33 +02:00

913 lines
37 KiB
C++

// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
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/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
*
* \copydoc Opm::TabulatedComponent
*/
#ifndef OPM_TABULATED_COMPONENT_HPP
#define OPM_TABULATED_COMPONENT_HPP
#include <cmath>
#include <limits>
#include <cassert>
#include <iostream>
#include <opm/common/Exceptions.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <opm/material/common/MathToolbox.hpp>
namespace Opm {
/*!
* \ingroup Components
*
* \brief A generic class which tabulates all thermodynamic properties
* of a given component.
*
* At the moment, this class can only handle the sub-critical fluids
* since it tabulates along the vapor pressure curve.
*
* \tparam Scalar The type used for scalar values
* \tparam RawComponent The component which ought to be tabulated
* \tparam useVaporPressure If true, tabulate all quantities along the
* vapor pressure curve, if false use the
* pressure range [p_min, p_max]
*/
template <class ScalarT, class RawComponent, bool useVaporPressure=true>
class TabulatedComponent
{
public:
typedef ScalarT Scalar;
static const bool isTabulated = true;
/*!
* \brief Initialize the tables.
*
* \param tempMin The minimum of the temperature range in \f$\mathrm{[K]}\f$
* \param tempMax The maximum of the temperature range in \f$\mathrm{[K]}\f$
* \param nTemp The number of entries/steps within the temperature range
* \param pressMin The minimum of the pressure range in \f$\mathrm{[Pa]}\f$
* \param pressMax The maximum of the pressure range in \f$\mathrm{[Pa]}\f$
* \param nPress The number of entries/steps within the pressure range
*/
static void init(Scalar tempMin, Scalar tempMax, unsigned nTemp,
Scalar pressMin, Scalar pressMax, unsigned nPress)
{
tempMin_ = tempMin;
tempMax_ = tempMax;
nTemp_ = nTemp;
pressMin_ = pressMin;
pressMax_ = pressMax;
nPress_ = nPress;
nDensity_ = nPress_;
// allocate the arrays
vaporPressure_ = new Scalar[nTemp_];
minGasDensity__ = new Scalar[nTemp_];
maxGasDensity__ = new Scalar[nTemp_];
minLiquidDensity__ = new Scalar[nTemp_];
maxLiquidDensity__ = new Scalar[nTemp_];
gasEnthalpy_ = new Scalar[nTemp_*nPress_];
liquidEnthalpy_ = new Scalar[nTemp_*nPress_];
gasHeatCapacity_ = new Scalar[nTemp_*nPress_];
liquidHeatCapacity_ = new Scalar[nTemp_*nPress_];
gasDensity_ = new Scalar[nTemp_*nPress_];
liquidDensity_ = new Scalar[nTemp_*nPress_];
gasViscosity_ = new Scalar[nTemp_*nPress_];
liquidViscosity_ = new Scalar[nTemp_*nPress_];
gasThermalConductivity_ = new Scalar[nTemp_*nPress_];
liquidThermalConductivity_ = new Scalar[nTemp_*nPress_];
gasPressure_ = new Scalar[nTemp_*nDensity_];
liquidPressure_ = new Scalar[nTemp_*nDensity_];
assert(std::numeric_limits<Scalar>::has_quiet_NaN);
Scalar NaN = std::numeric_limits<Scalar>::quiet_NaN();
// fill the temperature-pressure arrays
for (unsigned iT = 0; iT < nTemp_; ++ iT) {
Scalar temperature = iT * (tempMax_ - tempMin_)/(nTemp_ - 1) + tempMin_;
try { vaporPressure_[iT] = RawComponent::vaporPressure(temperature); }
catch (std::exception) { vaporPressure_[iT] = NaN; }
Scalar pgMax = maxGasPressure_(iT);
Scalar pgMin = minGasPressure_(iT);
// fill the temperature, pressure gas arrays
for (unsigned iP = 0; iP < nPress_; ++ iP) {
Scalar pressure = iP * (pgMax - pgMin)/(nPress_ - 1) + pgMin;
unsigned i = iT + iP*nTemp_;
try { gasEnthalpy_[i] = RawComponent::gasEnthalpy(temperature, pressure); }
catch (std::exception) { gasEnthalpy_[i] = NaN; }
try { gasHeatCapacity_[i] = RawComponent::gasHeatCapacity(temperature, pressure); }
catch (std::exception) { gasHeatCapacity_[i] = NaN; }
try { gasDensity_[i] = RawComponent::gasDensity(temperature, pressure); }
catch (std::exception) { gasDensity_[i] = NaN; }
try { gasViscosity_[i] = RawComponent::gasViscosity(temperature, pressure); }
catch (std::exception) { gasViscosity_[i] = NaN; }
try { gasThermalConductivity_[i] = RawComponent::gasThermalConductivity(temperature, pressure); }
catch (std::exception) { gasThermalConductivity_[i] = NaN; }
};
Scalar plMin = minLiquidPressure_(iT);
Scalar plMax = maxLiquidPressure_(iT);
for (unsigned iP = 0; iP < nPress_; ++ iP) {
Scalar pressure = iP * (plMax - plMin)/(nPress_ - 1) + plMin;
unsigned i = iT + iP*nTemp_;
try { liquidEnthalpy_[i] = RawComponent::liquidEnthalpy(temperature, pressure); }
catch (std::exception) { liquidEnthalpy_[i] = NaN; }
try { liquidHeatCapacity_[i] = RawComponent::liquidHeatCapacity(temperature, pressure); }
catch (std::exception) { liquidHeatCapacity_[i] = NaN; }
try { liquidDensity_[i] = RawComponent::liquidDensity(temperature, pressure); }
catch (std::exception) { liquidDensity_[i] = NaN; }
try { liquidViscosity_[i] = RawComponent::liquidViscosity(temperature, pressure); }
catch (std::exception) { liquidViscosity_[i] = NaN; }
try { liquidThermalConductivity_[i] = RawComponent::liquidThermalConductivity(temperature, pressure); }
catch (std::exception) { liquidThermalConductivity_[i] = NaN; }
}
}
// fill the temperature-density arrays
for (unsigned iT = 0; iT < nTemp_; ++ iT) {
Scalar temperature = iT * (tempMax_ - tempMin_)/(nTemp_ - 1) + tempMin_;
// calculate the minimum and maximum values for the gas
// densities
minGasDensity__[iT] = RawComponent::gasDensity(temperature, minGasPressure_(iT));
if (iT < nTemp_ - 1)
maxGasDensity__[iT] = RawComponent::gasDensity(temperature, maxGasPressure_(iT + 1));
else
maxGasDensity__[iT] = RawComponent::gasDensity(temperature, maxGasPressure_(iT));
// fill the temperature, density gas arrays
for (unsigned iRho = 0; iRho < nDensity_; ++ iRho) {
Scalar density =
Scalar(iRho)/(nDensity_ - 1) *
(maxGasDensity__[iT] - minGasDensity__[iT])
+
minGasDensity__[iT];
unsigned i = iT + iRho*nTemp_;
try { gasPressure_[i] = RawComponent::gasPressure(temperature, density); }
catch (std::exception) { gasPressure_[i] = NaN; };
};
// calculate the minimum and maximum values for the liquid
// densities
minLiquidDensity__[iT] = RawComponent::liquidDensity(temperature, minLiquidPressure_(iT));
if (iT < nTemp_ - 1)
maxLiquidDensity__[iT] = RawComponent::liquidDensity(temperature, maxLiquidPressure_(iT + 1));
else
maxLiquidDensity__[iT] = RawComponent::liquidDensity(temperature, maxLiquidPressure_(iT));
// fill the temperature, density liquid arrays
for (unsigned iRho = 0; iRho < nDensity_; ++ iRho) {
Scalar density =
Scalar(iRho)/(nDensity_ - 1) *
(maxLiquidDensity__[iT] - minLiquidDensity__[iT])
+
minLiquidDensity__[iT];
unsigned i = iT + iRho*nTemp_;
try { liquidPressure_[i] = RawComponent::liquidPressure(temperature, density); }
catch (std::exception) { liquidPressure_[i] = NaN; };
};
}
}
/*!
* \brief A human readable name for the component.
*/
static const char *name()
{ return RawComponent::name(); }
/*!
* \brief The molar mass in \f$\mathrm{[kg/mol]}\f$ of the component.
*/
static Scalar molarMass()
{ return RawComponent::molarMass(); }
/*!
* \brief Returns the critical temperature in \f$\mathrm{[K]}\f$ of the component.
*/
static Scalar criticalTemperature()
{ return RawComponent::criticalTemperature(); }
/*!
* \brief Returns the critical pressure in \f$\mathrm{[Pa]}\f$ of the component.
*/
static Scalar criticalPressure()
{ return RawComponent::criticalPressure(); }
/*!
* \brief Returns the temperature in \f$\mathrm{[K]}\f$ at the component's triple point.
*/
static Scalar tripleTemperature()
{ return RawComponent::tripleTemperature(); }
/*!
* \brief Returns the pressure in \f$\mathrm{[Pa]}\f$ at the component's triple point.
*/
static Scalar triplePressure()
{ return RawComponent::triplePressure(); }
/*!
* \brief The vapor pressure in \f$\mathrm{[Pa]}\f$ of the component at a given
* temperature.
*
* \param T temperature of component
*/
template <class Evaluation>
static Evaluation vaporPressure(const Evaluation& temperature)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateT_(vaporPressure_, temperature);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::vaporPressure(temperature);
return result;
}
/*!
* \brief Specific enthalpy of the gas \f$\mathrm{[J/kg]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation gasEnthalpy(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateGasTP_(gasEnthalpy_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::gasEnthalpy(temperature, pressure);
return result;
}
/*!
* \brief Specific enthalpy of the liquid \f$\mathrm{[J/kg]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation liquidEnthalpy(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateLiquidTP_(liquidEnthalpy_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::liquidEnthalpy(temperature, pressure);
return result;
}
/*!
* \brief Specific isobaric heat capacity of the gas \f$\mathrm{[J/(kg K)]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation gasHeatCapacity(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateGasTP_(gasHeatCapacity_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::gasHeatCapacity(temperature, pressure);
return result;
}
/*!
* \brief Specific isobaric heat capacity of the liquid \f$\mathrm{[J/(kg K)]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation liquidHeatCapacity(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateLiquidTP_(liquidHeatCapacity_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::liquidHeatCapacity(temperature, pressure);
return result;
}
/*!
* \brief Specific internal energy of the gas \f$\mathrm{[J/kg]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation gasInternalEnergy(const Evaluation& temperature, const Evaluation& pressure)
{ return gasEnthalpy(temperature, pressure) - pressure/gasDensity(temperature, pressure); }
/*!
* \brief Specific internal energy of the liquid \f$\mathrm{[J/kg]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation liquidInternalEnergy(const Evaluation& temperature, const Evaluation& pressure)
{ return liquidEnthalpy(temperature, pressure) - pressure/liquidDensity(temperature, pressure); }
/*!
* \brief The pressure of gas in \f$\mathrm{[Pa]}\f$ at a given density and temperature.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param density density of component in \f$\mathrm{[kg/m^3]}\f$
*/
template <class Evaluation>
static Evaluation gasPressure(const Evaluation& temperature, Scalar density)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateGasTRho_(gasPressure_,
temperature,
density);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::gasPressure(temperature,
density);
return result;
}
/*!
* \brief The pressure of liquid in \f$\mathrm{[Pa]}\f$ at a given density and temperature.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param density density of component in \f$\mathrm{[kg/m^3]}\f$
*/
template <class Evaluation>
static Evaluation liquidPressure(const Evaluation& temperature, Scalar density)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateLiquidTRho_(liquidPressure_,
temperature,
density);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::liquidPressure(temperature,
density);
return result;
}
/*!
* \brief Returns true iff the gas phase is assumed to be compressible
*/
static bool gasIsCompressible()
{ return RawComponent::gasIsCompressible(); }
/*!
* \brief Returns true iff the liquid phase is assumed to be compressible
*/
static bool liquidIsCompressible()
{ return RawComponent::liquidIsCompressible(); }
/*!
* \brief Returns true iff the gas phase is assumed to be ideal
*/
static bool gasIsIdeal()
{ return RawComponent::gasIsIdeal(); }
/*!
* \brief The density of gas at a given pressure and temperature
* \f$\mathrm{[kg/m^3]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation gasDensity(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateGasTP_(gasDensity_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::gasDensity(temperature, pressure);
return result;
}
/*!
* \brief The density of liquid at a given pressure and
* temperature \f$\mathrm{[kg/m^3]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation liquidDensity(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateLiquidTP_(liquidDensity_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::liquidDensity(temperature, pressure);
return result;
}
/*!
* \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of gas.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation gasViscosity(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateGasTP_(gasViscosity_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::gasViscosity(temperature, pressure);
return result;
}
/*!
* \brief The dynamic viscosity \f$\mathrm{[Pa*s]}\f$ of liquid.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation liquidViscosity(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateLiquidTP_(liquidViscosity_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::liquidViscosity(temperature, pressure);
return result;
}
/*!
* \brief The thermal conductivity of gaseous water \f$\mathrm{[W / (m K)]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation gasThermalConductivity(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateGasTP_(gasThermalConductivity_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::gasThermalConductivity(temperature, pressure);
return result;
}
/*!
* \brief The thermal conductivity of liquid water \f$\mathrm{[W / (m K)]}\f$.
*
* \param temperature temperature of component in \f$\mathrm{[K]}\f$
* \param pressure pressure of component in \f$\mathrm{[Pa]}\f$
*/
template <class Evaluation>
static Evaluation liquidThermalConductivity(const Evaluation& temperature, const Evaluation& pressure)
{
typedef MathToolbox<Evaluation> Toolbox;
const Evaluation& result = interpolateLiquidTP_(liquidThermalConductivity_,
temperature,
pressure);
if (std::isnan(Toolbox::scalarValue(result)))
return RawComponent::liquidThermalConductivity(temperature, pressure);
return result;
}
private:
// returns an interpolated value depending on temperature
template <class Evaluation>
static Evaluation interpolateT_(const Scalar *values, const Evaluation& T)
{
typedef Opm::MathToolbox<Evaluation> Toolbox;
Evaluation alphaT = tempIdx_(T);
if (alphaT < 0 || alphaT >= nTemp_ - 1)
return std::numeric_limits<Scalar>::quiet_NaN();
unsigned iT = (unsigned) Toolbox::scalarValue(alphaT);
alphaT -= iT;
return
values[iT ]*(1 - alphaT) +
values[iT + 1]*( alphaT);
}
// returns an interpolated value for liquid depending on
// temperature and pressure
template <class Evaluation>
static Evaluation interpolateLiquidTP_(const Scalar *values, const Evaluation& T, const Evaluation& p)
{
typedef MathToolbox<Evaluation> Toolbox;
Evaluation alphaT = tempIdx_(T);
if (alphaT < 0 || alphaT >= nTemp_ - 1) {
return Toolbox::createConstant(std::numeric_limits<Scalar>::quiet_NaN());
}
int iT =
std::max<int>(0,
std::min<int>(nTemp_ - 2,
static_cast<int>(Toolbox::scalarValue(alphaT))));
alphaT -= iT;
Evaluation alphaP1 = pressLiquidIdx_(p, iT);
Evaluation alphaP2 = pressLiquidIdx_(p, iT + 1);
int iP1 =
std::max<int>(0,
std::min<int>(nPress_ - 2,
static_cast<int>(Toolbox::scalarValue(alphaP1))));
int iP2 =
std::max<int>(0,
std::min<int>(nPress_ - 2,
static_cast<int>(Toolbox::scalarValue(alphaP2))));
alphaP1 -= iP1;
alphaP2 -= iP2;
#if 0 && !defined NDEBUG
if(!(0 <= alphaT && alphaT <= 1.0))
OPM_THROW(NumericalProblem, "Temperature out of range: "
<< "T=" << T << " range: [" << tempMin_ << ", " << tempMax_ << "]");
if(!(0 <= alphaP1 && alphaP1 <= 1.0))
OPM_THROW(NumericalProblem, "First liquid pressure out of range: "
<< "p=" << p << " range: [" << minLiquidPressure_(tempIdx_(T)) << ", " << maxLiquidPressure_(tempIdx_(T)) << "]");
if(!(0 <= alphaP2 && alphaP2 <= 1.0))
OPM_THROW(NumericalProblem, "Second liquid pressure out of range: "
<< "p=" << p << " range: [" << minLiquidPressure_(tempIdx_(T) + 1) << ", " << maxLiquidPressure_(tempIdx_(T) + 1) << "]");
#endif
return
values[(iT ) + (iP1 )*nTemp_]*(1 - alphaT)*(1 - alphaP1) +
values[(iT ) + (iP1 + 1)*nTemp_]*(1 - alphaT)*( alphaP1) +
values[(iT + 1) + (iP2 )*nTemp_]*( alphaT)*(1 - alphaP2) +
values[(iT + 1) + (iP2 + 1)*nTemp_]*( alphaT)*( alphaP2);
}
// returns an interpolated value for gas depending on
// temperature and pressure
template <class Evaluation>
static Evaluation interpolateGasTP_(const Scalar *values, const Evaluation& T, const Evaluation& p)
{
typedef MathToolbox<Evaluation> Toolbox;
Evaluation alphaT = tempIdx_(T);
if (alphaT < 0 || alphaT >= nTemp_ - 1) {
return Toolbox::createConstant(std::numeric_limits<Scalar>::quiet_NaN());
}
int iT =
std::max<int>(0,
std::min<int>(nTemp_ - 2,
static_cast<int>(Toolbox::scalarValue(alphaT))));
alphaT -= iT;
Evaluation alphaP1 = pressGasIdx_(p, iT);
Evaluation alphaP2 = pressGasIdx_(p, iT + 1);
int iP1 =
std::max<int>(0, std::min<int>(nPress_ - 2,
static_cast<int>(Toolbox::scalarValue(alphaP1))));
int iP2 =
std::max<int>(0,
std::min<int>(nPress_ - 2,
static_cast<int>(Toolbox::scalarValue(alphaP2))));
alphaP1 -= iP1;
alphaP2 -= iP2;
#if 0 && !defined NDEBUG
if(!(0 <= alphaT && alphaT <= 1.0))
OPM_THROW(NumericalProblem, "Temperature out of range: "
<< "T=" << T << " range: [" << tempMin_ << ", " << tempMax_ << "]");
if(!(0 <= alphaP1 && alphaP1 <= 1.0))
OPM_THROW(NumericalProblem, "First gas pressure out of range: "
<< "p=" << p << " range: [" << minGasPressure_(tempIdx_(T)) << ", " << maxGasPressure_(tempIdx_(T)) << "]");
if(!(0 <= alphaP2 && alphaP2 <= 1.0))
OPM_THROW(NumericalProblem, "Second gas pressure out of range: "
<< "p=" << p << " range: [" << minGasPressure_(tempIdx_(T) + 1) << ", " << maxGasPressure_(tempIdx_(T) + 1) << "]");
#endif
return
values[(iT ) + (iP1 )*nTemp_]*(1 - alphaT)*(1 - alphaP1) +
values[(iT ) + (iP1 + 1)*nTemp_]*(1 - alphaT)*( alphaP1) +
values[(iT + 1) + (iP2 )*nTemp_]*( alphaT)*(1 - alphaP2) +
values[(iT + 1) + (iP2 + 1)*nTemp_]*( alphaT)*( alphaP2);
}
// returns an interpolated value for gas depending on
// temperature and density
template <class Evaluation>
static Evaluation interpolateGasTRho_(const Scalar *values, const Evaluation& T, const Evaluation& rho)
{
Evaluation alphaT = tempIdx_(T);
int iT = std::max<int>(0, std::min<int>(nTemp_ - 2, (int) alphaT));
alphaT -= iT;
Evaluation alphaP1 = densityGasIdx_(rho, iT);
Evaluation alphaP2 = densityGasIdx_(rho, iT + 1);
unsigned iP1 = std::max<int>(0, std::min<int>(nDensity_ - 2, (int) alphaP1));
unsigned iP2 = std::max<int>(0, std::min<int>(nDensity_ - 2, (int) alphaP2));
alphaP1 -= iP1;
alphaP2 -= iP2;
return
values[(iT ) + (iP1 )*nTemp_]*(1 - alphaT)*(1 - alphaP1) +
values[(iT ) + (iP1 + 1)*nTemp_]*(1 - alphaT)*( alphaP1) +
values[(iT + 1) + (iP2 )*nTemp_]*( alphaT)*(1 - alphaP2) +
values[(iT + 1) + (iP2 + 1)*nTemp_]*( alphaT)*( alphaP2);
}
// returns an interpolated value for liquid depending on
// temperature and density
template <class Evaluation>
static Evaluation interpolateLiquidTRho_(const Scalar *values, const Evaluation& T, const Evaluation& rho)
{
Evaluation alphaT = tempIdx_(T);
int iT = std::max<int>(0, std::min<int>(nTemp_ - 2, (int) alphaT));
alphaT -= iT;
Evaluation alphaP1 = densityLiquidIdx_(rho, iT);
Evaluation alphaP2 = densityLiquidIdx_(rho, iT + 1);
unsigned iP1 = std::max<int>(0, std::min<int>(nDensity_ - 2, (int) alphaP1));
unsigned iP2 = std::max<int>(0, std::min<int>(nDensity_ - 2, (int) alphaP2));
alphaP1 -= iP1;
alphaP2 -= iP2;
return
values[(iT ) + (iP1 )*nTemp_]*(1 - alphaT)*(1 - alphaP1) +
values[(iT ) + (iP1 + 1)*nTemp_]*(1 - alphaT)*( alphaP1) +
values[(iT + 1) + (iP2 )*nTemp_]*( alphaT)*(1 - alphaP2) +
values[(iT + 1) + (iP2 + 1)*nTemp_]*( alphaT)*( alphaP2);
}
// returns the index of an entry in a temperature field
template <class Evaluation>
static Evaluation tempIdx_(const Evaluation& temperature)
{
return (nTemp_ - 1)*(temperature - tempMin_)/(tempMax_ - tempMin_);
}
// returns the index of an entry in a pressure field
template <class Evaluation>
static Evaluation pressLiquidIdx_(const Evaluation& pressure, size_t tempIdx)
{
Scalar plMin = minLiquidPressure_(tempIdx);
Scalar plMax = maxLiquidPressure_(tempIdx);
return (nPress_ - 1)*(pressure - plMin)/(plMax - plMin);
}
// returns the index of an entry in a temperature field
template <class Evaluation>
static Evaluation pressGasIdx_(const Evaluation& pressure, size_t tempIdx)
{
Scalar pgMin = minGasPressure_(tempIdx);
Scalar pgMax = maxGasPressure_(tempIdx);
return (nPress_ - 1)*(pressure - pgMin)/(pgMax - pgMin);
}
// returns the index of an entry in a density field
template <class Evaluation>
static Evaluation densityLiquidIdx_(const Evaluation& density, size_t tempIdx)
{
Scalar densityMin = minLiquidDensity_(tempIdx);
Scalar densityMax = maxLiquidDensity_(tempIdx);
return (nDensity_ - 1) * (density - densityMin)/(densityMax - densityMin);
}
// returns the index of an entry in a density field
template <class Evaluation>
static Evaluation densityGasIdx_(const Evaluation& density, size_t tempIdx)
{
Scalar densityMin = minGasDensity_(tempIdx);
Scalar densityMax = maxGasDensity_(tempIdx);
return (nDensity_ - 1) * (density - densityMin)/(densityMax - densityMin);
}
// returns the minimum tabulized liquid pressure at a given
// temperature index
static Scalar minLiquidPressure_(size_t tempIdx)
{
if (!useVaporPressure)
return pressMin_;
else
return std::max<Scalar>(pressMin_, vaporPressure_[tempIdx] / 1.1);
}
// returns the maximum tabulized liquid pressure at a given
// temperature index
static Scalar maxLiquidPressure_(size_t tempIdx)
{
if (!useVaporPressure)
return pressMax_;
else
return std::max<Scalar>(pressMax_, vaporPressure_[tempIdx] * 1.1);
}
// returns the minumum tabulized gas pressure at a given
// temperature index
static Scalar minGasPressure_(size_t tempIdx)
{
if (!useVaporPressure)
return pressMin_;
else
return std::min<Scalar>(pressMin_, vaporPressure_[tempIdx] / 1.1 );
}
// returns the maximum tabulized gas pressure at a given
// temperature index
static Scalar maxGasPressure_(size_t tempIdx)
{
if (!useVaporPressure)
return pressMax_;
else
return std::min<Scalar>(pressMax_, vaporPressure_[tempIdx] * 1.1);
}
// returns the minimum tabulized liquid density at a given
// temperature index
static Scalar minLiquidDensity_(size_t tempIdx)
{ return minLiquidDensity__[tempIdx]; }
// returns the maximum tabulized liquid density at a given
// temperature index
static Scalar maxLiquidDensity_(size_t tempIdx)
{ return maxLiquidDensity__[tempIdx]; }
// returns the minumum tabulized gas density at a given
// temperature index
static Scalar minGasDensity_(size_t tempIdx)
{ return minGasDensity__[tempIdx]; }
// returns the maximum tabulized gas density at a given
// temperature index
static Scalar maxGasDensity_(size_t tempIdx)
{ return maxGasDensity__[tempIdx]; }
// 1D fields with the temperature as degree of freedom
static Scalar *vaporPressure_;
static Scalar *minLiquidDensity__;
static Scalar *maxLiquidDensity__;
static Scalar *minGasDensity__;
static Scalar *maxGasDensity__;
// 2D fields with the temperature and pressure as degrees of
// freedom
static Scalar *gasEnthalpy_;
static Scalar *liquidEnthalpy_;
static Scalar *gasHeatCapacity_;
static Scalar *liquidHeatCapacity_;
static Scalar *gasDensity_;
static Scalar *liquidDensity_;
static Scalar *gasViscosity_;
static Scalar *liquidViscosity_;
static Scalar *gasThermalConductivity_;
static Scalar *liquidThermalConductivity_;
// 2D fields with the temperature and density as degrees of
// freedom
static Scalar *gasPressure_;
static Scalar *liquidPressure_;
// temperature, pressure and density ranges
static Scalar tempMin_;
static Scalar tempMax_;
static unsigned nTemp_;
static Scalar pressMin_;
static Scalar pressMax_;
static unsigned nPress_;
static Scalar densityMin_;
static Scalar densityMax_;
static unsigned nDensity_;
};
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::vaporPressure_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::minLiquidDensity__;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::maxLiquidDensity__;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::minGasDensity__;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::maxGasDensity__;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::gasEnthalpy_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::liquidEnthalpy_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::gasHeatCapacity_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::liquidHeatCapacity_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::gasDensity_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::liquidDensity_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::gasViscosity_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::liquidViscosity_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::gasThermalConductivity_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::liquidThermalConductivity_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::gasPressure_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar* TabulatedComponent<Scalar, RawComponent, useVaporPressure>::liquidPressure_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar TabulatedComponent<Scalar, RawComponent, useVaporPressure>::tempMin_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar TabulatedComponent<Scalar, RawComponent, useVaporPressure>::tempMax_;
template <class Scalar, class RawComponent, bool useVaporPressure>
unsigned TabulatedComponent<Scalar, RawComponent, useVaporPressure>::nTemp_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar TabulatedComponent<Scalar, RawComponent, useVaporPressure>::pressMin_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar TabulatedComponent<Scalar, RawComponent, useVaporPressure>::pressMax_;
template <class Scalar, class RawComponent, bool useVaporPressure>
unsigned TabulatedComponent<Scalar, RawComponent, useVaporPressure>::nPress_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar TabulatedComponent<Scalar, RawComponent, useVaporPressure>::densityMin_;
template <class Scalar, class RawComponent, bool useVaporPressure>
Scalar TabulatedComponent<Scalar, RawComponent, useVaporPressure>::densityMax_;
template <class Scalar, class RawComponent, bool useVaporPressure>
unsigned TabulatedComponent<Scalar, RawComponent, useVaporPressure>::nDensity_;
} // namespace Opm
#endif