Refactor of mixing parameters successful

Signed-off-by: Ian Bell <ian.h.bell@gmail.com>
This commit is contained in:
Ian Bell
2014-09-06 15:41:33 +02:00
parent 8294acb71e
commit 8fdd1fddaf
21 changed files with 640 additions and 601 deletions

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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);

View 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 */

View 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

View File

@@ -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;
}

View File

@@ -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 */

View File

@@ -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

View File

@@ -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)
{