diff --git a/CMakeLists.txt b/CMakeLists.txt index 85fecd4d83797d591b975494368485bf15de38c4..83a4c8e65e337c9fadb14a0f6d0b8a8194d51ec4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,16 +41,19 @@ set(AUTODIFF_BUILD_PYTHON FALSE CACHE BOOL "No autodiff python") set(AUTODIFF_BUILD_EXAMPLES FALSE CACHE BOOL "No autodiff examples") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/externals/autodiff") -# Find eigen library -# find_package(Eigen3 REQUIRED) - # Turn on more useful diagnostic messages in nlohmann::json, for instance if you are accessing a field that doesn't exist set(JSON_Diagnostics TRUE CACHE BOOL "Turn on more helpful diagnostics in nlohmann::json") + + option (TEQP_NO_PYTHON "Enable to NOT build the Python interface" OFF) +option (TEQP_TESTTEQPCPP + "Enable to add a target with a test of the C++ interface" + OFF) + option (TEQP_TEQPC "Enable to build the shared library with extern \"C\" interface" OFF) @@ -71,6 +74,18 @@ option (TEQP_MULTIPRECISION_ENABLED "Enable the use of boost::multiprecision" OFF) +# Add a static library with the C++ interface that uses only STL +# types so that recompilation of a library that uses teqp +# doesn't require a full compile for a single LOC change +add_library(teqpcpp STATIC "${CMAKE_CURRENT_SOURCE_DIR}/interface/CPP/teqpcpp.cpp") +target_link_libraries(teqpcpp PUBLIC teqpinterface PUBLIC autodiff) + + +if (TEQP_TESTTEQPCPP) + add_executable(test_teqpcpp "${CMAKE_CURRENT_SOURCE_DIR}/interface/CPP/test_teqpcpp.cpp") + target_link_libraries(test_teqpcpp PUBLIC teqpcpp) +endif() + if (TEQP_JAVASCRIPT_MODULE) # cmake -DTEQP_JAVASCRIPT_MODULE=ON # -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Platform/Emscripten.cmake diff --git a/include/teqp/json_builder.hpp b/include/teqp/json_builder.hpp index 60167a30baedb48adacff0d9016f4df4425c9d02..a7664cfca97399d821bf08f983a9813fd4e9454f 100644 --- a/include/teqp/json_builder.hpp +++ b/include/teqp/json_builder.hpp @@ -1,10 +1,6 @@ #pragma once -#include "teqp/models/vdW.hpp" -#include "teqp/models/cubics.hpp" -#include "teqp/models/CPA.hpp" -#include "teqp/models/pcsaft.hpp" -#include "teqp/models/multifluid.hpp" +#include "teqp/models/fwd.hpp" #include "teqp/exceptions.hpp" @@ -12,17 +8,7 @@ namespace teqp { - using vad = std::valarray<double>; - - // Define the EOS types by interrogating the types returned by the respective factory function - using cub = decltype(canonical_PR(vad{}, vad{}, vad{})); - using cpatype = decltype(CPA::CPAfactory(nlohmann::json{})); - using pcsafttype = decltype(PCSAFT::PCSAFTfactory(nlohmann::json{})); - using multifluidtype = decltype(multifluidfactory(nlohmann::json{})); - - using AllowedModels = std::variant<vdWEOS1, cub, cpatype, pcsafttype, multifluidtype>; - - AllowedModels build_model(const nlohmann::json& json) { + static AllowedModels build_model(const nlohmann::json& json) { // Extract the name of the model and the model parameters std::string kind = json.at("kind"); diff --git a/include/teqp/models/cubics.hpp b/include/teqp/models/cubics.hpp index 9d47cf30a267dc206ffe7e996e903cda8aa1be30..e8a437135568c73bab51bf1a6abc2c61061cb381 100644 --- a/include/teqp/models/cubics.hpp +++ b/include/teqp/models/cubics.hpp @@ -29,7 +29,7 @@ public: template<typename TType> auto operator () (const TType& T) const { - return forceeval(powi(forceeval(1.0 + mi * (1.0 - sqrt(T / Tci))), 2)); + return forceeval(pow2(forceeval(1.0 + mi * (1.0 - sqrt(T / Tci))))); } }; @@ -60,7 +60,7 @@ public: ai.resize(Tc_K.size()); bi.resize(Tc_K.size()); for (auto i = 0; i < Tc_K.size(); ++i) { - ai[i] = OmegaA * powi(Ru * Tc_K[i], 2) / pc_Pa[i]; + ai[i] = OmegaA * pow2(Ru * Tc_K[i]) / pc_Pa[i]; bi[i] = OmegaB * Ru * Tc_K[i] / pc_Pa[i]; } k = std::valarray<std::valarray<NumType>>(std::valarray<NumType>(0.0, Tc_K.size()), Tc_K.size()); @@ -169,10 +169,10 @@ auto canonical_PR(TCType Tc_K, PCType pc_K, AcentricType acentric) { std::vector<AlphaFunctionOptions> alphas; for (auto i = 0; i < Tc_K.size(); ++i) { if (acentric[i] < 0.491) { - m[i] = 0.37464 + 1.54226*acentric[i] - 0.26992*powi(acentric[i], 2); + m[i] = 0.37464 + 1.54226*acentric[i] - 0.26992*pow2(acentric[i]); } else { - m[i] = 0.379642 + 1.48503*acentric[i] -0.164423*powi(acentric[i], 2) + 0.016666*powi(acentric[i], 3); + m[i] = 0.379642 + 1.48503*acentric[i] -0.164423*pow2(acentric[i]) + 0.016666*pow3(acentric[i]); } alphas.emplace_back(BasicAlphaFunction(Tc_K[i], m[i])); } diff --git a/include/teqp/models/fwd.hpp b/include/teqp/models/fwd.hpp new file mode 100644 index 0000000000000000000000000000000000000000..9a65966c02f1914d10b7da4321d89872fe6b1195 --- /dev/null +++ b/include/teqp/models/fwd.hpp @@ -0,0 +1,32 @@ +#pragma once + +/** +* The name of this file is currently a bit of a misnomer while +* we think about whether it is possible to forward-declare the models +* +* It seems like perhaps that is not possible. For now this header +* just provides the main variant with the model definitions. +*/ + +#include <valarray> +#include <variant> + +#include "teqp/models/vdW.hpp" +#include "teqp/models/cubics.hpp" +#include "teqp/models/CPA.hpp" +#include "teqp/models/pcsaft.hpp" +#include "teqp/models/multifluid.hpp" + +namespace teqp { + + using vad = std::valarray<double>; + + // Define the EOS types by interrogating the types returned by the respective factory function + using AllowedModels = std::variant< + vdWEOS1, + decltype(canonical_PR(vad{}, vad{}, vad{})), + decltype(CPA::CPAfactory(nlohmann::json{})), + decltype(PCSAFT::PCSAFTfactory(nlohmann::json{})), + decltype(multifluidfactory(nlohmann::json{})) + >; +} \ No newline at end of file diff --git a/include/teqp/models/multifluid_reducing.hpp b/include/teqp/models/multifluid_reducing.hpp index e51c571e6f81e6f41364e0ba6263a315733eaefd..01c9d95c52b46e2d26edd7220d6dd524f62bce8a 100644 --- a/include/teqp/models/multifluid_reducing.hpp +++ b/include/teqp/models/multifluid_reducing.hpp @@ -157,15 +157,6 @@ namespace teqp { private: Eigen::MatrixXd YT, Yv; - template <typename Num> - auto cube(Num x) const { - return forceeval(x * x * x); - } - template <typename Num> - auto square(Num x) const { - return forceeval(x * x); - } - public: const Eigen::MatrixXd betaT, gammaT, betaV, gammaV; const Eigen::ArrayXd Tc, vc; @@ -185,8 +176,8 @@ namespace teqp { for (auto j = i + 1; j < N; ++j) { YT(i, j) = betaT(i, j) * gammaT(i, j) * sqrt(Tc[i] * Tc[j]); YT(j, i) = betaT(j, i) * gammaT(j, i) * sqrt(Tc[i] * Tc[j]); - Yv(i, j) = 1.0 / 8.0 * betaV(i, j) * gammaV(i, j) * cube(cbrt(vc[i]) + cbrt(vc[j])); - Yv(j, i) = 1.0 / 8.0 * betaV(j, i) * gammaV(j, i) * cube(cbrt(vc[i]) + cbrt(vc[j])); + Yv(i, j) = 1.0 / 8.0 * betaV(i, j) * gammaV(i, j) * pow3(cbrt(vc[i]) + cbrt(vc[j])); + Yv(j, i) = 1.0 / 8.0 * betaV(j, i) * gammaV(j, i) * pow3(cbrt(vc[i]) + cbrt(vc[j])); } } } @@ -197,13 +188,13 @@ namespace teqp { auto N = z.size(); typename MoleFractions::value_type sum1 = 0.0; for (auto i = 0; i < N; ++i) { - sum1 = sum1 + square(z[i]) * Yc[i]; + sum1 = sum1 + pow2(z[i]) * Yc[i]; } typename MoleFractions::value_type sum2 = 0.0; for (auto i = 0; i < N - 1; ++i) { for (auto j = i + 1; j < N; ++j) { - sum2 = sum2 + 2.0 * z[i] * z[j] * (z[i] + z[j]) / (square(beta(i, j)) * z[i] + z[j]) * Yij(i, j); + sum2 = sum2 + 2.0 * z[i] * z[j] * (z[i] + z[j]) / (pow2(beta(i, j)) * z[i] + z[j]) * Yij(i, j); } } @@ -217,8 +208,7 @@ namespace teqp { class MultiFluidInvariantReducingFunction { private: Eigen::MatrixXd YT, Yv; - template <typename Num> auto cube(Num x) const { return x * x * x; } - template <typename Num> auto square(Num x) const { return x * x; } + public: const Eigen::MatrixXd phiT, lambdaT, phiV, lambdaV; const Eigen::ArrayXd Tc, vc; @@ -238,8 +228,8 @@ namespace teqp { for (auto j = 0; j < N; ++j) { YT(i, j) = sqrt(Tc[i] * Tc[j]); YT(j, i) = sqrt(Tc[i] * Tc[j]); - Yv(i, j) = 1.0 / 8.0 * cube(cbrt(vc[i]) + cbrt(vc[j])); - Yv(j, i) = 1.0 / 8.0 * cube(cbrt(vc[i]) + cbrt(vc[j])); + Yv(i, j) = 1.0 / 8.0 * pow3(cbrt(vc[i]) + cbrt(vc[j])); + Yv(j, i) = 1.0 / 8.0 * pow3(cbrt(vc[i]) + cbrt(vc[j])); } } } diff --git a/include/teqp/models/pcsaft.hpp b/include/teqp/models/pcsaft.hpp index ee8f4e80063adb5180899788d9ed5d622f84fc30..9fd6d3f79f94dd7e96cd637ad5044694e5c8e953 100644 --- a/include/teqp/models/pcsaft.hpp +++ b/include/teqp/models/pcsaft.hpp @@ -219,11 +219,12 @@ public: auto get_sigma_Angstrom() { return sigma_Angstrom; } auto get_epsilon_over_k_K() { return epsilon_over_k; } - void print_info() { - std::cout << "i m sigma / A e/kB / K \n ++++++++++++++" << std::endl; + auto print_info() { + std::string s = std::string("i m sigma / A e/kB / K \n ++++++++++++++") + "\n"; for (auto i = 0; i < m.size(); ++i) { - std::cout << i << " " << m[i] << " " << sigma_Angstrom[i] << " " << epsilon_over_k[i] << std::endl; + s += std::to_string(i) + " " + std::to_string(m[i]) + " " + std::to_string(sigma_Angstrom[i]) + " " + std::to_string(epsilon_over_k[i]) + "\n"; } + return s; } template<typename VecType> double max_rhoN(double T, const VecType& mole_fractions) { diff --git a/include/teqp/types.hpp b/include/teqp/types.hpp index 1db3936f0a8d96f5a1aa62f495a71ec8eba901cf..c9ab7ba40716b521f264144fef38dacef34115f6 100644 --- a/include/teqp/types.hpp +++ b/include/teqp/types.hpp @@ -1,10 +1,23 @@ #pragma once +#include <vector> +#include "Eigen/Dense" + +namespace teqp { + template<typename T> inline T pow2(const T& x) { return x * x; } + template<typename T> inline T pow3(const T& x) { return x * x * x; } + + inline auto toeig(const std::vector<double>& v) -> Eigen::ArrayXd { return Eigen::Map<const Eigen::ArrayXd>(&(v[0]), v.size()); } +} + +// Everything inside this NO_TYPES_HEADER section involves slow and large headers +// so if you are just defining types (but not their implementations), you can avoid the +// compilation speed hit invoked by these headers +#if !defined(NO_TYPES_HEADER) + #include "MultiComplex/MultiComplex.hpp" -#include <vector> #include <valarray> -#include <set> #include <chrono> #if defined(TEQP_MULTIPRECISION_ENABLED) @@ -17,8 +30,6 @@ #include <autodiff/forward/dual/eigen.hpp> using namespace autodiff; -#include "Eigen/Dense" - namespace teqp { // Registration of types that are considered to be containers @@ -77,7 +88,7 @@ namespace teqp { } } - inline auto toeig (const std::vector<double>& v) -> Eigen::ArrayXd { return Eigen::Map<const Eigen::ArrayXd>(&(v[0]), v.size()); } + class Timer { private: @@ -175,4 +186,6 @@ namespace teqp { return o; } -}; // namespace teqp \ No newline at end of file +}; // namespace teqp + +#endif \ No newline at end of file diff --git a/interface/CPP/teqpcpp.cpp b/interface/CPP/teqpcpp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..45c8356d4513275e67e4dc6769a1cc5cd7405a36 --- /dev/null +++ b/interface/CPP/teqpcpp.cpp @@ -0,0 +1,17 @@ +#include "teqpcpp.hpp" +#include "teqp/derivs.hpp" +#include "teqp/algorithms/critical_tracing.hpp" + +double teqp::cppinterface::get_Arxy(const teqp::AllowedModels&model, const int NT, const int ND, const double T, const double rho, const Eigen::ArrayXd &molefracs){ + return std::visit([&](const auto& model) { + using tdx = teqp::TDXDerivatives<decltype(model), double, std::decay_t<decltype(molefracs)>>; + return tdx::get_Ar(NT, ND, model, T, rho, molefracs); + }, model); +} + +nlohmann::json teqp::cppinterface::trace_critical_arclength_binary(const teqp::AllowedModels& model, const double T0, const Eigen::ArrayXd &rhovec0) { + return std::visit([&](const auto& model) { + using crit = teqp::CriticalTracing<decltype(model), double, std::decay_t<decltype(rhovec0)>>; + return crit::trace_critical_arclength_binary(model, T0, rhovec0, ""); + }, model); +} \ No newline at end of file diff --git a/interface/CPP/teqpcpp.hpp b/interface/CPP/teqpcpp.hpp new file mode 100644 index 0000000000000000000000000000000000000000..207f848d18b46b3c19dd264fb7ac55a752322b12 --- /dev/null +++ b/interface/CPP/teqpcpp.hpp @@ -0,0 +1,15 @@ +#pragma once + +#include <valarray> + +// Pulls in the AllowedModels variant +#include "teqp/models/fwd.hpp" + +namespace teqp { + namespace cppinterface { + + // Wrapper functions + double get_Arxy(const AllowedModels& model, const int NT, const int ND, const double T, const double rho, const Eigen::ArrayXd& molefracs); + nlohmann::json trace_critical_arclength_binary(const AllowedModels& model, const double T0, const Eigen::ArrayXd& rhovec0); + } +} \ No newline at end of file diff --git a/interface/CPP/test_teqpcpp.cpp b/interface/CPP/test_teqpcpp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1bcfa9b0847ca18083f72c759d6371e13663157c --- /dev/null +++ b/interface/CPP/test_teqpcpp.cpp @@ -0,0 +1,17 @@ +#define NO_TYPES_HEADER +#include "teqpcpp.hpp" + +using namespace teqp::cppinterface; + +int main(){ + teqp::AllowedModels model = teqp::build_multifluid_model({ "Methane","Ethane" }, "../mycp"); + + //teqp::AllowedModels model = teqp::vdWEOS1(3, 0.1); + + auto z = (Eigen::ArrayXd(2) << 0.5, 0.5).finished( ); + + double Ar01 = get_Arxy(model, 0, 1, 300, 3, z); + + double Tc1 = 371.1; + auto cr = trace_critical_arclength_binary(model, Tc1, z); +} \ No newline at end of file