diff --git a/MaterialsLib/adsorption/CMakeLists.txt b/MaterialsLib/adsorption/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..5889ae34c4c433e862f53b023545e258a33eb498 --- /dev/null +++ b/MaterialsLib/adsorption/CMakeLists.txt @@ -0,0 +1,23 @@ +file(GLOB adsorption_SOURCES *.cpp) +file(GLOB adsorption_HEADERS *.h) + +# set( HEADERS +# adsorption.h +# density_legacy.h +# density_hauer.h +# density_mette.h +# ) +# +# set( SOURCES +# adsorption.cpp +# density_legacy.cpp +# density_hauer.cpp +# density_mette.cpp +# ) + + +# include_directories( +# ${CMAKE_SOURCE_DIR}/FEM +# ) + +add_library(MaterialsLib_adsorption STATIC ${adsorption_HEADERS} ${adsorption_SOURCES} ) diff --git a/MaterialsLib/adsorption/adsorption.cpp b/MaterialsLib/adsorption/adsorption.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5c19af34bcbedd45f0044ebb89e92ae4ce1e57e0 --- /dev/null +++ b/MaterialsLib/adsorption/adsorption.cpp @@ -0,0 +1,262 @@ + +#include "logog/include/logog.hpp" + +#include "adsorption.h" + +#include "density_legacy.h" +#include "density_100MPa.h" +#include "density_const.h" +#include "density_cook.h" +#include "density_dubinin.h" +#include "density_hauer.h" +#include "density_mette.h" +#include "density_nunez.h" +#include "density_inert.h" + +namespace { + const double k_rate = 6.0e-3; //to be specified + + template <typename T> + T square(const T& v) + { + return v * v; + } +} + +namespace Ads +{ + +//Saturation pressure for water used in Nunez +double Adsorption::get_equilibrium_vapour_pressure(const double T_Ads) +{ + //critical T and p + const double Tc = 647.3; //K + const double pc = 221.2e5; //Pa + //dimensionless T + const double Tr = T_Ads/Tc; + const double theta = 1. - Tr; + //empirical constants + const double c[] = {-7.69123,-26.08023,-168.17065,64.23285,-118.96462,4.16717,20.97506,1.0e9,6.0}; + const double K[] = {c[0]*theta + c[1]*pow(theta,2) + c[2]*pow(theta,3) + c[3]*pow(theta,4) + c[4]*pow(theta,5), + 1. + c[5]*theta + c[6]*pow(theta,2)}; + + const double exponent = K[0]/(K[1]*Tr) - theta/(c[7]*pow(theta,2) + c[8]); + return pc * exp(exponent); //in Pa +} + +//Evaporation enthalpy of water from Nunez +double Adsorption::get_evaporation_enthalpy(double T_Ads) //in kJ/kg +{ + T_Ads -= 273.15; + if (T_Ads <= 10.){ + const double c[] = {2.50052e3,-2.1068,-3.57500e-1,1.905843e-1,-5.11041e-2,7.52511e-3,-6.14313e-4,2.59674e-5,-4.421e-7}; + double hv = 0.; + for (size_t i=0; i< sizeof(c)/sizeof(c[0]);i++) + hv += c[i] * pow(T_Ads,i); + return hv; + } else if (T_Ads <= 300.){ + const double c[] = {2.50043e3,-2.35209,1.91685e-4,-1.94824e-5,2.89539e-7,-3.51199e-9,2.06926e-11,-6.4067e-14,8.518e-17,1.558e-20,-1.122e-22}; + double hv = 0.; + for (size_t i=0; i< sizeof(c)/sizeof(c[0]);i++) + hv += c[i] * pow(T_Ads,i); + return hv; + } else { + const double c[] = {2.99866e3,-3.1837e-3,-1.566964e1,-2.514e-6,2.045933e-2,1.0389e-8}; + return ((c[0] + c[2]*T_Ads + c[4]*pow(T_Ads,2))/(1. + c[1]*T_Ads + c[3]*pow(T_Ads,2) + c[5]*pow(T_Ads,3))); + } +} + + +//evaluate specific heat capacity of adsorbate follwing Nunez +double Adsorption::get_specific_heat_capacity(const double T_Ads) +{ + const double c[] = {4.224,-3.716e-3,9.351e-5,-7.1786e-7,-9.1266e-9,2.69247e-10,-2.773104e-12,1.553177e-14,-4.982795e-17,8.578e-20,-6.12423e-23}; + double cp = 0.; + for (unsigned i=0; i< sizeof(c)/sizeof(c[0]);i++) + cp += c[i] * pow(T_Ads,i); + return cp; //kJ/(kg*K) +} + + +double Adsorption::get_molar_fraction(double xm, double M_this, double M_other) +{ + return M_other*xm/(M_other*xm + M_this*(1.0-xm)); +} + + +double Adsorption::get_mass_fraction(double xn, double M_this, double M_other) +{ + return M_this*xn/(M_this*xn + M_other*(1.0-xn)); +} + + +double Adsorption::d_molar_fraction(double xm, double M_this, double M_other) +{ + return M_other * M_this + / square(M_other * xm + M_this * (1.0 - xm)); +} + + +double Adsorption::get_reaction_rate(const double p_Ads, const double T_Ads, + const double M_Ads, const double loading) const +{ + // const double k_rate = 3.0e-3; //to be specified + + const double A = get_potential(p_Ads, T_Ads, M_Ads); + double C_eq = get_adsorbate_density(T_Ads) * characteristic_curve(A); + if (C_eq < 0.0) C_eq = 0.0; + + // return 0.0; // TODO [CL] for testing only + + return k_rate * (C_eq - loading); //scaled with mass fraction + // this the rate in terms of loading! +} + +void Adsorption::get_d_reaction_rate(const double p_Ads, const double T_Ads, + const double M_Ads, const double /*loading*/, + std::array<double, 3> &dqdr) const +{ + const double A = get_potential(p_Ads, T_Ads, M_Ads); + const double p_S = get_equilibrium_vapour_pressure(T_Ads); + const double dAdT = GAS_CONST * log(p_S/p_Ads) / (M_Ads*1.e3); + const double dAdp = - GAS_CONST * T_Ads / M_Ads / p_Ads; + + const double W = characteristic_curve(A); + const double dWdA = d_characteristic_curve(A); + + const double rho_Ads = get_adsorbate_density(T_Ads); + const double drhodT = - rho_Ads * get_alphaT(T_Ads); + + dqdr = std::array<double, 3>{{ + rho_Ads*dWdA*dAdp, + drhodT*W + rho_Ads*dWdA*dAdT, + -k_rate + }}; +} + + +//Evaluate adsorbtion potential A +double Adsorption::get_potential(const double p_Ads, double T_Ads, const double M_Ads) const +{ + double A = GAS_CONST * T_Ads * log(get_equilibrium_vapour_pressure(T_Ads)/p_Ads) / (M_Ads*1.e3); //in kJ/kg = J/g + if (A < 0.0) { + // vapour partial pressure > saturation pressure + // A = 0.0; // TODO [CL] debug output + } + return A; +} + + +double Adsorption::get_loading(const double rho_curr, const double rho_dry) +{ + return rho_curr / rho_dry - 1.0; +} + + +//Calculate sorption entropy +double Adsorption::get_entropy(const double T_Ads, const double A) const +{ + const double epsilon = 1.0e-8; + + //* // This change will also change simulation results. + const double W_p = characteristic_curve(A+epsilon); + const double W_m = characteristic_curve(A-epsilon); + const double dAdlnW = 2.0*epsilon/(log(W_p/W_m)); + // */ + + if (W_p <= 0.0 || W_m <= 0.0) + { + ERR("characteristic curve in negative region (W-, W+): %g, %g", W_m, W_p); + return 0.0; + } + + // const double dAdlnW = 2.0*epsilon/(log(characteristic_curve(A+epsilon)) - log(characteristic_curve(A-epsilon))); + return dAdlnW * get_alphaT(T_Ads); +} + + +//Calculate sorption enthalpy +double Adsorption::get_enthalpy(const double p_Ads, const double T_Ads, const double M_Ads) const +{ + // TODO [CL] consider using A as obtained from current loading (needs inverse CC A(W)) instead of p_Vapour, T_Vapour + const double A = get_potential(p_Ads, T_Ads, M_Ads); + + // return 0.0; // TODO [CL] for testing only + return (get_evaporation_enthalpy(T_Ads) + A - T_Ads * get_entropy(T_Ads,A))*1000.0; //in J/kg +} + + +double Adsorption::get_equilibrium_loading(const double p_Ads, const double T_Ads, const double M_Ads) +{ + const double A = get_potential(p_Ads, T_Ads, M_Ads); + return get_adsorbate_density(T_Ads) * characteristic_curve(A); +} + + +bool +stringToReactiveSystem(std::string const& name, SolidReactiveSystem& rsys_out) +{ + if (name == "Z13XBF") + rsys_out = SolidReactiveSystem::Z13XBF; + else if (name == "Z13XBF_100MPa") + rsys_out = SolidReactiveSystem::Z13XBF_100MPa; + else if (name == "Z13XBF_Const") + rsys_out = SolidReactiveSystem::Z13XBF_Const; + else if (name == "Z13XBF_Cook") + rsys_out = SolidReactiveSystem::Z13XBF_Cook; + else if (name == "Z13XBF_Dubinin") + rsys_out = SolidReactiveSystem::Z13XBF_Dubinin; + else if (name == "Z13XBF_Hauer") + rsys_out = SolidReactiveSystem::Z13XBF_Hauer; + else if (name == "Z13XBF_Mette") + rsys_out = SolidReactiveSystem::Z13XBF_Mette; + else if (name == "Z13XBF_Nunez") + rsys_out = SolidReactiveSystem::Z13XBF_Nunez; + else if (name == "Inert") + rsys_out = SolidReactiveSystem::Inert; + else return false; + + return true; +} + + +Adsorption* Adsorption::newInstance(std::string const& rsys) +{ + SolidReactiveSystem r; + if (stringToReactiveSystem(rsys, r)) { + return newInstance(r); + } else { + ERR("unknown reactive system: %s", rsys); + return nullptr; + } +} + + +Adsorption* Adsorption::newInstance(const SolidReactiveSystem rsys) +{ + switch (rsys) + { + case SolidReactiveSystem::Z13XBF: + return new DensityLegacy(); + case SolidReactiveSystem::Z13XBF_100MPa: + return new Density100MPa(); + case SolidReactiveSystem::Z13XBF_Const: + return new DensityConst(); + case SolidReactiveSystem::Z13XBF_Cook: + return new DensityCook(); + case SolidReactiveSystem::Z13XBF_Dubinin: + return new DensityDubinin(); + case SolidReactiveSystem::Z13XBF_Hauer: + return new DensityHauer(); + case SolidReactiveSystem::Z13XBF_Mette: + return new DensityMette(); + case SolidReactiveSystem::Z13XBF_Nunez: + return new DensityNunez(); + case SolidReactiveSystem::Inert: + return new DensityInert(); + } + + return nullptr; +} + +} // namespace Ads diff --git a/MaterialsLib/adsorption/adsorption.h b/MaterialsLib/adsorption/adsorption.h new file mode 100644 index 0000000000000000000000000000000000000000..8c953ca58061fe02fafa39e8f0cf23a2ba12dcc8 --- /dev/null +++ b/MaterialsLib/adsorption/adsorption.h @@ -0,0 +1,112 @@ +#ifndef ADSORPTION_H +#define ADSORPTION_H + +#include <array> +#include <cmath> + +namespace Ads +{ + +const double GAS_CONST = 8.3144621; + +const double M_N2 = 0.028; +const double M_H2O = 0.018; + +enum class SolidReactiveSystem +{ + Z13XBF, + Z13XBF_Const, + Z13XBF_Hauer, + Z13XBF_Mette, + Z13XBF_Nunez, + Z13XBF_Cook, + Z13XBF_Dubinin, + Z13XBF_100MPa, + Inert +}; + +class Adsorption +{ +public: +// static members + static Adsorption* newInstance(SolidReactiveSystem rsys); + static Adsorption* newInstance(std::string const& rsys); + + // TODO [CL] move those four methods to water properties class + static double get_evaporation_enthalpy(const double T_Ads); + static double get_equilibrium_vapour_pressure(const double T_Ads); + static double get_specific_heat_capacity(const double T_Ads); // TODO [CL] why unused? + + static double get_molar_fraction(double xm, double M_this, double M_other); + static double get_mass_fraction(double xn, double M_this, double M_other); + static double d_molar_fraction(double xm, double M_this, double M_other); + + static double get_loading(const double rho_curr, const double rho_dry); + +// non-virtual members + double get_equilibrium_loading(const double p_Ads, const double T_Ads, const double M_Ads); + +// virtual members: + virtual ~Adsorption() {} + + virtual double get_enthalpy(const double p_Ads, const double T_Ads, const double M_Ads) const; + virtual double get_reaction_rate(const double p_Ads, const double T_Ads, + const double M_Ads, const double loading) const; + /** + * @brief get_d_reaction_rate + * @param p_Ads + * @param T_ads + * @param M_Ads + * @param loading + * @param dqdr array containing the differentials wrt: p, T, C + */ + virtual void get_d_reaction_rate(const double p_Ads, const double T_Ads, + const double M_Ads, const double loading, + std::array<double, 3>& dqdr) const; + +protected: + virtual double get_adsorbate_density(const double T_Ads) const = 0; + virtual double get_alphaT(const double T_Ads) const = 0; + virtual double characteristic_curve(const double A) const = 0; + virtual double d_characteristic_curve(const double A) const = 0; + +private: +// non-virtual members + double get_potential(const double p_Ads, const double T_Ads, const double M_Ads) const; + double get_entropy(const double T_Ads, const double A) const; +}; + + +inline double curve_polyfrac(const double* coeffs, const double x) +{ + return ( coeffs[0] + coeffs[2] * x + coeffs[4] * pow(x,2) + coeffs[6] * pow(x,3) ) + / ( 1.0 + coeffs[1] * x + coeffs[3] * pow(x,2) + coeffs[5] * pow(x,3) ); + + // Apparently, even pow and std::pow are different + // return ( coeffs[0] + coeffs[2] * x + coeffs[4] * std::pow(x,2) + coeffs[6] * std::pow(x,3) ) + // / ( 1.0 + coeffs[1] * x + coeffs[3] * std::pow(x,2) + coeffs[5] * std::pow(x,3) ); + + // Analytically the same, but numerically quite different + // return ( coeffs[0] + x * ( coeffs[2] + x * (coeffs[4] + x * coeffs[6] ) ) ) + // / ( 1.0 + x * ( coeffs[1] + x * (coeffs[3] + x * coeffs[5] ) ) ); + + // Analytically the same, but numerically quite different + // return ( coeffs[0] + x * coeffs[2] + x*x * coeffs[4] + x*x*x * coeffs[6] ) + // / ( 1.0 + x * coeffs[1] + x*x * coeffs[3] + x*x*x * coeffs[5] ); +} + +inline double d_curve_polyfrac(const double* coeffs, const double x) +{ + const double x2 = x*x; + const double x3 = x2*x; + const double u = coeffs[0] + coeffs[2] * x + coeffs[4] * x2 + coeffs[6] * x3; + const double du = coeffs[2] + 2.0*coeffs[4] * x + 3.0*coeffs[6] * x2; + const double v = 1.0 + coeffs[1] * x + coeffs[3] * x2 + coeffs[5] * x3; + const double dv = coeffs[1] + 2.0*coeffs[3] * x + 3.0*coeffs[5] * x2; + + return (du*v - u*dv) / v / v; +} + +} + +#endif // ADSORPTION_H diff --git a/MaterialsLib/adsorption/density_100MPa.cpp b/MaterialsLib/adsorption/density_100MPa.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f49eb1f221beb7b3b85ed66ca80d91ac3f40e656 --- /dev/null +++ b/MaterialsLib/adsorption/density_100MPa.cpp @@ -0,0 +1,56 @@ +#include "density_100MPa.h" + +namespace +{ + +// NaX_HighP_polyfrac_CC.pickle +// date extracted 2015-06-23 15:38:35 file mtime 2015-06-23 15:19:57 +const double c[] = { + 0.3490302932983226, /* a0 */ + -0.0014061345691831226, /* a1 */ + -0.0007399303393402753, /* a2 */ + 5.129318840267485e-09, /* a3 */ + 5.243619689772646e-07, /* a4 */ + 6.347011955956523e-10, /* a5 */ + -9.919599580166727e-11 /* a6 */ +}; + +} + +namespace Ads +{ + +double Density100MPa::get_adsorbate_density(const double T_Ads) const +{ + return -0.0013*T_Ads*T_Ads + 0.3529*T_Ads + 1049.2; +} + + +//Thermal expansivity model for water found in the works of Hauer +double Density100MPa::get_alphaT(const double T_Ads) const +{ + const double rho = -0.0013*T_Ads*T_Ads+0.3529*T_Ads+1049.2; + const double drhodT = -0.0026*T_Ads + 0.3529; + + return - drhodT / rho; +} + + +//Characteristic curve. Return W (A) +double Density100MPa::characteristic_curve(const double A) const +{ + double W = curve_polyfrac(c, A); //cm^3/g + + if (W < 0.0) { + W = 0.0; // TODO [CL] debug output + } + + return W/1.e3; //m^3/kg +} + +double Density100MPa::d_characteristic_curve(const double A) const +{ + return d_curve_polyfrac(c, A); +} + +} diff --git a/MaterialsLib/adsorption/density_100MPa.h b/MaterialsLib/adsorption/density_100MPa.h new file mode 100644 index 0000000000000000000000000000000000000000..54ae755290bc7a8ecb29616d5c62c124eaf7937c --- /dev/null +++ b/MaterialsLib/adsorption/density_100MPa.h @@ -0,0 +1,17 @@ +#pragma once + +#include "adsorption.h" + +namespace Ads +{ + +class Density100MPa : public Adsorption +{ +public: + double get_adsorbate_density(const double T_Ads) const; + double get_alphaT(const double T_Ads) const; + double characteristic_curve(const double A) const; + double d_characteristic_curve(const double A) const; +}; + +} diff --git a/MaterialsLib/adsorption/density_const.cpp b/MaterialsLib/adsorption/density_const.cpp new file mode 100644 index 0000000000000000000000000000000000000000..29164e7fc72492f5d9b0d9a4b238936deeb94680 --- /dev/null +++ b/MaterialsLib/adsorption/density_const.cpp @@ -0,0 +1,55 @@ +#include "density_const.h" + +#include "density_hauer.h" + +namespace +{ + +// NaX_Constant_polyfrac_CC.pickle +// date extracted 2015-06-23 15:38:35 file mtime 2015-06-23 15:20:05 +const double c[] = { + 0.3824098506898007, /* a0 */ + -0.001316857559708455, /* a1 */ + -0.0007935756090263691, /* a2 */ + -1.1600036977157845e-07, /* a3 */ + 5.610354459181838e-07, /* a4 */ + 7.113664938298873e-10, /* a5 */ + -1.0668790477629686e-10 /* a6 */ +}; + +} + +namespace Ads +{ + +double DensityConst::get_adsorbate_density(const double /*T_Ads*/) const +{ + return rho_water_Hauer(150.0+273.15); +} + + +//Thermal expansivity model for water found in the works of Hauer +double DensityConst::get_alphaT(const double /*T_Ads*/) const +{ + return 0.0; +} + + +//Characteristic curve. Return W (A) +double DensityConst::characteristic_curve(const double A) const +{ + double W = curve_polyfrac(c, A); //cm^3/g + + if (W < 0.0) { + W = 0.0; // TODO [CL] debug output + } + + return W/1.e3; //m^3/kg +} + +double DensityConst::d_characteristic_curve(const double A) const +{ + return d_curve_polyfrac(c, A); +} + +} diff --git a/MaterialsLib/adsorption/density_const.h b/MaterialsLib/adsorption/density_const.h new file mode 100644 index 0000000000000000000000000000000000000000..7d64ec9df4993415ec0d589b096bcda180445bd3 --- /dev/null +++ b/MaterialsLib/adsorption/density_const.h @@ -0,0 +1,17 @@ +#pragma once + +#include "adsorption.h" + +namespace Ads +{ + +class DensityConst : public Adsorption +{ +public: + double get_adsorbate_density(const double T_Ads) const; + double get_alphaT(const double T_Ads) const; + double characteristic_curve(const double A) const; + double d_characteristic_curve(const double A) const; +}; + +} diff --git a/MaterialsLib/adsorption/density_cook.cpp b/MaterialsLib/adsorption/density_cook.cpp new file mode 100644 index 0000000000000000000000000000000000000000..96aeb959ae858343b38d19564584f11fcb0fda82 --- /dev/null +++ b/MaterialsLib/adsorption/density_cook.cpp @@ -0,0 +1,53 @@ +#include "density_cook.h" + +namespace +{ + +// NaX_Dean_polyfrac_CC.pickle +// date extracted 2015-06-23 15:38:35 file mtime 2015-06-23 15:19:42 +const double c[] = { + 0.3632627555646154, /* a0 */ + -0.0014090624975800715, /* a1 */ + -0.0007717609035743321, /* a2 */ + 5.03634836561135e-09, /* a3 */ + 5.478509959282738e-07, /* a4 */ + 6.36458510620815e-10, /* a5 */ + -1.037977321231462e-10 /* a6 */ +}; + +} + +namespace Ads +{ + +double DensityCook::get_adsorbate_density(const double T_Ads) const +{ + return rho_water_Dean(T_Ads); +} + + +//Thermal expansivity model for water found in the works of Hauer +double DensityCook::get_alphaT(const double T_Ads) const +{ + return alphaT_water_Dean(T_Ads); +} + + +//Characteristic curve. Return W (A) +double DensityCook::characteristic_curve(const double A) const +{ + double W = curve_polyfrac(c, A); //cm^3/g + + if (W < 0.0) { + W = 0.0; // TODO [CL] debug output + } + + return W/1.e3; //m^3/kg +} + +double DensityCook::d_characteristic_curve(const double A) const +{ + return d_curve_polyfrac(c, A); +} + +} diff --git a/MaterialsLib/adsorption/density_cook.h b/MaterialsLib/adsorption/density_cook.h new file mode 100644 index 0000000000000000000000000000000000000000..8ef429833c430c7fe3c1e031f0269c977cd7e7b0 --- /dev/null +++ b/MaterialsLib/adsorption/density_cook.h @@ -0,0 +1,47 @@ +#pragma once + +#include "adsorption.h" + +namespace Ads +{ + +class DensityCook : public Adsorption +{ +public: + double get_adsorbate_density(const double T_Ads) const; + double get_alphaT(const double T_Ads) const; + double characteristic_curve(const double A) const; + double d_characteristic_curve(const double A) const; +}; + + +inline double rho_water_Dean(const double T_Ads) +{ + const double Tcel = T_Ads - 273.15; + const double b[] = { 999.9,2.03E-02,-6.16E-03,2.26E-05,-4.68E-08 }; + if (Tcel <= 100.) { + return b[0] + Tcel * (b[1] + Tcel * (b[2] + Tcel * (b[3] + Tcel * b[4]) ) ); + } + else { + const double rho_100 = b[0] + b[1]*1.e2 + b[2]*1.e4 + b[3]*1.e6 + b[4]*1.e8; + const double aT_100 = -1./rho_100 * (b[1] + 2.*b[2]*1.e2 + 3.*b[3]*1.e4 + 4.*b[4]*1.e6); + return rho_100 * (1. - aT_100*(Tcel-100.)); + } +} + +inline double alphaT_water_Dean(const double T_Ads) +{ + const double Tcel = T_Ads - 273.15; + const double b[] = { 999.9,2.03E-02,-6.16E-03,2.26E-05,-4.68E-08 }; + if (Tcel <= 100.) { + const double r = b[0] + Tcel * (b[1] + Tcel * (b[2] + Tcel * (b[3] + Tcel * b[4]) ) ); + return -1.0/r * ( b[1] + Tcel * (2.0*b[2] + Tcel * (3.0*b[3] + Tcel * 4.0*b[4]) ) ); + } + else { + const double rho_100 = b[0] + b[1]*1.e2 + b[2]*1.e4 + b[3]*1.e6 + b[4]*1.e8; + const double aT_100 = -1./rho_100 * (b[1] + 2.*b[2]*1.e2 + 3.*b[3]*1.e4 + 4.*b[4]*1.e6); + return aT_100 / (1. - aT_100*(Tcel-100.)); + } +} + +} diff --git a/MaterialsLib/adsorption/density_dubinin.cpp b/MaterialsLib/adsorption/density_dubinin.cpp new file mode 100644 index 0000000000000000000000000000000000000000..91a5248f026490f12bde98d18d385f53402da1ce --- /dev/null +++ b/MaterialsLib/adsorption/density_dubinin.cpp @@ -0,0 +1,89 @@ +#include "density_dubinin.h" +#include "density_cook.h" +#include "adsorption.h" + +namespace +{ + +// NaX_Dubinin_polyfrac_CC.pickle +// date extracted 2015-06-23 16:47:50 file mtime 2015-06-23 16:47:23 +const double c[] = { + 0.3635538371322433, /* a0 */ + -0.0014521033261199435, /* a1 */ + -0.0007855160157616825, /* a2 */ + 4.385666000850253e-08, /* a3 */ + 5.567776459188524e-07, /* a4 */ + 6.026002134230559e-10, /* a5 */ + -1.0477401124006098e-10 /* a6 */ +}; + +} + +namespace Ads +{ + +double DensityDubinin::get_adsorbate_density(const double T_Ads) const +{ + const double Tb = 373.1; + + if (T_Ads < Tb) { + return rho_water_Dean(T_Ads); + } else { + const double Tc = 647.3; //K + // const double rhoc = 322.; //kg/m^3 + const double pc = 221.2e5; //Pa + //boiling point density + const double rhob = rho_water_Dean(Tb); + //state values + const double R = GAS_CONST; + const double M = M_H2O; + const double b = R * Tc/(8. * pc); //m^3/mol + const double rhom = M/b; //kg/m^3 + const double rho = rhob - (rhob-rhom)/(Tc-Tb)*(T_Ads-Tb); + return rho; + } +} + + +//Thermal expansivity model for water found in the works of Hauer +double DensityDubinin::get_alphaT(const double T_Ads) const +{ + const double Tb = 373.1; + if (T_Ads <= Tb) { + return alphaT_water_Dean(T_Ads); + } else { + //critical T and p + const double Tc = 647.3; //K + // const double rhoc = 322.; //kg/m^3 + const double pc = 221.2e5; //Pa + //boiling point density + const double rhob = rho_water_Dean(Tb); + //state values + const double R = GAS_CONST; + const double M = M_H2O; + const double b = R * Tc/(8. * pc); //m^3/mol + const double rhom = M/(b); //kg/m^3 + const double rho = rhob - (rhob-rhom)/(Tc-Tb)*(T_Ads-Tb); + return ((rhob-rhom)/(Tc-Tb)*1./rho); + } +} + + +//Characteristic curve. Return W (A) +double DensityDubinin::characteristic_curve(const double A) const +{ + double W = curve_polyfrac(c, A); //cm^3/g + + if (W < 0.0) { + W = 0.0; // TODO [CL] debug output + } + + return W/1.e3; //m^3/kg +} + +double DensityDubinin::d_characteristic_curve(const double A) const +{ + return d_curve_polyfrac(c, A); +} + +} diff --git a/MaterialsLib/adsorption/density_dubinin.h b/MaterialsLib/adsorption/density_dubinin.h new file mode 100644 index 0000000000000000000000000000000000000000..678aea58c167702dd1d874c9a9b624b95edc6af7 --- /dev/null +++ b/MaterialsLib/adsorption/density_dubinin.h @@ -0,0 +1,17 @@ +#pragma once + +#include "adsorption.h" + +namespace Ads +{ + +class DensityDubinin : public Adsorption +{ +public: + double get_adsorbate_density(const double T_Ads) const; + double get_alphaT(const double T_Ads) const; + double characteristic_curve(const double A) const; + double d_characteristic_curve(const double A) const; +}; + +} diff --git a/MaterialsLib/adsorption/density_hauer.cpp b/MaterialsLib/adsorption/density_hauer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e9211f552545cd40964ab572a71686aaae004409 --- /dev/null +++ b/MaterialsLib/adsorption/density_hauer.cpp @@ -0,0 +1,56 @@ +#include "density_hauer.h" + +namespace +{ + +// NaX_Hauer_polyfrac_CC.pickle +// date extracted 2015-06-23 15:38:35 file mtime 2015-06-23 15:19:19 +const double c[] = { + 0.36490158988356747, /* a0 */ + -0.0013723270478333963, /* a1 */ + -0.0007655780628099964, /* a2 */ + -3.353324854315774e-08, /* a3 */ + 5.424357157710913e-07, /* a4 */ + 6.613430586648678e-10, /* a5 */ + -1.0300151379421499e-10 /* a6 */ +}; + +} + +namespace Ads +{ + +double DensityHauer::get_adsorbate_density(const double T_Ads) const +{ + return rho_water_Hauer(T_Ads); +} + + +//Thermal expansivity model for water found in the works of Hauer +double DensityHauer::get_alphaT(const double T_Ads) const +{ + // data like in python script + const double T0 = 283.15, alpha0 = 3.781e-4; //K; 1/K + + return alpha0/(1. - alpha0 * (T_Ads-T0)); //in 1/K +} + + +//Characteristic curve. Return W (A) +double DensityHauer::characteristic_curve(const double A) const +{ + double W = curve_polyfrac(c, A); //cm^3/g + + if (W < 0.0) { + W = 0.0; // TODO [CL] debug output + } + + return W/1.e3; //m^3/kg +} + +double DensityHauer::d_characteristic_curve(const double A) const +{ + return d_curve_polyfrac(c, A); +} + +} diff --git a/MaterialsLib/adsorption/density_hauer.h b/MaterialsLib/adsorption/density_hauer.h new file mode 100644 index 0000000000000000000000000000000000000000..4d65991d0f129f8f302e0615ecebd34f39a20536 --- /dev/null +++ b/MaterialsLib/adsorption/density_hauer.h @@ -0,0 +1,26 @@ +#pragma once + +#include "adsorption.h" +#include "density_cook.h" + +namespace Ads +{ + +class DensityHauer : public Adsorption +{ +public: + double get_adsorbate_density(const double T_Ads) const; + double get_alphaT(const double T_Ads) const; + double characteristic_curve(const double A) const; + double d_characteristic_curve(const double A) const; +}; + +inline double rho_water_Hauer(const double T_Ads) +{ + // data like in python script + const double T0 = 283.15, rho0 = rho_water_Dean(T0), alpha0 = 3.781e-4; //K; kg/m^3; 1/K + + return rho0 * (1. - alpha0 * (T_Ads-T0)); //in kg/m^3 +} + +} diff --git a/MaterialsLib/adsorption/density_inert.h b/MaterialsLib/adsorption/density_inert.h new file mode 100644 index 0000000000000000000000000000000000000000..e16f9c93b79c96772f52676f345e6d16f2fee779 --- /dev/null +++ b/MaterialsLib/adsorption/density_inert.h @@ -0,0 +1,42 @@ +#pragma once + +#include "adsorption.h" + +namespace Ads +{ + +class DensityInert final : public Adsorption +{ +public: + double get_enthalpy(const double /*p_Ads*/, const double /*T_Ads*/, + const double /*M_Ads*/) const override + { + return 0.0; + } + double get_reaction_rate(const double /*p_Ads*/, const double /*T_Ads*/, + const double /*M_Ads*/, const double /*loading*/ + ) const override + { + return 0.0; + } + +protected: + double get_adsorbate_density(const double /*T_Ads*/) const override + { + return 1.0; + } + double get_alphaT(const double /*T_Ads*/) const override + { + return 0.0; + } + double characteristic_curve(const double A) const override + { + return A; + } + double d_characteristic_curve(const double /*A*/) const override + { + return 1.0; + } +}; + +} diff --git a/MaterialsLib/adsorption/density_legacy.cpp b/MaterialsLib/adsorption/density_legacy.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e8b07e86f2c6c7b9ff6b2c1e1b78c72986fa181c --- /dev/null +++ b/MaterialsLib/adsorption/density_legacy.cpp @@ -0,0 +1,59 @@ +#include "density_legacy.h" + +namespace +{ + +//parameters from least squares fit (experimental data) +const double c[] = { 0.34102920966608297, + -0.0013106032830951296, + -0.00060754147575378876, + 3.7843404172683339e-07, + 4.0107503869519016e-07, + 3.1274595098338057e-10, + -7.610441241719489e-11 + }; + +} + +namespace Ads +{ + +double DensityLegacy::get_adsorbate_density(const double T_Ads) const +{ + //set reference state for adsorbate EOS in Hauer + const double T0 = 293.15, rho0 = 998.084, alpha0 = 2.06508e-4; //K; kg/m^3; 1/K + + return (rho0 * (1. - alpha0 * (T_Ads-T0))); //in kg/m^3 +} + + +//Thermal expansivity model for water found in the works of Hauer +double DensityLegacy::get_alphaT(const double T_Ads) const +{ + //set reference state for adsorbate EOS in Hauer + const double T0 = 293.15, /*rho0 = 998.084,*/ alpha0 = 2.06508e-4; //K; kg/m^3; 1/K + + return (alpha0/(1. - alpha0 * (T_Ads-T0))); //in 1/K +} + + +//Characteristic curve. Return W (A) +double DensityLegacy::characteristic_curve(const double A) const +{ + double W = curve_polyfrac(c, A); //cm^3/g + + /* + if (W < 0.0) { + W = 0.0; // TODO [CL] debug output + } + */ + + return W/1.e3; //m^3/kg +} + +double DensityLegacy::d_characteristic_curve(const double A) const +{ + return d_curve_polyfrac(c, A); +} + +} diff --git a/MaterialsLib/adsorption/density_legacy.h b/MaterialsLib/adsorption/density_legacy.h new file mode 100644 index 0000000000000000000000000000000000000000..d9123fc6a1a293ed24d68676b07cbcf32f2784de --- /dev/null +++ b/MaterialsLib/adsorption/density_legacy.h @@ -0,0 +1,17 @@ +#pragma once + +#include "adsorption.h" + +namespace Ads +{ + +class DensityLegacy : public Adsorption +{ +public: + double get_adsorbate_density(const double T_Ads) const; + double get_alphaT(const double T_Ads) const; + double characteristic_curve(const double A) const; + double d_characteristic_curve(const double A) const; +}; + +} diff --git a/MaterialsLib/adsorption/density_mette.cpp b/MaterialsLib/adsorption/density_mette.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7cf6f36e29887a71781e0990ed5c82e8fa06b4cb --- /dev/null +++ b/MaterialsLib/adsorption/density_mette.cpp @@ -0,0 +1,57 @@ +#include "density_mette.h" +#include "density_cook.h" + +namespace +{ +// NaX_Mette_polyfrac_CC.pickle +// date extracted 2015-06-23 15:38:35 file mtime 2015-06-23 15:19:26 +const double c[] = { + 0.36340572890087813, /* a0 */ + -0.0013449597038375108, /* a1 */ + -0.0007581210111121073, /* a2 */ + -7.331279615575401e-08, /* a3 */ + 5.365656973806218e-07, /* a4 */ + 6.854673678427112e-10, /* a5 */ + -1.0197050219481966e-10 /* a6 */ +}; +} + +namespace Ads +{ + +double DensityMette::get_adsorbate_density(const double T_Ads) const +{ + const double T0 = 293.15; + const double rho0 = rho_water_Dean(T0); + const double alpha20 = alphaT_water_Dean(T0); + return rho0 / (1. + alpha20*(T_Ads-T0)); +} + + +//Thermal expansivity model for water found in the works of Hauer +double DensityMette::get_alphaT(const double T_Ads) const +{ + const double T0 = 293.15; + const double alpha20 = alphaT_water_Dean(T0); + return alpha20 / (1. + alpha20 * (T_Ads-T0)); +} + + +//Characteristic curve. Return W (A) +double DensityMette::characteristic_curve(const double A) const +{ + double W = curve_polyfrac(c, A); //cm^3/g + + if (W < 0.0) { + W = 0.0; // TODO [CL] debug output + } + + return W/1.e3; //m^3/kg +} + +double DensityMette::d_characteristic_curve(const double A) const +{ + return d_curve_polyfrac(c, A); +} + +} diff --git a/MaterialsLib/adsorption/density_mette.h b/MaterialsLib/adsorption/density_mette.h new file mode 100644 index 0000000000000000000000000000000000000000..b66b8ca214905ac7a70f6816a7515051a8e84701 --- /dev/null +++ b/MaterialsLib/adsorption/density_mette.h @@ -0,0 +1,17 @@ +#pragma once + +#include "adsorption.h" + +namespace Ads +{ + +class DensityMette : public Adsorption +{ +public: + double get_adsorbate_density(const double T_Ads) const; + double get_alphaT(const double T_Ads) const; + double characteristic_curve(const double A) const; + double d_characteristic_curve(const double A) const; +}; + +} diff --git a/MaterialsLib/adsorption/density_nunez.cpp b/MaterialsLib/adsorption/density_nunez.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ac81d53f6973bead70e502fc226a81d920b7955f --- /dev/null +++ b/MaterialsLib/adsorption/density_nunez.cpp @@ -0,0 +1,75 @@ +#include "density_nunez.h" + +namespace +{ + +// NaX_Nunez_polyfrac_CC.pickle +// date extracted 2015-06-23 15:38:35 file mtime 2015-06-23 15:19:34 +const double c[] = { + 0.3631900485031771, /* a0 */ + -0.0014242280940080726, /* a1 */ + -0.0007751726942386291, /* a2 */ + 2.1775655036811842e-08, /* a3 */ + 5.488166913667265e-07, /* a4 */ + 6.204064716725214e-10, /* a5 */ + -1.0345385018952998e-10 /* a6 */ +}; + +} + +namespace Ads +{ + +double DensityNunez::get_adsorbate_density(const double T_Ads) const +{ + if (T_Ads < 273.16 or T_Ads > 633.15) { + // print('Value outside admissible range for rho.'); + // return -1; + } + + const double a[] = { 1.0644e3,-8.01905,1.445348e-2,-4.19589e-6,-4.5294e-9 }; + const double b[] = { -8.039e-3,1.8698e-5,-2.3015e-8,2.3809e-11,-1.388e-14 }; + const double u = a[0] + T_Ads * (a[1] + T_Ads * (a[2] + T_Ads * (a[3] + T_Ads * a[4]) ) ); + const double v = 1.0 + T_Ads * (b[0] + T_Ads * (b[1] + T_Ads * (b[2] + T_Ads * (b[3] + T_Ads * b[4]) ) ) ); + return u/v; +} + + +//Thermal expansivity model for water found in the works of Hauer +double DensityNunez::get_alphaT(const double T_Ads) const +{ + if (T_Ads < 273.16 or T_Ads > 633.15) { + // print('Value outside admissible range for rho.'); + // return -1; + } + + const double a[] = { 1.0644e3,-8.01905,1.445348e-2,-4.19589e-6,-4.5294e-9 }; + const double b[] = { -8.039e-3,1.8698e-5,-2.3015e-8,2.3809e-11,-1.388e-14 }; + const double u = a[0] + T_Ads * (a[1] + T_Ads * (a[2] + T_Ads * (a[3] + T_Ads * a[4]) ) ); + const double v = 1.0 + T_Ads * (b[0] + T_Ads * (b[1] + T_Ads * (b[2] + T_Ads * (b[3] + T_Ads * b[4]) ) ) ); + const double du = a[1] + T_Ads * (2.0*a[2] + T_Ads * (3.0*a[3] + T_Ads * 4.0*a[4]) ); + const double dv = b[0] + T_Ads * (2.0*b[1] + T_Ads * (3.0*b[2] + T_Ads * (4.0*b[3] + T_Ads * 5.0*b[4]) ) ); + // return - (du*v - dv*u) / u / v; + // return (dv*u - du*v) / u / v; + return dv/v - du/u; +} + + +//Characteristic curve. Return W (A) +double DensityNunez::characteristic_curve(const double A) const +{ + double W = curve_polyfrac(c, A); //cm^3/g + + if (W < 0.0) { + W = 0.0; // TODO [CL] debug output + } + + return W/1.e3; //m^3/kg +} + +double DensityNunez::d_characteristic_curve(const double A) const +{ + return d_curve_polyfrac(c, A); +} + +} diff --git a/MaterialsLib/adsorption/density_nunez.h b/MaterialsLib/adsorption/density_nunez.h new file mode 100644 index 0000000000000000000000000000000000000000..1d05d83feba29a514388eedbf8da4ebcc33bcea2 --- /dev/null +++ b/MaterialsLib/adsorption/density_nunez.h @@ -0,0 +1,17 @@ +#pragma once + +#include "adsorption.h" + +namespace Ads +{ + +class DensityNunez : public Adsorption +{ +public: + double get_adsorbate_density(const double T_Ads) const; + double get_alphaT(const double T_Ads) const; + double characteristic_curve(const double A) const; + double d_characteristic_curve(const double A) const; +}; + +}