mirror of
https://github.com/CoolProp/CoolProp.git
synced 2026-04-23 03:00:17 -04:00
Refactored tables to remove nearly all the copying of data
Some bugs remain still
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
|
||||
@@ -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:{
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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*/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user