mirror of
https://github.com/CoolProp/CoolProp.git
synced 2026-02-13 07:15:14 -05:00
Refactor of mixing parameters successful
Signed-off-by: Ian Bell <ian.h.bell@gmail.com>
This commit is contained in:
@@ -1,164 +1,10 @@
|
||||
#include <memory>
|
||||
|
||||
#include "ReducingFunctions.h"
|
||||
#include "ExcessHEFunction.h"
|
||||
#include "mixture_excess_term_JSON.h"
|
||||
|
||||
namespace CoolProp{
|
||||
|
||||
static MixtureExcessHELibrary mixtureexcesslibrary;
|
||||
|
||||
MixtureExcessHELibrary::MixtureExcessHELibrary()
|
||||
{
|
||||
rapidjson::Document dd;
|
||||
|
||||
dd.Parse<0>(mixture_excess_term_JSON.c_str());
|
||||
if (dd.HasParseError()){throw ValueError();}
|
||||
|
||||
// Iterate over the papers in the listing
|
||||
for (rapidjson::Value::ValueIterator itr = dd.Begin(); itr != dd.End(); ++itr)
|
||||
{
|
||||
// Iterate over the coeffs in the entry
|
||||
rapidjson::Value &Coeffs = (*itr)["Coeffs"];
|
||||
std::string model = cpjson::get_string(*itr, "Model");
|
||||
std::string BibTeX = cpjson::get_string(*itr, "BibTeX");
|
||||
for (rapidjson::Value::ValueIterator itr_coeff = Coeffs.Begin(); itr_coeff != Coeffs.End(); ++itr_coeff)
|
||||
{
|
||||
std::vector<std::string> CAS1V, Name1V, CAS2V, Name2V;
|
||||
|
||||
if ((itr_coeff->HasMember("Name1") && (*itr_coeff)["Name1"].IsString())
|
||||
&& (itr_coeff->HasMember("Name2") && (*itr_coeff)["Name2"].IsString())
|
||||
&& (itr_coeff->HasMember("CAS1") && (*itr_coeff)["CAS1"].IsString())
|
||||
&& (itr_coeff->HasMember("CAS2") && (*itr_coeff)["CAS2"].IsString()))
|
||||
{
|
||||
// Turn the strings into one-element vectors
|
||||
CAS1V = std::vector<std::string>(1,cpjson::get_string(*itr_coeff,"CAS1"));
|
||||
Name1V = std::vector<std::string>(1,cpjson::get_string(*itr_coeff,"Name1"));
|
||||
CAS2V = std::vector<std::string>(1,cpjson::get_string(*itr_coeff,"CAS2"));
|
||||
Name2V = std::vector<std::string>(1,cpjson::get_string(*itr_coeff,"Name2"));
|
||||
}
|
||||
else
|
||||
{
|
||||
CAS1V = cpjson::get_string_array((*itr_coeff)["CAS1"]);
|
||||
Name1V = cpjson::get_string_array((*itr_coeff)["Name1"]);
|
||||
CAS2V = cpjson::get_string_array((*itr_coeff)["CAS2"]);
|
||||
Name2V = cpjson::get_string_array((*itr_coeff)["Name2"]);
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < CAS1V.size(); ++i)
|
||||
{
|
||||
// Get the vector of CAS numbers
|
||||
std::vector<std::string> CAS;
|
||||
CAS.resize(2);
|
||||
CAS[0] = CAS1V[i];
|
||||
CAS[1] = CAS2V[i];
|
||||
|
||||
// Sort the CAS number vector
|
||||
std::sort(CAS.begin(), CAS.end());
|
||||
|
||||
// Get the empty dictionary to be filled by the appropriate reducing parameter filling function
|
||||
Dictionary d;
|
||||
|
||||
// Populate the dictionary with common terms
|
||||
d.add_string("model", model);
|
||||
d.add_string("name1", Name1V[i]);
|
||||
d.add_string("name2", Name2V[i]);
|
||||
d.add_string("bibtex", BibTeX);
|
||||
|
||||
if (!model.compare("Kunz-JCED-2012"))
|
||||
{
|
||||
parse_Kunz_JCED_2012(d, *itr_coeff, i);
|
||||
}
|
||||
else if (!model.compare("Lemmon-JPCRD-2004"))
|
||||
{
|
||||
parse_Lemmon_JPCRD_2004(d, *itr_coeff);
|
||||
}
|
||||
else if (!model.compare("Lemmon-JPCRD-2000"))
|
||||
{
|
||||
parse_Lemmon_JPCRD_2000(d, *itr_coeff);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ValueError();
|
||||
}
|
||||
|
||||
// If not in map, add new entry to map with dictionary
|
||||
if (excess_map.find(CAS) == excess_map.end())
|
||||
{
|
||||
// One-element vector of the dictionary
|
||||
std::vector<Dictionary> vd(1, d);
|
||||
// Pair for adding to map
|
||||
std::pair<std::vector<std::string>, std::vector<Dictionary> > p(CAS, vd);
|
||||
// Add
|
||||
excess_map.insert(p);
|
||||
}
|
||||
else // If already in map, add entry to the end of the vector
|
||||
{
|
||||
// Append dictionary to listing
|
||||
excess_map[CAS].push_back(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExcessTerm::construct(const std::vector<CoolPropFluid*> &components)
|
||||
{
|
||||
std::string _model;
|
||||
N = components.size();
|
||||
|
||||
F.resize(N, std::vector<double>(N, 0));
|
||||
DepartureFunctionMatrix.resize(N);
|
||||
|
||||
for (unsigned int i = 0; i < N; ++i)
|
||||
{
|
||||
DepartureFunctionMatrix[i].resize(N);
|
||||
for (unsigned int j = 0; j < N; ++j)
|
||||
{
|
||||
if (i == j){ continue; }
|
||||
|
||||
std::string CAS1 = components[i]->CAS;
|
||||
std::vector<std::string> CAS(2,"");
|
||||
CAS[0] = components[i]->CAS;
|
||||
CAS[1] = components[j]->CAS;
|
||||
std::sort(CAS.begin(), CAS.end());
|
||||
|
||||
std::vector<Dictionary> & vd = mixtureexcesslibrary.excess_map[CAS];
|
||||
if (vd.size() != 1) { throw NotImplementedError(); }
|
||||
// Get a reference to the dictionary itself to save a few dereferences
|
||||
Dictionary &dic = vd[0];
|
||||
|
||||
std::string model = dic.get_string("model");
|
||||
|
||||
if (!model.compare("Kunz-JCED-2012"))
|
||||
{
|
||||
F[i][j] = dic.get_number("F");
|
||||
|
||||
std::vector<double> n = dic.get_double_vector("n");
|
||||
std::vector<double> d = dic.get_double_vector("d");
|
||||
std::vector<double> t = dic.get_double_vector("t");
|
||||
// Terms for the gaussian
|
||||
std::vector<double> eta = dic.get_double_vector("eta");
|
||||
std::vector<double> epsilon = dic.get_double_vector("epsilon");
|
||||
std::vector<double> beta = dic.get_double_vector("beta");
|
||||
std::vector<double> gamma = dic.get_double_vector("gamma");
|
||||
int Npower = static_cast<int>(dic.get_number("Npower"));
|
||||
DepartureFunctionMatrix[i][j].reset(new GERG2008DepartureFunction(n,d,t,eta,epsilon,beta,gamma,Npower));
|
||||
}
|
||||
else if (!model.compare("Lemmon-JPCRD-2004") || !model.compare("Lemmon-JPCRD-2000"))
|
||||
{
|
||||
throw NotImplementedError();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ValueError();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExcessTerm::~ExcessTerm()
|
||||
{
|
||||
}
|
||||
double ExcessTerm::alphar(double tau, double delta, const std::vector<long double> &x)
|
||||
{
|
||||
double summer = 0;
|
||||
@@ -283,7 +129,6 @@ GERG2008DepartureFunction::GERG2008DepartureFunction(const std::vector<double> &
|
||||
const std::vector<double> &eta,const std::vector<double> &epsilon,const std::vector<double> &beta,
|
||||
const std::vector<double> &gamma, unsigned int Npower)
|
||||
{
|
||||
|
||||
/// Break up into power and gaussian terms
|
||||
{
|
||||
std::vector<long double> _n(n.begin(), n.begin()+Npower);
|
||||
|
||||
@@ -10,60 +10,11 @@ namespace CoolProp{
|
||||
|
||||
typedef std::vector<std::vector<long double> > STLMatrix;
|
||||
|
||||
|
||||
/// A container for the mixing parameters for CoolProp mixtures
|
||||
/**
|
||||
|
||||
*/
|
||||
class MixtureExcessHELibrary
|
||||
{
|
||||
public:
|
||||
/// Map from sorted pair of CAS numbers to excess term dictionary.
|
||||
std::map<std::vector<std::string>, std::vector<Dictionary> > excess_map;
|
||||
MixtureExcessHELibrary();
|
||||
|
||||
/// Parse a term from GERG 2008
|
||||
void parse_Kunz_JCED_2012(Dictionary &d, rapidjson::Value &val, int i)
|
||||
{
|
||||
assert(val.HasMember("F"));
|
||||
if (val["F"].IsDouble())
|
||||
{
|
||||
d.add_number("F",val["F"].GetDouble());
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<double> F = cpjson::get_double_array(val["F"]);
|
||||
assert(static_cast<std::size_t>(i) < F.size());
|
||||
d.add_number("F", F[i]);
|
||||
}
|
||||
d.add_number("Npower", cpjson::get_double(val,"Npower"));
|
||||
|
||||
// Terms for the power
|
||||
d.add_double_vector("n", cpjson::get_double_array(val["n"]));
|
||||
d.add_double_vector("d", cpjson::get_double_array(val["d"]));
|
||||
d.add_double_vector("t", cpjson::get_double_array(val["t"]));
|
||||
// Terms for the gaussian
|
||||
d.add_double_vector("eta", cpjson::get_double_array(val["eta"]));
|
||||
d.add_double_vector("epsilon", cpjson::get_double_array(val["epsilon"]));
|
||||
d.add_double_vector("beta", cpjson::get_double_array(val["beta"]));
|
||||
d.add_double_vector("gamma", cpjson::get_double_array(val["gamma"]));
|
||||
|
||||
};
|
||||
|
||||
/// Parse a term from HFC mixtures
|
||||
void parse_Lemmon_JPCRD_2004(Dictionary &d, rapidjson::Value &val)
|
||||
{
|
||||
};
|
||||
|
||||
/// Parse a term from Air
|
||||
void parse_Lemmon_JPCRD_2000(Dictionary &d, rapidjson::Value &val)
|
||||
{
|
||||
};
|
||||
};
|
||||
|
||||
/*!
|
||||
The abstract base class for departure functions for the excess part of the Helmholtz energy
|
||||
*/
|
||||
/** \brief The abstract base class for departure functions used in the excess part of the Helmholtz energy
|
||||
*
|
||||
* The only code included in the ABC is the structure for the derivatives of the Helmholtz energy with
|
||||
* the reduced density and reciprocal reduced temperature
|
||||
*/
|
||||
class DepartureFunction
|
||||
{
|
||||
public:
|
||||
@@ -80,31 +31,14 @@ public:
|
||||
virtual double d2alphar_dTau2(double tau, double delta) = 0;
|
||||
};
|
||||
|
||||
typedef shared_ptr<DepartureFunction> DepartureFunctionPointer;
|
||||
|
||||
class ExcessTerm
|
||||
{
|
||||
public:
|
||||
unsigned int N;
|
||||
std::vector<std::vector<DepartureFunctionPointer> > DepartureFunctionMatrix;
|
||||
std::vector<std::vector<double> > F;
|
||||
|
||||
ExcessTerm(){};
|
||||
void construct(const std::vector<CoolPropFluid*> &components);
|
||||
~ExcessTerm();
|
||||
|
||||
double alphar(double tau, double delta, const std::vector<long double> &x);
|
||||
double dalphar_dDelta(double tau, double delta, const std::vector<long double> &x);
|
||||
double d2alphar_dDelta2(double tau, double delta, const std::vector<long double> &x);
|
||||
double d2alphar_dDelta_dTau(double tau, double delta, const std::vector<long double> &x);
|
||||
double dalphar_dTau(double tau, double delta, const std::vector<long double> &x);
|
||||
double d2alphar_dTau2(double tau, double delta, const std::vector<long double> &x);
|
||||
double dalphar_dxi(double tau, double delta, const std::vector<long double> &x, unsigned int i);
|
||||
double d2alphardxidxj(double tau, double delta, const std::vector<long double> &x, unsigned int i, unsigned int j);
|
||||
double d2alphar_dxi_dTau(double tau, double delta, const std::vector<long double> &x, unsigned int i);
|
||||
double d2alphar_dxi_dDelta(double tau, double delta, const std::vector<long double> &x, unsigned int i);
|
||||
};
|
||||
|
||||
/** \brief The departure function used by the GERG-2008 formulation
|
||||
*
|
||||
* This departure function has a form like
|
||||
* \f[
|
||||
* \alphar^r_{ij} = \sum_k n_{ij,k}\delta^{d_{ij,k}}\tau^{t_{ij,k}} + \sum_k n_{ij,k}\delta^{d_{ij,k}}\tau^{t_{ij,k}}\exp[-\eta_{ij,k}(\delta-\varepsilon_{ij,k})^2-\beta_{ij,k}(\delta-\gamma_{ij,k})]
|
||||
* \f]
|
||||
* It is symmetric so \f$\alphar^r_{ij} = \alphar^r_{ji}\f$
|
||||
*/
|
||||
class GERG2008DepartureFunction : public DepartureFunction
|
||||
{
|
||||
protected:
|
||||
@@ -125,5 +59,72 @@ public:
|
||||
double d2alphar_dTau2(double tau, double delta){return phi.dTau2(tau, delta);};
|
||||
};
|
||||
|
||||
/** \brief A polynomial/exponential departure function
|
||||
*
|
||||
* This departure function has a form like
|
||||
* \f[
|
||||
* \alpha^r_{ij} = \sum_k n_{ij,k}\delta^{d_{ij,k}}\tau^{t_{ij,k}}\exp(-\delta^{l_{ij,k}})
|
||||
* \f]
|
||||
* It is symmetric so \f$\alphar^r_{ij} = \alphar^r_{ji}\f$
|
||||
*/
|
||||
class ExponentialDepartureFunction : public DepartureFunction
|
||||
{
|
||||
protected:
|
||||
ResidualHelmholtzGeneralizedExponential phi;
|
||||
public:
|
||||
ExponentialDepartureFunction(){};
|
||||
ExponentialDepartureFunction(const std::vector<double> &n, const std::vector<double> &d,
|
||||
const std::vector<double> &t, const std::vector<double> &l)
|
||||
{
|
||||
std::vector<long double> _n(n.begin(), n.begin()+n.size());
|
||||
std::vector<long double> _d(d.begin(), d.begin()+d.size());
|
||||
std::vector<long double> _t(t.begin(), t.begin()+t.size());
|
||||
std::vector<long double> _l(l.begin(), l.begin()+l.size());
|
||||
phi.add_Power(_n, _d, _t, _l);
|
||||
};
|
||||
~ExponentialDepartureFunction(){};
|
||||
|
||||
double alphar(double tau, double delta){return phi.base(tau, delta);};
|
||||
double dalphar_dDelta(double tau, double delta){return phi.dDelta(tau, delta);};
|
||||
double d2alphar_dDelta_dTau(double tau, double delta){return phi.dDelta_dTau(tau, delta);};
|
||||
double dalphar_dTau(double tau, double delta){return phi.dTau(tau, delta);};
|
||||
double d2alphar_dDelta2(double tau, double delta){return phi.dDelta2(tau, delta);};
|
||||
double d2alphar_dTau2(double tau, double delta){return phi.dTau2(tau, delta);};
|
||||
};
|
||||
|
||||
typedef shared_ptr<DepartureFunction> DepartureFunctionPointer;
|
||||
|
||||
class ExcessTerm
|
||||
{
|
||||
public:
|
||||
unsigned int N;
|
||||
std::vector<std::vector<DepartureFunctionPointer> > DepartureFunctionMatrix;
|
||||
std::vector<std::vector<long double> > F;
|
||||
|
||||
ExcessTerm(){};
|
||||
~ExcessTerm(){};
|
||||
|
||||
/// Resize the parts of this term
|
||||
void resize(std::size_t N){
|
||||
this->N = N;
|
||||
F.resize(N, std::vector<long double>(N, 0));
|
||||
DepartureFunctionMatrix.resize(N);
|
||||
for (std::size_t i = 0; i < N; ++i){
|
||||
DepartureFunctionMatrix[i].resize(N);
|
||||
}
|
||||
};
|
||||
|
||||
double alphar(double tau, double delta, const std::vector<long double> &x);
|
||||
double dalphar_dDelta(double tau, double delta, const std::vector<long double> &x);
|
||||
double d2alphar_dDelta2(double tau, double delta, const std::vector<long double> &x);
|
||||
double d2alphar_dDelta_dTau(double tau, double delta, const std::vector<long double> &x);
|
||||
double dalphar_dTau(double tau, double delta, const std::vector<long double> &x);
|
||||
double d2alphar_dTau2(double tau, double delta, const std::vector<long double> &x);
|
||||
double dalphar_dxi(double tau, double delta, const std::vector<long double> &x, unsigned int i);
|
||||
double d2alphardxidxj(double tau, double delta, const std::vector<long double> &x, unsigned int i, unsigned int j);
|
||||
double d2alphar_dxi_dTau(double tau, double delta, const std::vector<long double> &x, unsigned int i);
|
||||
double d2alphar_dxi_dDelta(double tau, double delta, const std::vector<long double> &x, unsigned int i);
|
||||
};
|
||||
|
||||
} /* namespace CoolProp */
|
||||
#endif
|
||||
|
||||
@@ -66,7 +66,7 @@ void FlashRoutines::QT_flash(HelmholtzEOSMixtureBackend &HEOS)
|
||||
HEOS._p = HEOS.SatL->p();
|
||||
}
|
||||
else if (splines.enabled && HEOS._T > splines.T_min){
|
||||
double rhoL, rhoV;
|
||||
double rhoL = _HUGE, rhoV = _HUGE;
|
||||
// Use critical region spline if it has it and temperature is in its range
|
||||
splines.get_densities(T, splines.rhomolar_min, HEOS.rhomolar_critical(), splines.rhomolar_max, rhoL, rhoV);
|
||||
HEOS.SatL->update(DmolarT_INPUTS, rhoL, HEOS._T);
|
||||
@@ -114,7 +114,7 @@ void FlashRoutines::QT_flash(HelmholtzEOSMixtureBackend &HEOS)
|
||||
}
|
||||
else{
|
||||
// Pseudo-pure fluid
|
||||
long double rhoLanc, rhoVanc, rhoLsat, rhoVsat;
|
||||
long double rhoLanc = _HUGE, rhoVanc = _HUGE, rhoLsat = _HUGE, rhoVsat = _HUGE;
|
||||
long double psatLanc = HEOS.components[0]->ancillaries.pL.evaluate(HEOS._T); // These ancillaries are used explicitly
|
||||
long double psatVanc = HEOS.components[0]->ancillaries.pV.evaluate(HEOS._T); // These ancillaries are used explicitly
|
||||
try{
|
||||
@@ -454,7 +454,7 @@ void FlashRoutines::PHSU_D_flash(HelmholtzEOSMixtureBackend &HEOS, int other)
|
||||
void FlashRoutines::HSU_P_flash_singlephase_Newton(HelmholtzEOSMixtureBackend &HEOS, int other, long double T0, long double rhomolar0)
|
||||
{
|
||||
double A[2][2], B[2][2];
|
||||
long double y;
|
||||
long double y = _HUGE;
|
||||
HelmholtzEOSMixtureBackend _HEOS(HEOS.get_components());
|
||||
_HEOS.update(DmolarT_INPUTS, rhomolar0, T0);
|
||||
long double Tc = HEOS.calc_T_critical();
|
||||
@@ -465,6 +465,7 @@ void FlashRoutines::HSU_P_flash_singlephase_Newton(HelmholtzEOSMixtureBackend &H
|
||||
{
|
||||
case iHmolar: y = HEOS.hmolar(); break;
|
||||
case iSmolar: y = HEOS.smolar(); break;
|
||||
default: throw ValueError("other is invalid in HSU_P_flash_singlephase_Newton");
|
||||
}
|
||||
|
||||
long double worst_error = 999;
|
||||
@@ -602,7 +603,7 @@ void FlashRoutines::HSU_P_flash_singlephase_Brent(HelmholtzEOSMixtureBackend &HE
|
||||
|
||||
std::string errstr;
|
||||
try{
|
||||
double T = Brent(resid, Tmin, Tmax, DBL_EPSILON, 1e-12, 100, errstr);
|
||||
Brent(resid, Tmin, Tmax, DBL_EPSILON, 1e-12, 100, errstr);
|
||||
// Un-specify the phase of the fluid
|
||||
HEOS.unspecify_phase();
|
||||
}
|
||||
@@ -621,8 +622,6 @@ void FlashRoutines::HSU_P_flash_singlephase_Brent(HelmholtzEOSMixtureBackend &HE
|
||||
}
|
||||
throw;
|
||||
}
|
||||
|
||||
int rr = 4;
|
||||
}
|
||||
|
||||
// P given and one of H, S, or U
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
#include "TransportRoutines.h"
|
||||
#include "MixtureDerivatives.h"
|
||||
#include "PhaseEnvelopeRoutines.h"
|
||||
#include "ReducingFunctions.h"
|
||||
#include "MixtureParameters.h"
|
||||
|
||||
static int deriv_counter = 0;
|
||||
|
||||
@@ -73,9 +75,8 @@ void HelmholtzEOSMixtureBackend::set_components(std::vector<CoolPropFluid*> comp
|
||||
// Set the excess Helmholtz energy if a mixture
|
||||
if (!is_pure_or_pseudopure)
|
||||
{
|
||||
// Set the reducing model
|
||||
set_reducing_function();
|
||||
set_excess_term();
|
||||
// Set the mixture parameters - binary pair reducing functions, departure functions, F_ij, etc.
|
||||
set_mixture_parameters();
|
||||
}
|
||||
|
||||
imposed_phase_index = iphase_not_imposed;
|
||||
@@ -117,13 +118,10 @@ void HelmholtzEOSMixtureBackend::calc_phase_envelope(const std::string &type)
|
||||
{
|
||||
PhaseEnvelopeRoutines::build(*this);
|
||||
};
|
||||
void HelmholtzEOSMixtureBackend::set_reducing_function()
|
||||
void HelmholtzEOSMixtureBackend::set_mixture_parameters()
|
||||
{
|
||||
Reducing.set(ReducingFunction::factory(components));
|
||||
}
|
||||
void HelmholtzEOSMixtureBackend::set_excess_term()
|
||||
{
|
||||
Excess.construct(components);
|
||||
// Build the matrix of binary-pair reducing functions
|
||||
MixtureParameters::set_mixture_parameters(*this);
|
||||
}
|
||||
void HelmholtzEOSMixtureBackend::update_states(void)
|
||||
{
|
||||
@@ -1335,7 +1333,6 @@ void get_dT_drho_second_derivatives(HelmholtzEOSMixtureBackend *HEOS, int index,
|
||||
rho = HEOS->rhomolar(),
|
||||
rhor = HEOS->get_reducing_state().rhomolar,
|
||||
Tr = HEOS->get_reducing_state().T,
|
||||
dT_dtau = -pow(T, 2)/Tr,
|
||||
R = HEOS->gas_constant(),
|
||||
delta = rho/rhor,
|
||||
tau = Tr/T;
|
||||
@@ -1606,6 +1603,9 @@ long double HelmholtzEOSMixtureBackend::solver_for_rho_given_T_oneof_HSU(long do
|
||||
throw ValueError();
|
||||
}
|
||||
}
|
||||
else{
|
||||
throw ValueError(format("phase to solver_for_rho_given_T_oneof_HSU is invalid"));
|
||||
}
|
||||
}
|
||||
long double HelmholtzEOSMixtureBackend::solver_rho_Tp(long double T, long double p, long double rhomolar_guess)
|
||||
{
|
||||
@@ -2038,8 +2038,8 @@ SimpleState HelmholtzEOSMixtureBackend::calc_reducing_state_nocache(const std::v
|
||||
|
||||
}
|
||||
else{
|
||||
reducing.T = Reducing.p->Tr(mole_fractions);
|
||||
reducing.rhomolar = Reducing.p->rhormolar(mole_fractions);
|
||||
reducing.T = Reducing->Tr(mole_fractions);
|
||||
reducing.rhomolar = Reducing->rhormolar(mole_fractions);
|
||||
}
|
||||
return reducing;
|
||||
}
|
||||
|
||||
@@ -30,14 +30,15 @@ protected:
|
||||
|
||||
SimpleState _crit;
|
||||
phases imposed_phase_index;
|
||||
int N; ///< Number of components
|
||||
std::size_t N; ///< Number of components
|
||||
|
||||
public:
|
||||
HelmholtzEOSMixtureBackend(){imposed_phase_index = iphase_not_imposed; _phase = iphase_unknown;};
|
||||
HelmholtzEOSMixtureBackend(){
|
||||
imposed_phase_index = iphase_not_imposed; _phase = iphase_unknown;};
|
||||
HelmholtzEOSMixtureBackend(std::vector<CoolPropFluid*> components, bool generate_SatL_and_SatV = true);
|
||||
HelmholtzEOSMixtureBackend(std::vector<std::string> &component_names, bool generate_SatL_and_SatV = true);
|
||||
virtual ~HelmholtzEOSMixtureBackend(){};
|
||||
ReducingFunctionContainer Reducing;
|
||||
shared_ptr<ReducingFunction> Reducing;
|
||||
ExcessTerm Excess;
|
||||
PhaseEnvelopeData PhaseEnvelope;
|
||||
|
||||
@@ -45,6 +46,7 @@ public:
|
||||
friend class TransportRoutines; // Allows the static methods in the TransportRoutines class to have access to all the protected members and methods of this class
|
||||
friend class MixtureDerivatives; // Allows the static methods in the MixtureDerivatives class to have access to all the protected members and methods of this class
|
||||
friend class PhaseEnvelopeRoutines; // Allows the static methods in the PhaseEnvelopeRoutines class to have access to all the protected members and methods of this class
|
||||
friend class MixtureParameters; // Allows the static methods in the MixtureParameters class to have access to all the protected members and methods of this class
|
||||
|
||||
// Helmholtz EOS backend uses mole fractions
|
||||
bool using_mole_fractions(){return true;}
|
||||
@@ -70,40 +72,40 @@ public:
|
||||
void update_TP_guessrho(long double T, long double p, long double rho_guess);
|
||||
void update_DmolarT_direct(long double rhomolar, long double T);
|
||||
|
||||
/// Set the components of the mixture
|
||||
/**
|
||||
@param components The components that are to be used in this mixture
|
||||
@param generate_SatL_and_SatV true if SatL and SatV classes should be added, false otherwise. Added so that saturation classes can be added without infinite recursion of adding saturation classes
|
||||
*/
|
||||
/** \brief Set the components of the mixture
|
||||
*
|
||||
* @param components The components that are to be used in this mixture
|
||||
* @param generate_SatL_and_SatV true if SatL and SatV classes should be added, false otherwise. Added so that saturation classes can be added without infinite recursion of adding saturation classes
|
||||
*/
|
||||
void set_components(std::vector<CoolPropFluid*> components, bool generate_SatL_and_SatV = true);
|
||||
|
||||
/**
|
||||
\brief Specify the phase - this phase will always be used in calculations
|
||||
@param phase_index The index from CoolProp::phases
|
||||
*/
|
||||
/** \brief Specify the phase - this phase will always be used in calculations
|
||||
*
|
||||
* @param phase_index The index from CoolProp::phases
|
||||
*/
|
||||
void specify_phase(phases phase_index){imposed_phase_index = phase_index; _phase = phase_index;};
|
||||
|
||||
/**
|
||||
\brief Unspecify the phase - the phase is no longer imposed, different solvers can do as they like
|
||||
*/
|
||||
/**\brief Unspecify the phase - the phase is no longer imposed, different solvers can do as they like
|
||||
*/
|
||||
void unspecify_phase(){imposed_phase_index = iphase_not_imposed;};
|
||||
|
||||
void set_reducing_function();
|
||||
void set_excess_term();
|
||||
/** \brief Set the mixture parameters - binary pair reducing functions, departure functions, F_ij, etc.
|
||||
*/
|
||||
void set_mixture_parameters();
|
||||
|
||||
/// Set the mole fractions
|
||||
/**
|
||||
@param mole_fractions The vector of mole fractions of the components
|
||||
*/
|
||||
/** \brief Set the mole fractions
|
||||
*
|
||||
* @param mole_fractions The vector of mole fractions of the components
|
||||
*/
|
||||
void set_mole_fractions(const std::vector<long double> &mole_fractions);
|
||||
|
||||
std::vector<long double> &get_mole_fractions(){return mole_fractions;};
|
||||
const std::vector<long double> &get_const_mole_fractions(){return mole_fractions;};
|
||||
|
||||
/// Set the mass fractions
|
||||
/**
|
||||
@param mass_fractions The vector of mass fractions of the components
|
||||
*/
|
||||
/** \brief Set the mass fractions
|
||||
*
|
||||
* @param mass_fractions The vector of mass fractions of the components
|
||||
*/
|
||||
void set_mass_fractions(const std::vector<long double> &mass_fractions){throw std::exception();};
|
||||
|
||||
long double calc_molar_mass(void);
|
||||
|
||||
@@ -151,10 +151,10 @@ long double MixtureDerivatives::dln_fugacity_i_ddelta__consttau_x(HelmholtzEOSMi
|
||||
}
|
||||
long double MixtureDerivatives::dln_fugacity_dxj__constT_rho_xi(HelmholtzEOSMixtureBackend &HEOS, std::size_t i, std::size_t j, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
long double rhor = HEOS.Reducing.p->rhormolar(HEOS.get_const_mole_fractions());
|
||||
long double Tr = HEOS.Reducing.p->Tr(HEOS.get_const_mole_fractions());
|
||||
long double dTrdxj = HEOS.Reducing.p->dTrdxi__constxj(HEOS.get_const_mole_fractions(),j,xN_flag);
|
||||
long double drhordxj = HEOS.Reducing.p->drhormolardxi__constxj(HEOS.get_const_mole_fractions(),j,xN_flag);
|
||||
long double rhor = HEOS.Reducing->rhormolar(HEOS.get_const_mole_fractions());
|
||||
long double Tr = HEOS.Reducing->Tr(HEOS.get_const_mole_fractions());
|
||||
long double dTrdxj = HEOS.Reducing->dTrdxi__constxj(HEOS.get_const_mole_fractions(),j,xN_flag);
|
||||
long double drhordxj = HEOS.Reducing->drhormolardxi__constxj(HEOS.get_const_mole_fractions(),j,xN_flag);
|
||||
|
||||
// These lines are all the same
|
||||
long double line1 = dln_fugacity_i_dtau__constdelta_x(HEOS, i, xN_flag)*1/HEOS.T()*dTrdxj;
|
||||
@@ -165,7 +165,7 @@ long double MixtureDerivatives::dln_fugacity_dxj__constT_rho_xi(HelmholtzEOSMixt
|
||||
std::size_t N = x.size();
|
||||
|
||||
// This is a term to which some more might be added depending on i and j
|
||||
long double line3 = 1/rhor*HEOS.Reducing.p->drhormolardxi__constxj(x, j, xN_flag) + 1/Tr*HEOS.Reducing.p->dTrdxi__constxj(x, j, xN_flag);
|
||||
long double line3 = 1/rhor*HEOS.Reducing->drhormolardxi__constxj(x, j, xN_flag) + 1/Tr*HEOS.Reducing->dTrdxi__constxj(x, j, xN_flag);
|
||||
|
||||
if (i == N-1){
|
||||
line3 += -1/x[N-1];
|
||||
@@ -213,12 +213,12 @@ long double MixtureDerivatives::d_ndalphardni_dxj__constT_V_xi(HelmholtzEOSMixtu
|
||||
long double MixtureDerivatives::ddelta_dxj__constT_V_xi(HelmholtzEOSMixtureBackend &HEOS, std::size_t j, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
// Gernert 3.121 (Catch test provided)
|
||||
return -HEOS._delta.pt()/HEOS._reducing.rhomolar*HEOS.Reducing.p->drhormolardxi__constxj(HEOS.mole_fractions,j, xN_flag);
|
||||
return -HEOS._delta.pt()/HEOS._reducing.rhomolar*HEOS.Reducing->drhormolardxi__constxj(HEOS.mole_fractions,j, xN_flag);
|
||||
}
|
||||
long double MixtureDerivatives::dtau_dxj__constT_V_xi(HelmholtzEOSMixtureBackend &HEOS, std::size_t j, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
// Gernert 3.122 (Catch test provided)
|
||||
return 1/HEOS._T*HEOS.Reducing.p->dTrdxi__constxj(HEOS.mole_fractions,j, xN_flag);
|
||||
return 1/HEOS._T*HEOS.Reducing->dTrdxi__constxj(HEOS.mole_fractions,j, xN_flag);
|
||||
}
|
||||
|
||||
long double MixtureDerivatives::dpdT__constV_n(HelmholtzEOSMixtureBackend &HEOS)
|
||||
@@ -240,8 +240,8 @@ long double MixtureDerivatives::ndpdni__constT_V_nj(HelmholtzEOSMixtureBackend &
|
||||
{
|
||||
// Eqn 7.64 and 7.63
|
||||
long double R_u = HEOS.gas_constant();
|
||||
double ndrhorbar_dni__constnj = HEOS.Reducing.p->ndrhorbardni__constnj(HEOS.mole_fractions,i, xN_flag);
|
||||
double ndTr_dni__constnj = HEOS.Reducing.p->ndTrdni__constnj(HEOS.mole_fractions,i, xN_flag);
|
||||
double ndrhorbar_dni__constnj = HEOS.Reducing->ndrhorbardni__constnj(HEOS.mole_fractions,i, xN_flag);
|
||||
double ndTr_dni__constnj = HEOS.Reducing->ndTrdni__constnj(HEOS.mole_fractions,i, xN_flag);
|
||||
double summer = 0;
|
||||
std::size_t kmax = HEOS.mole_fractions.size();
|
||||
if (xN_flag == XN_DEPENDENT){ kmax--; }
|
||||
@@ -255,8 +255,8 @@ long double MixtureDerivatives::ndpdni__constT_V_nj(HelmholtzEOSMixtureBackend &
|
||||
|
||||
long double MixtureDerivatives::ndalphar_dni__constT_V_nj(HelmholtzEOSMixtureBackend &HEOS, std::size_t i, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
double term1 = HEOS._delta.pt()*HEOS.dalphar_dDelta()*(1-1/HEOS._reducing.rhomolar*HEOS.Reducing.p->ndrhorbardni__constnj(HEOS.mole_fractions,i, xN_flag));
|
||||
double term2 = HEOS._tau.pt()*HEOS.dalphar_dTau()*(1/HEOS._reducing.T)*HEOS.Reducing.p->ndTrdni__constnj(HEOS.mole_fractions,i, xN_flag);
|
||||
double term1 = HEOS._delta.pt()*HEOS.dalphar_dDelta()*(1-1/HEOS._reducing.rhomolar*HEOS.Reducing->ndrhorbardni__constnj(HEOS.mole_fractions,i, xN_flag));
|
||||
double term2 = HEOS._tau.pt()*HEOS.dalphar_dTau()*(1/HEOS._reducing.T)*HEOS.Reducing->ndTrdni__constnj(HEOS.mole_fractions,i, xN_flag);
|
||||
|
||||
double s = 0;
|
||||
std::size_t kmax = HEOS.mole_fractions.size();
|
||||
@@ -275,18 +275,18 @@ long double MixtureDerivatives::ndln_fugacity_coefficient_dnj__constT_p(Helmholt
|
||||
}
|
||||
long double MixtureDerivatives::nddeltadni__constT_V_nj(HelmholtzEOSMixtureBackend &HEOS, std::size_t i, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
return HEOS._delta.pt()-HEOS._delta.pt()/HEOS._reducing.rhomolar*HEOS.Reducing.p->ndrhorbardni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
return HEOS._delta.pt()-HEOS._delta.pt()/HEOS._reducing.rhomolar*HEOS.Reducing->ndrhorbardni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
}
|
||||
long double MixtureDerivatives::ndtaudni__constT_V_nj(HelmholtzEOSMixtureBackend &HEOS, std::size_t i, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
return HEOS._tau.pt()/HEOS._reducing.T*HEOS.Reducing.p->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
return HEOS._tau.pt()/HEOS._reducing.T*HEOS.Reducing->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
}
|
||||
long double MixtureDerivatives::d_ndalphardni_dxj__constdelta_tau_xi(HelmholtzEOSMixtureBackend &HEOS, std::size_t i, std::size_t j, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
double line1 = HEOS._delta.pt()*d2alphar_dxi_dDelta(HEOS, j, xN_flag)*(1-1/HEOS._reducing.rhomolar*HEOS.Reducing.p->ndrhorbardni__constnj(HEOS.mole_fractions, i, xN_flag));
|
||||
double line3 = HEOS._tau.pt()*d2alphar_dxi_dTau(HEOS, j, xN_flag)*(1/HEOS._reducing.T)*HEOS.Reducing.p->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
double line2 = -HEOS._delta.pt()*HEOS.dalphar_dDelta()*(1/HEOS._reducing.rhomolar)*(HEOS.Reducing.p->d_ndrhorbardni_dxj__constxi(HEOS.mole_fractions, i, j, xN_flag)-1/HEOS._reducing.rhomolar*HEOS.Reducing.p->drhormolardxi__constxj(HEOS.mole_fractions,j, xN_flag)*HEOS.Reducing.p->ndrhorbardni__constnj(HEOS.mole_fractions,i, xN_flag));
|
||||
double line4 = HEOS._tau.pt()*HEOS.dalphar_dTau()*(1/HEOS._reducing.T)*(HEOS.Reducing.p->d_ndTrdni_dxj__constxi(HEOS.mole_fractions,i,j, xN_flag)-1/HEOS._reducing.T*HEOS.Reducing.p->dTrdxi__constxj(HEOS.mole_fractions, j, xN_flag)*HEOS.Reducing.p->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag));
|
||||
double line1 = HEOS._delta.pt()*d2alphar_dxi_dDelta(HEOS, j, xN_flag)*(1-1/HEOS._reducing.rhomolar*HEOS.Reducing->ndrhorbardni__constnj(HEOS.mole_fractions, i, xN_flag));
|
||||
double line3 = HEOS._tau.pt()*d2alphar_dxi_dTau(HEOS, j, xN_flag)*(1/HEOS._reducing.T)*HEOS.Reducing->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
double line2 = -HEOS._delta.pt()*HEOS.dalphar_dDelta()*(1/HEOS._reducing.rhomolar)*(HEOS.Reducing->d_ndrhorbardni_dxj__constxi(HEOS.mole_fractions, i, j, xN_flag)-1/HEOS._reducing.rhomolar*HEOS.Reducing->drhormolardxi__constxj(HEOS.mole_fractions,j, xN_flag)*HEOS.Reducing->ndrhorbardni__constnj(HEOS.mole_fractions,i, xN_flag));
|
||||
double line4 = HEOS._tau.pt()*HEOS.dalphar_dTau()*(1/HEOS._reducing.T)*(HEOS.Reducing->d_ndTrdni_dxj__constxi(HEOS.mole_fractions,i,j, xN_flag)-1/HEOS._reducing.T*HEOS.Reducing->dTrdxi__constxj(HEOS.mole_fractions, j, xN_flag)*HEOS.Reducing->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag));
|
||||
|
||||
double s = 0;
|
||||
std::size_t kmax = HEOS.mole_fractions.size();
|
||||
@@ -316,10 +316,10 @@ long double MixtureDerivatives::nd2nalphardnidnj__constT_V(HelmholtzEOSMixtureBa
|
||||
long double MixtureDerivatives::d_ndalphardni_dDelta(HelmholtzEOSMixtureBackend &HEOS, std::size_t i, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
// The first line
|
||||
double term1 = (HEOS._delta.pt()*HEOS.d2alphar_dDelta2()+HEOS.dalphar_dDelta())*(1-1/HEOS._reducing.rhomolar*HEOS.Reducing.p->ndrhorbardni__constnj(HEOS.mole_fractions, i, xN_flag));
|
||||
double term1 = (HEOS._delta.pt()*HEOS.d2alphar_dDelta2()+HEOS.dalphar_dDelta())*(1-1/HEOS._reducing.rhomolar*HEOS.Reducing->ndrhorbardni__constnj(HEOS.mole_fractions, i, xN_flag));
|
||||
|
||||
// The second line
|
||||
double term2 = HEOS._tau.pt()*HEOS.d2alphar_dDelta_dTau()*(1/HEOS._reducing.T)*HEOS.Reducing.p->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
double term2 = HEOS._tau.pt()*HEOS.d2alphar_dDelta_dTau()*(1/HEOS._reducing.T)*HEOS.Reducing->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
|
||||
// The third line
|
||||
double term3 = d2alphar_dxi_dDelta(HEOS, i, xN_flag);
|
||||
@@ -334,10 +334,10 @@ long double MixtureDerivatives::d_ndalphardni_dDelta(HelmholtzEOSMixtureBackend
|
||||
long double MixtureDerivatives::d_ndalphardni_dTau(HelmholtzEOSMixtureBackend &HEOS, std::size_t i, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
// The first line
|
||||
double term1 = HEOS._delta.pt()*HEOS.d2alphar_dDelta_dTau()*(1-1/HEOS._reducing.rhomolar*HEOS.Reducing.p->ndrhorbardni__constnj(HEOS.mole_fractions, i, xN_flag));
|
||||
double term1 = HEOS._delta.pt()*HEOS.d2alphar_dDelta_dTau()*(1-1/HEOS._reducing.rhomolar*HEOS.Reducing->ndrhorbardni__constnj(HEOS.mole_fractions, i, xN_flag));
|
||||
|
||||
// The second line
|
||||
double term2 = (HEOS._tau.pt()*HEOS.d2alphar_dTau2()+HEOS.dalphar_dTau())*(1/HEOS._reducing.T)*HEOS.Reducing.p->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
double term2 = (HEOS._tau.pt()*HEOS.d2alphar_dTau2()+HEOS.dalphar_dTau())*(1/HEOS._reducing.T)*HEOS.Reducing->ndTrdni__constnj(HEOS.mole_fractions, i, xN_flag);
|
||||
|
||||
// The third line
|
||||
double term3 = d2alphar_dxi_dTau(HEOS, i, xN_flag);
|
||||
@@ -674,21 +674,21 @@ TEST_CASE("Mixture derivative checks", "[mixtures],[mixture_derivs]")
|
||||
rHEOS.update(DmolarT_INPUTS, 300, 300);
|
||||
|
||||
double rho1 = rHEOS.rhomolar();
|
||||
double analytic = rHEOS.Reducing.p->d_ndTrdni_dxj__constxi(rHEOS.get_const_mole_fractions(), i, j, xN_flag);
|
||||
double analytic = rHEOS.Reducing->d_ndTrdni_dxj__constxi(rHEOS.get_const_mole_fractions(), i, j, xN_flag);
|
||||
|
||||
// Increment mole fraction
|
||||
std::vector<long double> zp = z; /// Copy base composition
|
||||
zp[j] += dz; zp[1-j] -= dz;
|
||||
rHEOS.set_mole_fractions(zp);
|
||||
rHEOS.update(DmolarT_INPUTS, rho1, 300);
|
||||
double v1 = rHEOS.Reducing.p->ndTrdni__constnj(rHEOS.get_const_mole_fractions(), i, xN_flag);
|
||||
double v1 = rHEOS.Reducing->ndTrdni__constnj(rHEOS.get_const_mole_fractions(), i, xN_flag);
|
||||
|
||||
// Decrement mole fraction
|
||||
std::vector<long double> zm = z; /// Copy base composition
|
||||
zm[j] -= dz; zm[1-j] += dz;
|
||||
rHEOS.set_mole_fractions(zm);
|
||||
rHEOS.update(DmolarT_INPUTS, rho1, 300);
|
||||
double v2 = rHEOS.Reducing.p->ndTrdni__constnj(rHEOS.get_const_mole_fractions(), i, xN_flag);
|
||||
double v2 = rHEOS.Reducing->ndTrdni__constnj(rHEOS.get_const_mole_fractions(), i, xN_flag);
|
||||
|
||||
double numeric = (v1 - v2)/(2*dz);
|
||||
double err = std::abs((numeric-analytic)/analytic);
|
||||
@@ -707,21 +707,21 @@ TEST_CASE("Mixture derivative checks", "[mixtures],[mixture_derivs]")
|
||||
rHEOS.update(DmolarT_INPUTS, 300, 300);
|
||||
|
||||
double rho1 = rHEOS.rhomolar();
|
||||
double analytic = rHEOS.Reducing.p->d_ndrhorbardni_dxj__constxi(rHEOS.get_const_mole_fractions(), i, j, xN_flag);
|
||||
double analytic = rHEOS.Reducing->d_ndrhorbardni_dxj__constxi(rHEOS.get_const_mole_fractions(), i, j, xN_flag);
|
||||
|
||||
// Increment mole fraction
|
||||
std::vector<long double> zp = z; /// Copy base composition
|
||||
zp[j] += dz; zp[1-j] -= dz;
|
||||
rHEOS.set_mole_fractions(zp);
|
||||
rHEOS.update(DmolarT_INPUTS, rho1, 300);
|
||||
double v1 = rHEOS.Reducing.p->ndrhorbardni__constnj(rHEOS.get_const_mole_fractions(), i, xN_flag);
|
||||
double v1 = rHEOS.Reducing->ndrhorbardni__constnj(rHEOS.get_const_mole_fractions(), i, xN_flag);
|
||||
|
||||
// Decrement mole fraction
|
||||
std::vector<long double> zm = z; /// Copy base composition
|
||||
zm[j] -= dz; zm[1-j] += dz;
|
||||
rHEOS.set_mole_fractions(zm);
|
||||
rHEOS.update(DmolarT_INPUTS, rho1, 300);
|
||||
double v2 = rHEOS.Reducing.p->ndrhorbardni__constnj(rHEOS.get_const_mole_fractions(), i, xN_flag);
|
||||
double v2 = rHEOS.Reducing->ndrhorbardni__constnj(rHEOS.get_const_mole_fractions(), i, xN_flag);
|
||||
|
||||
double numeric = (v1 - v2)/(2*dz);
|
||||
double err = std::abs((numeric-analytic)/analytic);
|
||||
|
||||
294
src/Backends/Helmholtz/MixtureParameters.cpp
Normal file
294
src/Backends/Helmholtz/MixtureParameters.cpp
Normal file
@@ -0,0 +1,294 @@
|
||||
#include "MixtureParameters.h"
|
||||
#include "mixture_departure_functions_JSON.h" // Creates the variable mixture_departure_functions_JSON
|
||||
#include "mixture_binary_pairs_JSON.h" // Creates the variable mixture_binary_pairs_JSON
|
||||
|
||||
namespace CoolProp{
|
||||
|
||||
/** \brief A library of binary pair parameters for the mixture
|
||||
*
|
||||
* Each entry in the binary pair library includes reducing parameters as well as the name of the reducing function to be used and
|
||||
*/
|
||||
class MixtureBinaryPairLibrary{
|
||||
public:
|
||||
/// Map from sorted pair of CAS numbers to reducing parameter map. The reducing parameter map is a map from key (string) to value (double)
|
||||
std::map< std::vector<std::string>, std::vector<Dictionary> > binary_pair_map;
|
||||
|
||||
/** \brief Construct the binary pair library including all the binary pairs that are possible
|
||||
*
|
||||
* The data structure also includes space for a string that gives the pointer to the departure function to be used for this binary pair. *
|
||||
*/
|
||||
MixtureBinaryPairLibrary()
|
||||
{
|
||||
rapidjson::Document doc;
|
||||
|
||||
doc.Parse<0>(mixture_binary_pairs_JSON.c_str());
|
||||
if (doc.HasParseError()){throw ValueError();}
|
||||
|
||||
// Iterate over the papers in the listing
|
||||
for (rapidjson::Value::ValueIterator itr = doc.Begin(); itr != doc.End(); ++itr)
|
||||
{
|
||||
// Get the empty dictionary to be filled by the appropriate reducing parameter filling function
|
||||
Dictionary dict;
|
||||
|
||||
// Get the vector of CAS numbers
|
||||
std::vector<std::string> CAS;
|
||||
CAS.push_back(cpjson::get_string(*itr, "CAS1"));
|
||||
CAS.push_back(cpjson::get_string(*itr, "CAS2"));
|
||||
std::string name1 = cpjson::get_string(*itr, "Name1");
|
||||
std::string name2 = cpjson::get_string(*itr, "Name2");
|
||||
|
||||
// Sort the CAS number vector
|
||||
std::sort(CAS.begin(), CAS.end());
|
||||
|
||||
// A sort was carried out, names/CAS were swapped
|
||||
bool swapped = CAS[0].compare(cpjson::get_string(*itr, "CAS1")) != 0;
|
||||
|
||||
if (swapped){ std::swap(name1, name2); }
|
||||
|
||||
// Populate the dictionary with common terms
|
||||
dict.add_string("name1", name1);
|
||||
dict.add_string("name2", name2);
|
||||
dict.add_string("BibTeX", cpjson::get_string(*itr, "BibTeX"));
|
||||
dict.add_number("F", cpjson::get_double(*itr, "F"));
|
||||
if (std::abs(dict.get_number("F")) > DBL_EPSILON){
|
||||
dict.add_string("function", cpjson::get_string(*itr, "function"));
|
||||
}
|
||||
|
||||
if (itr->HasMember("xi") && itr->HasMember("zeta")){
|
||||
dict.add_string("type","Lemmon-xi-zeta");
|
||||
// Air and HFC mixtures from Lemmon - we could also directly do the conversion
|
||||
dict.add_number("xi", cpjson::get_double(*itr, "xi"));
|
||||
dict.add_number("zeta", cpjson::get_double(*itr, "zeta"));
|
||||
}
|
||||
else if (itr->HasMember("gammaT") && itr->HasMember("gammaV") && itr->HasMember("betaT") && itr->HasMember("betaV")){
|
||||
dict.add_string("type","GERG-2008");
|
||||
dict.add_number("gammaV", cpjson::get_double(*itr, "gammaV"));
|
||||
dict.add_number("gammaT", cpjson::get_double(*itr, "gammaT"));
|
||||
|
||||
double betaV = cpjson::get_double(*itr, "betaV");
|
||||
double betaT = cpjson::get_double(*itr, "betaT");
|
||||
if (swapped){
|
||||
dict.add_number("betaV", 1/betaV);
|
||||
dict.add_number("betaT", 1/betaT);
|
||||
}
|
||||
else{
|
||||
dict.add_number("betaV", betaV);
|
||||
dict.add_number("betaT", betaT);
|
||||
}
|
||||
}
|
||||
else{ throw ValueError(); }
|
||||
|
||||
if (binary_pair_map.find(CAS) == binary_pair_map.end()){
|
||||
// Add to binary pair map by creating one-element vector
|
||||
binary_pair_map.insert(std::pair<std::vector<std::string>, std::vector<Dictionary> >(CAS, std::vector<Dictionary>(1, dict)));
|
||||
}
|
||||
else
|
||||
{
|
||||
binary_pair_map[CAS].push_back(dict);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
static MixtureBinaryPairLibrary mixturebinarypairlibrary;
|
||||
|
||||
std::string get_reducing_function_name(std::string CAS1, std::string CAS2)
|
||||
{
|
||||
std::vector<std::string> CAS;
|
||||
CAS.push_back(CAS1);
|
||||
CAS.push_back(CAS2);
|
||||
|
||||
// Sort the CAS number vector - map is based on sorted CAS codes
|
||||
std::sort(CAS.begin(), CAS.end());
|
||||
|
||||
if (mixturebinarypairlibrary.binary_pair_map.find(CAS) != mixturebinarypairlibrary.binary_pair_map.end()){
|
||||
return mixturebinarypairlibrary.binary_pair_map.at(CAS)[0].get_string("function");
|
||||
}
|
||||
else{
|
||||
throw ValueError(format("Could not match the binary pair [%s,%s] - for now this is an error.",CAS1.c_str(), CAS2.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief A container for the departure functions for CoolProp mixtures
|
||||
*/
|
||||
class MixtureDepartureFunctionsLibrary{
|
||||
public:
|
||||
/// Map from sorted pair of CAS numbers to departure term dictionary.
|
||||
std::map<std::string, Dictionary> departure_function_map;
|
||||
|
||||
MixtureDepartureFunctionsLibrary()
|
||||
{
|
||||
rapidjson::Document doc;
|
||||
|
||||
// Load the JSON data for the departure functions
|
||||
doc.Parse<0>(mixture_departure_functions_JSON.c_str());
|
||||
if (doc.HasParseError()){
|
||||
std::cout << mixture_departure_functions_JSON << std::endl ;
|
||||
throw ValueError("Unable to parse mixture_departure_functions_JSON.h");
|
||||
}
|
||||
|
||||
// Iterate over the departure functions in the listing
|
||||
for (rapidjson::Value::ValueIterator itr = doc.Begin(); itr != doc.End(); ++itr)
|
||||
{
|
||||
// Get the empty dictionary to be filled in
|
||||
Dictionary dict;
|
||||
|
||||
// Populate the dictionary with common terms
|
||||
std::string Name = cpjson::get_string(*itr, "Name");
|
||||
std::string type = cpjson::get_string(*itr, "type");
|
||||
dict.add_string("Name", Name);
|
||||
dict.add_string("BibTeX", cpjson::get_string(*itr, "BibTeX"));
|
||||
dict.add_string_vector("aliases", cpjson::get_string_array(*itr, "aliases"));
|
||||
dict.add_string("type", type);
|
||||
|
||||
// Terms for the power (common to both types)
|
||||
dict.add_double_vector("n", cpjson::get_double_array(*itr, "n"));
|
||||
dict.add_double_vector("d", cpjson::get_double_array(*itr, "d"));
|
||||
dict.add_double_vector("t", cpjson::get_double_array(*itr, "t"));
|
||||
|
||||
// Now we need to load additional terms
|
||||
if (!type.compare("GERG-2008")){
|
||||
// Number of terms that are power terms
|
||||
dict.add_number("Npower", cpjson::get_double(*itr, "Npower"));
|
||||
// Terms for the gaussian
|
||||
dict.add_double_vector("eta", cpjson::get_double_array(*itr, "eta"));
|
||||
dict.add_double_vector("epsilon", cpjson::get_double_array(*itr, "epsilon"));
|
||||
dict.add_double_vector("beta", cpjson::get_double_array(*itr, "beta"));
|
||||
dict.add_double_vector("gamma", cpjson::get_double_array(*itr, "gamma"));
|
||||
}
|
||||
else if (!type.compare("Exponential")){
|
||||
dict.add_double_vector("l", cpjson::get_double_array(*itr, "l"));
|
||||
}
|
||||
else{
|
||||
throw ValueError(format("It was not possible to parse departure function with type [%s]", type.c_str()));
|
||||
}
|
||||
|
||||
// Check if this name is already in use
|
||||
if (departure_function_map.find(Name) == departure_function_map.end())
|
||||
{
|
||||
// Not in map, add new entry to map with dictionary as value and Name as key
|
||||
departure_function_map.insert(std::pair<std::string, Dictionary>(Name, dict));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Error if already in map!
|
||||
//
|
||||
// Collect all the current names for departure functions for a nicer error message
|
||||
std::vector<std::string> names;
|
||||
for (std::map<std::string, Dictionary>::iterator it = departure_function_map.begin(); it != departure_function_map.end(); ++it)
|
||||
{
|
||||
names.push_back(it->first);
|
||||
}
|
||||
throw ValueError(format("Name of departure function [%s] is already loaded. Current departure function names are: %s", Name.c_str(), strjoin(names,",").c_str() ));
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
static MixtureDepartureFunctionsLibrary mixturedeparturefunctionslibrary;
|
||||
|
||||
void MixtureParameters::set_mixture_parameters(HelmholtzEOSMixtureBackend &HEOS)
|
||||
{
|
||||
std::vector<CoolPropFluid*> components = HEOS.get_components();
|
||||
|
||||
std::size_t N = components.size();
|
||||
|
||||
STLMatrix beta_v, gamma_v, beta_T, gamma_T;
|
||||
beta_v.resize(N, std::vector<long double>(N, 0));
|
||||
gamma_v.resize(N, std::vector<long double>(N, 0));
|
||||
beta_T.resize(N, std::vector<long double>(N, 0));
|
||||
gamma_T.resize(N, std::vector<long double>(N, 0));
|
||||
|
||||
HEOS.Excess.resize(N);
|
||||
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
for (std::size_t j = 0; j < N; ++j)
|
||||
{
|
||||
if (i == j){ continue; }
|
||||
|
||||
std::string CAS1 = components[i]->CAS;
|
||||
std::vector<std::string> CAS(2,"");
|
||||
CAS[0] = components[i]->CAS;
|
||||
CAS[1] = components[j]->CAS;
|
||||
std::sort(CAS.begin(), CAS.end());
|
||||
|
||||
// The variable swapped is true if a swap occured.
|
||||
bool swapped = (CAS1.compare(CAS[0]) != 0);
|
||||
|
||||
// ***************************************************
|
||||
// Reducing parameters for binary pair
|
||||
// ***************************************************
|
||||
|
||||
// Get a reference to the first matching binary pair in the dictionary
|
||||
Dictionary &dict_red = mixturebinarypairlibrary.binary_pair_map[CAS][0];
|
||||
|
||||
// Get the name of the type being used, one of GERG-2008, Lemmon-xi-zeta, etc.
|
||||
std::string type_red = dict_red.get_string("type");
|
||||
|
||||
if (!type_red.compare("GERG-2008")){
|
||||
if (swapped){
|
||||
beta_v[i][j] = 1/dict_red.get_number("betaV");
|
||||
beta_T[i][j] = 1/dict_red.get_number("betaT");
|
||||
}
|
||||
else{
|
||||
beta_v[i][j] = dict_red.get_number("betaV");
|
||||
beta_T[i][j] = dict_red.get_number("betaT");
|
||||
}
|
||||
gamma_v[i][j] = dict_red.get_number("gammaV");
|
||||
gamma_T[i][j] = dict_red.get_number("gammaT");
|
||||
}
|
||||
else if (!type_red.compare("Lemmon-xi-zeta")){
|
||||
LemmonAirHFCReducingFunction::convert_to_GERG(components,i,j,dict_red,beta_T[i][j],beta_v[i][j],gamma_T[i][j],gamma_v[i][j]);
|
||||
}
|
||||
else{
|
||||
throw ValueError(format("type [%s] for reducing function for pair [%s, %s] is invalid", type_red.c_str(),
|
||||
dict_red.get_string("Name1").c_str(),
|
||||
dict_red.get_string("Name2").c_str() ));
|
||||
}
|
||||
|
||||
// ***************************************************
|
||||
// Departure functions used in excess term
|
||||
// ***************************************************
|
||||
|
||||
// Get the name of the departure function to be used for this binary pair
|
||||
std::string Name = CoolProp::get_reducing_function_name(components[i]->CAS, components[j]->CAS);
|
||||
|
||||
// Get the dictionary itself
|
||||
Dictionary &dict_dep = mixturedeparturefunctionslibrary.departure_function_map[Name];
|
||||
|
||||
// These terms are common
|
||||
std::vector<double> n = dict_dep.get_double_vector("n");
|
||||
std::vector<double> d = dict_dep.get_double_vector("d");
|
||||
std::vector<double> t = dict_dep.get_double_vector("t");
|
||||
|
||||
// Set the scaling factor F for the excess term
|
||||
HEOS.Excess.F[i][j] = dict_red.get_number("F");
|
||||
|
||||
std::string type_dep = dict_dep.get_string("type");
|
||||
|
||||
if (!type_dep.compare("GERG-2008")){
|
||||
// Number of power terms needed
|
||||
int Npower = static_cast<int>(dict_dep.get_number("Npower"));
|
||||
// Terms for the gaussian
|
||||
std::vector<double> eta = dict_dep.get_double_vector("eta");
|
||||
std::vector<double> epsilon = dict_dep.get_double_vector("epsilon");
|
||||
std::vector<double> beta = dict_dep.get_double_vector("beta");
|
||||
std::vector<double> gamma = dict_dep.get_double_vector("gamma");
|
||||
HEOS.Excess.DepartureFunctionMatrix[i][j].reset(new GERG2008DepartureFunction(n,d,t,eta,epsilon,beta,gamma,Npower));
|
||||
}
|
||||
else if (!type_dep.compare("Exponential"))
|
||||
{
|
||||
// Powers of the exponents inside the exponential term
|
||||
std::vector<double> l = dict_dep.get_double_vector("l");
|
||||
HEOS.Excess.DepartureFunctionMatrix[i][j].reset(new ExponentialDepartureFunction(n,d,t,l));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ValueError();
|
||||
}
|
||||
}
|
||||
}
|
||||
// We have obtained all the parameters needed for the reducing function, now set the reducing function for the mixture
|
||||
HEOS.Reducing = shared_ptr<ReducingFunction>(new GERG2008ReducingFunction(components, beta_v, gamma_v, beta_T, gamma_T));
|
||||
}
|
||||
|
||||
} /* namespace CoolProp */
|
||||
15
src/Backends/Helmholtz/MixtureParameters.h
Normal file
15
src/Backends/Helmholtz/MixtureParameters.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#ifndef MIXTURE_PARAMETERS_H
|
||||
#define MIXTURE_PARAMETERS_H
|
||||
|
||||
#include "HelmholtzEOSMixtureBackend.h"
|
||||
|
||||
namespace CoolProp{
|
||||
|
||||
class MixtureParameters
|
||||
{
|
||||
public:
|
||||
static void set_mixture_parameters(HelmholtzEOSMixtureBackend &HEOS);
|
||||
};
|
||||
|
||||
} /* namespace CoolProp */
|
||||
#endif
|
||||
@@ -111,7 +111,7 @@ void PhaseEnvelopeRoutines::build(HelmholtzEOSMixtureBackend &HEOS)
|
||||
IO.x[IO.x.size()-1] = 1 - std::accumulate(IO.x.begin(), IO.x.end()-1, 0.0);
|
||||
factor = rho_vap_new/IO.rhomolar_vap;
|
||||
dont_extrapolate = true; // So that we use the mole fractions we calculated here instead of the extrapolated values
|
||||
std::cout << "dv " << rho_vap_new << " dl " << IO.rhomolar_liq << " " << vec_to_string(IO.x, "%0.10Lg") << " " << vec_to_string(IO.y, "%0.10Lg") << std::endl;
|
||||
//std::cout << "dv " << rho_vap_new << " dl " << IO.rhomolar_liq << " " << vec_to_string(IO.x, "%0.10Lg") << " " << vec_to_string(IO.y, "%0.10Lg") << std::endl;
|
||||
iter0 = iter - 1; // Back to linear interpolation again
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1,149 +1,7 @@
|
||||
#include "ReducingFunctions.h"
|
||||
#include "mixture_reducing_parameters_JSON.h" // Creates the variable mixture_reducing_parameters_JSON
|
||||
|
||||
namespace CoolProp{
|
||||
|
||||
static MixingParameterLibrary mixturelibrary;
|
||||
|
||||
MixingParameterLibrary::MixingParameterLibrary()
|
||||
{
|
||||
rapidjson::Document dd;
|
||||
|
||||
dd.Parse<0>(mixture_reducing_parameters_JSON.c_str());
|
||||
if (dd.HasParseError()){throw ValueError();}
|
||||
|
||||
// Iterate over the papers in the listing
|
||||
for (rapidjson::Value::ValueIterator itr = dd.Begin(); itr != dd.End(); ++itr)
|
||||
{
|
||||
// Iterate over the coeffs in the entry
|
||||
rapidjson::Value &Coeffs = (*itr)["Coeffs"];
|
||||
std::string model = cpjson::get_string(*itr, "Model");
|
||||
std::string BibTeX = cpjson::get_string(*itr, "BibTeX");
|
||||
for (rapidjson::Value::ValueIterator itr_coeff = Coeffs.Begin(); itr_coeff != Coeffs.End(); ++itr_coeff)
|
||||
{
|
||||
// Get the vector of CAS numbers
|
||||
std::vector<std::string> CAS;
|
||||
CAS.resize(2);
|
||||
CAS[0] = cpjson::get_string(*itr_coeff, "CAS1");
|
||||
CAS[1] = cpjson::get_string(*itr_coeff, "CAS2");
|
||||
std::string name1 = cpjson::get_string(*itr_coeff, "Name1");
|
||||
std::string name2 = cpjson::get_string(*itr_coeff, "Name2");
|
||||
|
||||
// Sort the CAS number vector
|
||||
std::sort(CAS.begin(), CAS.end());
|
||||
|
||||
// Get the empty dictionary to be filled by the appropriate reducing parameter filling function
|
||||
Dictionary d;
|
||||
|
||||
// A sort was carried out, names/CAS were swapped
|
||||
bool swapped = CAS[0].compare(cpjson::get_string(*itr_coeff, "CAS1")) != 0;
|
||||
|
||||
if (swapped){
|
||||
std::swap(name1,name2);
|
||||
}
|
||||
|
||||
// Populate the dictionary with common terms
|
||||
d.add_string("model", model);
|
||||
d.add_string("name1", name1);
|
||||
d.add_string("name2", name2);
|
||||
d.add_string("bibtex", BibTeX);
|
||||
|
||||
if (!model.compare("Kunz-JCED-2012"))
|
||||
{
|
||||
parse_Kunz_JCED_2012(d, *itr_coeff, swapped);
|
||||
}
|
||||
else if (!model.compare("Lemmon-JPCRD-2004"))
|
||||
{
|
||||
parse_Lemmon_JPCRD_2004(d, *itr_coeff, swapped);
|
||||
}
|
||||
else if (!model.compare("Lemmon-JPCRD-2000"))
|
||||
{
|
||||
parse_Lemmon_JPCRD_2000(d, *itr_coeff, swapped);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ValueError();
|
||||
}
|
||||
|
||||
// If not in map, add new entry to map with dictionary
|
||||
if (reducing_map.find(CAS) == reducing_map.end())
|
||||
{
|
||||
// One-element vector of the dictionary
|
||||
std::vector<Dictionary> vd(1, d);
|
||||
// Pair for adding to map
|
||||
std::pair<std::vector<std::string>, std::vector<Dictionary> > p(CAS, vd);
|
||||
// Add
|
||||
reducing_map.insert(p);
|
||||
}
|
||||
else // If already in map, add entry to the end of the vector
|
||||
{
|
||||
// Append dictionary to listing
|
||||
reducing_map[CAS].push_back(d);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReducingFunction *ReducingFunction::factory(const std::vector<CoolPropFluid*> &components)
|
||||
{
|
||||
std::string _model;
|
||||
std::size_t N = components.size();
|
||||
|
||||
STLMatrix beta_v, gamma_v, beta_T, gamma_T;
|
||||
beta_v.resize(N, std::vector<long double>(N, 0));
|
||||
gamma_v.resize(N, std::vector<long double>(N, 0));
|
||||
beta_T.resize(N, std::vector<long double>(N, 0));
|
||||
gamma_T.resize(N, std::vector<long double>(N, 0));
|
||||
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
for (std::size_t j = 0; j < N; ++j)
|
||||
{
|
||||
if (i == j){ continue; }
|
||||
|
||||
std::string CAS1 = components[i]->CAS;
|
||||
std::vector<std::string> CAS(2,"");
|
||||
CAS[0] = components[i]->CAS;
|
||||
CAS[1] = components[j]->CAS;
|
||||
std::sort(CAS.begin(), CAS.end());
|
||||
|
||||
/// swapped is true if a swap occured.
|
||||
bool swapped = (CAS1.compare(CAS[0]) != 0);
|
||||
|
||||
std::vector<Dictionary> & vd = mixturelibrary.reducing_map[CAS];
|
||||
if (vd.size() != 1) { throw NotImplementedError(); }
|
||||
// Get a reference to the dictionary itself to save a few dereferences
|
||||
Dictionary &d = vd[0];
|
||||
|
||||
std::string model = d.get_string("model");
|
||||
|
||||
if (!model.compare("Kunz-JCED-2012"))
|
||||
{
|
||||
if (swapped)
|
||||
{
|
||||
beta_v[i][j] = 1/d.get_number("betaV");
|
||||
beta_T[i][j] = 1/d.get_number("betaT");
|
||||
}
|
||||
else
|
||||
{
|
||||
beta_v[i][j] = d.get_number("betaV");
|
||||
beta_T[i][j] = d.get_number("betaT");
|
||||
}
|
||||
gamma_v[i][j] = d.get_number("gammaV");
|
||||
gamma_T[i][j] = d.get_number("gammaT");
|
||||
}
|
||||
else if (!model.compare("Lemmon-JPCRD-2004") || !model.compare("Lemmon-JPCRD-2000"))
|
||||
{
|
||||
LemmonAirHFCReducingFunction::convert_to_GERG(components,i,j,d,beta_T[i][j],beta_v[i][j],gamma_T[i][j],gamma_v[i][j]);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ValueError();
|
||||
}
|
||||
}
|
||||
}
|
||||
return new GERG2008ReducingFunction(components,beta_v, gamma_v, beta_T, gamma_T);
|
||||
}
|
||||
|
||||
long double ReducingFunction::d_ndTrdni_dxj__constxi(const std::vector<long double> &x, std::size_t i, std::size_t j, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
if (xN_flag == XN_INDEPENDENT){
|
||||
@@ -199,7 +57,6 @@ long double ReducingFunction::ndrhorbardni__constnj(const std::vector<long doubl
|
||||
else{
|
||||
throw ValueError(format("xN dependency flag invalid"));
|
||||
}
|
||||
|
||||
}
|
||||
long double ReducingFunction::ndTrdni__constnj(const std::vector<long double> &x, std::size_t i, x_N_dependency_flag xN_flag)
|
||||
{
|
||||
@@ -454,5 +311,4 @@ long double GERG2008ReducingFunction::d2fYijdxidxj(const std::vector<long double
|
||||
-xi*xj/pow(beta_Y2*xi+xj,2)*(1+beta_Y2-2*beta_Y2*(xi+xj)/(beta_Y2*xi+xj));
|
||||
}
|
||||
|
||||
|
||||
} /* namespace CoolProp */
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
#ifndef DEPARTURE_FUNCTIONS_H
|
||||
#define DEPARTURE_FUNCTIONS_H
|
||||
/** \brief Code for all the binary pairs in the mixture
|
||||
*
|
||||
* This includes both binary pair information for the reducing functions as well as the departure
|
||||
* functions for the given binary pair.
|
||||
*/
|
||||
|
||||
#ifndef MIXTURE_BINARY_PAIRS_H
|
||||
#define MIXTURE_BINARY_PAIRS_H
|
||||
|
||||
#include <vector>
|
||||
#include "CoolPropFluid.h"
|
||||
#include "crossplatform_shared_ptr.h"
|
||||
|
||||
namespace CoolProp{
|
||||
|
||||
@@ -11,55 +18,13 @@ typedef std::vector<std::vector<long double> > STLMatrix;
|
||||
enum x_N_dependency_flag{XN_INDEPENDENT, ///< x_N is an independent variable, and not calculated by \f$ x_N = 1-\sum_i x_i\f$
|
||||
XN_DEPENDENT ///< x_N is an dependent variable, calculated by \f$ x_N = 1-\sum_i x_i\f$
|
||||
};
|
||||
|
||||
/// A container for the mixing parameters for CoolProp mixtures
|
||||
/**
|
||||
|
||||
std::string get_reducing_function_name(std::string CAS1, std::string CAS2);
|
||||
|
||||
*/
|
||||
class MixingParameterLibrary
|
||||
{
|
||||
public:
|
||||
/// Map from sorted pair of CAS numbers to reducing parameter map. The reducing parameter map is a map from key (string) to value (double)
|
||||
std::map<std::vector<std::string>, std::vector<Dictionary> > reducing_map;
|
||||
MixingParameterLibrary();
|
||||
|
||||
/// Parse a term from GERG 2008
|
||||
void parse_Kunz_JCED_2012(Dictionary &d, rapidjson::Value &val, bool swapped)
|
||||
{
|
||||
d.add_number("gammaV", cpjson::get_double(val, "gammaV"));
|
||||
d.add_number("gammaT", cpjson::get_double(val, "gammaT"));
|
||||
|
||||
double betaV = cpjson::get_double(val, "betaV");
|
||||
double betaT = cpjson::get_double(val, "betaT");
|
||||
if (swapped){
|
||||
d.add_number("betaV", 1/betaV);
|
||||
d.add_number("betaT", 1/betaT);
|
||||
}
|
||||
else{
|
||||
d.add_number("betaV", betaV);
|
||||
d.add_number("betaT", betaT);
|
||||
}
|
||||
};
|
||||
|
||||
/// Parse a term from HFC mixtures
|
||||
void parse_Lemmon_JPCRD_2004(Dictionary &d, rapidjson::Value &val, bool swapped)
|
||||
{
|
||||
d.add_number("xi", cpjson::get_double(val, "xi"));
|
||||
d.add_number("zeta", cpjson::get_double(val, "zeta"));
|
||||
};
|
||||
|
||||
/// Parse a term from Air
|
||||
void parse_Lemmon_JPCRD_2000(Dictionary &d, rapidjson::Value &val, bool swapped)
|
||||
{
|
||||
d.add_number("xi", cpjson::get_double(val, "xi"));
|
||||
d.add_number("zeta", cpjson::get_double(val, "zeta"));
|
||||
};
|
||||
};
|
||||
|
||||
/*!
|
||||
An abstract base class for the reducing function to allow for
|
||||
Lemmon-Jacobsen, GERG, or other reducing function to yield the
|
||||
reducing parameters \f$ \rho_r \f$ and \f$ T_r \f$
|
||||
/** \brief Abstract base class for reducing function
|
||||
* An abstract base class for the reducing function to allow for
|
||||
* Lemmon-Jacobsen, GERG, or other reducing function to yield the
|
||||
* reducing parameters \f$\rho_r\f$ and \f$T_r\f$
|
||||
*/
|
||||
class ReducingFunction
|
||||
{
|
||||
@@ -69,8 +34,8 @@ public:
|
||||
ReducingFunction(){};
|
||||
virtual ~ReducingFunction(){};
|
||||
|
||||
/// A factory function to generate the required reducing function
|
||||
static ReducingFunction *factory(const std::vector<CoolPropFluid*> &components);
|
||||
/// A factory function to generate the requiredreducing function
|
||||
static shared_ptr<ReducingFunction> factory(const std::vector<CoolPropFluid*> &components, std::vector< std::vector< long double> > &F);
|
||||
|
||||
/// The reduced temperature
|
||||
virtual long double Tr(const std::vector<long double> &x) = 0;
|
||||
@@ -86,27 +51,30 @@ public:
|
||||
virtual long double d2Trdxi2__constxj(const std::vector<long double> &x, std::size_t i, x_N_dependency_flag xN_flag) = 0;
|
||||
virtual long double d2Trdxidxj(const std::vector<long double> &x, std::size_t i, std::size_t j, x_N_dependency_flag xN_flag) = 0;
|
||||
|
||||
/*! GERG 2004 Monograph equation 7.56:
|
||||
\f[
|
||||
\left(\frac{\partial}{\partial x_j}\left(n\left(\frac{\partial T_r}{\partial n_i} \right)_{n_j}\right)\right)_{x_i} = \left(\frac{\partial^2T_r}{\partial x_j \partial x_i}\right)-\left(\frac{\partial T_r}{\partial x_j}\right)_{x_i}-\sum_{k=1}^Nx_k\left(\frac{\partial^2T_r}{\partial x_j \partial x_k}\right)
|
||||
\f]
|
||||
*/
|
||||
/** \brief GERG 2004 Monograph equation 7.56:
|
||||
*
|
||||
* \f[
|
||||
* \left(\frac{\partial}{\partial x_j}\left(n\left(\frac{\partial T_r}{\partial n_i} \right)_{n_j}\right)\right)_{x_i} = \left(\frac{\partial^2T_r}{\partial x_j \partial x_i}\right)-\left(\frac{\partial T_r}{\partial x_j}\right)_{x_i}-\sum_{k=1}^Nx_k\left(\frac{\partial^2T_r}{\partial x_j \partial x_k}\right)
|
||||
* \f]
|
||||
*/
|
||||
long double d_ndTrdni_dxj__constxi(const std::vector<long double> &x, std::size_t i, std::size_t j, x_N_dependency_flag xN_flag);
|
||||
/*! GERG 2004 Monograph equation 7.55:
|
||||
\f[
|
||||
\left(\frac{\partial}{\partial x_j}\left(n\left(\frac{\partial \rho_r}{\partial n_i} \right)_{n_j}\right)\right)_{x_i} = \left(\frac{\partial^2\rho_r}{\partial x_j \partial x_i}\right)-\left(\frac{\partial \rho_r}{\partial x_j}\right)_{x_i}-\sum_{k=1}^Nx_k\left(\frac{\partial^2\rho_r}{\partial x_j \partial x_k}\right)
|
||||
\f]
|
||||
*/
|
||||
/** \brief GERG 2004 Monograph equation 7.55:
|
||||
*
|
||||
* \f[
|
||||
* \left(\frac{\partial}{\partial x_j}\left(n\left(\frac{\partial \rho_r}{\partial n_i} \right)_{n_j}\right)\right)_{x_i} = \left(\frac{\partial^2\rho_r}{\partial x_j \partial x_i}\right)-\left(\frac{\partial \rho_r}{\partial x_j}\right)_{x_i}-\sum_{k=1}^Nx_k\left(\frac{\partial^2\rho_r}{\partial x_j \partial x_k}\right)
|
||||
* \f]
|
||||
*/
|
||||
long double d_ndrhorbardni_dxj__constxi(const std::vector<long double> &x, std::size_t i, std::size_t j, x_N_dependency_flag xN_flag);
|
||||
|
||||
long double ndrhorbardni__constnj(const std::vector<long double> &x, std::size_t i, x_N_dependency_flag xN_flag);
|
||||
long double ndTrdni__constnj(const std::vector<long double> &x, std::size_t i, x_N_dependency_flag xN_flag);
|
||||
};
|
||||
|
||||
/*!
|
||||
The Reducing parameter model used by the GERG-2008 formulation to yield the
|
||||
reducing parameters \f$ \rho_r \f$ and \f$ T_r \f$ and derivatives thereof
|
||||
*/
|
||||
/** \brief The reducing function model of GERG-2008
|
||||
*
|
||||
* Used by the GERG-2008 formulation to yield the
|
||||
* reducing parameters \f$ \rho_r \f$ and \f$ T_r \f$ and derivatives thereof
|
||||
*/
|
||||
class GERG2008ReducingFunction : public ReducingFunction
|
||||
{
|
||||
private:
|
||||
@@ -181,27 +149,29 @@ public:
|
||||
long double d2fYijdxidxj(const std::vector<long double> &x, std::size_t i, std::size_t k, const STLMatrix &beta);
|
||||
};
|
||||
|
||||
/*! From Lemmon, JPCRD, 2000 for the properties of Dry Air, and also from Lemmon, JPCRD, 2004 for the properties of R404A, R410A, etc.
|
||||
\f[
|
||||
\rho_r(\bar x) = \left[ \sum_{i=1}^m\frac{x_i}{\rho_{c_i}}+\sum_{i=1}^{m-1}\sum_{j=i+1}^{m}x_ix_j\zeta_{ij}\right]^{-1}
|
||||
\f]
|
||||
\f[
|
||||
T_r(\bar x) = \sum_{i=1}^mx_iT_{c_i}+\sum_{i=1}^{m-1}\sum_{j=i+1}^mx_ix_j\xi_{ij}
|
||||
\f]
|
||||
|
||||
These can be converted to the form of GERG by the following equations:
|
||||
\f[
|
||||
\beta_T = 1\ \ \ \ \beta_v = 1
|
||||
\f]
|
||||
and
|
||||
\f[
|
||||
\boxed{\gamma_T = \dfrac{T_{c0}+T_{c1}+\xi_{01}}{2\sqrt{T_{c0}T_{c1}}}}
|
||||
\f]
|
||||
and
|
||||
\f[
|
||||
\boxed{\gamma_v = \dfrac{v_{c0}+v_{c1}+\zeta_{01}}{\frac{1}{4}\left(\frac{1}{\rho_{c,i}^{1/3}}+\frac{1}{\rho_{c,j}^{1/3}}\right)^{3}}}
|
||||
\f]
|
||||
*/
|
||||
/** \brief Reducing function converter for dry air and HFC blends
|
||||
*
|
||||
* From Lemmon, JPCRD, 2000 for the properties of Dry Air, and also from Lemmon, JPCRD, 2004 for the properties of R404A, R410A, etc.
|
||||
* \f[
|
||||
* \rho_r(\bar x) = \left[ \sum_{i=1}^m\frac{x_i}{\rho_{c_i}}+\sum_{i=1}^{m-1}\sum_{j=i+1}^{m}x_ix_j\zeta_{ij}\right]^{-1}
|
||||
* \f]
|
||||
* \f[
|
||||
* T_r(\bar x) = \sum_{i=1}^mx_iT_{c_i}+\sum_{i=1}^{m-1}\sum_{j=i+1}^mx_ix_j\xi_{ij}
|
||||
* \f]
|
||||
*
|
||||
* These can be converted to the form of GERG by the following equations:
|
||||
* \f[
|
||||
* \beta_T = 1\ \ \ \ \beta_v = 1
|
||||
* \f]
|
||||
* and
|
||||
* \f[
|
||||
* \boxed{\gamma_T = \dfrac{T_{c0}+T_{c1}+\xi_{01}}{2\sqrt{T_{c0}T_{c1}}}}
|
||||
* \f]
|
||||
* and
|
||||
* \f[
|
||||
* \boxed{\gamma_v = \dfrac{v_{c0}+v_{c1}+\zeta_{01}}{\frac{1}{4}\left(\frac{1}{\rho_{c,i}^{1/3}}+\frac{1}{\rho_{c,j}^{1/3}}\right)^{3}}}
|
||||
* \f]
|
||||
*/
|
||||
class LemmonAirHFCReducingFunction
|
||||
{
|
||||
protected:
|
||||
@@ -222,24 +192,5 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
class ReducingFunctionContainer
|
||||
{
|
||||
private:
|
||||
ReducingFunctionContainer(const ReducingFunctionContainer&);
|
||||
ReducingFunctionContainer& operator=(const ReducingFunctionContainer&);
|
||||
public:
|
||||
ReducingFunction *p;
|
||||
ReducingFunctionContainer(){
|
||||
p = NULL;
|
||||
};
|
||||
void set(ReducingFunction *pReducing){p = pReducing;};
|
||||
ReducingFunctionContainer(ReducingFunction *pReducing){
|
||||
p = pReducing;
|
||||
};
|
||||
~ReducingFunctionContainer(){delete(p);};
|
||||
|
||||
};
|
||||
|
||||
|
||||
} /* namespace CoolProp */
|
||||
#endif
|
||||
@@ -569,7 +569,7 @@ void SaturationSolvers::saturation_T_pure_Akasaka(HelmholtzEOSMixtureBackend &HE
|
||||
shared_ptr<HelmholtzEOSMixtureBackend> SatL = HEOS.SatL,
|
||||
SatV = HEOS.SatV;
|
||||
|
||||
long double rhoL,rhoV,JL,JV,KL,KV,dJL,dJV,dKL,dKV;
|
||||
long double rhoL = _HUGE, rhoV = _HUGE,JL,JV,KL,KV,dJL,dJV,dKL,dKV;
|
||||
long double DELTA, deltaL=0, deltaV=0, error, PL, PV, stepL, stepV;
|
||||
int iter=0;
|
||||
|
||||
@@ -879,8 +879,6 @@ void SaturationSolvers::newton_raphson_saturation::check_Jacobian()
|
||||
std::cout << format("For x0\n");
|
||||
std::cout << "numerical: " << vec_to_string(diffn, "%0.11Lg") << std::endl;
|
||||
std::cout << "analytic: " << vec_to_string(get_col(J0, 0), "%0.11Lg") << std::endl;
|
||||
|
||||
int rrr = 0;
|
||||
}
|
||||
void SaturationSolvers::newton_raphson_saturation::call(HelmholtzEOSMixtureBackend &HEOS, const std::vector<long double> &z, std::vector<long double> &z_incipient, newton_raphson_saturation_options &IO)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user