diff --git a/include/teqp/math/finite_derivs.hpp b/include/teqp/math/finite_derivs.hpp index f95818db..9f08dc33 100644 --- a/include/teqp/math/finite_derivs.hpp +++ b/include/teqp/math/finite_derivs.hpp @@ -1,20 +1,20 @@ #pragma once +namespace teqp{ + /** * Routines for finite differentiation, useful for testing derivatives obtained by other methods -* +* * From: * Bengt Fornberg, 1988, "Coefficients from Generation of Finite Difference Formulas on Arbitrarily Spaced Grids", MATHEMATICS OF COMPUTATION, v. 51, n. 184, pp. 699-706 -* +* * Higher derivatives should always be done in extended precision mathematics! -* +* * Warning: these routines may give entirely erroneous results for double precision arithmetic, * especially the higher derivatives -* +* * Warning: these routines are optimized for accuracy, not for speed or memory use */ -namespace teqp{ - template auto centered_diff(const Function &f, const Scalar x, const Scalar h) { @@ -63,4 +63,10 @@ auto centered_diff(const Function &f, const Scalar x, const Scalar h) { auto val = num / pow(h, Nderiv); return val; } -}; // namespace teqp \ No newline at end of file + +template +auto centered_diff_xy(const Function &f, const Scalarx x, const Scalary y, const Scalarx dx, const Scalary dy) { + return (f(x+dx, y+dy) - f(x+dx, y-dy) - f(x-dx, y+dy) + f(x-dx, y-dy))/(4*dx*dy); +} + +}; // namespace teqp diff --git a/include/teqp/models/CPA.hpp b/include/teqp/models/CPA.hpp index 21199e0a..7c138d43 100644 --- a/include/teqp/models/CPA.hpp +++ b/include/teqp/models/CPA.hpp @@ -159,7 +159,7 @@ class CPACubic { template auto get_ai(TType T, int i) const { - return a0[i] * POW2(1.0 + c1[i]*(1.0 - sqrt(T / Tc[i]))); + return forceeval(a0[i] * POW2(1.0 + c1[i]*(1.0 - sqrt(T / Tc[i])))); } template diff --git a/src/tests/catch_tests.cxx b/src/tests/catch_tests.cxx index ba19bbda..59475802 100644 --- a/src/tests/catch_tests.cxx +++ b/src/tests/catch_tests.cxx @@ -430,11 +430,19 @@ TEST_CASE("Test water Clapeyron.jl", "[CPA]") { auto R = 8.31446261815324; CPA::CPACubic cub(CPA::cubic_flag::SRK, a0, bi, c1, Tc, R); double T = 303.15, rhomolar = 1/1.7915123921401366e-5; + using my_float_type = boost::multiprecision::number>; + my_float_type Trecip = 1/T, rhof = rhomolar; auto z = (Eigen::ArrayXd(1) << 1).finished(); using tdx = TDXDerivatives; auto alphar = cub.alphar(T, rhomolar, molefrac); + auto Ar11_cub = tdx::get_Ar11(cub, T, rhomolar, z); + auto fcub = [&cub, &z](const auto& Trecip, const auto& rho) -> my_float_type{ + return cub.alphar(forceeval(1/Trecip), rho, z); + }; + auto Ar11_cd_cubic = static_cast(centered_diff_xy(fcub, Trecip, rhof, my_float_type(1e-30), my_float_type(1e-30)) * Trecip * rhof); + CHECK(Ar11_cub == Approx(Ar11_cd_cubic)); CHECK(alphar == Approx(-1.2713135319123854)); // Value from Clapeyron.jl double p_noassoc = T*rhomolar*R*(1+tdx::get_Ar01(cub, T, rhomolar, z)); CAPTURE(p_noassoc); @@ -451,6 +459,15 @@ TEST_CASE("Test water Clapeyron.jl", "[CPA]") { CAPTURE(p_withassoc); REQUIRE(p_withassoc == Approx(100000.000)); + + auto f = [&cpa, &z](const auto& Trecip, const auto& rho) -> my_float_type{ + return cpa.alphar(forceeval(1/Trecip), rho, z); + }; + auto Ar11_cd = static_cast(centered_diff_xy(f, Trecip, rhof, my_float_type(1e-30), my_float_type(1e-30)) * Trecip * rhof); + + auto Ar11 = tdc::get_Ar11(cpa, T, rhomolar, z); + REQUIRE(std::isfinite(Ar11)); + CHECK(Ar11 == Approx(Ar11_cd)); } TEST_CASE("Test water", "[CPA]") { @@ -481,6 +498,31 @@ TEST_CASE("Test water", "[CPA]") { REQUIRE(p_withassoc == Approx(312682.0709)); } +TEST_CASE("Test [C2mim][NTF2]", "[CPA]") { + std::valarray a0 = {25.8}, bi = {251.70e-6}, c1 = {0.273}, Tc = {1244.9}, + molefrac = {1.0}; + auto R = 8.3144598; + CPA::CPACubic cub(CPA::cubic_flag::SRK, a0, bi, c1, Tc, R); + double T = 313, rhomolar = 1503/0.39132; // From https://pubs.acs.org/doi/epdf/10.1021/je700205n + + auto z = (Eigen::ArrayXd(1) << 1).finished(); + + using tdx = TDXDerivatives; + auto alphar = cub.alphar(T, rhomolar, molefrac); + + std::vector schemes = { CPA::association_classes::a2B }; + std::valarray epsAB = { 177388/10.0 }, betaAB = { 0.00266 }; + CPA::CPAAssociation cpaa(std::move(cub), schemes, CPA::radial_dist::KG, epsAB, betaAB, R); + + CPA::CPAEOS cpa(std::move(cub), std::move(cpaa)); + using tdc = TDXDerivatives; + auto Ar01 = tdc::get_Ar01(cpa, T, rhomolar, z); + double p_withassoc = T*rhomolar*R*(1 + Ar01); + CAPTURE(p_withassoc); + +// REQUIRE(p_withassoc == Approx(312682.0709)); +} + TEST_CASE("Test water w/ factory", "") { using namespace CPA; nlohmann::json water = {