From 381bd3cc745c621ac5804ef3b4079c4732ba8c28 Mon Sep 17 00:00:00 2001 From: Ian Bell <ian.bell@nist.gov> Date: Tue, 27 Apr 2021 09:44:22 -0400 Subject: [PATCH] Add script for critical curves in multifluid, VLE routines, extrapolation from critical --- CMakeLists.txt | 6 + include/teqp/algorithms/VLE.hpp | 5 + include/teqp/algorithms/critical_tracing.hpp | 5 +- include/teqp/derivs.hpp | 101 ++++--- include/teqp/models/multifluid.hpp | 4 +- include/teqp/types.hpp | 19 +- interface/pybind11_wrapper.cpp | 4 + notebooks/trace_critical.py | 23 +- src/multifluid.cpp | 301 ++++++++++--------- src/multifluid_crit.cpp | 77 +++++ 10 files changed, 344 insertions(+), 201 deletions(-) create mode 100644 src/multifluid_crit.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 37f9251..6dcc8dc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,12 @@ if (MSVC) endif() target_link_libraries(multifluid autodiff) +add_executable(multifluid2 "${CMAKE_CURRENT_SOURCE_DIR}/src/multifluid2.cpp") +if (MSVC) + target_sources(multifluid2 PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/externals/Eigen/debug/msvc/eigen.natvis") +endif() +target_link_libraries(multifluid2 autodiff) + # add_executable(test_autodiff "${CMAKE_CURRENT_SOURCE_DIR}/src/test_autodiff.cpp") # if (MSVC) # target_sources(test_autodiff PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/externals/Eigen/debug/msvc/eigen.natvis") diff --git a/include/teqp/algorithms/VLE.hpp b/include/teqp/algorithms/VLE.hpp index c12ddd0..0c94243 100644 --- a/include/teqp/algorithms/VLE.hpp +++ b/include/teqp/algorithms/VLE.hpp @@ -101,6 +101,11 @@ auto do_pure_VLE_T(Residual &resid, Scalar rhoL, Scalar rhoV, int maxiter) { return (Eigen::ArrayXd(2) << rhovec[0], rhovec[1]).finished(); } +template<typename Model, typename Scalar> +auto pure_VLE_T(const Model& model, Scalar T, Scalar rhoL, Scalar rhoV, int maxiter) { + return do_pure_VLE_T(IsothermPureVLEResiduals(model, T), rhoL, rhoV, maxiter); +} + template<typename Model, typename Scalar> auto extrapolate_from_critical(const Model& model, const Scalar Tc, const Scalar rhoc, const Scalar T) { diff --git a/include/teqp/algorithms/critical_tracing.hpp b/include/teqp/algorithms/critical_tracing.hpp index f59aff2..0186129 100644 --- a/include/teqp/algorithms/critical_tracing.hpp +++ b/include/teqp/algorithms/critical_tracing.hpp @@ -51,10 +51,7 @@ struct CriticalTracing { } } - int nonzero_count = 0; - for (auto& m : mask) { - nonzero_count += (m == 1); - } + int nonzero_count = mask.count(); auto zero_count = N - nonzero_count; if (zero_count == 0) { diff --git a/include/teqp/derivs.hpp b/include/teqp/derivs.hpp index 1eb6e3f..183ab68 100644 --- a/include/teqp/derivs.hpp +++ b/include/teqp/derivs.hpp @@ -12,18 +12,6 @@ #include <autodiff/forward/dual/eigen.hpp> using namespace autodiff; -template<typename T> -auto forceeval(T&& expr) -{ - using namespace autodiff::detail; - if constexpr (isDual<T> || isExpr<T> || isNumber<T>) { - return eval(expr); - } - else { - return expr; - } -} - /*** * \brief Given a function, use complex step derivatives to calculate the derivative with * respect to the first variable which here is temperature @@ -91,7 +79,7 @@ struct TDXDerivatives { return (1.0/T)*der; } else { - static_assert("algorithmic differentiation backend is invalid in get_Ar10"); + static_assert(false, "algorithmic differentiation backend is invalid in get_Ar10"); } } @@ -116,7 +104,7 @@ struct TDXDerivatives { return rho*der; } else { - static_assert("algorithmic differentiation backend is invalid in get_Ar01"); + static_assert(false, "algorithmic differentiation backend is invalid in get_Ar01"); } } @@ -129,7 +117,7 @@ struct TDXDerivatives { return rho*rho*ders[2]; } else { - static_assert("algorithmic differentiation backend is invalid in get_Ar02"); + static_assert(false, "algorithmic differentiation backend is invalid in get_Ar02"); } } @@ -141,25 +129,25 @@ struct TDXDerivatives { auto f = [&model, &T, &molefrac](const auto& rho_) { return eval(model.alphar(T, rho_, molefrac)); }; auto ders = derivatives(f, wrt(rhodual), at(rhodual)); for (auto n = 0; n <= Nderiv; ++n) { - o[n] = pow(rho, n)*ders[n]; + o[n] = pow(rho, n) * ders[n]; } return o; } else { - static_assert("algorithmic differentiation backend is invalid in get_Ar0n"); + static_assert(false, "algorithmic differentiation backend is invalid in get_Ar0n"); } } template<ADBackends be = ADBackends::autodiff> static auto get_Ar20(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) { if constexpr (be == ADBackends::autodiff) { - autodiff::dual2nd Trecipdual = 1/T; - auto f = [&model, &rho, &molefrac](const auto& Trecip) { return eval(model.alphar(eval(1/Trecip), rho, molefrac)); }; + autodiff::dual2nd Trecipdual = 1 / T; + auto f = [&model, &rho, &molefrac](const auto& Trecip) { return eval(model.alphar(eval(1 / Trecip), rho, molefrac)); }; auto ders = derivatives(f, wrt(Trecipdual), at(Trecipdual)); - return (1/T)*(1/T)*ders[2]; + return (1 / T) * (1 / T) * ders[2]; } else { - static_assert("algorithmic differentiation backend is invalid in get_Ar20"); + static_assert(false, "algorithmic differentiation backend is invalid in get_Ar20"); } } @@ -170,22 +158,22 @@ struct TDXDerivatives { using fcn_t = std::function< mcx::MultiComplex<double>(const std::valarray<mcx::MultiComplex<double>>&)>; const fcn_t func = [&model, &molefrac](const auto& zs) { auto rhomolar = zs[0], Trecip = zs[1]; - return model.alphar(1.0/Trecip, rhomolar, molefrac); + return model.alphar(1.0 / Trecip, rhomolar, molefrac); }; - std::vector<double> xs = { rho, 1.0/T}; - std::vector<int> order = { 1, 1}; + std::vector<double> xs = { rho, 1.0 / T }; + std::vector<int> order = { 1, 1 }; auto der = mcx::diff_mcxN(func, xs, order); - return (1.0/T)*rho*der; + return (1.0 / T) * rho * der; } else if constexpr (be == ADBackends::autodiff) { - autodiff::dual2nd rhodual = rho, Trecipdual=1/T; - auto f = [&model, &molefrac](const auto& Trecip, const auto&rho_) { return eval(model.alphar(eval(1/Trecip), rho_, molefrac)); }; + autodiff::dual2nd rhodual = rho, Trecipdual = 1 / T; + auto f = [&model, &molefrac](const autodiff::dual2nd& Trecip, const autodiff::dual2nd& rho_) { return eval(model.alphar(eval(1 / Trecip), rho_, molefrac)); }; //auto der = derivative(f, wrt(Trecipdual, rhodual), at(Trecipdual, rhodual)); // d^2alphar/drhod(1/T) // This should work, but gives instead 1,0 derivative auto [u01, u10, u11] = derivatives(f, wrt(Trecipdual, rhodual), at(Trecipdual, rhodual)); // d^2alphar/drhod(1/T) - return (1.0/T)*rho*u11; + return (1.0 / T) * rho * u11; } else { - static_assert("algorithmic differentiation backend is invalid in get_Ar11"); + static_assert(false, "algorithmic differentiation backend is invalid in get_Ar11"); } } @@ -198,20 +186,63 @@ struct TDXDerivatives { auto rhomolar = zs[0], Trecip = zs[1]; return model.alphar(1.0 / Trecip, rhomolar, molefrac); }; - std::vector<double> xs = { rho, 1.0/T }; + std::vector<double> xs = { rho, 1.0 / T }; std::vector<int> order = { 1, 2 }; auto der = mcx::diff_mcxN(func, xs, order); - return (1.0/T)*rho*rho*der; + return (1.0 / T) * rho * rho * der; } else if constexpr (be == ADBackends::autodiff) { //static_assert("bug in autodiff, can't use autodiff for cross derivative"); autodiff::dual3rd rhodual = rho, Trecipdual = 1 / T; auto f = [&model, &molefrac](const auto& Trecip, const auto& rho_) { return eval(model.alphar(eval(1 / Trecip), rho_, molefrac)); }; auto ders = derivatives(f, wrt(Trecipdual, rhodual, rhodual), at(Trecipdual, rhodual)); - return (1.0/T)*rho*rho*ders.back(); + return (1.0 / T) * rho * rho * ders.back(); + } + else { + static_assert(false, "algorithmic differentiation backend is invalid in get_Ar12"); + } + } + + template<ADBackends be = ADBackends::autodiff> + static auto get_Ar(const int itau, const int idelta, const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) { + if (itau == 0) { + if (idelta == 0) { + return get_Ar00(model, T, rho, molefrac); + } + //else if (idelta == 1) { + // return get_Ar01(model, T, rho, molefrac); + //} + //else if (idelta == 2) { + // return get_Ar02(model, T, rho, molefrac); + //} + else { + throw std::invalid_argument("Invalid value for idelta"); + } + } + else if (itau == 1){ + if (idelta == 0) { + return get_Ar10(model, T, rho, molefrac); + } + //else if (idelta == 1) { + // return get_Ar11(model, T, rho, molefrac); + //} + /*else if (idelta == 2) { + return get_Ar12(model, T, rho, molefrac); + }*/ + else { + throw std::invalid_argument("Invalid value for idelta"); + } + } + else if (itau == 2) { + if (idelta == 0) { + return get_Ar20(model, T, rho, molefrac); + } + else { + throw std::invalid_argument("Invalid value for idelta"); + } } else { - static_assert("algorithmic differentiation backend is invalid in get_Ar12"); + throw std::invalid_argument("Invalid value for idelta"); } } @@ -219,7 +250,7 @@ struct TDXDerivatives { static auto get_neff(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) { auto Ar01 = get_Ar01<be>(model, T, rho, molefrac); auto Ar11 = get_Ar11<be>(model, T, rho, molefrac); - auto Ar20 = get_Ar20(model, T, rho, molefrac); + auto Ar20 = get_Ar20<be>(model, T, rho, molefrac); return -3*(Ar01-Ar11)/Ar20; } }; @@ -266,7 +297,7 @@ struct VirialDerivatives { } } else{ - static_assert("algorithmic differentiation backend is invalid"); + static_assert(false, "algorithmic differentiation backend is invalid"); } std::map<int, Scalar> o; for (int n = 2; n < Nderiv+1; ++n) { diff --git a/include/teqp/models/multifluid.hpp b/include/teqp/models/multifluid.hpp index 5c1626a..328d90f 100644 --- a/include/teqp/models/multifluid.hpp +++ b/include/teqp/models/multifluid.hpp @@ -6,6 +6,8 @@ #include <fstream> #include <string> #include <cmath> +#include <optional> +#include "teqp/types.hpp" #include "MultiComplex/MultiComplex.hpp" // See https://eigen.tuxfamily.org/dox/TopicCustomizing_CustomScalar.html @@ -75,7 +77,7 @@ public: const CorrespondingTerm corr; const DepartureTerm dep; - const double R = get_R_gas<double>(); + const double R = 1.380649e-23 * 6.02214076e23; ///< Exact value, given by k_B*N_A MultiFluid(ReducingFunction&& redfunc, CorrespondingTerm&& corr, DepartureTerm&& dep) : redfunc(redfunc), corr(corr), dep(dep) {}; diff --git a/include/teqp/types.hpp b/include/teqp/types.hpp index 91a54a0..9061d31 100644 --- a/include/teqp/types.hpp +++ b/include/teqp/types.hpp @@ -9,4 +9,21 @@ template <typename Container> struct is_container : std::false_type { }; template <typename... Ts> struct is_container<std::vector<Ts...> > : std::true_type { }; template <typename... Ts> struct is_container<std::valarray<Ts...> > : std::true_type { }; -// Missing Eigen::Array and Eigen::Matrix types here \ No newline at end of file +// Missing Eigen::Array and Eigen::Matrix types here + +// autodiff include +#include <autodiff/forward/dual.hpp> +#include <autodiff/forward/dual/eigen.hpp> +using namespace autodiff; + +template<typename T> +auto forceeval(T&& expr) +{ + using namespace autodiff::detail; + if constexpr (isDual<T> || isExpr<T> || isNumber<T>) { + return eval(expr); + } + else { + return expr; + } +} \ No newline at end of file diff --git a/interface/pybind11_wrapper.cpp b/interface/pybind11_wrapper.cpp index 1680037..bb368bc 100644 --- a/interface/pybind11_wrapper.cpp +++ b/interface/pybind11_wrapper.cpp @@ -13,6 +13,7 @@ #include "teqp/algorithms/critical_tracing.hpp" #include "teqp/models/pcsaft.hpp" #include "teqp/models/multifluid.hpp" +#include "teqp/algorithms/VLE.hpp" namespace py = pybind11; @@ -50,6 +51,9 @@ void add_derivatives(py::module &m, Wrapper &cls) { using ct = CriticalTracing<Model, double, Eigen::Array<double, Eigen::Dynamic, 1>>; m.def("trace_critical_arclength_binary", &ct::trace_critical_arclength_binary); + m.def("extrapolate_from_critical", &extrapolate_from_critical<Model, double>); + m.def("pure_VLE_T", &pure_VLE_T<Model, double>); + //cls.def("get_Ar01", [](const Model& m, const double T, const Eigen::ArrayXd& rhovec) { return id::get_Ar01(m, T, rhovec); }); //cls.def("get_Ar10", [](const Model& m, const double T, const Eigen::ArrayXd& rhovec) { return id::get_Ar10(m, T, rhovec); }); using tdx = TDXDerivatives<Model, double, Eigen::Array<double, Eigen::Dynamic, 1> >; diff --git a/notebooks/trace_critical.py b/notebooks/trace_critical.py index 10e1881..a953e18 100644 --- a/notebooks/trace_critical.py +++ b/notebooks/trace_critical.py @@ -9,7 +9,7 @@ import pandas import scipy.optimize def trace(): - model = teqp.build_multifluid_model(["Methane", "Ethane"], '../mycp', '../mycp/dev/mixtures/mixture_binary_pairs.json') + model = teqp.build_multifluid_model(["R1234yf", "R32"], '../mycp', '../mycp/dev/mixtures/mixture_binary_pairs.json') Tcvec = model.get_Tcvec() rhocvec = 1/model.get_vcvec() models = [model] @@ -18,7 +18,7 @@ def trace(): for i in range(2): z = [0,0]; z[i] = 1 z = np.array(z) - p = 8.314462618*Tcvec[i]*rhocvec[i]*(1+model.get_Ar01(Tcvec[i], rhocvec[i]*z)) + p = 8.314462618*Tcvec[i]*rhocvec[i]*(1+model.get_Ar01(Tcvec[i], rhocvec[i], z)) pc_Pa.append(p) model = teqp.vdWEOS(Tcvec, pc_Pa) models.append(model) @@ -26,24 +26,27 @@ def trace(): i = 1 T0 = Tcvec[i] z = np.array([0, 0]); z[i] = 1 - if isinstance(model, teqp.vdWEOS): - rho0 = z*pc_Pa[i]/(8.314462618*Tcvec[i])*8/3 - else: - rho0 = z*rhocvec[i] fig1, ax1 = plt.subplots(1,1) fig2, ax2 = plt.subplots(1,1) fig3, ax3 = plt.subplots(1,1) for model in models: + + if isinstance(model, teqp.vdWEOS): + rho0 = z*pc_Pa[i]/(8.314462618*Tcvec[i])*8/3 + else: + rho0 = z*rhocvec[i] + tic = timeit.default_timer() curveJSON = teqp.trace_critical_arclength_binary(model, T0, rho0, "") toc = timeit.default_timer() - print(toc-tic, 's') + print(toc-tic) + df = pandas.DataFrame(curveJSON) df['z0 / mole frac.'] = df['rho0 / mol/m^3']/(df['rho0 / mol/m^3']+df['rho1 / mol/m^3']) - ax1.plot(df['z0 / mole frac.'], df['T / K']) - ax2.plot(df['T / K'], df['p / Pa']) - ax3.plot(df['z0 / mole frac.'], df['rho0 / mol/m^3']+df['rho1 / mol/m^3']) + ax1.plot(df['z0 / mole frac.'], df['T / K']); ax1.set(xlabel='z0 / mole frac.', ylabel='$T$ / K') + ax2.plot(df['T / K'], df['p / Pa']); ax2.set(xlabel='$T$ / K', ylabel='$p$ / Pa') + ax3.plot(df['z0 / mole frac.'], df['s^+']/df['s^+'].iloc[0]); ax3.set(xlabel='x0 / mole frac.', ylabel='') plt.show() if __name__ == '__main__': diff --git a/src/multifluid.cpp b/src/multifluid.cpp index 44461a1..cbf7919 100644 --- a/src/multifluid.cpp +++ b/src/multifluid.cpp @@ -5,146 +5,146 @@ #include "teqp/algorithms/critical_tracing.hpp" #include <optional> - -class Timer { -private: - int N; - decltype(std::chrono::steady_clock::now()) tic; -public: - Timer(int N) : N(N), tic(std::chrono::steady_clock::now()){} - ~Timer() { - auto elap = std::chrono::duration<double>(std::chrono::steady_clock::now()-tic).count(); - std::cout << elap/N*1e6 << " us/call" << std::endl; - } -}; - -void trace_critical_loci(const std::string &coolprop_root, const nlohmann::json &BIPcollection) { - std::vector<std::vector<std::string>> pairs = { - { "CarbonDioxide", "R1234YF" }, { "CarbonDioxide","R1234ZE(E)" }, { "ETHYLENE","R1243ZF" }, - { "R1234YF","R1234ZE(E)" }, { "R134A","R1234YF" }, { "R23","R1234YF" }, - { "R32","R1123" }, { "R32","R1234YF" }, { "R32","R1234ZE(E)" } - }; - for (auto &pp : pairs) { - using ModelType = decltype(build_multifluid_model(pp, coolprop_root, BIPcollection)); - std::optional<ModelType> optmodel{std::nullopt}; - try { - optmodel.emplace(build_multifluid_model(pp, coolprop_root, BIPcollection)); - } - catch (std::exception &e) { - std::cout << e.what() << std::endl; - std::cout << pp[0] << "&" << pp[1] << std::endl; - continue; - } - for (int i : {0, 1}){ - const auto &model = optmodel.value(); - auto rhoc0 = 1.0 / model.redfunc.vc[i]; - auto T0 = model.redfunc.Tc[i]; - Eigen::ArrayXd rhovec(2); rhovec[i] = { rhoc0 }; rhovec[1L - i] = 0.0; - - using ct = CriticalTracing<ModelType>; - - // Non-analytic terms make it impossible to initialize AT the pure components - if (pp[0] == "CarbonDioxide" || pp[1] == "CarbonDioxide") { - if (i == 0) { - rhovec[i] *= 0.9999; - rhovec[1L - i] = 0.9999; - } - else { - rhovec[i] *= 1.0001; - rhovec[1L - i] = 1.0001; - } - double zi = rhovec[i] / rhovec.sum(); - double T = zi * model.redfunc.Tc[i] + (1 - zi) * model.redfunc.Tc[1L - i]; - double z0 = (i == 0) ? zi : 1-zi; - auto [Tnew, rhonew] = ct::critical_polish_molefrac(model, T, rhovec, z0); - T0 = Tnew; - rhoc0 = rhovec.sum(); - } - std::string filename = pp[0] + "_" + pp[1] + ".csv"; - ct::trace_critical_arclength_binary(model, T0, rhovec, filename); - } - } -} - -template<typename J> -void time_calls(const std::string &coolprop_root, const J &BIPcollection) { - auto model = build_multifluid_model({ "methane", "ethane" }, coolprop_root, BIPcollection); - Eigen::ArrayXd rhovec(2); rhovec << 1.0, 2.0; - double T = 300; - { - const auto molefrac = (Eigen::ArrayXd(2) << rhovec[0] / rhovec.sum(), rhovec[1] / rhovec.sum()).finished(); - - using vd = VirialDerivatives<decltype(model)>; - auto B12 = vd::get_B12vir(model, T, molefrac); - - using id = IsochoricDerivatives<decltype(model)>; - auto mu = id::get_chempot_autodiff(model, T, rhovec); - - const double rho = rhovec.sum(); - double T = 300.0; - constexpr int N = 10000; - volatile double alphar; - using tdx = TDXDerivatives<decltype(model)>; - double rrrr = tdx::get_Ar01(model, T, rho, molefrac); - double rrrr2 = tdx::get_Ar02(model, T, rho, molefrac); - { - Timer t(N); - for (auto i = 0; i < N; ++i) { - alphar = model.alphar(T, rho, molefrac); - } - std::cout << alphar << " function call" << std::endl; - } - { - Timer t(N); - for (auto i = 0; i < N; ++i) { - alphar = tdx::get_Ar01<ADBackends::complex_step>(model, T, rho, molefrac); - } - std::cout << alphar << "; 1st CSD" << std::endl; - } - { - Timer t(N); - for (auto i = 0; i < N; ++i) { - alphar = tdx::get_Ar01<ADBackends::autodiff>(model, T, rho, molefrac); - } - std::cout << alphar << "; 1st autodiff::autodiff" << std::endl; - } - { - Timer t(N); - for (auto i = 0; i < N; ++i) { - alphar = tdx::get_Ar01<ADBackends::multicomplex>(model, T, rho, molefrac); - } - std::cout << alphar << "; 1st MCX" << std::endl; - } - { - Timer t(N); - for (auto i = 0; i < N; ++i) { - alphar = tdx::get_Ar02(model, T, rho, molefrac); - } - std::cout << alphar << "; 2nd autodiff" << std::endl; - } - { - Timer t(N); - for (auto i = 0; i < N; ++i) { - auto o = vd::template get_Bnvir<3, ADBackends::autodiff>(model, T, molefrac)[3]; - } - std::cout << alphar << "; 3 derivs" << std::endl; - } - { - Timer t(N); - for (auto i = 0; i < N; ++i) { - auto o = vd::template get_Bnvir<4, ADBackends::autodiff>(model, T, molefrac)[4]; - } - std::cout << alphar << "; 4 derivs" << std::endl; - } - { - Timer t(N); - for (auto i = 0; i < N; ++i) { - auto o = vd::template get_Bnvir<5, ADBackends::autodiff>(model, T, molefrac)[5]; - } - std::cout << alphar << "; 5 derivs" << std::endl; - } - } -} +// +//class Timer { +//private: +// int N; +// decltype(std::chrono::steady_clock::now()) tic; +//public: +// Timer(int N) : N(N), tic(std::chrono::steady_clock::now()){} +// ~Timer() { +// auto elap = std::chrono::duration<double>(std::chrono::steady_clock::now()-tic).count(); +// std::cout << elap/N*1e6 << " us/call" << std::endl; +// } +//}; +// +//void trace_critical_loci(const std::string &coolprop_root, const nlohmann::json &BIPcollection) { +// std::vector<std::vector<std::string>> pairs = { +// { "CarbonDioxide", "R1234YF" }, { "CarbonDioxide","R1234ZE(E)" }, { "ETHYLENE","R1243ZF" }, +// { "R1234YF","R1234ZE(E)" }, { "R134A","R1234YF" }, { "R23","R1234YF" }, +// { "R32","R1123" }, { "R32","R1234YF" }, { "R32","R1234ZE(E)" } +// }; +// for (auto &pp : pairs) { +// using ModelType = decltype(build_multifluid_model(pp, coolprop_root, BIPcollection)); +// std::optional<ModelType> optmodel{std::nullopt}; +// try { +// optmodel.emplace(build_multifluid_model(pp, coolprop_root, BIPcollection)); +// } +// catch (std::exception &e) { +// std::cout << e.what() << std::endl; +// std::cout << pp[0] << "&" << pp[1] << std::endl; +// continue; +// } +// for (int i : {0, 1}){ +// const auto &model = optmodel.value(); +// auto rhoc0 = 1.0 / model.redfunc.vc[i]; +// auto T0 = model.redfunc.Tc[i]; +// Eigen::ArrayXd rhovec(2); rhovec[i] = { rhoc0 }; rhovec[1L - i] = 0.0; +// +// using ct = CriticalTracing<ModelType>; +// +// // Non-analytic terms make it impossible to initialize AT the pure components +// if (pp[0] == "CarbonDioxide" || pp[1] == "CarbonDioxide") { +// if (i == 0) { +// rhovec[i] *= 0.9999; +// rhovec[1L - i] = 0.9999; +// } +// else { +// rhovec[i] *= 1.0001; +// rhovec[1L - i] = 1.0001; +// } +// double zi = rhovec[i] / rhovec.sum(); +// double T = zi * model.redfunc.Tc[i] + (1 - zi) * model.redfunc.Tc[1L - i]; +// double z0 = (i == 0) ? zi : 1-zi; +// auto [Tnew, rhonew] = ct::critical_polish_molefrac(model, T, rhovec, z0); +// T0 = Tnew; +// rhoc0 = rhovec.sum(); +// } +// std::string filename = pp[0] + "_" + pp[1] + ".csv"; +// ct::trace_critical_arclength_binary(model, T0, rhovec, filename); +// } +// } +//} +// +//template<typename J> +//void time_calls(const std::string &coolprop_root, const J &BIPcollection) { +// auto model = build_multifluid_model({ "methane", "ethane" }, coolprop_root, BIPcollection); +// Eigen::ArrayXd rhovec(2); rhovec << 1.0, 2.0; +// double T = 300; +// { +// const auto molefrac = (Eigen::ArrayXd(2) << rhovec[0] / rhovec.sum(), rhovec[1] / rhovec.sum()).finished(); +// +// using vd = VirialDerivatives<decltype(model)>; +// auto B12 = vd::get_B12vir(model, T, molefrac); +// +// using id = IsochoricDerivatives<decltype(model)>; +// auto mu = id::get_chempot_autodiff(model, T, rhovec); +// +// const double rho = rhovec.sum(); +// double T = 300.0; +// constexpr int N = 10000; +// volatile double alphar; +// using tdx = TDXDerivatives<decltype(model)>; +// double rrrr = tdx::get_Ar01(model, T, rho, molefrac); +// double rrrr2 = tdx::get_Ar02(model, T, rho, molefrac); +// { +// Timer t(N); +// for (auto i = 0; i < N; ++i) { +// alphar = model.alphar(T, rho, molefrac); +// } +// std::cout << alphar << " function call" << std::endl; +// } +// { +// Timer t(N); +// for (auto i = 0; i < N; ++i) { +// alphar = tdx::get_Ar01<ADBackends::complex_step>(model, T, rho, molefrac); +// } +// std::cout << alphar << "; 1st CSD" << std::endl; +// } +// { +// Timer t(N); +// for (auto i = 0; i < N; ++i) { +// alphar = tdx::get_Ar01<ADBackends::autodiff>(model, T, rho, molefrac); +// } +// std::cout << alphar << "; 1st autodiff::autodiff" << std::endl; +// } +// { +// Timer t(N); +// for (auto i = 0; i < N; ++i) { +// alphar = tdx::get_Ar01<ADBackends::multicomplex>(model, T, rho, molefrac); +// } +// std::cout << alphar << "; 1st MCX" << std::endl; +// } +// { +// Timer t(N); +// for (auto i = 0; i < N; ++i) { +// alphar = tdx::get_Ar02(model, T, rho, molefrac); +// } +// std::cout << alphar << "; 2nd autodiff" << std::endl; +// } +// { +// Timer t(N); +// for (auto i = 0; i < N; ++i) { +// auto o = vd::template get_Bnvir<3, ADBackends::autodiff>(model, T, molefrac)[3]; +// } +// std::cout << alphar << "; 3 derivs" << std::endl; +// } +// { +// Timer t(N); +// for (auto i = 0; i < N; ++i) { +// auto o = vd::template get_Bnvir<4, ADBackends::autodiff>(model, T, molefrac)[4]; +// } +// std::cout << alphar << "; 4 derivs" << std::endl; +// } +// { +// Timer t(N); +// for (auto i = 0; i < N; ++i) { +// auto o = vd::template get_Bnvir<5, ADBackends::autodiff>(model, T, molefrac)[5]; +// } +// std::cout << alphar << "; 5 derivs" << std::endl; +// } +// } +//} int main(){ @@ -153,10 +153,10 @@ int main(){ auto BIPcollection = coolprop_root + "/dev/mixtures/mixture_binary_pairs.json"; // Critical curves - { + /* { Timer t(1); trace_critical_loci(coolprop_root, BIPcollection); - } + }*/ //time_calls(coolprop_root, BIPcollection); @@ -166,18 +166,19 @@ int main(){ double T = 300; const auto molefrac = rhovec/rhovec.sum(); - using tdx = TDXDerivatives<decltype(model)>; + using tdx = TDXDerivatives<decltype(model), double, Eigen::ArrayXd>; const auto b = ADBackends::autodiff; - auto rho = rhovec.sum(); + auto rho = rhovec.sum(); auto alphar = model.alphar(T, rho, rhovec); auto Ar01 = tdx::get_Ar01<b>(model, T, rho, molefrac); - auto Ar10 = tdx::get_Ar10(model, T, rho, molefrac); - auto Ar02 = tdx::get_Ar02(model, T, rho, molefrac); + auto Ar10 = tdx::get_Ar10<b>(model, T, rho, molefrac); + auto Ar02 = tdx::get_Ar02<b>(model, T, rho, molefrac); auto Ar11 = tdx::get_Ar11<b>(model, T, rho, molefrac); - auto Ar11mcx = tdx::get_Ar11<ADBackends::multicomplex>(model, T, rho, molefrac); - auto Ar20 = tdx::get_Ar20(model, T, rho, molefrac); - using id = IsochoricDerivatives<decltype(model)>; - auto splus = id::get_splus(model, T, rhovec); + + //auto Ar11mcx = tdx::get_Ar11<ADBackends::multicomplex>(model, T, rho, molefrac); + //auto Ar20 = tdx::get_Ar20(model, T, rho, molefrac); + //using id = IsochoricDerivatives<decltype(model), double, Eigen::ArrayXd>; + //auto splus = id::get_splus(model, T, rhovec);*/ int ttt = 0; } diff --git a/src/multifluid_crit.cpp b/src/multifluid_crit.cpp new file mode 100644 index 0000000..4823cd3 --- /dev/null +++ b/src/multifluid_crit.cpp @@ -0,0 +1,77 @@ +#define USE_AUTODIFF + +#include "teqp/core.hpp" +#include "teqp/models/multifluid.hpp" +#include "teqp/algorithms/critical_tracing.hpp" + +#include <optional> + +class Timer { +private: + int N; + decltype(std::chrono::steady_clock::now()) tic; +public: + Timer(int N) : N(N), tic(std::chrono::steady_clock::now()){} + ~Timer() { + auto elap = std::chrono::duration<double>(std::chrono::steady_clock::now()-tic).count(); + std::cout << elap/N*1e6 << " us/call" << std::endl; + } +}; + +void trace_critical_loci(const std::string &coolprop_root, const nlohmann::json &BIPcollection) { + std::vector<std::vector<std::string>> pairs = { + { "CarbonDioxide", "R1234YF" }, { "CarbonDioxide","R1234ZE(E)" }, { "ETHYLENE","R1243ZF" }, + { "R1234YF","R1234ZE(E)" }, { "R134A","R1234YF" }, { "R23","R1234YF" }, + { "R32","R1123" }, { "R32","R1234YF" }, { "R32","R1234ZE(E)" } + }; + for (auto &pp : pairs) { + using ModelType = decltype(build_multifluid_model(pp, coolprop_root, BIPcollection)); + std::optional<ModelType> optmodel{std::nullopt}; + try { + optmodel.emplace(build_multifluid_model(pp, coolprop_root, BIPcollection)); + } + catch (std::exception &e) { + std::cout << e.what() << std::endl; + std::cout << pp[0] << "&" << pp[1] << std::endl; + continue; + } + for (int i : {0, 1}){ + const auto &model = optmodel.value(); + auto rhoc0 = 1.0 / model.redfunc.vc[i]; + auto T0 = model.redfunc.Tc[i]; + Eigen::ArrayXd rhovec(2); rhovec[i] = { rhoc0 }; rhovec[1L - i] = 0.0; + + using ct = CriticalTracing<ModelType>; + + // Non-analytic terms make it impossible to initialize AT the pure components + if (pp[0] == "CarbonDioxide" || pp[1] == "CarbonDioxide") { + if (i == 0) { + rhovec[i] *= 0.9999; + rhovec[1L - i] = 0.9999; + } + else { + rhovec[i] *= 1.0001; + rhovec[1L - i] = 1.0001; + } + double zi = rhovec[i] / rhovec.sum(); + double T = zi * model.redfunc.Tc[i] + (1 - zi) * model.redfunc.Tc[1L - i]; + double z0 = (i == 0) ? zi : 1-zi; + auto [Tnew, rhonew] = ct::critical_polish_molefrac(model, T, rhovec, z0); + T0 = Tnew; + rhoc0 = rhovec.sum(); + } + std::string filename = pp[0] + "_" + pp[1] + ".csv"; + ct::trace_critical_arclength_binary(model, T0, rhovec, filename); + } + } +} + +int main(){ + + std::string coolprop_root = "../mycp"; + auto BIPcollection = coolprop_root + "/dev/mixtures/mixture_binary_pairs.json"; + // Critical curves + Timer t(1); + trace_critical_loci(coolprop_root, BIPcollection); + return EXIT_SUCCESS; +} \ No newline at end of file -- GitLab