Started with conductivity - implemented n-Hexane

Signed-off-by: Ian Bell <ian.h.bell@gmail.com>
This commit is contained in:
Ian Bell
2014-05-23 17:13:54 +02:00
parent 83994c1de5
commit 3c8eb8746b
9 changed files with 514 additions and 29 deletions

View File

@@ -9,9 +9,11 @@
#include <map>
#include <algorithm>
namespace CoolProp{
// Forward declaration of the necessary debug function to avoid including the whole header
extern int get_debug_level();
/// A container for the fluid parameters for the CoolProp fluids
/**
This container holds copies of all of the fluid instances for the fluids that are loaded in CoolProp.
@@ -440,13 +442,13 @@ protected:
if (viscosity.HasMember("hardcoded")){
std::string target = cpjson::get_string(viscosity,"hardcoded");
if (!target.compare("Water")){
fluid.transport.hardcoded = CoolProp::TransportPropertyData::VISCOSITY_HARDCODED_WATER; return;
fluid.transport.hardcoded_viscosity = CoolProp::TransportPropertyData::VISCOSITY_HARDCODED_WATER; return;
}
else if (!target.compare("Helium")){
fluid.transport.hardcoded = CoolProp::TransportPropertyData::VISCOSITY_HARDCODED_HELIUM; return;
fluid.transport.hardcoded_viscosity = CoolProp::TransportPropertyData::VISCOSITY_HARDCODED_HELIUM; return;
}
else if (!target.compare("R23")){
fluid.transport.hardcoded = CoolProp::TransportPropertyData::VISCOSITY_HARDCODED_R23; return;
fluid.transport.hardcoded_viscosity = CoolProp::TransportPropertyData::VISCOSITY_HARDCODED_R23; return;
}
else{
throw ValueError();
@@ -475,20 +477,130 @@ protected:
parse_higher_order_viscosity(viscosity["higher_order"], fluid);
}
};
/// Parse the transport properties
void parse_dilute_conductivity(rapidjson::Value &dilute, CoolPropFluid & fluid)
{
/*if (dilute.HasMember("hardcoded")){
std::string target = cpjson::get_string(dilute, "hardcoded");
if (!target.compare("Ethane")){
fluid.transport.viscosity_dilute.type = CoolProp::ViscosityDiluteVariables::VISCOSITY_DILUTE_ETHANE; return;
}
}*/
std::string type = cpjson::get_string(dilute, "type");
if (!type.compare("ratio_of_polynomials")){
// Get a reference to the entry in the fluid instance
CoolProp::ConductivityDiluteRatioPolynomialsData &data = fluid.transport.conductivity_dilute.ratio_polynomials;
// Set the type flag
fluid.transport.conductivity_dilute.type = CoolProp::ConductivityDiluteVariables::CONDUCTIVITY_DILUTE_RATIO_POLYNOMIALS;
// Load up the values
data.A = cpjson::get_long_double_array(dilute["A"]);
data.B = cpjson::get_long_double_array(dilute["B"]);
data.n = cpjson::get_long_double_array(dilute["n"]);
data.m = cpjson::get_long_double_array(dilute["m"]);
data.T_reducing = cpjson::get_double(dilute, "T_reducing");
}
else{
throw ValueError(format("type [%s] is not understood for fluid %s",type.c_str(),fluid.name.c_str()));
}
};
/// Parse the transport properties
void parse_residual_conductivity(rapidjson::Value &dilute, CoolPropFluid & fluid)
{
/*if (dilute.HasMember("hardcoded")){
std::string target = cpjson::get_string(dilute, "hardcoded");
if (!target.compare("Ethane")){
fluid.transport.viscosity_dilute.type = CoolProp::ViscosityDiluteVariables::VISCOSITY_DILUTE_ETHANE; return;
}
}*/
std::string type = cpjson::get_string(dilute, "type");
if (!type.compare("polynomial")){
// Get a reference to the entry in the fluid instance
CoolProp::ConductivityResidualPolynomialData &data = fluid.transport.conductivity_residual.polynomials;
// Set the type flag
fluid.transport.conductivity_residual.type = CoolProp::ConductivityResidualVariables::CONDUCTIVITY_RESIDUAL_POLYNOMIAL;
// Load up the values
data.B = cpjson::get_long_double_array(dilute["B"]);
data.d = cpjson::get_long_double_array(dilute["d"]);
data.t = cpjson::get_long_double_array(dilute["t"]);
data.T_reducing = cpjson::get_double(dilute, "T_reducing");
data.rhomass_reducing = cpjson::get_double(dilute, "rhomass_reducing");
}
else{
throw ValueError(format("type [%s] is not understood for fluid %s",type.c_str(),fluid.name.c_str()));
}
};
void parse_critical_conductivity(rapidjson::Value &critical, CoolPropFluid & fluid)
{
/*if (dilute.HasMember("hardcoded")){
std::string target = cpjson::get_string(dilute, "hardcoded");
if (!target.compare("Ethane")){
fluid.transport.viscosity_dilute.type = CoolProp::ViscosityDiluteVariables::VISCOSITY_DILUTE_ETHANE; return;
}
}*/
std::string type = cpjson::get_string(critical, "type");
if (!type.compare("simplified_Olchowy_Sengers")){
//// Get a reference to the entry in the fluid instance
//CoolProp::ConductivityResidualPolynomialData &data = fluid.transport.conductivity_residual.polynomials;
// Set the type flag
fluid.transport.conductivity_critical.type = CoolProp::ConductivityCriticalVariables::CONDUCTIVITY_CRITICAL_SIMPLIFIED_OLCHOWY_SENGERS;
}
else{
throw ValueError(format("type [%s] is not understood for fluid %s",type.c_str(),fluid.name.c_str()));
}
};
/// Parse the thermal conductivity data
void parse_thermal_conductivity(rapidjson::Value &conductivity, CoolPropFluid & fluid)
{
// Load dilute conductivity term
if (conductivity.HasMember("dilute")){
parse_dilute_conductivity(conductivity["dilute"], fluid);
}
// Load residual conductivity term
if (conductivity.HasMember("residual")){
parse_residual_conductivity(conductivity["residual"], fluid);
}
// Load critical conductivity term
if (conductivity.HasMember("critical")){
parse_critical_conductivity(conductivity["critical"], fluid);
}
};
/// Parse the transport properties
void parse_transport(rapidjson::Value &transport, CoolPropFluid & fluid)
{
//if (!fluid.name.compare("n-Hexane")){
// rapidjson::Document dd;
// dd.SetObject();
// dd.AddMember("core",transport,dd.GetAllocator());
// rapidjson::StringBuffer buffer;
// rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(buffer);
// dd.Accept(writer);
// std::string json0 = buffer.GetString();
// //std::cout << json0 << std::endl;
// FILE *fp;
// fp = fopen("nHexane_transport.json","w");
// fprintf(fp,"%s",json0.c_str());
// fclose(fp);
//}
// Parse viscosity
if (transport.HasMember("viscosity")){
parse_viscosity(transport["viscosity"],fluid);
}
// Parse thermal conductivity
// Parse thermal conductivity
if (transport.HasMember("conductivity")){
parse_thermal_conductivity(transport["conductivity"],fluid);
}
@@ -582,7 +694,9 @@ public:
// Surface tension
if (!(fluid_json["ANCILLARIES"].HasMember("surface_tension"))){
std::cout << format("Surface tension curves are missing for fluid [%s]\n", fluid.name.c_str()) ;
if (get_debug_level() > 0){
std::cout << format("Surface tension curves are missing for fluid [%s]\n", fluid.name.c_str()) ;
}
}
else{
parse_surface_tension(fluid_json["ANCILLARIES"]["surface_tension"], fluid);
@@ -590,7 +704,9 @@ public:
// Parse the environmental parameters
if (!(fluid_json.HasMember("ENVIRONMENTAL"))){
std::cout << format("Environmental data are missing for fluid [%s]\n", fluid.name.c_str()) ;
if (get_debug_level() > 0){
std::cout << format("Environmental data are missing for fluid [%s]\n", fluid.name.c_str()) ;
}
}
else{
parse_environmental(fluid_json["ENVIRONMENTAL"], fluid);

View File

@@ -132,9 +132,9 @@ long double HelmholtzEOSMixtureBackend::calc_viscosity(void)
{
if (is_pure_or_pseudopure)
{
if (components[0]->transport.hardcoded != CoolProp::TransportPropertyData::VISCOSITY_NOT_HARDCODED)
if (components[0]->transport.hardcoded_viscosity != CoolProp::TransportPropertyData::VISCOSITY_NOT_HARDCODED)
{
switch(components[0]->transport.hardcoded)
switch(components[0]->transport.hardcoded_viscosity)
{
case CoolProp::TransportPropertyData::VISCOSITY_HARDCODED_WATER:
return TransportRoutines::viscosity_water_hardcoded(*this);
@@ -143,7 +143,7 @@ long double HelmholtzEOSMixtureBackend::calc_viscosity(void)
case CoolProp::TransportPropertyData::VISCOSITY_HARDCODED_R23:
return TransportRoutines::viscosity_R23_hardcoded(*this);
default:
throw ValueError(format("hardcoded viscosity type [%d] is invalid for fluid %s", components[0]->transport.hardcoded, name().c_str()));
throw ValueError(format("hardcoded viscosity type [%d] is invalid for fluid %s", components[0]->transport.hardcoded_viscosity, name().c_str()));
}
}
// Dilute part
@@ -198,6 +198,58 @@ long double HelmholtzEOSMixtureBackend::calc_viscosity(void)
throw NotImplementedError(format("viscosity not implemented for mixtures"));
}
}
long double HelmholtzEOSMixtureBackend::calc_conductivity(void)
{
if (is_pure_or_pseudopure)
{
if (components[0]->transport.hardcoded_conductivity != CoolProp::TransportPropertyData::CONDUCTIVITY_NOT_HARDCODED)
{
switch(components[0]->transport.hardcoded_conductivity)
{
case CoolProp::TransportPropertyData::CONDUCTIVITY_HARDCODED_WATER:
return TransportRoutines::viscosity_water_hardcoded(*this);
default:
throw ValueError(format("hardcoded viscosity type [%d] is invalid for fluid %s", components[0]->transport.hardcoded_conductivity, name().c_str()));
}
}
// Dilute part
long double lambda_dilute = _HUGE;
switch(components[0]->transport.conductivity_dilute.type)
{
case ConductivityDiluteVariables::CONDUCTIVITY_DILUTE_RATIO_POLYNOMIALS:
lambda_dilute = TransportRoutines::conductivity_dilute_ratio_polynomials(*this); break;
default:
throw ValueError(format("dilute conductivity type [%d] is invalid for fluid %s", components[0]->transport.conductivity_dilute.type, name().c_str()));
}
// Residual part
long double lambda_residual = _HUGE;
switch(components[0]->transport.conductivity_residual.type)
{
case ConductivityResidualVariables::CONDUCTIVITY_RESIDUAL_POLYNOMIAL:
lambda_residual = TransportRoutines::conductivity_residual_polynomial(*this); break;
default:
throw ValueError(format("residual conductivity type [%d] is invalid for fluid %s", components[0]->transport.conductivity_residual.type, name().c_str()));
}
// Critical part
long double lambda_critical = _HUGE;
switch(components[0]->transport.conductivity_critical.type)
{
case ConductivityCriticalVariables::CONDUCTIVITY_CRITICAL_SIMPLIFIED_OLCHOWY_SENGERS:
lambda_critical = TransportRoutines::conductivity_critical_simplified_Olchowy_Sengers(*this); break;
default:
throw ValueError(format("critical conductivity type [%d] is invalid for fluid %s", components[0]->transport.viscosity_dilute.type, name().c_str()));
}
return lambda_dilute + lambda_residual + lambda_critical;
}
else
{
throw NotImplementedError(format("viscosity not implemented for mixtures"));
}
}
long double HelmholtzEOSMixtureBackend::calc_Ttriple(void)
{
double summer = 0;

View File

@@ -118,6 +118,7 @@ public:
long double calc_surface_tension(void);
long double calc_viscosity(void);
long double calc_conductivity(void);
long double calc_Tmax(void);
long double calc_pmax(void);

View File

@@ -445,4 +445,57 @@ long double TransportRoutines::viscosity_ethane_higher_order_hardcoded(Helmholtz
return 15.977*sum1/(1+sum2)/1e6;
}
long double TransportRoutines::conductivity_dilute_ratio_polynomials(HelmholtzEOSMixtureBackend &HEOS){
if (HEOS.is_pure_or_pseudopure)
{
// Retrieve values from the state class
CoolProp::ConductivityDiluteRatioPolynomialsData &data = HEOS.components[0]->transport.conductivity_dilute.ratio_polynomials;
long double summer1 = 0, summer2 = 0, Tr = HEOS.T()/data.T_reducing;
for (std::size_t i = 0; i < data.A.size(); ++i)
{
summer1 += data.A[i]*pow(Tr, data.n[i]);
}
for (std::size_t i = 0; i < data.B.size(); ++i)
{
summer2 += data.B[i]*pow(Tr, data.m[i]);
}
return summer1/summer2;
}
else{
throw NotImplementedError("TransportRoutines::conductivity_dilute_ratio_polynomials is only for pure and pseudo-pure");
}
};
long double TransportRoutines::conductivity_residual_polynomial(HelmholtzEOSMixtureBackend &HEOS){
if (HEOS.is_pure_or_pseudopure)
{
// Retrieve values from the state class
CoolProp::ConductivityResidualPolynomialData &data = HEOS.components[0]->transport.conductivity_residual.polynomials;
long double summer = 0, tau = data.T_reducing/HEOS.T(), delta = HEOS.keyed_output(CoolProp::iDmass)/data.rhomass_reducing;
for (std::size_t i = 0; i < data.B.size(); ++i)
{
summer += data.B[i]*pow(tau, data.t[i])*pow(delta, data.d[i]);
}
return summer;
}
else{
throw NotImplementedError("TransportRoutines::conductivity_residual_polynomial is only for pure and pseudo-pure");
}
};
long double TransportRoutines::conductivity_critical_simplified_Olchowy_Sengers(HelmholtzEOSMixtureBackend &HEOS){
if (HEOS.is_pure_or_pseudopure)
{
return 0;
}
else{
throw NotImplementedError("TransportRoutines::conductivity_critical_simplified_Olchowy_Sengers is only for pure and pseudo-pure");
}
};
}; /* namespace CoolProp */

View File

@@ -40,7 +40,7 @@ public:
\f[
\eta^0 = \displaystyle\sum_ia_iT^{t_i}
\f]
with T in K, \f$eta^0\f$ in Pa-s
with T in K, \f$\eta^0\f$ in Pa-s
*/
static long double viscosity_dilute_powers_of_T(HelmholtzEOSMixtureBackend &HEOS);
@@ -83,18 +83,82 @@ public:
static long double viscosity_higher_order_modified_Batschinski_Hildebrand(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_dilute_ethane(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_ethane_higher_order_hardcoded(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_water_hardcoded(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_helium_hardcoded(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_R23_hardcoded(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_ethane_higher_order_hardcoded(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_hydrogen_higher_order_hardcoded(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_hexane_higher_order_hardcoded(HelmholtzEOSMixtureBackend &HEOS);
static long double viscosity_higher_order_friction_theory(HelmholtzEOSMixtureBackend &HEOS);
/**
\brief The general dilute gas conductivity term formed of a ratio of polynomial like terms
\f[
\lambda^0 = \frac{A_i\displaystyle\sum_iT_r^{n_i}}{B_i\displaystyle\sum_iT_r^{m_i}}
\f]
with \f$\lambda^0\f$ in W/m/K, T_r is the reduced temperature \f$T_{r} = T/T_{red}\f$
*/
static long double conductivity_dilute_ratio_polynomials(HelmholtzEOSMixtureBackend &HEOS);
/**
This term is given by
\f[
\Delta\lambda(\rho,T) = \displaystyle\sum_iA_i\tau^{t,i}\delta^{d_i}
\f]
As used by Assael, Perkins, Huber, etc., the residual term is given by
\f[
\Delta\lambda(\rho,T) = \displaystyle\sum_i(B_{1,i}+B_{2,i}(T/T_c))(\rho/\rho_c)^i
\f]
which can be easily converted by noting that \f$\tau=Tc/T\f$ and \f$\delta=\rho/\rho_c\f$
*/
static long double conductivity_residual_polynomial(HelmholtzEOSMixtureBackend &HEOS);
/**
\brief The simplified critical conductivity term of Olchowy and Sengers
Olchowy, G. A. & Sengers, J. V. (1989), "A Simplified Representation for the Thermal Conductivity of Fluids in the Critical Region", International Journal of Thermophysics, 10, (2), 417-426
\f[
\lambda^{(c)} = \frac{\rho c_p R_DkT}{6\pi\eta\zeta}(\Omega-\Omega_0)
\f]
\f[
\Omega = \frac{2}{\pi}\left[ \left( \frac{c_p-c_v}{c_p}\right)\arctan(q_d\zeta)+\frac{c_v}{c_p}q_d\zeta \right]
\f]
\f[
\Omega_0 = \frac{2}{\pi}\left[1-\exp\left(-\frac{1}{(q_d\zeta)^{-1}+(q_d\zeta\rho_c/\rho)^2/3} \right) \right]
\f]
\f[
\zeta = \zeta_0\left(\frac{p_c\rho}{\Gamma\rho_c^2}\right)^{\nu/\gamma}\left[\left.\frac{\partial \rho(T,\rho)}{\partial p} \right|_{T}- \frac{T_R}{T}\left.\frac{\partial \rho(T_R,\rho)}{\partial p} \right|_{T} \right]^{\nu/\gamma},
\f]
where \f$\lambda^{(c)}\f$ is in W\f$\cdot\f$m\f$^{-1}\f$\f$\cdot\f$K\f$^{-1}\f$, \f$\zeta\f$ is in m,
\f$c_p\f$ and \f$c_v\f$ are in J\f$\cdot\f$kg\f$^{-1}\cdot\f$K\f$^{-1}\f$, \f$p\f$ and \f$p_c\f$ are in Pa,
\f$\rho\f$ and \f$\rho_c\f$ are in mol\f$\cdot\f$m\f$^{-3}\f$, \f$\eta\f$ is the viscosity in Pa\f$\cdot\f$s,
and the remaining parameters are defined in the following tables.
Coefficients for use in the simplified Olchowy-Sengers critical term
Parameter | Variable | Value
--------- | -------- | ------
Boltzmann constant | \f$k\f$ | \f$1.3806488\times 10^{-23}\f$ J\f$\cdot\f$K\f$^{-1}\f$
Universal amplitude | \f$R_D\f$ | 1.03
Critical exponent | \f$\nu\f$ | 0.63
Critical exponent | \f$\gamma\f$ | 1.239
Reference temperature | \f$T_R\f$ | 1.5\f$T_c\f$
Recommended default constants (see Huber (I&ECR, 2003))
Parameter | Variable | Value
--------- | -------- | ------
Amplitude | \f$\Gamma\f$ | 0.0496
Amplitude |\f$\zeta_0\f$ | 1.94 \f$\times\f$ 10\f$^{-10}\f$ m
Effective cutoff | \f$q_d\f$ | 2 \f$\times\f$ 10\f$^{9}\f$ m
*/
static long double conductivity_critical_simplified_Olchowy_Sengers(HelmholtzEOSMixtureBackend &HEOS);
}; /* class TransportRoutines */
}; /* namespace CoolProp */

View File

@@ -11,9 +11,9 @@
#include "catch.hpp"
namespace ViscosityValidation{
namespace TransportValidation{
// A structure to hold the values for one validation call for viscosity
// A structure to hold the values for one validation call
struct vel
{
public:
@@ -22,7 +22,8 @@ public:
vel(std::string fluid, std::string in1, double v1, std::string in2, double v2, std::string out, double expected, double tol)
{
this->in1 = in1; this->in2 = in2; this->fluid = fluid;
this->v1 = v1; this->v2 = v2; this->expected = expected; this->tol = tol;
this->v1 = v1; this->v2 = v2; this->expected = expected;
this->tol = tol;
};
};
@@ -199,15 +200,15 @@ vel("R134a", "T", 360, "Q", 1, "V", 1.7140264998576107e-005, 1e-4),
};
class ViscosityValidationFixture
class TransportValidationFixture
{
protected:
long double actual, x1, x2;
CoolProp::AbstractState *pState;
int pair;
public:
ViscosityValidationFixture(){ pState = NULL; }
~ViscosityValidationFixture(){ delete pState; }
TransportValidationFixture(){ pState = NULL; }
~TransportValidationFixture(){ delete pState; }
void set_backend(std::string backend, std::string fluid_name){
pState = CoolProp::AbstractState::factory(backend, fluid_name);
}
@@ -218,13 +219,13 @@ public:
long pair = CoolProp::generate_update_pair(iin1, v1, iin2, v2, o1, o2);
pState->update(pair, o1, o2);
}
void get_value()
void get_value(long key)
{
actual = pState->viscosity();
actual = pState->keyed_output(key);
}
};
TEST_CASE_METHOD(ViscosityValidationFixture, "Compare viscosities against published data", "[viscosity]")
TEST_CASE_METHOD(TransportValidationFixture, "Compare viscosities against published data", "[viscosity]")
{
int inputsN = sizeof(viscosity_validation_data)/sizeof(viscosity_validation_data[0]);
for (int i = 0; i < inputsN; ++i)
@@ -238,14 +239,44 @@ TEST_CASE_METHOD(ViscosityValidationFixture, "Compare viscosities against publis
CAPTURE(el.in2);
CAPTURE(el.v2);
CHECK_NOTHROW(set_pair(el.in1, el.v1, el.in2, el.v2));
get_value();
get_value(CoolProp::iviscosity);
CAPTURE(el.expected);
CAPTURE(actual);
CHECK(fabs(actual/el.expected-1) < el.tol);
}
}
}; /* namespace ViscosityValidation */
vel conductivity_validation_data[] = {
// From Assael, JPCRD, 2013
vel("Hexane", "T", 250, "Dmass", 700, "L", 137.62e-3, 1e-3),
vel("Hexane", "T", 400, "Dmass", 2, "L", 23.558e-3, 1e-3),
vel("Hexane", "T", 400, "Dmass", 650, "L", 129.28e-3, 1e-3),
vel("Hexane", "T", 510, "Dmass", 2, "L", 36.772e-3, 1e-3),
};
TEST_CASE_METHOD(TransportValidationFixture, "Compare thermal conductivities against published data", "[conductivity]")
{
int inputsN = sizeof(conductivity_validation_data)/sizeof(conductivity_validation_data[0]);
for (int i = 0; i < inputsN; ++i)
{
vel el = conductivity_validation_data[i];
CHECK_NOTHROW(set_backend("HEOS", el.fluid));
CAPTURE(el.fluid);
CAPTURE(el.in1);
CAPTURE(el.v1);
CAPTURE(el.in2);
CAPTURE(el.v2);
CHECK_NOTHROW(set_pair(el.in1, el.v1, el.in2, el.v2));
get_value(CoolProp::iconductivity);
CAPTURE(el.expected);
CAPTURE(actual);
CHECK(fabs(actual/el.expected-1) < el.tol);
}
}
}; /* namespace TransportValidation */
static int inputs[] = {
CoolProp::DmolarT_INPUTS,