Added some new functions to handle volume fractions, hope this does not cause any trouble other places

This commit is contained in:
jowr
2014-07-22 17:29:01 +02:00
parent 85c2e7954f
commit 6360e84a54
13 changed files with 278 additions and 65 deletions

View File

@@ -40,6 +40,8 @@ public:
// Helmholtz EOS backend uses mole fractions
bool using_mole_fractions(){return true;}
bool using_mass_fractions(){return false;}
bool using_volu_fractions(){return false;}
const std::vector<CoolPropFluid*> &get_components(){return components;};
std::vector<long double> &get_K(){return K;};

View File

@@ -13,17 +13,24 @@
#include "IncompressibleBackend.h"
#include "IncompressibleFluid.h"
#include "IncompressibleLibrary.h"
#include "DataStructures.h"
#include "Solvers.h"
#include "MatrixMath.h"
namespace CoolProp {
IncompressibleBackend::IncompressibleBackend() {
//this->_fractions_id = ifrac_undefined;
}
IncompressibleBackend::IncompressibleBackend(IncompressibleFluid* fluid) {
//this->_fractions_id = fluid->getxid();
this->fluid = fluid;
}
IncompressibleBackend::IncompressibleBackend(const std::string &fluid_name) {
fluid = &get_incompressible_fluid(fluid_name);
this->fluid = &get_incompressible_fluid(fluid_name);
//this->_fractions_id = this->fluid->getxid();
}
IncompressibleBackend::IncompressibleBackend(const std::vector<std::string> &component_names) {
@@ -47,10 +54,12 @@ void IncompressibleBackend::update(long input_pair, double value1, double value2
} else {
this->_fluid_type = FLUID_TYPE_INCOMPRESSIBLE_SOLUTION;
}
if (get_debug_level()>=50) std::cout << format("Incompressible backend: Fluid type is %d ",this->_fluid_type) << std::endl;
this->_phase = iphase_liquid;
if (get_debug_level()>=50) std::cout << format("Incompressible backend: Phase type is %d ",this->_phase) << std::endl;
if (this->_fluid_type==FLUID_TYPE_INCOMPRESSIBLE_SOLUTION && mass_fractions.size()==0){
if (this->_fluid_type==FLUID_TYPE_INCOMPRESSIBLE_SOLUTION && _fractions.size()==0){
throw ValueError("This is a solution or brine. Mass fractions must be set");
}
@@ -91,34 +100,67 @@ void IncompressibleBackend::update(long input_pair, double value1, double value2
if (!ValidNumber(_p)){ throw ValueError("p is not a valid number");}
if (_T < 0){ throw ValueError("T is less than zero");}
if (!ValidNumber(_T)){ throw ValueError("T is not a valid number");}
if (get_debug_level()>=50) std::cout << format("Incompressible backend: Update finished T=%f, p=%f, x=%s ",this->_T,this->_p,vec_to_string(_fractions).c_str()) << std::endl;
}
/// Set the mole fractions
/**
@param mole_fractions The vector of mole fractions of the components
*/
void IncompressibleBackend::set_mole_fractions(const std::vector<long double> &mole_fractions) {
throw NotImplementedError("Cannot set mole fractions for incompressible fluid");
void IncompressibleBackend::set_mole_fractions(const std::vector<long double> &mole_fractions){
if (get_debug_level()>=10) std::cout << format("Incompressible backend: Called set_mole_fractions with %s ",vec_to_string(mole_fractions).c_str()) << std::endl;
if (mole_fractions.size()!=1) throw ValueError(format("The incompressible backend only supports one entry in the mole fraction vector and not %d.",mole_fractions.size()));
if (fluid->getxid()==ifrac_pure) {
this->_fractions = std::vector<long double>(1,0);
if (get_debug_level()>=20) std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s",vec_to_string(mole_fractions).c_str(),vec_to_string(this->_fractions).c_str()) << std::endl;
} else if (fluid->getxid()==ifrac_mole) {
this->_fractions = mole_fractions;
} else {
this->_fractions.clear();
for (std::size_t i = 0; i < mole_fractions.size(); i++) {
this->_fractions.push_back((long double) fluid->inputFromMole(0.0, mole_fractions[i]));
}
}
}
/// Set the mass fractions
/**
@param mass_fractions The vector of mass fractions of the components
*/
void IncompressibleBackend::set_mass_fractions(const std::vector<long double> &mass_fractions) {
//if (get_debug_level()>=10) std::cout << format("Incompressible backend: Called set_mass_fractions with %s ",vec_to_string(std::vector<double>(mass_fractions.begin(), mass_fractions.end()))) << std::endl;
void IncompressibleBackend::set_mass_fractions(const std::vector<long double> &mass_fractions){
if (get_debug_level()>=10) std::cout << format("Incompressible backend: Called set_mass_fractions with %s ",vec_to_string(mass_fractions).c_str()) << std::endl;
if (mass_fractions.size()!=1) throw ValueError(format("The incompressible backend only supports one entry in the mass fraction vector and not %d.",mass_fractions.size()));
this->mass_fractions = mass_fractions;
if (fluid->getxid()==ifrac_pure) {
this->_fractions = std::vector<long double>(1,0);
if (get_debug_level()>=20) std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s",vec_to_string(mass_fractions).c_str(),vec_to_string(this->_fractions).c_str()) << std::endl;
} else if (fluid->getxid()==ifrac_mass) {
this->_fractions = mass_fractions;
} else {
this->_fractions.clear();
for (std::size_t i = 0; i < mass_fractions.size(); i++) {
this->_fractions.push_back((long double) fluid->inputFromMass(0.0, mass_fractions[i]));
}
}
}
/// Set the mass fractions
/// Set the volume fractions
/**
@param mass_fraction The mass fraction of the component other than water
@param volu_fractions The vector of volume fractions of the components
*/
void IncompressibleBackend::set_mass_fractions(const long double &mass_fraction) {
if (get_debug_level()>=10) std::cout << format("Incompressible backend: Called set_mass_fractions with %s ",vec_to_string((double)mass_fraction).c_str()) << std::endl;
this->mass_fractions.clear();
this->mass_fractions.push_back(mass_fraction);
void IncompressibleBackend::set_volu_fractions(const std::vector<long double> &volu_fractions){
if (get_debug_level()>=10) std::cout << format("Incompressible backend: Called set_volu_fractions with %s ",vec_to_string(volu_fractions).c_str()) << std::endl;
if (volu_fractions.size()!=1) throw ValueError(format("The incompressible backend only supports one entry in the volume fraction vector and not %d.",volu_fractions.size()));
if (fluid->getxid()==ifrac_pure) {
this->_fractions = std::vector<long double>(1,0);
if (get_debug_level()>=20) std::cout << format("Incompressible backend: Overwriting fractions for pure fluid with %s -> %s",vec_to_string(volu_fractions).c_str(),vec_to_string(this->_fractions).c_str()) << std::endl;
} else if (fluid->getxid()==ifrac_volume) {
this->_fractions = volu_fractions;
} else {
this->_fractions.clear();
for (std::size_t i = 0; i < volu_fractions.size(); i++) {
this->_fractions.push_back((long double) fluid->inputFromVolume(0.0, volu_fractions[i]));
}
}
}
/// Check if the mole fractions have been set, etc.
@@ -133,7 +175,7 @@ void IncompressibleBackend::check_status() {
@returns T The temperature in K
*/
long double IncompressibleBackend::DmassP_flash(long double rhomass, long double p){
return fluid->T_rho(rhomass, p, mass_fractions[0]);
return fluid->T_rho(rhomass, p, _fractions[0]);
}
/// Calculate T given pressure and enthalpy
/**
@@ -165,7 +207,7 @@ long double IncompressibleBackend::HmassP_flash(long double hmass, long double p
//double T_tmp = this->PUmass_flash(p, hmass); // guess value from u=h
HmassP_residual res = HmassP_residual(fluid, p, mass_fractions[0], hmass);
HmassP_residual res = HmassP_residual(fluid, p, _fractions[0], hmass);
std::string errstring;
double macheps = DBL_EPSILON;
@@ -182,7 +224,7 @@ long double IncompressibleBackend::HmassP_flash(long double hmass, long double p
@returns T The temperature in K
*/
long double IncompressibleBackend::PSmass_flash(long double p, long double smass){
return fluid->T_s(smass, p, mass_fractions[0]);
return fluid->T_s(smass, p, _fractions[0]);
}
/// Calculate T given pressure and internal energy
@@ -192,7 +234,7 @@ long double IncompressibleBackend::PSmass_flash(long double p, long double smass
@returns T The temperature in K
*/
long double IncompressibleBackend::PUmass_flash(long double p, long double umass){
return fluid->T_u(umass, p, mass_fractions[0]);
return fluid->T_u(umass, p, _fractions[0]);
}
@@ -230,7 +272,6 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi
CHECK_NOTHROW( backend.set_mass_fractions(fractions) );
fractions.push_back(0.4);
CHECK_THROWS( backend.set_mass_fractions(fractions) );
CHECK_NOTHROW( backend.set_mass_fractions(0.4) );
CHECK_THROWS( backend.check_status() );
@@ -240,7 +281,7 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi
double T = 273.15+10;
double p = 10e5;
double x = 0.25;
backend.set_mass_fractions(x);
backend.set_mass_fractions(std::vector<long double>(1,x));
double val = 0;
double res = 0;
@@ -387,6 +428,21 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi
CAPTURE(res);
CHECK( check_abs(val,res,acc) );
}
// Compare Tfreeze
val = fluid.Tfreeze(p, x);//-20.02+273.15;// 253.1293105454671;
res = -20.02+273.15;
{
CAPTURE(T);
CAPTURE(p);
CAPTURE(x);
CAPTURE(val);
CAPTURE(res);
CHECK( check_abs(val,res,acc) );
}
}
SECTION("Tests for the full implementation using PropsSI") {

View File

@@ -4,6 +4,7 @@
#include "IncompressibleFluid.h"
#include "AbstractState.h"
#include "DataStructures.h"
#include "Exceptions.h"
#include <vector>
@@ -12,13 +13,13 @@ namespace CoolProp {
class IncompressibleBackend : public AbstractState {
protected:
int Ncomp;
bool _mole_fractions_set;
static bool _REFPROP_supported;
std::vector<long double> mass_fractions;
//int Ncomp;
//static bool _REFPROP_supported;
//int _fractions_id;
std::vector<long double> _fractions;
IncompressibleFluid *fluid;
public:
IncompressibleBackend(){};
IncompressibleBackend();
virtual ~IncompressibleBackend(){};
/// The instantiator
@@ -31,8 +32,10 @@ public:
/// @param fluid_names The vector of strings of the fluid components, without file ending
IncompressibleBackend(const std::vector<std::string> &component_names);
// Incompressible backend uses mole fractions
bool using_mole_fractions(){return false;};
// Incompressible backend uses different compositions
bool using_mole_fractions(){return this->fluid->getxid()==ifrac_mole;};
bool using_mass_fractions(){return (this->fluid->getxid()==ifrac_mass || this->fluid->getxid()==ifrac_pure);};
bool using_volu_fractions(){return this->fluid->getxid()==ifrac_volume;};
/// Updating function for incompressible fluid
/**
@@ -57,11 +60,11 @@ public:
*/
void set_mass_fractions(const std::vector<long double> &mass_fractions);
/// Set the mass fraction
/// Set the volume fractions
/**
@param mass_fractions The mass fraction of the component other than water
@param volu_fractions The vector of volume fractions of the components
*/
void set_mass_fractions(const long double &mass_fraction);
void set_volu_fractions(const std::vector<long double> &volu_fractions);
/// Check if the mole fractions have been set, etc.
void check_status();
@@ -97,16 +100,16 @@ public:
long double PUmass_flash(long double p, long double umass);
/// Get the viscosity [Pa-s]
long double calc_viscosity(void){return fluid->visc(_T, _p, mass_fractions[0]);};
long double calc_viscosity(void){return fluid->visc(_T, _p, _fractions[0]);};
/// Get the thermal conductivity [W/m/K] (based on the temperature and pressure in the state class)
long double calc_conductivity(void){return fluid->cond(_T, _p, mass_fractions[0]);};
long double calc_conductivity(void){return fluid->cond(_T, _p, _fractions[0]);};
long double calc_rhomass(void){return fluid->rho(_T, _p, mass_fractions[0]);};
long double calc_hmass(void){return fluid->h(_T, _p, mass_fractions[0]);};
long double calc_smass(void){return fluid->s(_T, _p, mass_fractions[0]);};
long double calc_umass(void){return fluid->u(_T, _p, mass_fractions[0]);};
long double calc_cpmass(void){return fluid->cp(_T, _p, mass_fractions[0]);};
long double calc_cvmass(void){return fluid->cv(_T, _p, mass_fractions[0]);};
long double calc_rhomass(void){return fluid->rho(_T, _p, _fractions[0]);};
long double calc_hmass(void){return fluid->h(_T, _p, _fractions[0]);};
long double calc_smass(void){return fluid->s(_T, _p, _fractions[0]);};
long double calc_umass(void){return fluid->u(_T, _p, _fractions[0]);};
long double calc_cpmass(void){return fluid->cp(_T, _p, _fractions[0]);};
long double calc_cvmass(void){return fluid->cv(_T, _p, _fractions[0]);};
};
} /* namespace CoolProp */

View File

@@ -3,6 +3,7 @@
#include "math.h"
#include "MatrixMath.h"
#include "PolyMath.h"
#include "DataStructures.h"
namespace CoolProp {
@@ -14,7 +15,7 @@ This fluid instance is populated using an entry from a JSON file
*/
//IncompressibleFluid::IncompressibleFluid();
void IncompressibleFluid::set_reference_state(double T0, double p0, double x0=0.0, double h0=0.0, double s0=0.0){
void IncompressibleFluid::set_reference_state(double T0, double p0, double x0, double h0, double s0){
this->rhoref = rho(T0,p0,x0);
this->pref = p0;
this->uref = h0 - p0/rhoref;
@@ -265,10 +266,116 @@ double IncompressibleFluid::Tfreeze( double p, double x){
return _HUGE;
}
/// Conversion from volume-based to mass-based composition.
double IncompressibleFluid::V2M (double T, double y){throw NotImplementedError("TODO");}
/// Conversion from mass-based to mole-based composition.
double IncompressibleFluid::M2M (double T, double x){throw NotImplementedError("TODO");}
/// Mass fraction conversion function
/** If the fluid type is mass-based, it does not do anything. Otherwise,
* it converts the mass fraction to the required input. */
double IncompressibleFluid::inputFromMass (double T, double x){
if (this->xid==ifrac_pure) {
return _HUGE;
} else if (this->xid==ifrac_mass) {
return x;
} else {
throw NotImplementedError("Mass composition conversion has not been implemented.");
switch (mass2input.type) {
case IncompressibleData::INCOMPRESSIBLE_POLYNOMIAL:
return poly.evaluate(mass2input.coeffs, T, x, 0, 0, 0.0, 0.0); // TODO: make sure Tbase and xbase is defined in the correct way
break;
case IncompressibleData::INCOMPRESSIBLE_EXPONENTIAL:
return baseExponential(mass2input, T, Tbase);
break;
case IncompressibleData::INCOMPRESSIBLE_EXPPOLYNOMIAL:
return exp(poly.evaluate(mass2input.coeffs, T, x, 0, 0, 0.0, 0.0)); // TODO: make sure Tbase and xbase is defined in the correct way
break;
case IncompressibleData::INCOMPRESSIBLE_EXPOFFSET:
return baseExponentialOffset(mass2input, T);
break;
case IncompressibleData::INCOMPRESSIBLE_POLYOFFSET:
return basePolyOffset(mass2input, T, x);
break;
case IncompressibleData::INCOMPRESSIBLE_NOT_SET:
throw ValueError(format("%s (%d): The function type is not specified (\"[%d]\"), are you sure the coefficients have been set?",__FILE__,__LINE__,mass2input.type));
break;
default:
throw ValueError(format("%s (%d): Your function type \"[%d]\" is unknown.",__FILE__,__LINE__,mass2input.type));
break;
}
return _HUGE;
}
}
/// Volume fraction conversion function
/** If the fluid type is volume-based, it does not do anything. Otherwise,
* it converts the volume fraction to the required input. */
double IncompressibleFluid::inputFromVolume (double T, double x){
if (this->xid==ifrac_pure) {
return _HUGE;
} else if (this->xid==ifrac_volume) {
return x;
} else {
throw NotImplementedError("Volume composition conversion has not been implemented.");
switch (volume2input.type) {
case IncompressibleData::INCOMPRESSIBLE_POLYNOMIAL:
return poly.evaluate(volume2input.coeffs, T, x, 0, 0, 0.0, 0.0); // TODO: make sure Tbase and xbase is defined in the correct way
break;
case IncompressibleData::INCOMPRESSIBLE_EXPONENTIAL:
return baseExponential(volume2input, T, Tbase);
break;
case IncompressibleData::INCOMPRESSIBLE_EXPPOLYNOMIAL:
return exp(poly.evaluate(volume2input.coeffs, T, x, 0, 0, 0.0, 0.0)); // TODO: make sure Tbase and xbase is defined in the correct way
break;
case IncompressibleData::INCOMPRESSIBLE_EXPOFFSET:
return baseExponentialOffset(volume2input, T);
break;
case IncompressibleData::INCOMPRESSIBLE_POLYOFFSET:
return basePolyOffset(volume2input, T, x);
break;
case IncompressibleData::INCOMPRESSIBLE_NOT_SET:
throw ValueError(format("%s (%d): The function type is not specified (\"[%d]\"), are you sure the coefficients have been set?",__FILE__,__LINE__,volume2input.type));
break;
default:
throw ValueError(format("%s (%d): Your function type \"[%d]\" is unknown.",__FILE__,__LINE__,volume2input.type));
break;
}
return _HUGE;
}
}
/// Mole fraction conversion function
/** If the fluid type is mole-based, it does not do anything. Otherwise,
* it converts the mole fraction to the required input. */
double IncompressibleFluid::inputFromMole (double T, double x){
if (this->xid==ifrac_pure) {
return _HUGE;
} else if (this->xid==ifrac_mole) {
return x;
} else {
throw NotImplementedError("Mole composition conversion has not been implemented.");
switch (mole2input.type) {
case IncompressibleData::INCOMPRESSIBLE_POLYNOMIAL:
return poly.evaluate(mole2input.coeffs, T, x, 0, 0, 0.0, 0.0); // TODO: make sure Tbase and xbase is defined in the correct way
break;
case IncompressibleData::INCOMPRESSIBLE_EXPONENTIAL:
return baseExponential(mole2input, T, Tbase);
break;
case IncompressibleData::INCOMPRESSIBLE_EXPPOLYNOMIAL:
return exp(poly.evaluate(mole2input.coeffs, T, x, 0, 0, 0.0, 0.0)); // TODO: make sure Tbase and xbase is defined in the correct way
break;
case IncompressibleData::INCOMPRESSIBLE_EXPOFFSET:
return baseExponentialOffset(mole2input, T);
break;
case IncompressibleData::INCOMPRESSIBLE_POLYOFFSET:
return basePolyOffset(mole2input, T, x);
break;
case IncompressibleData::INCOMPRESSIBLE_NOT_SET:
throw ValueError(format("%s (%d): The function type is not specified (\"[%d]\"), are you sure the coefficients have been set?",__FILE__,__LINE__,mole2input.type));
break;
default:
throw ValueError(format("%s (%d): Your function type \"[%d]\" is unknown.",__FILE__,__LINE__,mole2input.type));
break;
}
return _HUGE;
}
}
/* Some functions can be inverted directly, those are listed
* here. It is also possible to solve for other quantities, but
@@ -783,7 +890,7 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi
tmpVector.clear();
tmpVector.push_back( 27.755555600/100.0); // reference concentration in per cent
tmpVector.push_back(-22.973221700);
tmpVector.push_back(-22.973221700+273.15);
tmpVector.push_back(-1.1040507200*100.0);
tmpVector.push_back(-0.0120762281*100.0*100.0);
tmpVector.push_back(-9.343458E-05*100.0*100.0*100.0);
@@ -954,7 +1061,7 @@ TEST_CASE("Internal consistency checks and example use cases for the incompressi
// Compare Tfreeze
val = -20.02+273.15;// 253.1293105454671;
res = CH3OH.Tfreeze(p,x)+273.15;
res = CH3OH.Tfreeze(p,x);
{
CAPTURE(T);
CAPTURE(p);

View File

@@ -452,6 +452,7 @@ void JSONIncompressibleLibrary::add_one(rapidjson::Value &fluid_json) {
fluid.setTmin(parse_value(fluid_json, "Tmin", true, 0.0));
fluid.setxmax(parse_value(fluid_json, "xmax", false, 1.0));
fluid.setxmin(parse_value(fluid_json, "xmin", false, 0.0));
fluid.setxid((int) parse_value(fluid_json, "xid", true, 0.0));
fluid.setTminPsat(parse_value(fluid_json, "TminPsat", false, 0.0));
fluid.setTbase(parse_value(fluid_json, "Tbase", false, 0.0));
@@ -465,8 +466,9 @@ void JSONIncompressibleLibrary::add_one(rapidjson::Value &fluid_json) {
fluid.setConductivity(parse_coefficients(fluid_json, "conductivity", false));
fluid.setPsat(parse_coefficients(fluid_json, "saturation_pressure", false));
fluid.setTfreeze(parse_coefficients(fluid_json, "T_freeze", false));
fluid.setVolToMass(parse_coefficients(fluid_json, "volume2mass", false));
fluid.setMassToMole(parse_coefficients(fluid_json, "mass2mole", false));
fluid.setMass2input(parse_coefficients(fluid_json, "mass2input", false));
fluid.setVolume2input(parse_coefficients(fluid_json, "volume2input", false));
fluid.setMole2input(parse_coefficients(fluid_json, "mole2input", false));
if (get_debug_level()>=20) std::cout << format("Incompressible library: Loading reference state for %s ",fluid.getName().c_str()) << std::endl;
fluid.set_reference_state(

View File

@@ -32,6 +32,8 @@ public:
// REFPROP backend uses mole fractions
bool using_mole_fractions(){return true;}
bool using_mass_fractions(){return false;}
bool using_volu_fractions(){return false;}
/// Updating function for REFPROP
/**