Refactored tables to remove nearly all the copying of data

Some bugs remain still
This commit is contained in:
Ian Bell
2015-06-27 20:57:12 -06:00
parent 59f2b0da88
commit 350004f1c4
6 changed files with 367 additions and 281 deletions

View File

@@ -140,6 +140,7 @@ void CoolProp::BicubicBackend::build_coeffs(SinglePhaseGriddedTableData &table,
void CoolProp::BicubicBackend::update(CoolProp::input_pairs input_pair, double val1, double val2)
{
if (get_debug_level() > 0){ std::cout << format("update(%s,%g,%g)\n", get_input_pair_short_desc(input_pair).c_str(), val1, val2); }
// Clear cached values
clear();
@@ -152,6 +153,11 @@ void CoolProp::BicubicBackend::update(CoolProp::input_pairs input_pair, double v
cached_saturation_iL = std::numeric_limits<std::size_t>::max();
cached_saturation_iV = std::numeric_limits<std::size_t>::max();
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
switch(input_pair){
case HmolarP_INPUTS:{
_hmolar = val1; _p = val2;

View File

@@ -131,6 +131,8 @@ class BicubicBackend : public TabularBackend
// If a pure fluid, don't need to set fractions, go ahead and build
if (this->AS->get_mole_fractions().size() == 1){
check_tables();
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
build_coeffs(single_phase_logph, coeffs_ph);
build_coeffs(single_phase_logpT, coeffs_pT);
is_mixture = false;
@@ -143,6 +145,8 @@ class BicubicBackend : public TabularBackend
check_tables();
// For mixtures, the construction of the coefficients is delayed until this
// function so that the set_mole_fractions function can be called
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
build_coeffs(single_phase_logph, coeffs_ph);
build_coeffs(single_phase_logpT, coeffs_pT);
};
@@ -168,9 +172,11 @@ class BicubicBackend : public TabularBackend
*/
double evaluate_single_phase_derivative(SinglePhaseGriddedTableData &table, std::vector<std::vector<CellCoeffs> > &coeffs, parameters output, double x, double y, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny);
double evaluate_single_phase_phmolar_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny){
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
return evaluate_single_phase_derivative(single_phase_logph, coeffs_ph, output, _hmolar, _p, i, j, Nx, Ny);
};
double evaluate_single_phase_pT_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny){
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
return evaluate_single_phase_derivative(single_phase_logpT, coeffs_pT, output, _T, _p, i, j, Nx, Ny);
};
@@ -187,9 +193,11 @@ class BicubicBackend : public TabularBackend
*/
double evaluate_single_phase(const SinglePhaseGriddedTableData &table, const std::vector<std::vector<CellCoeffs> > &coeffs, const parameters output, const double x, const double y, const std::size_t i, const std::size_t j);
double evaluate_single_phase_phmolar(parameters output, std::size_t i, std::size_t j){
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
return evaluate_single_phase(single_phase_logph, coeffs_ph, output, _hmolar, _p, i, j);
};
double evaluate_single_phase_pT(parameters output, std::size_t i, std::size_t j){
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
return evaluate_single_phase(single_phase_logpT, coeffs_pT, output, _T, _p, i, j);
};
@@ -204,9 +212,11 @@ class BicubicBackend : public TabularBackend
double evaluate_single_phase_transport(SinglePhaseGriddedTableData &table, parameters output, double x, double y, std::size_t i, std::size_t j);
double evaluate_single_phase_phmolar_transport(parameters output, std::size_t i, std::size_t j){
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
return evaluate_single_phase_transport(single_phase_logph, output, _hmolar, _p, i, j);
};
double evaluate_single_phase_pT_transport(parameters output, std::size_t i, std::size_t j){
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
return evaluate_single_phase_transport(single_phase_logpT, output, _T, _p, i, j);
};

View File

@@ -20,6 +20,11 @@ void CoolProp::TTSEBackend::update(CoolProp::input_pairs input_pair, double val1
// To start, set quality to value that is impossible
_Q = -1000;
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
switch(input_pair){
case HmolarP_INPUTS:{

View File

@@ -21,15 +21,19 @@ class TTSEBackend : public TabularBackend
double evaluate_single_phase(SinglePhaseGriddedTableData &table, parameters output, double x, double y, std::size_t i, std::size_t j);
double evaluate_single_phase_transport(SinglePhaseGriddedTableData &table, parameters output, double x, double y, std::size_t i, std::size_t j);
double evaluate_single_phase_phmolar(parameters output, std::size_t i, std::size_t j){
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
return evaluate_single_phase(single_phase_logph, output, _hmolar, _p, i, j);
}
double evaluate_single_phase_pT(parameters output, std::size_t i, std::size_t j){
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
return evaluate_single_phase(single_phase_logpT, output, _T, _p, i, j);
}
double evaluate_single_phase_phmolar_transport(parameters output, std::size_t i, std::size_t j){
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
return evaluate_single_phase_transport(single_phase_logph, output, _hmolar, _p, i, j);
}
double evaluate_single_phase_pT_transport(parameters output, std::size_t i, std::size_t j){
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
return evaluate_single_phase_transport(single_phase_logpT, output, _T, _p, i, j);
}
double invert_single_phase_x(SinglePhaseGriddedTableData &table, parameters output, double x, double y, std::size_t i, std::size_t j);
@@ -50,9 +54,11 @@ class TTSEBackend : public TabularBackend
*/
double evaluate_single_phase_derivative(SinglePhaseGriddedTableData &table, parameters output, double x, double y, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny);
double evaluate_single_phase_phmolar_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny){
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
return evaluate_single_phase_derivative(single_phase_logph, output, _hmolar, _p, i, j, Nx, Ny);
};
double evaluate_single_phase_pT_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny){
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
return evaluate_single_phase_derivative(single_phase_logpT, output, _T, _p, i, j, Nx, Ny);
};
};

View File

@@ -7,8 +7,9 @@
#include "time.h"
#include "miniz.h"
namespace CoolProp{
CoolProp::TabularDataLibrary library;
namespace CoolProp{
/**
* @brief
@@ -299,25 +300,259 @@ std::string CoolProp::TabularBackend::path_to_tables(void){
void CoolProp::TabularBackend::write_tables(){
std::string path_to_tables = this->path_to_tables();
make_dirs(path_to_tables);
bool loaded = false;
dataset = library.get_set_of_tables(this->AS, loaded);
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
write_table(single_phase_logph, path_to_tables, "single_phase_logph");
write_table(single_phase_logpT, path_to_tables, "single_phase_logpT");
write_table(pure_saturation, path_to_tables, "pure_saturation");
write_table(phase_envelope, path_to_tables, "phase_envelope");
}
void CoolProp::TabularBackend::load_tables(){
std::string path_to_tables = this->path_to_tables();
single_phase_logph.AS = this->AS;
single_phase_logpT.AS = this->AS;
pure_saturation.AS = this->AS;
single_phase_logph.set_limits();
single_phase_logpT.set_limits();
load_table(single_phase_logph, path_to_tables, "single_phase_logph.bin.z");
load_table(single_phase_logpT, path_to_tables, "single_phase_logpT.bin.z");
load_table(pure_saturation, path_to_tables, "pure_saturation.bin.z");
load_table(phase_envelope, path_to_tables, "phase_envelope.bin.z");
bool loaded = false;
dataset = library.get_set_of_tables(this->AS, loaded);
if (loaded == false){
throw UnableToLoadError("Could not load tables");
}
if (get_debug_level() > 0){ std::cout << "Tables loaded" << std::endl; }
}
CoolPropDbl CoolProp::TabularBackend::calc_T(void){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (using_single_phase_table){
switch (selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar(iT, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return _T;
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
return pure_saturation.evaluate(iT, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
CoolPropDbl CoolProp::TabularBackend::calc_rhomolar(void){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (using_single_phase_table){
switch (selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar(iDmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT(iDmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
if (is_mixture){
return phase_envelope_sat(phase_envelope, iDmolar, iP, _p);
}
else{
return pure_saturation.evaluate(iDmolar, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
}
CoolPropDbl CoolProp::TabularBackend::calc_hmolar(void){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (using_single_phase_table){
switch (selected_table){
case SELECTED_PH_TABLE: return _hmolar;
case SELECTED_PT_TABLE: return evaluate_single_phase_pT(iHmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
if (is_mixture){
return phase_envelope_sat(phase_envelope, iHmolar, iP, _p);
}
else{
return pure_saturation.evaluate(iHmolar, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
}
CoolPropDbl CoolProp::TabularBackend::calc_smolar(void){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (using_single_phase_table){
switch (selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar(iSmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT(iSmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
if (is_mixture){
return phase_envelope_sat(phase_envelope, iSmolar, iP, _p);
}
else{
return pure_saturation.evaluate(iSmolar, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
}
CoolPropDbl CoolProp::TabularBackend::calc_umolar(void){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (using_single_phase_table){
switch (selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar(iUmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT(iUmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
if (is_mixture){
return phase_envelope_sat(phase_envelope, iUmolar, iP, _p);
}
else{
return pure_saturation.evaluate(iUmolar, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
}
CoolPropDbl CoolProp::TabularBackend::calc_cpmolar(void){
if (using_single_phase_table){
return calc_first_partial_deriv(iHmolar, iT, iP);
}
else{
throw ValueError("Two-phase not possible for cpmolar currently");
}
}
CoolPropDbl CoolProp::TabularBackend::calc_cvmolar(void){
if (using_single_phase_table){
return calc_first_partial_deriv(iUmolar, iT, iDmolar);
}
else{
throw ValueError("Two-phase not possible for cvmolar currently");
}
}
CoolPropDbl CoolProp::TabularBackend::calc_viscosity(void){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (using_single_phase_table){
switch (selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar_transport(iviscosity, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT_transport(iviscosity, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
return pure_saturation.evaluate(iviscosity, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
CoolPropDbl CoolProp::TabularBackend::calc_conductivity(void){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (using_single_phase_table){
switch (selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar_transport(iconductivity, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT_transport(iconductivity, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
return pure_saturation.evaluate(iconductivity, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
CoolPropDbl CoolProp::TabularBackend::calc_first_partial_deriv(parameters Of, parameters Wrt, parameters Constant){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (using_single_phase_table){
CoolPropDbl dOf_dx, dOf_dy, dWrt_dx, dWrt_dy, dConstant_dx, dConstant_dy;
// If a mass-based parameter is provided, get a conversion factor and change the key to the molar-based key
double Of_conversion_factor = 1.0, Wrt_conversion_factor = 1.0, Constant_conversion_factor = 1.0;
mass_to_molar(Of, Of_conversion_factor, AS->molar_mass());
mass_to_molar(Wrt, Wrt_conversion_factor, AS->molar_mass());
mass_to_molar(Constant, Constant_conversion_factor, AS->molar_mass());
switch (selected_table){
case SELECTED_PH_TABLE: {
dOf_dx = evaluate_single_phase_phmolar_derivative(Of, cached_single_phase_i, cached_single_phase_j, 1, 0);
dOf_dy = evaluate_single_phase_phmolar_derivative(Of, cached_single_phase_i, cached_single_phase_j, 0, 1);
dWrt_dx = evaluate_single_phase_phmolar_derivative(Wrt, cached_single_phase_i, cached_single_phase_j, 1, 0);
dWrt_dy = evaluate_single_phase_phmolar_derivative(Wrt, cached_single_phase_i, cached_single_phase_j, 0, 1);
dConstant_dx = evaluate_single_phase_phmolar_derivative(Constant, cached_single_phase_i, cached_single_phase_j, 1, 0);
dConstant_dy = evaluate_single_phase_phmolar_derivative(Constant, cached_single_phase_i, cached_single_phase_j, 0, 1);
break;
}
case SELECTED_PT_TABLE:{
dOf_dx = evaluate_single_phase_pT_derivative(Of, cached_single_phase_i, cached_single_phase_j, 1, 0);
dOf_dy = evaluate_single_phase_pT_derivative(Of, cached_single_phase_i, cached_single_phase_j, 0, 1);
dWrt_dx = evaluate_single_phase_pT_derivative(Wrt, cached_single_phase_i, cached_single_phase_j, 1, 0);
dWrt_dy = evaluate_single_phase_pT_derivative(Wrt, cached_single_phase_i, cached_single_phase_j, 0, 1);
dConstant_dx = evaluate_single_phase_pT_derivative(Constant, cached_single_phase_i, cached_single_phase_j, 1, 0);
dConstant_dy = evaluate_single_phase_pT_derivative(Constant, cached_single_phase_i, cached_single_phase_j, 0, 1);
break;
}
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
double val = (dOf_dx*dConstant_dy-dOf_dy*dConstant_dx)/(dWrt_dx*dConstant_dy-dWrt_dy*dConstant_dx);
return val*Of_conversion_factor/Wrt_conversion_factor;
}
else{
return pure_saturation.evaluate(iconductivity, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
};
CoolPropDbl CoolProp::TabularBackend::calc_first_saturation_deriv(parameters Of1, parameters Wrt1){
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (AS->get_mole_fractions().size() > 1){ throw ValueError("calc_first_saturation_deriv not available for mixtures"); }
if (std::abs(_Q) < 1e-6){
return pure_saturation.first_saturation_deriv(Of1, Wrt1, 0, keyed_output(Wrt1), cached_saturation_iL);
}
else if (std::abs(_Q-1) < 1e-6){
return pure_saturation.first_saturation_deriv(Of1, Wrt1, 1, keyed_output(Wrt1), cached_saturation_iV);
}
else{
throw ValueError(format("Quality [%Lg] must be either 0 or 1 to within 1 ppm", _Q));
}
}
CoolPropDbl CoolProp::TabularBackend::calc_first_two_phase_deriv(parameters Of, parameters Wrt, parameters Constant)
{
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
if (Of == iDmolar && Wrt == iHmolar && Constant == iP){
CoolPropDbl rhoL = pure_saturation.evaluate(iDmolar, _p, 0, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl rhoV = pure_saturation.evaluate(iDmolar, _p, 1, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl hL = pure_saturation.evaluate(iHmolar, _p, 0, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl hV = pure_saturation.evaluate(iHmolar, _p, 1, cached_saturation_iL, cached_saturation_iV);
return -POW2(rhomolar())*(1/rhoV - 1/rhoL)/(hV - hL);
}
else if (Of == iDmass && Wrt == iHmass && Constant == iP){
return first_two_phase_deriv(iDmolar, iHmolar, iP)*POW2(molar_mass());
}
else if (Of == iDmolar && Wrt == iP && Constant == iHmolar){
// v = 1/rho; dvdrho = -rho^2; dvdrho = -1/rho^2
CoolPropDbl rhoL = pure_saturation.evaluate(iDmolar, _p, 0, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl rhoV = pure_saturation.evaluate(iDmolar, _p, 1, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl hL = pure_saturation.evaluate(iHmolar, _p, 0, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl hV = pure_saturation.evaluate(iHmolar, _p, 1, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl dvdrhoL = -1/POW2(rhoL);
CoolPropDbl dvdrhoV = -1/POW2(rhoV);
CoolPropDbl dvL_dp = dvdrhoL*pure_saturation.first_saturation_deriv(iDmolar, iP, 0, _p, cached_saturation_iL);
CoolPropDbl dvV_dp = dvdrhoV*pure_saturation.first_saturation_deriv(iDmolar, iP, 1, _p, cached_saturation_iV);
CoolPropDbl dhL_dp = pure_saturation.first_saturation_deriv(iHmolar, iP, 0, _p, cached_saturation_iL);
CoolPropDbl dhV_dp = pure_saturation.first_saturation_deriv(iHmolar, iP, 1, _p, cached_saturation_iV);
CoolPropDbl dxdp_h = (Q()*dhV_dp + (1 - Q())*dhL_dp)/(hL - hV);
CoolPropDbl dvdp_h = dvL_dp + dxdp_h*(1/rhoV - 1/rhoL) + Q()*(dvV_dp - dvL_dp);
return -POW2(rhomolar())*dvdp_h;
}
else if (Of == iDmass && Wrt == iP && Constant == iHmass){
return first_two_phase_deriv(iDmolar, iP, iHmolar)*molar_mass();
}
else{
throw ValueError("These inputs are not supported to calc_first_two_phase_deriv");
}
}
void CoolProp::TabularDataSet::write_tables(const std::string &path_to_tables)
{
make_dirs(path_to_tables);
@@ -338,25 +573,54 @@ void CoolProp::TabularDataSet::load_tables(const std::string &path_to_tables, sh
load_table(single_phase_logpT, path_to_tables, "single_phase_logpT.bin.z");
load_table(pure_saturation, path_to_tables, "pure_saturation.bin.z");
load_table(phase_envelope, path_to_tables, "phase_envelope.bin.z");
tables_loaded = true;
if (get_debug_level() > 0){ std::cout << "Tables loaded" << std::endl; }
};
void CoolProp::TabularDataSet::build_tables(shared_ptr<CoolProp::AbstractState> &AS)
{
// Pure or pseudo-pure fluid
if (AS->get_mole_fractions().size() == 1){
pure_saturation.build(AS);
}
else{
// Call function to actually construct the phase envelope
AS->build_phase_envelope("");
// Copy constructed phase envelope into this class
phase_envelope = AS->get_phase_envelope_data();
// Resize so that it will load properly
pure_saturation.resize(pure_saturation.N);
}
single_phase_logph.build(AS);
single_phase_logpT.build(AS);
}
/// Return the set of tabular datasets
CoolProp::TabularDataSet const * CoolProp::TabularDataLibrary::get_set(shared_ptr<AbstractState> &AS)
CoolProp::TabularDataSet * CoolProp::TabularDataLibrary::get_set_of_tables(shared_ptr<AbstractState> &AS, bool &loaded)
{
const std::string path = path_to_tables(AS);
// Try to find tabular set if it is already loaded
std::map<std::string, TabularDataSet>::iterator it = data.find(path);
// It is already in the map, return it
if (it != data.end()){
loaded = it->second.tables_loaded;
return &(it->second);
}
// It is not in the map, build it
else{
TabularDataSet set;
data.insert(std::pair<std::string, TabularDataSet>(path, set));
set.load_tables(path, AS);
return &(data[path]);
TabularDataSet &dataset = data[path];
try{
if (!dataset.tables_loaded){
dataset.load_tables(path, AS);
}
loaded = true;
}
catch (std::exception &){
loaded = false;
}
return &(dataset);
}
}

View File

@@ -12,6 +12,7 @@
#include "../Helmholtz/PhaseEnvelopeRoutines.h"
/** ***MAGIC WARNING***!! X Macros in use
* See http://stackoverflow.com/a/148610
* See http://stackoverflow.com/questions/147267/easy-way-to-use-variables-of-enum-types-as-string-in-c#202511
@@ -558,6 +559,41 @@ class LogPTTable : public SinglePhaseGriddedTableData
};
};
/// This class contains the data for one set of Tabular data including single-phase and two-phase data
class TabularDataSet
{
public:
bool tables_loaded;
LogPHTable single_phase_logph;
LogPTTable single_phase_logpT;
PureFluidSaturationTableData pure_saturation;
PhaseEnvelopeData phase_envelope;
TabularDataSet(){ tables_loaded = false; }
void write_tables(const std::string &path_to_tables);
void load_tables(const std::string &path_to_tables, shared_ptr<CoolProp::AbstractState> &AS);
void build_tables(shared_ptr<CoolProp::AbstractState> &AS);
};
class TabularDataLibrary
{
private:
std::map<std::string, TabularDataSet> data;
public:
TabularDataLibrary(){};
std::string path_to_tables(shared_ptr<CoolProp::AbstractState> &AS){
std::vector<std::string> fluids = AS->fluid_names();
std::vector<CoolPropDbl> fractions = AS->get_mole_fractions();
std::vector<std::string> components;
for (std::size_t i = 0; i < fluids.size(); ++i){
components.push_back(format("%s[%0.10Lf]", fluids[i].c_str(), fractions[i]));
}
return get_home_dir() + "/.CoolProp/Tables/" + AS->backend_name() + "(" + strjoin(components, "&") + ")";
}
/// Return the set of tabular datasets
TabularDataSet * get_set_of_tables(shared_ptr<AbstractState> &AS, bool &loaded);
};
/**
* @brief This class contains the general code for tabular backends (TTSE, bicubic, etc.)
*
@@ -621,10 +657,8 @@ class TabularBackend : public AbstractState
throw ValueError();
}
}
LogPHTable single_phase_logph;
LogPTTable single_phase_logpT;
PureFluidSaturationTableData pure_saturation; // This will ultimately be split into pure and mixture backends which derive from this backend
PhaseEnvelopeData phase_envelope;
TabularDataSet * dataset;
CoolPropDbl calc_T_critical(void){return this->AS->T_critical();};
CoolPropDbl calc_Ttriple(void){return this->AS->Ttriple();};
CoolPropDbl calc_p_triple(void){return this->AS->p_triple();};
@@ -649,24 +683,11 @@ class TabularBackend : public AbstractState
std::string path_to_tables(void);
/// Load the tables from file; throws UnableToLoadException if there is a problem
void load_tables();
/// Build the tables
void build_tables(){
// Pure or pseudo-pure fluid
if (AS->get_mole_fractions().size() == 1){
pure_saturation.build(AS);
}
else{
// Call function to actually construct the phase envelope
AS->build_phase_envelope("");
// Copy constructed phase envelope into this class
phase_envelope = AS->get_phase_envelope_data();
// Resize so that it will load properly
pure_saturation.resize(pure_saturation.N);
}
single_phase_logph.build(AS);
single_phase_logpT.build(AS);
}
void pack_matrices(){
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
PureFluidSaturationTableData &pure_saturation = dataset->pure_saturation;
SinglePhaseGriddedTableData &single_phase_logph = dataset->single_phase_logph;
SinglePhaseGriddedTableData &single_phase_logpT = dataset->single_phase_logpT;
single_phase_logph.pack();
single_phase_logpT.pack();
pure_saturation.pack();
@@ -676,6 +697,7 @@ class TabularBackend : public AbstractState
void write_tables();
CoolPropDbl phase_envelope_sat(const PhaseEnvelopeData &env, parameters output, parameters iInput1, double value1){
const PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
CoolPropDbl yL = PhaseEnvelopeRoutines::evaluate(phase_envelope, output, iInput1, value1, cached_saturation_iL);
CoolPropDbl yV = PhaseEnvelopeRoutines::evaluate(phase_envelope, output, iInput1, value1, cached_saturation_iV);
return _Q*yV + (1-_Q)*yL;
@@ -683,183 +705,34 @@ class TabularBackend : public AbstractState
CoolPropDbl calc_cpmolar_idealgas(void){
return this->AS->cp0molar();
}
CoolPropDbl calc_T(void){
if (using_single_phase_table){
switch(selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar(iT, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return _T;
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
return pure_saturation.evaluate(iT, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
CoolPropDbl calc_rhomolar(void){
if (using_single_phase_table){
switch(selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar(iDmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT(iDmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
if (is_mixture){
return phase_envelope_sat(phase_envelope, iDmolar, iP, _p);
}
else{
return pure_saturation.evaluate(iDmolar, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
}
CoolPropDbl calc_hmolar(void){
if (using_single_phase_table){
switch(selected_table){
case SELECTED_PH_TABLE: return _hmolar;
case SELECTED_PT_TABLE: return evaluate_single_phase_pT(iHmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
if (is_mixture){
return phase_envelope_sat(phase_envelope, iHmolar, iP, _p);
}
else{
return pure_saturation.evaluate(iHmolar, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
}
CoolPropDbl calc_smolar(void){
if (using_single_phase_table){
switch(selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar(iSmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT(iSmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
if (is_mixture){
return phase_envelope_sat(phase_envelope, iSmolar, iP, _p);
}
else{
return pure_saturation.evaluate(iSmolar, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
}
CoolPropDbl calc_umolar(void){
if (using_single_phase_table){
switch(selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar(iUmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT(iUmolar, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
if (is_mixture){
return phase_envelope_sat(phase_envelope, iUmolar, iP, _p);
}
else{
return pure_saturation.evaluate(iUmolar, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
}
CoolPropDbl calc_cpmolar(void){
if (using_single_phase_table){
return calc_first_partial_deriv(iHmolar, iT, iP);
}
else{
throw ValueError("Two-phase not possible for cpmolar currently");
}
}
CoolPropDbl calc_cvmolar(void){
if (using_single_phase_table){
return calc_first_partial_deriv(iUmolar, iT, iDmolar);
}
else{
throw ValueError("Two-phase not possible for cvmolar currently");
}
}
CoolPropDbl calc_viscosity(void){
if (using_single_phase_table){
switch(selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar_transport(iviscosity, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT_transport(iviscosity, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
return pure_saturation.evaluate(iviscosity, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
CoolPropDbl calc_conductivity(void){
if (using_single_phase_table){
switch(selected_table){
case SELECTED_PH_TABLE: return evaluate_single_phase_phmolar_transport(iconductivity, cached_single_phase_i, cached_single_phase_j);
case SELECTED_PT_TABLE: return evaluate_single_phase_pT_transport(iconductivity, cached_single_phase_i, cached_single_phase_j);
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
return _HUGE; // not needed, will never be hit, just to make compiler happy
}
else{
return pure_saturation.evaluate(iconductivity, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
}
CoolPropDbl calc_first_partial_deriv(parameters Of, parameters Wrt, parameters Constant){
if (using_single_phase_table){
CoolPropDbl dOf_dx, dOf_dy, dWrt_dx, dWrt_dy, dConstant_dx, dConstant_dy;
// If a mass-based parameter is provided, get a conversion factor and change the key to the molar-based key
double Of_conversion_factor = 1.0, Wrt_conversion_factor = 1.0, Constant_conversion_factor = 1.0;
mass_to_molar(Of, Of_conversion_factor, AS->molar_mass());
mass_to_molar(Wrt, Wrt_conversion_factor, AS->molar_mass());
mass_to_molar(Constant, Constant_conversion_factor, AS->molar_mass());
switch(selected_table){
case SELECTED_PH_TABLE: {
dOf_dx = evaluate_single_phase_phmolar_derivative(Of, cached_single_phase_i, cached_single_phase_j,1,0);
dOf_dy = evaluate_single_phase_phmolar_derivative(Of, cached_single_phase_i, cached_single_phase_j,0,1);
dWrt_dx = evaluate_single_phase_phmolar_derivative(Wrt, cached_single_phase_i, cached_single_phase_j,1,0);
dWrt_dy = evaluate_single_phase_phmolar_derivative(Wrt, cached_single_phase_i, cached_single_phase_j,0,1);
dConstant_dx = evaluate_single_phase_phmolar_derivative(Constant, cached_single_phase_i, cached_single_phase_j,1,0);
dConstant_dy = evaluate_single_phase_phmolar_derivative(Constant, cached_single_phase_i, cached_single_phase_j,0,1);
break;
}
case SELECTED_PT_TABLE:{
dOf_dx = evaluate_single_phase_pT_derivative(Of, cached_single_phase_i, cached_single_phase_j,1,0);
dOf_dy = evaluate_single_phase_pT_derivative(Of, cached_single_phase_i, cached_single_phase_j,0,1);
dWrt_dx = evaluate_single_phase_pT_derivative(Wrt, cached_single_phase_i, cached_single_phase_j,1,0);
dWrt_dy = evaluate_single_phase_pT_derivative(Wrt, cached_single_phase_i, cached_single_phase_j,0,1);
dConstant_dx = evaluate_single_phase_pT_derivative(Constant, cached_single_phase_i, cached_single_phase_j,1,0);
dConstant_dy = evaluate_single_phase_pT_derivative(Constant, cached_single_phase_i, cached_single_phase_j,0,1);
break;
}
case SELECTED_NO_TABLE: throw ValueError("table not selected");
}
double val = (dOf_dx*dConstant_dy-dOf_dy*dConstant_dx)/(dWrt_dx*dConstant_dy-dWrt_dy*dConstant_dx);
return val*Of_conversion_factor/Wrt_conversion_factor;
}
else{
return pure_saturation.evaluate(iconductivity, _p, _Q, cached_saturation_iL, cached_saturation_iV);
}
};
CoolPropDbl calc_T(void);
CoolPropDbl calc_rhomolar(void);
CoolPropDbl calc_hmolar(void);
CoolPropDbl calc_smolar(void);
CoolPropDbl calc_umolar(void);
CoolPropDbl calc_cpmolar(void);
CoolPropDbl calc_cvmolar(void);
CoolPropDbl calc_viscosity(void);
CoolPropDbl calc_conductivity(void);
CoolPropDbl calc_first_partial_deriv(parameters Of, parameters Wrt, parameters Constant);
/** /brief calculate the derivative along the saturation curve, but only if quality is 0 or 1
*/
CoolPropDbl calc_first_saturation_deriv(parameters Of1, parameters Wrt1);
CoolPropDbl calc_first_two_phase_deriv(parameters Of, parameters Wrt, parameters Constant);
void check_tables(){
if (!tables_loaded){
bool loaded;
try{
/// Try to load the tables if you can.
load_tables();
// Set the flag saying tables have been successfully loaded
tables_loaded = true;
}
catch(CoolProp::UnableToLoadError &){
catch(CoolProp::UnableToLoadError &e){
if (get_debug_level() > 0){ std::cout << format("Table loading failed with error: %s\n", e.what()); }
/// Check directory size
std::string table_path = get_home_dir() + "/.CoolProp/Tables/";
#if defined(__ISWINDOWS__)
@@ -876,7 +749,7 @@ class TabularBackend : public AbstractState
set_warning_string(format("Maximum allowed tabular directory size is %g GB, you have exceeded this limit", allowed_size_in_GB));
}
/// If you cannot load the tables, build them and then write them to file
build_tables();
dataset->build_tables(this->AS);
pack_matrices();
write_tables();
/// Load the tables back into memory as a consistency check
@@ -886,86 +759,8 @@ class TabularBackend : public AbstractState
}
}
};
/** /brief calculate the derivative along the saturation curve, but only if quality is 0 or 1
*/
CoolPropDbl calc_first_saturation_deriv(parameters Of1, parameters Wrt1){
if (AS->get_mole_fractions().size() > 1){throw ValueError("calc_first_saturation_deriv not available for mixtures");}
if (std::abs(_Q) < 1e-6){
return pure_saturation.first_saturation_deriv(Of1, Wrt1, 0, keyed_output(Wrt1), cached_saturation_iL);
}
else if (std::abs(_Q-1) < 1e-6){
return pure_saturation.first_saturation_deriv(Of1, Wrt1, 1, keyed_output(Wrt1), cached_saturation_iV);
}
else{
throw ValueError(format("Quality [%Lg] must be either 0 or 1 to within 1 ppm", _Q));
}
}
CoolPropDbl calc_first_two_phase_deriv(parameters Of, parameters Wrt, parameters Constant)
{
if (Of == iDmolar && Wrt == iHmolar && Constant == iP){
CoolPropDbl rhoL = pure_saturation.evaluate(iDmolar, _p, 0, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl rhoV = pure_saturation.evaluate(iDmolar, _p, 1, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl hL = pure_saturation.evaluate(iHmolar, _p, 0, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl hV = pure_saturation.evaluate(iHmolar, _p, 1, cached_saturation_iL, cached_saturation_iV);
return -POW2(rhomolar())*(1/rhoV - 1/rhoL)/(hV - hL);
}
else if (Of == iDmass && Wrt == iHmass && Constant == iP){
return first_two_phase_deriv(iDmolar, iHmolar, iP)*POW2(molar_mass());
}
else if (Of == iDmolar && Wrt == iP && Constant == iHmolar){
// v = 1/rho; dvdrho = -rho^2; dvdrho = -1/rho^2
CoolPropDbl rhoL = pure_saturation.evaluate(iDmolar, _p, 0, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl rhoV = pure_saturation.evaluate(iDmolar, _p, 1, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl hL = pure_saturation.evaluate(iHmolar, _p, 0, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl hV = pure_saturation.evaluate(iHmolar, _p, 1, cached_saturation_iL, cached_saturation_iV);
CoolPropDbl dvdrhoL = -1/POW2(rhoL);
CoolPropDbl dvdrhoV = -1/POW2(rhoV);
CoolPropDbl dvL_dp = dvdrhoL*pure_saturation.first_saturation_deriv(iDmolar, iP, 0, _p, cached_saturation_iL);
CoolPropDbl dvV_dp = dvdrhoV*pure_saturation.first_saturation_deriv(iDmolar, iP, 1, _p, cached_saturation_iV);
CoolPropDbl dhL_dp = pure_saturation.first_saturation_deriv(iHmolar, iP, 0, _p, cached_saturation_iL);
CoolPropDbl dhV_dp = pure_saturation.first_saturation_deriv(iHmolar, iP, 1, _p, cached_saturation_iV);
CoolPropDbl dxdp_h = (Q()*dhV_dp + (1 - Q())*dhL_dp)/(hL - hV);
CoolPropDbl dvdp_h = dvL_dp + dxdp_h*(1/rhoV - 1/rhoL) + Q()*(dvV_dp - dvL_dp);
return -POW2(rhomolar())*dvdp_h;
}
else if (Of == iDmass && Wrt == iP && Constant == iHmass){
return first_two_phase_deriv(iDmolar, iP, iHmolar)*molar_mass();
}
else{
throw ValueError("These inputs are not supported to calc_first_two_phase_deriv");
}
}
};
/// This class contains the data for one set of Tabular data including single-phase and two-phase data
class TabularDataSet
{
public:
LogPHTable single_phase_logph;
LogPTTable single_phase_logpT;
PureFluidSaturationTableData pure_saturation;
PhaseEnvelopeData phase_envelope;
void write_tables(const std::string &path_to_tables);
void load_tables(const std::string &path_to_tables, shared_ptr<CoolProp::AbstractState> &AS);
};
class TabularDataLibrary
{
private:
std::map<std::string, TabularDataSet> data;
public:
TabularDataLibrary(){};
std::string path_to_tables(shared_ptr<CoolProp::AbstractState> &AS){
std::vector<std::string> fluids = AS->fluid_names();
std::vector<CoolPropDbl> fractions = AS->get_mole_fractions();
std::vector<std::string> components;
for (std::size_t i = 0; i < fluids.size(); ++i){
components.push_back(format("%s[%0.10Lf]", fluids[i].c_str(), fractions[i]));
}
return get_home_dir() + "/.CoolProp/Tables/" + AS->backend_name() + "(" + strjoin(components, "&") + ")";
}
/// Return the set of tabular datasets
TabularDataSet const * get_set(shared_ptr<AbstractState> &AS);
};
} /* namespace CoolProp*/