Move HmolarP to TabularBackend

This commit is contained in:
Ian Bell
2015-12-06 16:49:09 -07:00
parent 8afb9efe60
commit ddaf0eee65
6 changed files with 102 additions and 124 deletions

View File

@@ -8,87 +8,34 @@
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();
// Clear cached variables
clear();
// Convert to mass-based units if necessary
CoolPropDbl ld_value1 = val1, ld_value2 = val2;
mass_to_molar_inputs(input_pair, ld_value1, ld_value2);
val1 = ld_value1; val2 = ld_value2;
// To start, set quality to value that is for single-phase
// Check the tables, build if neccessary
check_tables();
// Flush the cached indices (set to large number)
cached_single_phase_i = std::numeric_limits<std::size_t>::max();
cached_single_phase_j = std::numeric_limits<std::size_t>::max();
cached_saturation_iL = std::numeric_limits<std::size_t>::max();
cached_saturation_iV = std::numeric_limits<std::size_t>::max();
// To start, set quality to value that is impossible
_Q = -1000;
// Flush the cached indices (set to large number)
cached_single_phase_i = std::numeric_limits<std::size_t>::max();
cached_single_phase_j = std::numeric_limits<std::size_t>::max();
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;
if (!single_phase_logph.native_inputs_are_in_range(_hmolar, _p)){
// Use the AbstractState instance
using_single_phase_table = false;
if (get_debug_level() > 5){ std::cout << "inputs are not in range"; }
throw ValueError(format("inputs are not in range, hmolar=%Lg, p=%Lg", static_cast<CoolPropDbl>(_hmolar), _p));
}
else{
using_single_phase_table = true; // Use the table !
std::size_t iL, iV, iclosest = 0;
CoolPropDbl hL = 0, hV = 0;
SimpleState closest_state;
bool is_two_phase = false;
// Phase is imposed, use it
if (imposed_phase_index != iphase_not_imposed){
is_two_phase = (imposed_phase_index == iphase_twophase);
}
else{
if (is_mixture){
is_two_phase = PhaseEnvelopeRoutines::is_inside(phase_envelope, iP, _p, iHmolar, _hmolar, iclosest, closest_state);
}
else{
is_two_phase = pure_saturation.is_inside(iP, _p, iHmolar, _hmolar, iL, iV, hL, hV);
}
}
if ( is_two_phase )
{
using_single_phase_table = false;
_Q = (static_cast<double>(_hmolar)-hL)/(hV-hL);
if(!is_in_closed_range(0.0,1.0,static_cast<double>(_Q))){
throw ValueError("vapor quality is not in (0,1)");
}
else{
cached_saturation_iL = iL; cached_saturation_iV = iV;
_phase = iphase_twophase;
}
}
else{
// Find and cache the indices i, j
selected_table = SELECTED_PH_TABLE;
single_phase_logph.find_native_nearest_good_cell(_hmolar, _p, cached_single_phase_i, cached_single_phase_j);
CellCoeffs &cell = dataset->coeffs_ph[cached_single_phase_i][cached_single_phase_j];
if (!cell.valid()){
if (cell.has_valid_neighbor()){
// Get new good neighbor
cell.get_alternate(cached_single_phase_i, cached_single_phase_j);
}
else{
if (!cell.valid()){throw ValueError(format("Cell is invalid and has no good neighbors for hmolar = %g, p= %g",val1,val2));}
}
}
// Recalculate the phase
recalculate_singlephase_phase();
}
}
break;
}
case PUmolar_INPUTS:
case PSmolar_INPUTS:
case DmolarP_INPUTS:{
@@ -302,6 +249,7 @@ void CoolProp::BicubicBackend::update(CoolProp::input_pairs input_pair, double v
}
break;
}
case HmolarP_INPUTS:
case PQ_INPUTS:
case QT_INPUTS:
TabularBackend::update(input_pair, val1, val2); break;
@@ -310,6 +258,21 @@ void CoolProp::BicubicBackend::update(CoolProp::input_pairs input_pair, double v
}
}
void CoolProp::BicubicBackend::find_native_nearest_good_indices(SinglePhaseGriddedTableData &table, const std::vector<std::vector<CellCoeffs> > &coeffs, double x, double y, std::size_t &i, std::size_t &j)
{
table.find_native_nearest_good_cell(x, y, i, j);
const CellCoeffs &cell = coeffs[i][j];
if (!cell.valid()){
if (cell.has_valid_neighbor()){
// Get new good neighbor
cell.get_alternate(i, j);
}
else{
if (!cell.valid()){ throw ValueError(format("Cell is invalid and has no good neighbors for x = %g, y= %g", x, y)); }
}
}
}
/** Use the single_phase table to evaluate an output for a transport property
*
* Here we use linear interpolation because we don't have any information about the derivatives with respect to the

View File

@@ -134,6 +134,8 @@ class BicubicBackend : public TabularBackend
double evaluate_single_phase_pT(parameters output, std::size_t i, std::size_t j){
return evaluate_single_phase(dataset->single_phase_logpT, dataset->coeffs_pT, output, _T, _p, i, j);
};
virtual void find_native_nearest_good_indices(SinglePhaseGriddedTableData &table, const std::vector<std::vector<CellCoeffs> > &coeffs, double x, double y, std::size_t &i, std::size_t &j);
/**
* @brief Evaluate the single-phase transport properties using linear interpolation. Works well except for near the critical point

View File

@@ -6,6 +6,8 @@
void CoolProp::TTSEBackend::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 variables
clear();
@@ -16,69 +18,22 @@ void CoolProp::TTSEBackend::update(CoolProp::input_pairs input_pair, double val1
// Check the tables, build if neccessary
check_tables();
// Flush the cached indices (set to large number)
cached_single_phase_i = std::numeric_limits<std::size_t>::max();
cached_single_phase_i = std::numeric_limits<std::size_t>::max();
cached_single_phase_j = std::numeric_limits<std::size_t>::max();
cached_saturation_iL = std::numeric_limits<std::size_t>::max();
cached_saturation_iL = std::numeric_limits<std::size_t>::max();
cached_saturation_iV = std::numeric_limits<std::size_t>::max();
// To start, set quality to value that is impossible
_Q = -1000;
PhaseEnvelopeData & phase_envelope = dataset->phase_envelope;
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;
if (!single_phase_logph.native_inputs_are_in_range(_hmolar, _p)){
// Use the AbstractState instance
using_single_phase_table = false;
if (get_debug_level() > 5){ std::cout << "inputs are not in range"; }
throw ValueError(format("inputs are not in range, hmolar=%Lg, p=%Lg", static_cast<CoolPropDbl>(_hmolar), _p));
}
else{
using_single_phase_table = true; // Use the table !
std::size_t iL, iV;
CoolPropDbl hL = 0, hV = 0;
std::size_t iclosest = 0;
SimpleState closest_state;
bool is_two_phase = false;
// Phase is imposed, use it
if (imposed_phase_index != iphase_not_imposed){
is_two_phase = (imposed_phase_index == iphase_twophase);
}
else{
if (is_mixture){
is_two_phase = PhaseEnvelopeRoutines::is_inside(phase_envelope, iP, _p, iHmolar, _hmolar, iclosest, closest_state);
}
else{
is_two_phase = pure_saturation.is_inside(iP, _p, iHmolar, _hmolar, iL, iV, hL, hV);
}
}
if ( is_two_phase ){
using_single_phase_table = false;
_Q = (static_cast<double>(_hmolar)-hL)/(hV-hL);
if(!is_in_closed_range(0.0,1.0,static_cast<double>(_Q))){
throw ValueError("vapor quality is not in (0,1)");
}
else{
cached_saturation_iL = iL; cached_saturation_iV = iV; _phase = iphase_twophase;
}
}
else{
// Find and cache the indices i, j
selected_table = SELECTED_PH_TABLE;
single_phase_logph.find_native_nearest_good_neighbor(_hmolar, _p, cached_single_phase_i, cached_single_phase_j);
// Recalculate the phase
recalculate_singlephase_phase();
}
}
break;
}
case PUmolar_INPUTS:
case PSmolar_INPUTS:
case DmolarP_INPUTS:{
@@ -224,6 +179,7 @@ void CoolProp::TTSEBackend::update(CoolProp::input_pairs input_pair, double val1
}
break;
}
case HmolarP_INPUTS:
case PQ_INPUTS:
case QT_INPUTS:
TabularBackend::update(input_pair, val1, val2); break;

View File

@@ -45,6 +45,11 @@ class TTSEBackend : public TabularBackend
double invert_single_phase_x(SinglePhaseGriddedTableData &table, parameters output, double x, double y, std::size_t i, std::size_t j);
double invert_single_phase_y(SinglePhaseGriddedTableData &table, parameters output, double y, double x, std::size_t i, std::size_t j);
/// Find the best set of i,j for native inputs.
virtual void find_native_nearest_good_indices(SinglePhaseGriddedTableData &table, const std::vector<std::vector<CellCoeffs> > &coeffs, double x, double y, std::size_t &i, std::size_t &j){
return table.find_native_nearest_good_neighbor(x, y, i, j);
};
/**
* @brief Evaluate a derivative in terms of the native inputs of the table
* @param table A reference to the table to be used

View File

@@ -658,6 +658,53 @@ void CoolProp::TabularBackend::update(CoolProp::input_pairs input_pair, double v
switch (input_pair)
{
case HmolarP_INPUTS:{
_hmolar = val1; _p = val2;
if (!single_phase_logph.native_inputs_are_in_range(_hmolar, _p)){
// Use the AbstractState instance
using_single_phase_table = false;
if (get_debug_level() > 5){ std::cout << "inputs are not in range"; }
throw ValueError(format("inputs are not in range, hmolar=%Lg, p=%Lg", static_cast<CoolPropDbl>(_hmolar), _p));
}
else{
using_single_phase_table = true; // Use the table !
std::size_t iL, iV, iclosest = 0;
CoolPropDbl hL = 0, hV = 0;
SimpleState closest_state;
bool is_two_phase = false;
// Phase is imposed, use it
if (imposed_phase_index != iphase_not_imposed){
is_two_phase = (imposed_phase_index == iphase_twophase);
}
else{
if (is_mixture){
is_two_phase = PhaseEnvelopeRoutines::is_inside(phase_envelope, iP, _p, iHmolar, _hmolar, iclosest, closest_state);
}
else{
is_two_phase = pure_saturation.is_inside(iP, _p, iHmolar, _hmolar, iL, iV, hL, hV);
}
}
if (is_two_phase){
using_single_phase_table = false;
_Q = (static_cast<double>(_hmolar)-hL)/(hV-hL);
if (!is_in_closed_range(0.0, 1.0, static_cast<double>(_Q))){
throw ValueError("vapor quality is not in (0,1)");
}
else{
cached_saturation_iL = iL; cached_saturation_iV = iV;
_phase = iphase_twophase;
}
}
else{
selected_table = SELECTED_PH_TABLE;
// Find and cache the indices i, j
find_native_nearest_good_indices(single_phase_logph, dataset->coeffs_ph, _hmolar, _p, cached_single_phase_i, cached_single_phase_j);
// Recalculate the phase
recalculate_singlephase_phase();
}
}
break;
}
case PQ_INPUTS:{
std::size_t iL = 0, iV = 0;
_p = val1; _Q = val2;

View File

@@ -818,6 +818,16 @@ class TabularBackend : public AbstractState
*/
void calc_unspecify_phase(){ imposed_phase_index = iphase_not_imposed; };
virtual double evaluate_single_phase_phmolar(parameters output, std::size_t i, std::size_t j) = 0;
virtual double evaluate_single_phase_pT(parameters output, std::size_t i, std::size_t j) = 0;
virtual double evaluate_single_phase_phmolar_transport(parameters output, std::size_t i, std::size_t j) = 0;
virtual double evaluate_single_phase_pT_transport(parameters output, std::size_t i, std::size_t j) = 0;
virtual double evaluate_single_phase_phmolar_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny) = 0;
virtual double evaluate_single_phase_pT_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny) = 0;
/// Ask the derived class to find the nearest good set of i,j that it wants to use (pure virtual)
virtual void find_native_nearest_good_indices(SinglePhaseGriddedTableData &table, const std::vector<std::vector<CellCoeffs> > &coeffs, double x, double y, std::size_t &i, std::size_t &j) = 0;
phases calc_phase(void){ return _phase; }
CoolPropDbl calc_T_critical(void){return this->AS->T_critical();};
CoolPropDbl calc_Ttriple(void){return this->AS->Ttriple();};
@@ -837,12 +847,7 @@ class TabularBackend : public AbstractState
const std::vector<CoolPropDbl> calc_mass_fractions(void){ return AS->get_mass_fractions(); };
CoolPropDbl calc_molar_mass(void){return AS->molar_mass();};
virtual double evaluate_single_phase_phmolar(parameters output, std::size_t i, std::size_t j) = 0;
virtual double evaluate_single_phase_pT(parameters output, std::size_t i, std::size_t j) = 0;
virtual double evaluate_single_phase_phmolar_transport(parameters output, std::size_t i, std::size_t j) = 0;
virtual double evaluate_single_phase_pT_transport(parameters output, std::size_t i, std::size_t j) = 0;
virtual double evaluate_single_phase_phmolar_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny) = 0;
virtual double evaluate_single_phase_pT_derivative(parameters output, std::size_t i, std::size_t j, std::size_t Nx, std::size_t Ny) = 0;
CoolPropDbl calc_saturated_liquid_keyed_output(parameters key);
CoolPropDbl calc_saturated_vapor_keyed_output(parameters key);