From a575db0dbd5ad66ee4b942277a642673446e0af9 Mon Sep 17 00:00:00 2001
From: Ian Bell <ian.bell@nist.gov>
Date: Thu, 21 Oct 2021 18:21:36 -0400
Subject: [PATCH] Added a test of VLE integration for Peng-Robinson with
 stepping in p

---
 src/tests/catch_test_cubics.cxx | 78 +++++++++++++++++++++++++++++++++
 1 file changed, 78 insertions(+)

diff --git a/src/tests/catch_test_cubics.cxx b/src/tests/catch_test_cubics.cxx
index 3fd6258..7edd6a1 100644
--- a/src/tests/catch_test_cubics.cxx
+++ b/src/tests/catch_test_cubics.cxx
@@ -2,6 +2,11 @@
 
 #include "teqp/models/cubics.hpp"
 #include "teqp/derivs.hpp"
+#include "teqp/algorithms/VLE.hpp"
+
+
+#include <boost/numeric/odeint/stepper/euler.hpp>
+#include <boost/numeric/odeint/stepper/runge_kutta_cash_karp54.hpp>
 
 TEST_CASE("Test construction of cubic", "[cubic]")
 {
@@ -38,4 +43,77 @@ TEST_CASE("Check calling superancillary curves", "[cubic][superanc]")
         auto [rhoL, rhoV] = model.superanc_rhoLV(130.0);
         CHECK(rhoL > rhoV);
     }
+}
+
+TEST_CASE("Check manual integration of subcritical VLE isotherm for binary mixture", "[cubic][isochoric]")
+{
+    using namespace boost::numeric::odeint;
+    // Values taken from http://dx.doi.org/10.6028/jres.121.011
+    std::valarray<double> Tc_K = { 190.564, 154.581},
+                         pc_Pa = { 4599200, 5042800},
+                      acentric = { 0.011, 0.022};
+    auto model = canonical_PR(Tc_K, pc_Pa, acentric);
+    const auto N = Tc_K.size();
+    using state_type = std::vector<double>; 
+    REQUIRE(N == 2);
+    auto get_start = [&](double T, auto i) {
+        std::valarray<double> Tc_(Tc_K[i], 1), pc_(pc_Pa[i], 1), acentric_(acentric[i], 1);
+        auto PR = canonical_PR(Tc_, pc_, acentric_);
+        auto [rhoL, rhoV] = PR.superanc_rhoLV(T);
+        state_type o(N*2);
+        o[i] = rhoL;
+        o[i + N] = rhoV;
+        return o;
+    };
+    double T = 120; 
+    auto xprime = [&](const state_type& X, state_type& Xprime, double /*t*/) {
+        REQUIRE(X.size() % 2 == 0);
+        auto N = X.size() / 2;
+        // Memory maps into the state vector for inputs and their derivatives
+        auto rhovecL = Eigen::Map<const Eigen::ArrayXd>(&(X[0]), N);
+        auto rhovecV = Eigen::Map<const Eigen::ArrayXd>(&(X[0])+N, N);
+        auto drhovecdtL = Eigen::Map<Eigen::ArrayXd>(&(Xprime[0]), N);
+        auto drhovecdtV = Eigen::Map<Eigen::ArrayXd>(&(Xprime[0]) + N, N); 
+        std::tie(drhovecdtL, drhovecdtV) = get_drhovecdp_Tsat(model, T, rhovecL, rhovecV);
+    };
+    auto get_p = [&](const state_type& X) {
+        REQUIRE(X.size() % 2 == 0);
+        auto N = X.size() / 2;
+        // Memory maps into the state vector for rho vector
+        auto rhovecL = Eigen::Map<const Eigen::ArrayXd>(&(X[0]), N);
+        auto rho = rhovecL.sum();
+        auto molefrac = rhovecL / rhovecL.sum();
+
+        using id = IsochoricDerivatives<decltype(model)>; 
+        auto pfromderiv = rho * model.R(molefrac) * T + id::get_pr(model, T, rhovecL);
+        return pfromderiv;
+    };
+    
+    for (int i : { 0 }) {
+        state_type X0 = get_start(T, i); // Starting point; liquid, then vapor
+        double p0 = get_p(X0);
+        state_type Xfinal = get_start(T, 1-i); // Ending point; liquid, then vapor
+        double pfinal = get_p(Xfinal);
+
+        //euler<state_type> integrator;
+        runge_kutta_cash_karp54< state_type > integrator;
+        int Nstep = 10000;
+        double p = p0, pmax = pfinal, dp = (pmax - p0) / (Nstep - 1);
+
+        auto write = [&]() { 
+            //std::cout << p << " " << X0[0] << "," << X0[1] << std::endl;
+        };
+        for (auto i = 0; p < pmax; ++i) {
+            if (p + dp > pmax) { break; }
+            write();
+            integrator.do_step(xprime, X0, p, dp);
+            p += dp;
+        }
+        double diffs = 0;
+        for (auto i = 0; i < X0.size(); ++i) {
+            diffs += std::abs(X0[i] - Xfinal[i]);
+        }
+        CHECK(diffs < 0.1);
+        write();
+    }
 }
\ No newline at end of file
-- 
GitLab