mirror of
https://github.com/CoolProp/CoolProp.git
synced 2026-01-22 12:28:04 -05:00
1240 lines
54 KiB
C++
1240 lines
54 KiB
C++
|
|
#ifndef HELMHOLTZ_H
|
|
#define HELMHOLTZ_H
|
|
|
|
#include <vector>
|
|
#include "rapidjson/rapidjson_include.h"
|
|
|
|
namespace CoolProp{
|
|
|
|
/// The base class class for the Helmholtz energy terms
|
|
/**
|
|
|
|
Residual Helmholtz Energy Terms:
|
|
|
|
Term | Helmholtz Energy Contribution
|
|
---------- | ------------------------------
|
|
ResidualHelmholtzPower | \f$ \alpha^r=\left\lbrace\begin{array}{cc}\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} & l_i=0\\ \displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-\delta^{l_i}) & l_i\neq 0\end{array}\right.\f$
|
|
ResidualHelmholtzExponential | \f$ \alpha^r=\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-\gamma_i\delta^{l_i}) \f$
|
|
ResidualHelmholtzLemmon2005 | \f$ \alpha^r=\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-\delta^{l_i}-\tau^{m_i})\f$
|
|
ResidualHelmholtzGaussian | \f$ \alpha^r=\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-\eta_i(\delta-\epsilon_i)^2-\beta_i(\tau-\gamma_i)^2)\f$
|
|
ResidualHelmholtzGERG2008Gaussian | \f$ \alpha^r=\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-\eta_i(\delta-\epsilon_i)^2-\beta_i(\delta-\gamma_i))\f$
|
|
ResidualHelmholtzNonAnalytic | \f$ \begin{array}{c}\alpha^r&=&\displaystyle\sum_i n_i \Delta^{b_i}\delta\psi \\ \Delta & = & \theta^2+B_i[(\delta-1)^2]^{a_i}\\ \theta & = & (1-\tau)+A_i[(\delta-1)^2]^{1/(2\beta_i)}\\ \psi & = & \exp(-C_i(\delta-1)^2-D_i(\tau-1)^2) \end{array}\f$
|
|
ResidualHelmholtzSAFTAssociating | \f$ \alpha^r = am\left(\ln X-\frac{X}{2}+\frac{1}{2}\right); \f$
|
|
|
|
|
|
Ideal-Gas Helmholtz Energy Terms:
|
|
|
|
Term | Helmholtz Energy Contribution
|
|
---------- | ------------------------------
|
|
IdealHelmholtzLead | \f$ \alpha^0 = n_1 + n_2\tau + \ln\delta \f$
|
|
IdealHelmholtzEnthalpyEntropyOffset | \f$ \alpha^0 = \displaystyle\frac{\Delta s}{R_u/M}+\frac{\Delta h}{(R_u/M)T}\tau \f$
|
|
IdealHelmholtzLogTau | \f$ \alpha^0 = n_1\log\tau \f$
|
|
IdealHelmholtzPower | \f$ \alpha^0 = \displaystyle\sum_i n_i\tau^{t_i} \f$
|
|
IdealHelmholtzPlanckEinsteinGeneralized | \f$ \alpha^0 = \displaystyle\sum_i n_i\log[c_i+d_i\exp(\theta_i\tau)] \f$
|
|
*/
|
|
class BaseHelmholtzTerm{
|
|
public:
|
|
BaseHelmholtzTerm(){};
|
|
virtual ~BaseHelmholtzTerm(){};
|
|
/// Returns the base, non-dimensional, Helmholtz energy term (no derivatives) [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double base(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the first partial derivative of Helmholtz energy term with respect to tau [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dTau(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the second partial derivative of Helmholtz energy term with respect to tau [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dTau2(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the second mixed partial derivative (delta1,dtau1) of Helmholtz energy term with respect to delta and tau [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dDelta_dTau(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the first partial derivative of Helmholtz energy term with respect to delta [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dDelta(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the second partial derivative of Helmholtz energy term with respect to delta [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dDelta2(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the third mixed partial derivative (delta2,dtau1) of Helmholtz energy term with respect to delta and tau [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dDelta2_dTau(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the third mixed partial derivative (delta1,dtau2) of Helmholtz energy term with respect to delta and tau [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dDelta_dTau2(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the third partial derivative of Helmholtz energy term with respect to tau [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dTau3(const long double &tau, const long double &delta) throw() = 0;
|
|
/// Returns the third partial derivative of Helmholtz energy term with respect to delta [-]
|
|
/** @param tau Reciprocal reduced temperature where \f$\tau=T_c / T\f$
|
|
* @param delta Reduced density where \f$\delta = \rho / \rho_c \f$
|
|
*/
|
|
virtual long double dDelta3(const long double &tau, const long double &delta) throw() = 0;
|
|
};
|
|
|
|
// #############################################################################
|
|
// #############################################################################
|
|
// #############################################################################
|
|
// RESIDUAL TERMS
|
|
// #############################################################################
|
|
// #############################################################################
|
|
// #############################################################################
|
|
|
|
struct ResidualHelmholtzPowerElement
|
|
{
|
|
long double n,d,t,ld;
|
|
int l;
|
|
};
|
|
/// Power term
|
|
/*!
|
|
Term of the form
|
|
\f[
|
|
\alpha^r=\left\lbrace\begin{array}{cc}\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} & l_i=0\\ \displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-\delta^{l_i}) & l_i\neq 0\end{array}\right.
|
|
\f]
|
|
*/
|
|
class ResidualHelmholtzPower : public BaseHelmholtzTerm{
|
|
|
|
public:
|
|
/*std::vector<double> d, ///< The power for the delta terms
|
|
t, ///< The powers for the tau terms
|
|
l; ///< The powers for delta in the exp terms*/
|
|
std::vector<long double> s;
|
|
std::size_t N;
|
|
std::vector<ResidualHelmholtzPowerElement> elements;
|
|
// Default Constructor
|
|
ResidualHelmholtzPower(){N = 0;};
|
|
// Constructor
|
|
ResidualHelmholtzPower(const std::vector<long double> &n, const std::vector<long double> &d,
|
|
const std::vector<long double> &t, const std::vector<long double> &l)
|
|
{
|
|
N = n.size();
|
|
s.resize(N);
|
|
for (std::size_t i = 0; i < n.size(); ++i)
|
|
{
|
|
ResidualHelmholtzPowerElement el;
|
|
el.n = n[i];
|
|
el.d = d[i];
|
|
el.t = t[i];
|
|
el.ld = l[i];
|
|
el.l = (int)el.ld;
|
|
elements.push_back(el);
|
|
}
|
|
};
|
|
|
|
///< Destructor for the alphar_power class. No implementation
|
|
~ResidualHelmholtzPower(){};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw();
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
};
|
|
|
|
struct ResidualHelmholtzExponentialElement
|
|
{
|
|
long double n,d,t,g,l;
|
|
};
|
|
/**
|
|
Term of the form
|
|
\f[ \alpha^r=\displaystyle\sum_i n_i \delta^{d_i} \tau^{t_i} \exp(-\gamma_i\delta^{l_i}) \f]
|
|
*/
|
|
class ResidualHelmholtzExponential : public BaseHelmholtzTerm{
|
|
|
|
public:
|
|
std::vector<long double> s;
|
|
std::size_t N;
|
|
std::vector<ResidualHelmholtzExponentialElement> elements;
|
|
// Default Constructor
|
|
ResidualHelmholtzExponential(){N = 0;};
|
|
// Constructor
|
|
ResidualHelmholtzExponential(const std::vector<long double> &n, const std::vector<long double> &d,
|
|
const std::vector<long double> &t, const std::vector<long double> &g,
|
|
const std::vector<long double> &l)
|
|
{
|
|
N = n.size();
|
|
s.resize(N);
|
|
for (std::size_t i = 0; i < n.size(); ++i)
|
|
{
|
|
ResidualHelmholtzExponentialElement el;
|
|
el.d = d[i];
|
|
el.t = t[i];
|
|
el.g = g[i];
|
|
el.l = l[i];
|
|
el.n = n[i];
|
|
elements.push_back(el);
|
|
}
|
|
}
|
|
|
|
///< Destructor for the alphar_power class. No implementation
|
|
~ResidualHelmholtzExponential(){};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw();
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
};
|
|
|
|
struct ResidualHelmholtzGaussianElement
|
|
{
|
|
long double n, d, t, eta, epsilon, beta, gamma;
|
|
};
|
|
class ResidualHelmholtzGaussian : public BaseHelmholtzTerm{
|
|
|
|
public:
|
|
std::size_t N; ///< The number of terms
|
|
std::vector<ResidualHelmholtzGaussianElement> elements;
|
|
std::vector<long double> s;
|
|
// Default Constructor
|
|
ResidualHelmholtzGaussian(){N = 0;};
|
|
// Constructor
|
|
ResidualHelmholtzGaussian(const std::vector<long double> &n,
|
|
const std::vector<long double> &d,
|
|
const std::vector<long double> &t,
|
|
const std::vector<long double> &eta,
|
|
const std::vector<long double> &epsilon,
|
|
const std::vector<long double> &beta,
|
|
const std::vector<long double> &gamma
|
|
)
|
|
{
|
|
N = n.size();
|
|
this->s.resize(N);
|
|
for (std::size_t i = 0; i < n.size(); ++i)
|
|
{
|
|
ResidualHelmholtzGaussianElement el;
|
|
el.n = n[i];
|
|
el.d = d[i];
|
|
el.t = t[i];
|
|
el.eta = eta[i];
|
|
el.epsilon = epsilon[i];
|
|
el.beta = beta[i];
|
|
el.gamma = gamma[i];
|
|
elements.push_back(el);
|
|
}
|
|
};
|
|
|
|
///< Destructor for the alphar_power class. No implementation
|
|
~ResidualHelmholtzGaussian(){};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw();
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
};
|
|
|
|
class ResidualHelmholtzGERG2008Gaussian : public BaseHelmholtzTerm{
|
|
|
|
public:
|
|
std::vector<long double> s;
|
|
std::size_t N;
|
|
std::vector<ResidualHelmholtzGaussianElement> elements;
|
|
/// Default Constructor
|
|
ResidualHelmholtzGERG2008Gaussian(){N = 0;};
|
|
/// Constructor
|
|
ResidualHelmholtzGERG2008Gaussian(const std::vector<long double> &n,
|
|
const std::vector<long double> &d,
|
|
const std::vector<long double> &t,
|
|
const std::vector<long double> &eta,
|
|
const std::vector<long double> &epsilon,
|
|
const std::vector<long double> &beta,
|
|
const std::vector<long double> &gamma)
|
|
{
|
|
N = n.size();
|
|
s.resize(N);
|
|
for (std::size_t i = 0; i < n.size(); ++i)
|
|
{
|
|
ResidualHelmholtzGaussianElement el;
|
|
el.n = n[i];
|
|
el.d = d[i];
|
|
el.t = t[i];
|
|
el.eta = eta[i];
|
|
el.epsilon = epsilon[i];
|
|
el.beta = beta[i];
|
|
el.gamma = gamma[i];
|
|
elements.push_back(el);
|
|
}
|
|
};
|
|
|
|
///< Destructor. No implementation
|
|
~ResidualHelmholtzGERG2008Gaussian(){};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw();
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
};
|
|
|
|
struct ResidualHelmholtzLemmon2005Element{
|
|
long double n, d, t, ld, md;
|
|
int l, m;
|
|
};
|
|
class ResidualHelmholtzLemmon2005 : public BaseHelmholtzTerm{
|
|
public:
|
|
std::size_t N;
|
|
std::vector<long double> s; ///< Summation container
|
|
std::vector<ResidualHelmholtzLemmon2005Element> elements;
|
|
// Default Constructor
|
|
ResidualHelmholtzLemmon2005(){N = 0;};
|
|
// Constructor
|
|
ResidualHelmholtzLemmon2005(const std::vector<long double> &n,
|
|
const std::vector<long double> &d,
|
|
const std::vector<long double> &t,
|
|
const std::vector<long double> &l,
|
|
const std::vector<long double> &m)
|
|
{
|
|
N = n.size();
|
|
s.resize(N);
|
|
for (std::size_t i = 0; i < n.size(); ++i)
|
|
{
|
|
ResidualHelmholtzLemmon2005Element el;
|
|
el.n = n[i];
|
|
el.d = d[i];
|
|
el.t = t[i];
|
|
el.ld = l[i];
|
|
el.md = m[i];
|
|
el.l = (int)el.ld;
|
|
el.m = (int)el.md;
|
|
elements.push_back(el);
|
|
}
|
|
};
|
|
|
|
///< Destructor. No implementation
|
|
~ResidualHelmholtzLemmon2005(){};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw();
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
};
|
|
|
|
struct ResidualHelmholtzNonAnalyticElement
|
|
{
|
|
long double n, a, b, beta, A, B, C, D;
|
|
};
|
|
class ResidualHelmholtzNonAnalytic : public BaseHelmholtzTerm{
|
|
|
|
public:
|
|
std::size_t N;
|
|
std::vector<long double> s;
|
|
std::vector<ResidualHelmholtzNonAnalyticElement> elements;
|
|
/// Default Constructor
|
|
ResidualHelmholtzNonAnalytic(){N = 0;};
|
|
/// Destructor. No implementation
|
|
~ResidualHelmholtzNonAnalytic(){};
|
|
/// Constructor
|
|
ResidualHelmholtzNonAnalytic(const std::vector<long double> &n,
|
|
const std::vector<long double> &a,
|
|
const std::vector<long double> &b,
|
|
const std::vector<long double> &beta,
|
|
const std::vector<long double> &A,
|
|
const std::vector<long double> &B,
|
|
const std::vector<long double> &C,
|
|
const std::vector<long double> &D
|
|
)
|
|
{
|
|
N = n.size();
|
|
s.resize(N);
|
|
for (std::size_t i = 0; i < n.size(); ++i)
|
|
{
|
|
ResidualHelmholtzNonAnalyticElement el;
|
|
el.n = n[i];
|
|
el.a = a[i];
|
|
el.b = b[i];
|
|
el.beta = beta[i];
|
|
el.A = A[i];
|
|
el.B = B[i];
|
|
el.C = C[i];
|
|
el.D = D[i];
|
|
elements.push_back(el);
|
|
}
|
|
};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw();
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
};
|
|
|
|
class ResidualHelmholtzSAFTAssociating : public BaseHelmholtzTerm{
|
|
|
|
protected:
|
|
double a, m,epsilonbar, vbarn, kappabar;
|
|
|
|
long double Deltabar(const long double &tau, const long double &delta);
|
|
long double dDeltabar_ddelta__consttau(const long double &tau, const long double &delta);
|
|
long double d2Deltabar_ddelta2__consttau(const long double &tau, const long double &delta);
|
|
long double dDeltabar_dtau__constdelta(const long double &tau, const long double &delta);
|
|
long double d2Deltabar_dtau2__constdelta(const long double &tau, const long double &delta);
|
|
long double d2Deltabar_ddelta_dtau(const long double &tau, const long double &delta);
|
|
long double d3Deltabar_dtau3__constdelta(const long double &tau, const long double &delta);
|
|
long double d3Deltabar_ddelta_dtau2(const long double &tau, const long double &delta);
|
|
long double d3Deltabar_ddelta3__consttau(const long double &tau, const long double &delta);
|
|
long double d3Deltabar_ddelta2_dtau(const long double &tau, const long double &delta);
|
|
|
|
long double X(const long double &delta, const long double &Deltabar);
|
|
long double dX_dDeltabar__constdelta(const long double &delta, const long double &Deltabar);
|
|
long double dX_ddelta__constDeltabar(const long double &delta, const long double &Deltabar);
|
|
long double dX_dtau(const long double &tau, const long double &delta);
|
|
long double dX_ddelta(const long double &tau, const long double &delta);
|
|
long double d2X_dtau2(const long double &tau, const long double &delta);
|
|
long double d2X_ddeltadtau(const long double &tau, const long double &delta);
|
|
long double d2X_ddelta2(const long double &tau, const long double &delta);
|
|
|
|
long double d3X_dtau3(const long double &tau, const long double &delta);
|
|
long double d3X_ddelta3(const long double &tau, const long double &delta);
|
|
long double d3X_ddeltadtau2(const long double &tau, const long double &delta);
|
|
long double d3X_ddelta2dtau(const long double &tau, const long double &delta);
|
|
|
|
long double g(const long double &eta);
|
|
long double dg_deta(const long double &eta);
|
|
long double d2g_deta2(const long double &eta);
|
|
long double d3g_deta3(const long double &eta);
|
|
long double eta(const long double &delta);
|
|
|
|
public:
|
|
/// Default constructor
|
|
ResidualHelmholtzSAFTAssociating(){ disabled = true; };
|
|
// Constructor
|
|
ResidualHelmholtzSAFTAssociating(double a, double m, double epsilonbar, double vbarn, double kappabar)
|
|
: a(a), m(m), epsilonbar(epsilonbar), vbarn(vbarn), kappabar(kappabar)
|
|
{
|
|
disabled = false;
|
|
};
|
|
|
|
bool disabled;
|
|
|
|
//Destructor. No Implementation
|
|
~ResidualHelmholtzSAFTAssociating(){};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw();
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
};
|
|
|
|
class ResidualHelmholtzContainer
|
|
{
|
|
|
|
public:
|
|
ResidualHelmholtzPower Power;
|
|
ResidualHelmholtzExponential Exponential;
|
|
ResidualHelmholtzGaussian Gaussian;
|
|
ResidualHelmholtzLemmon2005 Lemmon2005;
|
|
ResidualHelmholtzNonAnalytic NonAnalytic;
|
|
ResidualHelmholtzSAFTAssociating SAFT;
|
|
|
|
long double base(long double tau, long double delta)
|
|
{
|
|
return (Power.base(tau, delta) + Exponential.base(tau, delta)
|
|
+Gaussian.base(tau, delta) + Lemmon2005.base(tau, delta)
|
|
+NonAnalytic.base(tau, delta) + SAFT.base(tau,delta));
|
|
};
|
|
|
|
long double dDelta(long double tau, long double delta)
|
|
{
|
|
return (Power.dDelta(tau, delta) + Exponential.dDelta(tau, delta)
|
|
+ Gaussian.dDelta(tau, delta) + Lemmon2005.dDelta(tau, delta)
|
|
+ NonAnalytic.dDelta(tau, delta) + SAFT.dDelta(tau,delta));
|
|
};
|
|
long double dTau(long double tau, long double delta)
|
|
{
|
|
return (Power.dTau(tau, delta) + Exponential.dTau(tau, delta)
|
|
+ Gaussian.dTau(tau, delta) + Lemmon2005.dTau(tau, delta)
|
|
+ NonAnalytic.dTau(tau, delta) + SAFT.dTau(tau,delta));
|
|
};
|
|
|
|
long double dDelta2(long double tau, long double delta)
|
|
{
|
|
return (Power.dDelta2(tau, delta) + Exponential.dDelta2(tau, delta)
|
|
+Gaussian.dDelta2(tau, delta) + Lemmon2005.dDelta2(tau, delta)
|
|
+NonAnalytic.dDelta2(tau, delta) + SAFT.dDelta2(tau,delta));
|
|
};
|
|
long double dDelta_dTau(long double tau, long double delta)
|
|
{
|
|
return (Power.dDelta_dTau(tau, delta) + Exponential.dDelta_dTau(tau, delta)
|
|
+ Gaussian.dDelta_dTau(tau, delta) + Lemmon2005.dDelta_dTau(tau, delta)
|
|
+ NonAnalytic.dDelta_dTau(tau, delta) + SAFT.dDelta_dTau(tau,delta));
|
|
};
|
|
long double dTau2(long double tau, long double delta)
|
|
{
|
|
return (Power.dTau2(tau, delta) + Exponential.dTau2(tau, delta)
|
|
+ Gaussian.dTau2(tau, delta) + Lemmon2005.dTau2(tau, delta)
|
|
+ NonAnalytic.dTau2(tau, delta) + SAFT.dTau2(tau,delta));
|
|
};
|
|
|
|
long double dDelta3(long double tau, long double delta)
|
|
{
|
|
return (Power.dDelta3(tau, delta) + Exponential.dDelta3(tau, delta)
|
|
+Gaussian.dDelta3(tau, delta) + Lemmon2005.dDelta3(tau, delta)
|
|
+NonAnalytic.dDelta3(tau, delta) + SAFT.dDelta3(tau,delta));
|
|
};
|
|
long double dDelta2_dTau(long double tau, long double delta)
|
|
{
|
|
return (Power.dDelta2_dTau(tau, delta) + Exponential.dDelta2_dTau(tau, delta)
|
|
+ Gaussian.dDelta2_dTau(tau, delta) + Lemmon2005.dDelta2_dTau(tau, delta)
|
|
+ NonAnalytic.dDelta2_dTau(tau, delta) + SAFT.dDelta2_dTau(tau,delta));
|
|
};
|
|
long double dDelta_dTau2(long double tau, long double delta)
|
|
{
|
|
return (Power.dDelta_dTau2(tau, delta) + Exponential.dDelta_dTau2(tau, delta)
|
|
+ Gaussian.dDelta_dTau2(tau, delta) + Lemmon2005.dDelta_dTau2(tau, delta)
|
|
+ NonAnalytic.dDelta_dTau2(tau, delta) + SAFT.dDelta_dTau2(tau,delta));
|
|
};
|
|
long double dTau3(long double tau, long double delta)
|
|
{
|
|
return (Power.dTau3(tau, delta) + Exponential.dTau3(tau, delta)
|
|
+Gaussian.dTau3(tau, delta) + Lemmon2005.dTau3(tau, delta)
|
|
+NonAnalytic.dTau3(tau, delta) + SAFT.dTau3(tau,delta));
|
|
};
|
|
};
|
|
|
|
|
|
// #############################################################################
|
|
// #############################################################################
|
|
// #############################################################################
|
|
// IDEAL GAS TERMS
|
|
// #############################################################################
|
|
// #############################################################################
|
|
// #############################################################################
|
|
|
|
/// The leading term in the EOS used to set the desired reference state
|
|
/**
|
|
\f[
|
|
\alpha^0 = \log(\delta)+a_1+a_2\tau
|
|
\f]
|
|
*/
|
|
class IdealHelmholtzLead : public BaseHelmholtzTerm{
|
|
|
|
private:
|
|
long double a1, a2;
|
|
bool enabled;
|
|
public:
|
|
// Default constructor
|
|
IdealHelmholtzLead(){enabled = false;};
|
|
|
|
// Constructor
|
|
IdealHelmholtzLead(const long double a1, const long double a2)
|
|
:a1(a1), a2(a2)
|
|
{enabled = true;};
|
|
|
|
//Destructor
|
|
~IdealHelmholtzLead(){};
|
|
|
|
bool is_enabled(){return enabled;};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc){
|
|
el.AddMember("type","IdealHelmholtzLead",doc.GetAllocator());
|
|
el.AddMember("a1", static_cast<double>(a1), doc.GetAllocator());
|
|
el.AddMember("a2", static_cast<double>(a2), doc.GetAllocator());
|
|
};
|
|
|
|
// Term and its derivatives
|
|
long double base(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return log(delta)+a1+a2*tau;
|
|
};
|
|
long double dDelta(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return 1.0/delta;
|
|
};
|
|
long double dTau(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return a2;
|
|
};
|
|
long double dDelta2(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return -1.0/delta/delta;
|
|
};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta3(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return 2/delta/delta/delta;
|
|
};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau3(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
};
|
|
|
|
/// The term in the EOS used to shift the reference state of the fluid
|
|
/**
|
|
\f[
|
|
\alpha^0 = a_1+a_2\tau
|
|
\f]
|
|
*/
|
|
class IdealHelmholtzEnthalpyEntropyOffset : public BaseHelmholtzTerm{
|
|
private:
|
|
long double a1,a2; // Use these variables internally
|
|
bool enabled;
|
|
std::string reference;
|
|
public:
|
|
IdealHelmholtzEnthalpyEntropyOffset(){enabled = false;};
|
|
|
|
// Constructor
|
|
IdealHelmholtzEnthalpyEntropyOffset(long double a1, long double a2, std::string reference):a1(a1), a2(a2){this->reference = reference; enabled = true;};
|
|
|
|
// Set the values in the class
|
|
void set(long double a1, long double a2, std::string reference){this->a1 = a1; this->a2 = a2; this->reference = reference; enabled = true;}
|
|
|
|
//Destructor
|
|
~IdealHelmholtzEnthalpyEntropyOffset(){};
|
|
|
|
bool is_enabled(){return enabled;};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc){
|
|
el.AddMember("type","IdealHelmholtzEnthalpyEntropyOffset",doc.GetAllocator());
|
|
el.AddMember("a1", static_cast<double>(a1), doc.GetAllocator());
|
|
el.AddMember("a2", static_cast<double>(a2), doc.GetAllocator());
|
|
};
|
|
|
|
// Term and its derivatives
|
|
long double base(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return a1+a2*tau;
|
|
};
|
|
long double dDelta(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return a2;
|
|
};
|
|
long double dDelta2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta3(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau3(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
};
|
|
|
|
|
|
/**
|
|
\f[
|
|
\alpha^0 = a_1\ln\tau
|
|
\f]
|
|
*/
|
|
class IdealHelmholtzLogTau : public BaseHelmholtzTerm
|
|
{
|
|
private:
|
|
long double a1;
|
|
bool enabled;
|
|
public:
|
|
|
|
/// Default constructor
|
|
IdealHelmholtzLogTau(){enabled = false;};
|
|
|
|
// Constructor
|
|
IdealHelmholtzLogTau(long double a1){this->a1=a1; enabled = true;};
|
|
|
|
bool is_enabled(){return enabled;};
|
|
|
|
//Destructor
|
|
~IdealHelmholtzLogTau(){};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc){
|
|
el.AddMember("type", "IdealHelmholtzLogTau", doc.GetAllocator());
|
|
el.AddMember("a1", static_cast<double>(a1), doc.GetAllocator());
|
|
};
|
|
|
|
// Term and its derivatives
|
|
long double base(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return a1*log(tau);
|
|
};
|
|
long double dTau(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return a1/tau;
|
|
};
|
|
long double dTau2(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return -a1/tau/tau;
|
|
};
|
|
long double dTau3(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return 2*a1/tau/tau/tau;
|
|
};
|
|
long double dDelta(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta3(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
};
|
|
|
|
/**
|
|
\f[
|
|
\alpha^0 = \displaystyle\sum_i n_i\tau^{t_i}
|
|
\f]
|
|
*/
|
|
class IdealHelmholtzPower : public BaseHelmholtzTerm{
|
|
|
|
private:
|
|
std::vector<long double> n, t; // Use these variables internally
|
|
std::size_t N;
|
|
bool enabled;
|
|
public:
|
|
IdealHelmholtzPower(){enabled = false;};
|
|
// Constructor
|
|
IdealHelmholtzPower(const std::vector<long double> &n, const std::vector<long double> &t)
|
|
:n(n), t(t)
|
|
{
|
|
this->N = n.size();
|
|
enabled = true;
|
|
};
|
|
|
|
//Destructor
|
|
~IdealHelmholtzPower(){};
|
|
|
|
bool is_enabled(){return enabled;};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc)
|
|
{
|
|
el.AddMember("type","IdealHelmholtzPower",doc.GetAllocator());
|
|
cpjson::set_long_double_array("n",n,el,doc);
|
|
cpjson::set_long_double_array("t",t,el,doc);
|
|
};
|
|
|
|
// Term and its derivatives
|
|
long double base(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
long double s=0; for (std::size_t i = 0; i<N; ++i){s += n[i]*pow(tau, t[i]);} return s;
|
|
};
|
|
long double dTau(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
long double s=0; for (std::size_t i = 0; i<N; ++i){s += n[i]*t[i]*pow(tau, t[i]-1);} return s;
|
|
};
|
|
long double dTau2(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
long double s=0; for (std::size_t i = 0; i<N; ++i){s += n[i]*t[i]*(t[i]-1)*pow(tau, t[i]-2);} return s;
|
|
};
|
|
long double dTau3(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
long double s=0; for (std::size_t i = 0; i<N; ++i){s += n[i]*t[i]*(t[i]-1)*(t[i]-2)*pow(tau, t[i]-3);} return s;
|
|
};
|
|
long double dDelta(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta3(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
};
|
|
|
|
/**
|
|
\f[
|
|
\alpha^0 = \displaystyle\sum_i n_i\log[c_i+d_i\exp(\theta_i\tau)]
|
|
\f]
|
|
|
|
To convert conventional Plank-Einstein forms, given by
|
|
\f$
|
|
\frac{c_p^0}{R} = a_k\displaystyle\frac{\left( b_k/T \right)^2\exp \left( b_k/T \right)}{\left(\exp \left(b_k/T\right) - 1 \right)^2}
|
|
\f$
|
|
and
|
|
\f$
|
|
\alpha^0 = a_k\ln \left[1 - \exp \left( \frac{-b_k\tau}{T_c} \right) \right]
|
|
\f$
|
|
use \f$c = 1\f$, \f$d = -1\f$, \f$n = a\f$, \f$\theta = -\displaystyle\frac{b_k}{T_c}\f$
|
|
|
|
To convert the second form of Plank-Einstein terms, given by
|
|
\f$
|
|
\frac{c_p^0}{R} = a_k\displaystyle\frac{\left( -b_k/T \right)^2\exp \left( b_k/T \right)}{c\left(\exp \left(-b_k/T\right) + 1 \right)^2}
|
|
\f$
|
|
and
|
|
\f$
|
|
\alpha^0 = a_k\ln \left[c + \exp \left( \frac{b_k\tau}{T_c} \right) \right]
|
|
\f$
|
|
use \f$c = 1\f$, \f$d = 1\f$, \f$n = -a\f$, \f$\theta = \displaystyle\frac{b_k}{T_c}\f$
|
|
|
|
Converting Aly-Lee tems is a bit more complex
|
|
|
|
Aly-Lee starts as
|
|
\f[\frac{c_p^0}{R_u} = A + B\left(\frac{C/T}{\sinh(C/T)}\right)^2 + D\left(\frac{E/T}{\cosh(E/T)}\right)^2\f]
|
|
|
|
Constant is separated out, and handled separately. sinh part can be expanded as
|
|
\f[B\left(\frac{C/T}{\sinh(C/T)}\right)^2 = \frac{B(-2C/T)^2\exp(-2C/T)}{(1-\exp(-2C/T))^2}\f]
|
|
where
|
|
\f[n_k = B\f]
|
|
\f[\theta_k = -\frac{2C}{T_c}\f]
|
|
\f[c_k = 1\f]
|
|
\f[d_k = -1\f]
|
|
|
|
cosh part can be expanded as
|
|
\f[D\left(\frac{E/T}{\cosh(E/T)}\right)^2 = \frac{D(-2E/T)^2\exp(-2E/T)}{(1+\exp(-2E/T))^2}\f]
|
|
where
|
|
\f[n_k = -D\f]
|
|
\f[\theta_k = -\frac{2E}{T_c}\f]
|
|
\f[c_k = 1\f]
|
|
\f[d_k = 1\f]
|
|
*/
|
|
class IdealHelmholtzPlanckEinsteinGeneralized : public BaseHelmholtzTerm{
|
|
|
|
private:
|
|
std::vector<long double> n,theta,c,d; // Use these variables internally
|
|
std::size_t N;
|
|
bool enabled;
|
|
public:
|
|
IdealHelmholtzPlanckEinsteinGeneralized(){N = 0; enabled = false;}
|
|
// Constructor with std::vector instances
|
|
IdealHelmholtzPlanckEinsteinGeneralized(std::vector<long double> n, std::vector<long double> theta, std::vector<long double> c, std::vector<long double> d)
|
|
:n(n), theta(theta), c(c), d(d)
|
|
{
|
|
N = n.size();
|
|
enabled = true;
|
|
};
|
|
|
|
// Destructor
|
|
~IdealHelmholtzPlanckEinsteinGeneralized(){};
|
|
|
|
// Extend the vectors to allow for multiple instances feeding values to this function
|
|
void extend(std::vector<long double> n, std::vector<long double> theta, std::vector<long double> c, std::vector<long double> d)
|
|
{
|
|
this->n.insert(this->n.end(), n.begin(), n.end());
|
|
this->theta.insert(this->theta.end(), theta.begin(), theta.end());
|
|
this->c.insert(this->c.end(), c.begin(), c.end());
|
|
this->d.insert(this->d.end(), d.begin(), d.end());
|
|
N += n.size();
|
|
}
|
|
|
|
bool is_enabled(){return enabled;};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc)
|
|
{
|
|
el.AddMember("type","IdealHelmholtzPlanckEinsteinGeneralized",doc.GetAllocator());
|
|
cpjson::set_long_double_array("n",n,el,doc);
|
|
cpjson::set_long_double_array("theta",theta,el,doc);
|
|
};
|
|
|
|
// Term and its derivatives
|
|
long double base(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
long double s=0; for (std::size_t i=0; i < N; ++i){
|
|
s += n[i]*log(c[i]+d[i]*exp(theta[i]*tau));
|
|
}
|
|
return s;
|
|
};
|
|
long double dTau(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
long double s=0; for (std::size_t i=0; i < N; ++i){s += n[i]*theta[i]*d[i]*exp(theta[i]*tau)/(c[i]+d[i]*exp(theta[i]*tau));}
|
|
return s;
|
|
};
|
|
long double dTau2(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
long double s=0; for (std::size_t i=0; i < N; ++i){s += n[i]*pow(theta[i],2)*c[i]*d[i]*exp(theta[i]*tau)/pow(c[i]+d[i]*exp(theta[i]*tau),2);} return s;
|
|
};
|
|
long double dTau3(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
long double s=0; for (std::size_t i=0; i < N; ++i){s += n[i]*pow(theta[i],3)*c[i]*d[i]*(c[i]-d[i]*exp(theta[i]*tau))*exp(theta[i]*tau)/pow(c[i]+d[i]*exp(theta[i]*tau),3);} return s;
|
|
};
|
|
long double dDelta(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta3(const long double &tau, const long double &delta) throw(){return 0;};
|
|
};
|
|
|
|
class IdealHelmholtzCP0Constant : public BaseHelmholtzTerm{
|
|
|
|
private:
|
|
double cp_over_R,Tc,T0,tau0; // Use these variables internally
|
|
bool enabled;
|
|
public:
|
|
/// Default constructor
|
|
IdealHelmholtzCP0Constant(){enabled = false;};
|
|
|
|
/// Constructor with just a single double value
|
|
IdealHelmholtzCP0Constant(long double cp_over_R, long double Tc, long double T0)
|
|
: cp_over_R(cp_over_R), Tc(Tc), T0(T0)
|
|
{
|
|
enabled = true; tau0 = Tc/T0;
|
|
};
|
|
|
|
/// Destructor
|
|
~IdealHelmholtzCP0Constant(){};
|
|
|
|
bool is_enabled(){return enabled;};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc)
|
|
{
|
|
el.AddMember("type","IdealGasHelmholtzCP0Constant", doc.GetAllocator());
|
|
el.AddMember("cp_over_R", cp_over_R, doc.GetAllocator());
|
|
el.AddMember("Tc", Tc, doc.GetAllocator());
|
|
el.AddMember("T0", T0, doc.GetAllocator());
|
|
};
|
|
|
|
// Term and its derivatives
|
|
long double base(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return cp_over_R-cp_over_R*tau/tau0+cp_over_R*log(tau/tau0);
|
|
};
|
|
long double dTau(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return cp_over_R/tau-cp_over_R/tau0;
|
|
};
|
|
long double dTau2(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return -cp_over_R/(tau*tau);
|
|
};
|
|
long double dTau3(const long double &tau, const long double &delta) throw(){
|
|
if (!enabled){return 0.0;}
|
|
return 2*cp_over_R/(tau*tau*tau);
|
|
};
|
|
long double dDelta(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta3(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
};
|
|
|
|
class IdealHelmholtzCP0PolyT : public BaseHelmholtzTerm{
|
|
private:
|
|
std::vector<long double> c, t;
|
|
long double Tc, T0, tau0; // Use these variables internally
|
|
std::size_t N;
|
|
bool enabled;
|
|
public:
|
|
/// Destructor
|
|
IdealHelmholtzCP0PolyT(){N = 0; enabled = false;};
|
|
|
|
/// Constructor with std::vectors
|
|
IdealHelmholtzCP0PolyT(const std::vector<long double> &c, const std::vector<long double> &t, double Tc, double T0)
|
|
: c(c), t(t), Tc(Tc), T0(T0)
|
|
{
|
|
assert(c.size() == t.size());
|
|
tau0 = Tc/T0;
|
|
enabled = true;
|
|
N = c.size();
|
|
};
|
|
|
|
void extend(const std::vector<long double> &c, const std::vector<long double> &t)
|
|
{
|
|
this->c.insert(this->c.end(), c.begin(), c.end());
|
|
this->t.insert(this->t.end(), t.begin(), t.end());
|
|
N += c.size();
|
|
}
|
|
|
|
/// Destructor
|
|
~IdealHelmholtzCP0PolyT(){};
|
|
|
|
bool is_enabled(){return enabled;};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
// Term and its derivatives
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
|
|
};
|
|
|
|
/// Term in the ideal-gas specific heat equation that is based on Aly-Lee formulation
|
|
/** Specific heat is of the form:
|
|
\f[
|
|
\frac{c_p^0}{R_u} = A + B\left(\frac{C/T}{\sinh(C/T)}\right)^2 + D\left(\frac{E/T}{\cosh(E/T)}\right)^2
|
|
\f]
|
|
Second partial of ideal-gas Helmholtz energy given directly by specific heat (\f$\displaystyle\alpha_{\tau\tau}^0=-\frac{1}{\tau^2}\frac{c_p^0}{R_u} \f$) - this is obtained by real gas \f$c_p\f$ relationship, and killing off residual Helmholtz terms
|
|
\f[
|
|
\alpha^0_{\tau\tau} = -\frac{A}{\tau^2} - \frac{B}{\tau^2}\left(\frac{C/T}{\sinh(C/T)}\right)^2 - \frac{D}{\tau^2}\left(\frac{E/T}{\cosh(E/T)}\right)^2
|
|
\f]
|
|
or in terms of \f$ \tau \f$:
|
|
\f[
|
|
\alpha^0_{\tau\tau} = -\frac{A}{\tau^2} - \frac{BC^2}{T_c^2}\left(\frac{1}{\sinh(C\tau/T_c)}\right)^2 - \frac{DE^2}{T_c^2}\left(\frac{1}{\cosh(E\tau/T_c)}\right)^2
|
|
\f]
|
|
Third partial:
|
|
\f[
|
|
\alpha^0_{\tau\tau\tau} = 2\frac{A}{\tau^3} + 2\frac{BC^3}{T_c^3}\frac{\cosh(C\tau/T_c)}{\sinh^3(C\tau/T_c)} +2 \frac{DE^3}{T_c^3}\frac{\sinh(E\tau/T_c)}{\cosh^3(E\tau/T_c)}
|
|
\f]
|
|
Now coming back to the ideal gas Helmholtz energy definition:
|
|
\f[
|
|
\alpha^0 = -\tau\displaystyle\int_{\tau_0}^{\tau} \frac{1}{\tau^2}\frac{c_p^0}{R_u}d\tau+\displaystyle\int_{\tau_0}^{\tau} \frac{1}{\tau}\frac{c_p^0}{R_u}d\tau
|
|
\f]
|
|
Applying derivative
|
|
\f[
|
|
\alpha^0_{\tau} = -\displaystyle\int_{\tau_0}^{\tau} \frac{1}{\tau^2}\frac{c_p^0}{R_u}d\tau-\tau\frac{\partial}{\partial \tau}\left[\displaystyle\int_{\tau_0}^{\tau} \frac{1}{\tau^2}\frac{c_p^0}{R_u}d\tau \right]+\frac{\partial}{\partial \tau}\left[\displaystyle\int_{\tau_0}^{\tau} \frac{1}{\tau}\frac{c_p^0}{R_u}d\tau \right]
|
|
\f]
|
|
Fundamental theorem of calculus
|
|
\f[
|
|
\alpha^0_{\tau} = -\int_{\tau_0}^{\tau} \frac{1}{\tau^2}\frac{c_p^0}{R_u}d\tau-\tau \frac{1}{\tau^2}\frac{c_p^0}{R_u}d\tau+\frac{1}{\tau}\frac{c_p^0}{R_u}
|
|
\f]
|
|
Last two terms cancel, leaving
|
|
\f[
|
|
\alpha^0_{\tau} = -\int_{\tau_0}^{\tau} \frac{1}{\tau^2}\frac{c_p^0}{R_u}d\tau
|
|
\f]
|
|
Another derivative yields (from fundamental theorem of calculus)
|
|
\f[
|
|
\alpha^0_{\tau\tau} = - \frac{1}{\tau^2}\frac{c_p^0}{R_u}
|
|
\f]
|
|
|
|
see also Jaeschke and Schley, 1995, (http://link.springer.com/article/10.1007%2FBF02083547#page-1)
|
|
*/
|
|
class IdealHelmholtzCP0AlyLee : public BaseHelmholtzTerm{
|
|
private:
|
|
std::vector<long double> c;
|
|
long double Tc, tau0, T0; // Use these variables internally
|
|
bool enabled;
|
|
public:
|
|
IdealHelmholtzCP0AlyLee(){enabled = false;};
|
|
|
|
/// Constructor with std::vectors
|
|
IdealHelmholtzCP0AlyLee(std::vector<long double> c, double Tc, double T0)
|
|
:c(c), Tc(Tc), T0(T0)
|
|
{
|
|
tau0=Tc/T0;
|
|
enabled = true;
|
|
};
|
|
|
|
/// Destructor
|
|
~IdealHelmholtzCP0AlyLee(){};
|
|
|
|
bool is_enabled(){return enabled;};
|
|
|
|
void to_json(rapidjson::Value &el, rapidjson::Document &doc);
|
|
|
|
|
|
/// The antiderivative given by \f$ \displaystyle\int \frac{1}{\tau^2}\frac{c_p^0}{R_u}d\tau \f$
|
|
/**
|
|
sympy code for this derivative:
|
|
|
|
from sympy import *
|
|
a1,a2,a3,a4,a5,Tc,tau = symbols('a1,a2,a3,a4,a5,Tc,tau', real = True)
|
|
integrand = a1 + a2*(a3/Tc/sinh(a3*tau/Tc))**2 + a4*(a5/Tc/cosh(a5*tau/Tc))**2
|
|
integrand = integrand.rewrite(exp)
|
|
antideriv = trigsimp(integrate(integrand,tau))
|
|
display(antideriv)
|
|
print latex(antideriv)
|
|
print ccode(antideriv)
|
|
|
|
\f[
|
|
\displaystyle\int \frac{1}{\tau^2}\frac{c_p^0}{R_u}d\tau = -\frac{a_0}{\tau}+\frac{2a_1a_2}{T_c\left[\exp\left(-\frac{2a_2\tau}{T_c}\right)-1\right]}+\frac{2a_3a_4}{T_c\left[\exp\left(-\frac{2a_4\tau}{T_c}\right)+1\right]}
|
|
\f]
|
|
*/
|
|
long double anti_deriv_cp0_tau2(const long double &tau);
|
|
|
|
/// The antiderivative given by \f$ \displaystyle\int \frac{1}{\tau}\frac{c_p^0}{R_u}d\tau \f$
|
|
/**
|
|
sympy code for this derivative:
|
|
|
|
a_0,a_1,a_2,a_3,a_4,Tc,tau = symbols('a_0,a_1,a_2,a_3,a_4,Tc,tau', real = True)
|
|
integrand = a_0/tau + a_1/tau*(a_2*tau/Tc/sinh(a_2*tau/Tc))**2 + a_3/tau*(a_4*tau/Tc/cosh(a_4*tau/Tc))**2
|
|
|
|
term2 = a_1/tau*(a_2*tau/Tc/sinh(a_2*tau/Tc))**2
|
|
term2 = term2.rewrite(exp) # Unpack the sinh to exp functions
|
|
antideriv2 = trigsimp(integrate(term2,tau))
|
|
display(antideriv2)
|
|
print latex(antideriv2)
|
|
print ccode(antideriv2)
|
|
|
|
term3 = a_3/tau*(a_4*tau/Tc/cosh(a_4*tau/Tc))**2
|
|
term3 = term3.rewrite(exp) # Unpack the cosh to exp functions
|
|
antideriv3 = factor(trigsimp(integrate(term3,tau).rewrite(exp)))
|
|
display(antideriv3)
|
|
print latex(antideriv3)
|
|
print ccode(antideriv3)
|
|
|
|
Can be broken into three parts (trick is to express \f$sinh\f$ and \f$cosh\f$ in terms of \f$exp\f$ function)
|
|
|
|
Term 2:
|
|
\f[
|
|
\displaystyle\int \frac{a_1a_2^2}{T_c^2}\frac{\tau}{\sinh\left(\displaystyle\frac{a_2\tau}{T_c}\right)^2} d\tau = \frac{2 a_{1} a_{2} \tau}{- Tc + Tc e^{- \frac{2 a_{2}}{Tc} \tau}} + a_{1} \log{\left (-1 + e^{- \frac{2 a_{2}}{Tc} \tau} \right )} + \frac{2 a_{1}}{Tc} a_{2} \tau
|
|
\f]
|
|
|
|
Term 3:
|
|
\f[
|
|
\displaystyle\int \frac{a_1a_2^2}{T_c^2}\frac{\tau}{\cosh\left(\displaystyle\frac{a_2\tau}{T_c}\right)^2} d\tau = - \frac{a_{3}}{Tc \left(e^{\frac{2 a_{4}}{Tc} \tau} + 1\right)} \left(Tc e^{\frac{2 a_{4}}{Tc} \tau} \log{\left (e^{\frac{2 a_{4}}{Tc} \tau} + 1 \right )} + Tc \log{\left (e^{\frac{2 a_{4}}{Tc} \tau} + 1 \right )} - 2 a_{4} \tau e^{\frac{2 a_{4}}{Tc} \tau}\right)
|
|
\f]
|
|
*/
|
|
long double anti_deriv_cp0_tau(const long double &tau);
|
|
|
|
long double base(const long double &tau, const long double &delta) throw();
|
|
long double dDelta(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau(const long double &tau, const long double &delta) throw();
|
|
long double dDelta2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau2(const long double &tau, const long double &delta) throw();
|
|
long double dDelta3(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta) throw(){return 0.0;};
|
|
long double dTau3(const long double &tau, const long double &delta) throw();
|
|
|
|
};
|
|
|
|
|
|
class IdealHelmholtzContainer
|
|
{
|
|
|
|
public:
|
|
IdealHelmholtzLead Lead;
|
|
IdealHelmholtzEnthalpyEntropyOffset EnthalpyEntropyOffset;
|
|
IdealHelmholtzLogTau LogTau;
|
|
IdealHelmholtzPower Power;
|
|
IdealHelmholtzPlanckEinsteinGeneralized PlanckEinstein;
|
|
|
|
IdealHelmholtzCP0Constant CP0Constant;
|
|
IdealHelmholtzCP0PolyT CP0PolyT;
|
|
|
|
long double base(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.base(tau, delta) + EnthalpyEntropyOffset.base(tau, delta)
|
|
+ LogTau.base(tau, delta) + Power.base(tau, delta)
|
|
+ PlanckEinstein.base(tau, delta)
|
|
+ CP0Constant.base(tau, delta) + CP0PolyT.base(tau, delta)
|
|
);
|
|
};
|
|
long double dDelta(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dDelta(tau, delta) + EnthalpyEntropyOffset.dDelta(tau, delta)
|
|
+ LogTau.dDelta(tau, delta) + Power.dDelta(tau, delta)
|
|
+ PlanckEinstein.dDelta(tau, delta)
|
|
+ CP0Constant.dDelta(tau, delta) + CP0PolyT.dDelta(tau, delta)
|
|
);
|
|
};
|
|
long double dTau(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dTau(tau, delta) + EnthalpyEntropyOffset.dTau(tau, delta)
|
|
+ LogTau.dTau(tau, delta) + Power.dTau(tau, delta)
|
|
+ PlanckEinstein.dTau(tau, delta)
|
|
+ CP0Constant.dTau(tau, delta) + CP0PolyT.dTau(tau, delta)
|
|
);
|
|
};
|
|
long double dDelta2(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dDelta2(tau, delta) + EnthalpyEntropyOffset.dDelta2(tau, delta)
|
|
+ LogTau.dDelta2(tau, delta) + Power.dDelta2(tau, delta)
|
|
+ PlanckEinstein.dDelta2(tau, delta)
|
|
+ CP0Constant.dDelta2(tau, delta) + CP0PolyT.dDelta2(tau, delta)
|
|
);
|
|
};
|
|
long double dDelta_dTau(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dDelta_dTau(tau, delta) + EnthalpyEntropyOffset.dDelta_dTau(tau, delta)
|
|
+ LogTau.dDelta_dTau(tau, delta) + Power.dDelta_dTau(tau, delta)
|
|
+ PlanckEinstein.dDelta_dTau(tau, delta)
|
|
+ CP0Constant.dDelta_dTau(tau, delta) + CP0PolyT.dDelta_dTau(tau, delta)
|
|
);
|
|
};
|
|
long double dTau2(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dTau2(tau, delta) + EnthalpyEntropyOffset.dTau2(tau, delta)
|
|
+ LogTau.dTau2(tau, delta) + Power.dTau2(tau, delta)
|
|
+ PlanckEinstein.dTau2(tau, delta)
|
|
+ CP0Constant.dTau2(tau, delta) + CP0PolyT.dTau2(tau, delta)
|
|
);
|
|
};
|
|
long double dDelta3(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dDelta3(tau, delta) + EnthalpyEntropyOffset.dDelta3(tau, delta)
|
|
+ LogTau.dDelta3(tau, delta) + Power.dDelta3(tau, delta)
|
|
+ PlanckEinstein.dDelta3(tau, delta)
|
|
+ CP0Constant.dDelta3(tau, delta) + CP0PolyT.dDelta3(tau, delta)
|
|
);
|
|
};
|
|
long double dDelta2_dTau(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dDelta2_dTau(tau, delta) + EnthalpyEntropyOffset.dDelta2_dTau(tau, delta)
|
|
+ LogTau.dDelta2_dTau(tau, delta) + Power.dDelta2_dTau(tau, delta)
|
|
+ PlanckEinstein.dDelta2_dTau(tau, delta)
|
|
+ CP0Constant.dDelta2_dTau(tau, delta) + CP0PolyT.dDelta2_dTau(tau, delta)
|
|
);
|
|
};
|
|
long double dDelta_dTau2(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dDelta_dTau2(tau, delta) + EnthalpyEntropyOffset.dDelta_dTau2(tau, delta)
|
|
+ LogTau.dDelta_dTau2(tau, delta) + Power.dDelta_dTau2(tau, delta)
|
|
+ PlanckEinstein.dDelta_dTau2(tau, delta)
|
|
+ CP0Constant.dDelta_dTau2(tau, delta) + CP0PolyT.dDelta_dTau2(tau, delta)
|
|
);
|
|
};
|
|
long double dTau3(const long double &tau, const long double &delta)
|
|
{
|
|
return (Lead.dTau3(tau, delta) + EnthalpyEntropyOffset.dTau3(tau, delta)
|
|
+ LogTau.dTau3(tau, delta) + Power.dTau3(tau, delta)
|
|
+ PlanckEinstein.dTau3(tau, delta)
|
|
+ CP0Constant.dTau3(tau, delta) + CP0PolyT.dTau3(tau, delta)
|
|
);
|
|
};
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|