diff --git a/include/AbstractState.h b/include/AbstractState.h index fa1e8e8d..842c3212 100644 --- a/include/AbstractState.h +++ b/include/AbstractState.h @@ -272,16 +272,20 @@ public: // The derived classes must implement this function to define whether they use mole fractions (true) or mass fractions (false) virtual bool using_mole_fractions(void) = 0; + virtual bool using_mass_fractions(void) = 0; + virtual bool using_volu_fractions(void) = 0; virtual void update(long input_pair, double Value1, double Value2) = 0; virtual void set_mole_fractions(const std::vector &mole_fractions) = 0; virtual void set_mass_fractions(const std::vector &mass_fractions) = 0; + virtual void set_volu_fractions(const std::vector &mass_fractions){throw NotImplementedError("Volume composition has not been implemented.");} /// Clear all the cached values bool clear(); void set_mole_fractions(const std::vector &mole_fractions){set_mole_fractions(std::vector(mole_fractions.begin(), mole_fractions.end()));}; void set_mass_fractions(const std::vector &mass_fractions){set_mass_fractions(std::vector(mass_fractions.begin(), mass_fractions.end()));}; + void set_volu_fractions(const std::vector &volu_fractions){set_volu_fractions(std::vector(volu_fractions.begin(), volu_fractions.end()));}; const CoolProp::SimpleState & get_reducing(){return _reducing;}; diff --git a/include/DataStructures.h b/include/DataStructures.h index 647cde8e..d4382751 100644 --- a/include/DataStructures.h +++ b/include/DataStructures.h @@ -73,6 +73,9 @@ int get_parameter_index(const std::string ¶m_name); std::string get_csv_parameter_list(); +/// These are constants for the compositions +enum compositions {ifrac_mass, ifrac_mole, ifrac_volume, ifrac_undefined, ifrac_pure}; + /// These are constants for the phases of the fluid enum phases {iphase_liquid, iphase_supercritical, iphase_gas, iphase_twophase, iphase_unknown}; diff --git a/include/IncompressibleFluid.h b/include/IncompressibleFluid.h index 7446a84e..b325573c 100644 --- a/include/IncompressibleFluid.h +++ b/include/IncompressibleFluid.h @@ -42,7 +42,7 @@ struct IncompressibleData { }; }; -/// A thermophysical property provider for critical and reducing values as well as derivatives of Helmholtz energy +/// A property provider for incompressible solutions and pure fluids /** This fluid instance is populated using an entry from a JSON file */ @@ -57,6 +57,7 @@ protected: double Tmin, Tmax; double xmin, xmax; + int xid; double TminPsat; double xref, Tref, pref; @@ -106,12 +107,23 @@ protected: * If 1D, should be a column vector of concentration coefficients */ IncompressibleData T_freeze; - /// Volume to mass fraction coefficients - /** Not implemented, yet */ - IncompressibleData volToMass; - /// Mass to mole fraction coefficients - /** Not implemented, yet */ - IncompressibleData massToMole; + + /// Mass fraction conversion coefficients + /** If the fluid type is mass-based, it does not do anything. Otherwise, + * it converts the mass fraction to the required input. + */ + IncompressibleData mass2input; + /// Volume fraction conversion coefficients + /** If the fluid type is volume-based, it does not do anything. Otherwise, + * it converts the volume fraction to the required input. + */ + IncompressibleData volume2input; + /// Mole fraction conversion coefficients + /** If the fluid type is mole-based, it does not do anything. Otherwise, + * it converts the mole fraction to the required input. + */ + IncompressibleData mole2input; + Polynomial2DFrac poly; @@ -120,7 +132,7 @@ protected: //double u_h(double T, double p, double x); public: - IncompressibleFluid(){strict = true;}; + IncompressibleFluid(){strict = true; xid = ifrac_undefined;}; virtual ~IncompressibleFluid(){}; std::string getName() const {return name;} @@ -132,6 +144,7 @@ public: double getTmin() const {return Tmin;} double getxmax() const {return xmax;} double getxmin() const {return xmin;} + int getxid() const {return xid;} double getTminPsat() const {return TminPsat;} double getTref() const {return Tref;} double getpref() const {return pref;} @@ -148,6 +161,7 @@ public: void setTmin(double Tmin) {this->Tmin = Tmin;} void setxmax(double xmax) {this->xmax = xmax;} void setxmin(double xmin) {this->xmin = xmin;} + void setxid(int xid) {this->xid = xid;} void setTminPsat(double TminPsat) {this->TminPsat = TminPsat;} //void setTref(double Tref) {this->Tref = Tref;} //void setpref(double pref) {this->pref = pref;} @@ -163,8 +177,11 @@ public: void setConductivity(IncompressibleData conductivity){this->conductivity = conductivity;} void setPsat(IncompressibleData p_sat){this->p_sat = p_sat;} void setTfreeze(IncompressibleData T_freeze){this->T_freeze = T_freeze;} - void setVolToMass(IncompressibleData volToMass){this->volToMass = volToMass;} - void setMassToMole(IncompressibleData massToMole){this->massToMole = massToMole;} + + /// Setters for the concentration conversion coefficients + void setMass2input(IncompressibleData mass2input){this->mass2input = mass2input;} + void setVolume2input(IncompressibleData volume2input){this->volume2input = volume2input;} + void setMole2input(IncompressibleData mole2input){this->mole2input = mole2input;} /// A function to check coefficients and equation types. void validate(); @@ -202,10 +219,21 @@ public: double psat(double T, double x); /// Freezing temperature as a function of pressure and composition. double Tfreeze( double p, double x); - /// Conversion from volume-based to mass-based composition. - double V2M (double T, double y); - /// Conversion from mass-based to mole-based composition. - double M2M (double T, double x); + + /// 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 inputFromMass (double T, double x); + /// 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 inputFromVolume (double T, double x); + /// 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 inputFromMole (double T, double x); + + /* Some functions can be inverted directly, those are listed * here. It is also possible to solve for other quantities, but diff --git a/include/PolyMath.h b/include/PolyMath.h index 47c3623c..0f6ff456 100644 --- a/include/PolyMath.h +++ b/include/PolyMath.h @@ -159,7 +159,7 @@ protected: double baseHorner(const std::vector &coefficients, double x); DEPRECATED(double baseHorner(const std::vector > &coefficients, double x, double y)); - bool do_debug(void){return get_debug_level()>=8;} + bool do_debug(void){return get_debug_level()>=18;} }; diff --git a/src/AbstractState.cpp b/src/AbstractState.cpp index 4ec30753..b40db701 100644 --- a/src/AbstractState.cpp +++ b/src/AbstractState.cpp @@ -159,6 +159,7 @@ bool AbstractState::clear() { double AbstractState::keyed_output(int key) { + if (get_debug_level()>=50) std::cout << format("AbstractState: keyed_output called for %s ",get_parameter_information(key,"short").c_str()) << std::endl; switch (key) { case iQ: diff --git a/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.h b/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.h index 66ef19f1..0ce1932c 100644 --- a/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.h +++ b/src/Backends/Helmholtz/HelmholtzEOSMixtureBackend.h @@ -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 &get_components(){return components;}; std::vector &get_K(){return K;}; diff --git a/src/Backends/Incompressible/IncompressibleBackend.cpp b/src/Backends/Incompressible/IncompressibleBackend.cpp index e7ccb824..d9a4f833 100644 --- a/src/Backends/Incompressible/IncompressibleBackend.cpp +++ b/src/Backends/Incompressible/IncompressibleBackend.cpp @@ -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 &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 &mole_fractions) { - throw NotImplementedError("Cannot set mole fractions for incompressible fluid"); +void IncompressibleBackend::set_mole_fractions(const std::vector &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(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 &mass_fractions) { - //if (get_debug_level()>=10) std::cout << format("Incompressible backend: Called set_mass_fractions with %s ",vec_to_string(std::vector(mass_fractions.begin(), mass_fractions.end()))) << std::endl; +void IncompressibleBackend::set_mass_fractions(const std::vector &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(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 &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(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(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") { diff --git a/src/Backends/Incompressible/IncompressibleBackend.h b/src/Backends/Incompressible/IncompressibleBackend.h index 36308981..e973e517 100644 --- a/src/Backends/Incompressible/IncompressibleBackend.h +++ b/src/Backends/Incompressible/IncompressibleBackend.h @@ -4,6 +4,7 @@ #include "IncompressibleFluid.h" #include "AbstractState.h" +#include "DataStructures.h" #include "Exceptions.h" #include @@ -12,13 +13,13 @@ namespace CoolProp { class IncompressibleBackend : public AbstractState { protected: - int Ncomp; - bool _mole_fractions_set; - static bool _REFPROP_supported; - std::vector mass_fractions; + //int Ncomp; + //static bool _REFPROP_supported; + //int _fractions_id; + std::vector _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 &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 &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 &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 */ diff --git a/src/Backends/Incompressible/IncompressibleFluid.cpp b/src/Backends/Incompressible/IncompressibleFluid.cpp index 0d6b3ee7..d2cac0a0 100644 --- a/src/Backends/Incompressible/IncompressibleFluid.cpp +++ b/src/Backends/Incompressible/IncompressibleFluid.cpp @@ -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); diff --git a/src/Backends/Incompressible/IncompressibleLibrary.cpp b/src/Backends/Incompressible/IncompressibleLibrary.cpp index 486fa4d7..ac32e453 100644 --- a/src/Backends/Incompressible/IncompressibleLibrary.cpp +++ b/src/Backends/Incompressible/IncompressibleLibrary.cpp @@ -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( diff --git a/src/Backends/REFPROP/REFPROPMixtureBackend.h b/src/Backends/REFPROP/REFPROPMixtureBackend.h index ba5b6728..b11b47fa 100644 --- a/src/Backends/REFPROP/REFPROPMixtureBackend.h +++ b/src/Backends/REFPROP/REFPROPMixtureBackend.h @@ -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 /** diff --git a/src/CoolProp.cpp b/src/CoolProp.cpp index 2bb7509d..30dfa1b5 100644 --- a/src/CoolProp.cpp +++ b/src/CoolProp.cpp @@ -333,7 +333,7 @@ std::string extract_concentrations(const std::string &fluid_string, std::vector< // Check if per cent or fraction syntax is used if (!strcmp(pEnd,"%")){ x *= 0.01;} fractions.push_back(x); - if (get_debug_level()>10) std::cout << format("%s:%d: Detected incompressible concentration of %d for %s.",__FILE__,__LINE__,vec_to_string(fractions).c_str(), fluid_parts[0].c_str()); + if (get_debug_level()>10) std::cout << format("%s:%d: Detected incompressible concentration of %s for %s.",__FILE__,__LINE__,vec_to_string(fractions).c_str(), fluid_parts[0].c_str()); return backend_string + fluid_parts[0]; } @@ -363,9 +363,12 @@ double _PropsSI(const std::string &Output, const std::string &Name1, double Prop if (State->using_mole_fractions()){ State->set_mole_fractions(z); - } - else{ + } else if (State->using_mass_fractions()){ State->set_mass_fractions(z); + } else if (State->using_volu_fractions()){ + State->set_volu_fractions(z); + } else { + if (get_debug_level()>50) std::cout << format("%s:%d: _PropsSI, could not set composition to %s, defaulting to mole fraction.\n",__FILE__,__LINE__, vec_to_string(z).c_str()).c_str(); } // Obtain the input pair diff --git a/src/Tests/TestObjects.cpp b/src/Tests/TestObjects.cpp index 09f96d5f..6062d348 100644 --- a/src/Tests/TestObjects.cpp +++ b/src/Tests/TestObjects.cpp @@ -6,6 +6,7 @@ * same in all places. */ #include "TestObjects.h" +#include "DataStructures.h" #include "IncompressibleFluid.h" #include "Eigen/Core" @@ -163,7 +164,7 @@ CoolProp::IncompressibleFluid CoolPropTesting::incompressibleFluidObject(){ 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); @@ -180,6 +181,7 @@ CoolProp::IncompressibleFluid CoolPropTesting::incompressibleFluidObject(){ CH3OH.setTmin(-50 + 273.15); CH3OH.setxmax(0.5); CH3OH.setxmin(0.0); + CH3OH.setxid(CoolProp::ifrac_mass); CH3OH.setTminPsat( 20 + 273.15); CH3OH.setTbase(-4.48 + 273.15);