From d751a20162adb7342e90ad6462114fd5051f5894 Mon Sep 17 00:00:00 2001 From: Ian Bell <ian.bell@nist.gov> Date: Sat, 21 May 2022 17:49:16 -0400 Subject: [PATCH] Enable setting kij for cubics --- include/teqp/models/cubics.hpp | 32 +++++++++++++++++++++++--------- interface/cubics.cpp | 4 ++-- src/tests/catch_test_cubics.cxx | 20 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 11 deletions(-) diff --git a/include/teqp/models/cubics.hpp b/include/teqp/models/cubics.hpp index e8a4371..aa9f0c7 100644 --- a/include/teqp/models/cubics.hpp +++ b/include/teqp/models/cubics.hpp @@ -14,6 +14,8 @@ Implementations of the canonical cubic equations of state #include "nlohmann/json.hpp" +#include <Eigen/Dense> + namespace teqp { /** @@ -40,10 +42,10 @@ template <typename NumType, typename AlphaFunctions> class GenericCubic { protected: std::valarray<NumType> ai, bi; - std::valarray<std::valarray<NumType>> k; const NumType Delta1, Delta2, OmegaA, OmegaB; int superanc_index; const AlphaFunctions alphas; + Eigen::ArrayXXd kmat; nlohmann::json meta; @@ -53,9 +55,21 @@ protected: template<typename TType, typename IndexType> auto get_bi(TType T, IndexType i) const { return bi[i]; } + void check_kmat(int N) { + if (kmat.cols() != kmat.rows()) { + throw teqp::InvalidArgument("kmat rows [" + std::to_string(kmat.rows()) + "] and columns [" + std::to_string(kmat.cols()) + "] are not identical"); + } + if (kmat.cols() == 0) { + kmat.resize(N, N); kmat.setZero(); + } + else if (kmat.cols() != N) { + throw teqp::InvalidArgument("kmat needs to be a square matrix the same size as the number of components [" + std::to_string(N) + "]"); + } + }; + public: - GenericCubic(NumType Delta1, NumType Delta2, NumType OmegaA, NumType OmegaB, int superanc_index, const std::valarray<NumType>& Tc_K, const std::valarray<NumType>& pc_Pa, const AlphaFunctions& alphas) - : Delta1(Delta1), Delta2(Delta2), OmegaA(OmegaA), OmegaB(OmegaB), superanc_index(superanc_index), alphas(alphas) + GenericCubic(NumType Delta1, NumType Delta2, NumType OmegaA, NumType OmegaB, int superanc_index, const std::valarray<NumType>& Tc_K, const std::valarray<NumType>& pc_Pa, const AlphaFunctions& alphas, const Eigen::ArrayXXd& kmat) + : Delta1(Delta1), Delta2(Delta2), OmegaA(OmegaA), OmegaB(OmegaB), superanc_index(superanc_index), alphas(alphas), kmat(kmat) { ai.resize(Tc_K.size()); bi.resize(Tc_K.size()); @@ -63,7 +77,7 @@ public: 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()); + check_kmat(ai.size()); }; void set_meta(const nlohmann::json& j) { meta = j; } @@ -101,7 +115,7 @@ public: for (auto j = 0; j < molefracs.size(); ++j) { auto alphaj = forceeval(std::visit([&](auto& t) { return t(T); }, alphas[j])); auto aj_ = ai[j] * alphaj; - auto aij = forceeval((1 - k[i][j]) * sqrt(ai_ * aj_)); + auto aij = forceeval((1 - kmat(i,j)) * sqrt(ai_ * aj_)); a_ = a_ + molefracs[i] * molefracs[j] * aij; } } @@ -134,7 +148,7 @@ public: }; template <typename TCType, typename PCType, typename AcentricType> -auto canonical_SRK(TCType Tc_K, PCType pc_K, AcentricType acentric) { +auto canonical_SRK(TCType Tc_K, PCType pc_K, AcentricType acentric, const Eigen::ArrayXXd& kmat = {}) { double Delta1 = 1; double Delta2 = 0; auto m = 0.48 + 1.574 * acentric - 0.176 * acentric * acentric; @@ -156,13 +170,13 @@ auto canonical_SRK(TCType Tc_K, PCType pc_K, AcentricType acentric) { {"kind", "Soave-Redlich-Kwong"} }; - auto cub = GenericCubic(Delta1, Delta2, OmegaA, OmegaB, CubicSuperAncillary::SRK_CODE, Tc_K, pc_K, std::move(alphas)); + auto cub = GenericCubic(Delta1, Delta2, OmegaA, OmegaB, CubicSuperAncillary::SRK_CODE, Tc_K, pc_K, std::move(alphas), kmat); cub.set_meta(meta); return cub; } template <typename TCType, typename PCType, typename AcentricType> -auto canonical_PR(TCType Tc_K, PCType pc_K, AcentricType acentric) { +auto canonical_PR(TCType Tc_K, PCType pc_K, AcentricType acentric, const Eigen::ArrayXXd& kmat = {}) { double Delta1 = 1+sqrt(2); double Delta2 = 1-sqrt(2); AcentricType m = acentric*0.0; @@ -189,7 +203,7 @@ auto canonical_PR(TCType Tc_K, PCType pc_K, AcentricType acentric) { {"kind", "Peng-Robinson"} }; - auto cub = GenericCubic(Delta1, Delta2, OmegaA, OmegaB, CubicSuperAncillary::PR_CODE, Tc_K, pc_K, std::move(alphas)); + auto cub = GenericCubic(Delta1, Delta2, OmegaA, OmegaB, CubicSuperAncillary::PR_CODE, Tc_K, pc_K, std::move(alphas), kmat); cub.set_meta(meta); return cub; } diff --git a/interface/cubics.cpp b/interface/cubics.cpp index 8f26cff..9598b80 100644 --- a/interface/cubics.cpp +++ b/interface/cubics.cpp @@ -6,8 +6,8 @@ void add_cubics(py::module& m) { using va = std::valarray<double>; - m.def("canonical_PR", &canonical_PR<va,va,va>, py::arg("Tc_K"), py::arg("pc_Pa"), py::arg("acentric")); - m.def("canonical_SRK", &canonical_SRK<va, va, va>, py::arg("Tc_K"), py::arg("pc_Pa"), py::arg("acentric")); + m.def("canonical_PR", &canonical_PR<va,va,va>, py::arg("Tc_K"), py::arg("pc_Pa"), py::arg("acentric"), py::arg_v("kmat", Eigen::ArrayXXd(0, 0), "None")); + m.def("canonical_SRK", &canonical_SRK<va, va, va>, py::arg("Tc_K"), py::arg("pc_Pa"), py::arg("acentric"), py::arg_v("kmat", Eigen::ArrayXXd(0, 0), "None")); using cub = decltype(canonical_PR(va{}, va{}, va{})); auto wcub = py::class_<cub>(m, "GenericCubic") diff --git a/src/tests/catch_test_cubics.cxx b/src/tests/catch_test_cubics.cxx index 03800c5..ef98d14 100644 --- a/src/tests/catch_test_cubics.cxx +++ b/src/tests/catch_test_cubics.cxx @@ -35,6 +35,26 @@ TEST_CASE("Test construction of cubic", "[cubic]") int rr = 0; } +TEST_CASE("Check SRK with kij setting", "[cubic]") +{ + // Values taken from http://dx.doi.org/10.6028/jres.121.011 + std::valarray<double> Tc_K = { 190.564, 154.581, 150.687 }, + pc_Pa = { 4599200, 5042800, 4863000 }, + acentric = { 0.011, 0.022, -0.002 }; + Eigen::ArrayXXd kij_right(3, 3); kij_right.setZero(); + Eigen::ArrayXXd kij_bad(2, 20); kij_bad.setZero(); + + SECTION("No kij") { + CHECK_NOTHROW(canonical_SRK(Tc_K, pc_Pa, acentric)); + } + SECTION("Correctly shaped kij matrix") { + CHECK_NOTHROW(canonical_SRK(Tc_K, pc_Pa, acentric, kij_right)); + } + SECTION("Incorrectly shaped kij matrix") { + CHECK_THROWS(canonical_SRK(Tc_K, pc_Pa, acentric, kij_bad)); + } +} + TEST_CASE("Check calling superancillary curves", "[cubic][superanc]") { std::valarray<double> Tc_K = { 150.687 }; -- GitLab