From 91c4d09c870cb7489f7239dc28b1af7db6d8ce1f Mon Sep 17 00:00:00 2001
From: Ian Bell <ian.bell@nist.gov>
Date: Thu, 11 Mar 2021 18:47:22 -0500
Subject: [PATCH] Switch Hessian evaluation to autodiff

Tracing is now crazy fast
---
 CMakeLists.txt          |  1 +
 include/teqp/derivs.hpp | 27 ++++++++++++++++++++++++++-
 src/test_autodiff.cpp   |  1 -
 src/trace_critical.cpp  |  5 ++++-
 4 files changed, 31 insertions(+), 3 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index bec5188..72594c0 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,6 +26,7 @@ add_executable(trace "${CMAKE_CURRENT_SOURCE_DIR}/src/trace_critical.cpp")
 if (MSVC)
     target_sources(trace PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/externals/Eigen/debug/msvc/eigen.natvis")
 endif()
+target_link_libraries(trace autodiff)
 
 add_executable(multifluid "${CMAKE_CURRENT_SOURCE_DIR}/src/multifluid.cpp")
 if (MSVC)
diff --git a/include/teqp/derivs.hpp b/include/teqp/derivs.hpp
index 3e34171..8d106aa 100644
--- a/include/teqp/derivs.hpp
+++ b/include/teqp/derivs.hpp
@@ -6,6 +6,11 @@
 
 #include "MultiComplex/MultiComplex.hpp"
 
+// autodiff include
+#include <autodiff/forward/dual.hpp>
+#include <autodiff/forward/dual/eigen.hpp>
+using namespace autodiff;
+
 template <typename TType, typename ContainerType, typename FuncType>
 typename std::enable_if<is_container<ContainerType>::value, typename ContainerType::value_type>::type
 caller(const FuncType& f, TType T, const ContainerType& rho) {
@@ -100,7 +105,7 @@ template <> void setval<std::valarray<std::valarray<double>>, std::size_t, doubl
 
 /***
 * \brief Calculate the Hessian of Psir = ar*rho w.r.t. the molar concentrations
-* 
+*
 * Requires the use of multicomplex derivatives to calculate second partial derivatives
 */
 template<typename Model, typename TType, typename RhoType>
@@ -108,6 +113,26 @@ auto build_Psir_Hessian(const Model& model, const TType T, const RhoType& rho) {
     // Double derivatives in each component's concentration
     // N^N matrix (symmetric)
 
+    dual2nd u; // the output scalar u = f(x), evaluated together with Hessian below
+    VectorXdual2nd g;
+    VectorXdual2nd rhovecc(2); rhovecc << rho[0], rho[1];
+    auto hfunc = [&model, &T](const VectorXdual2nd& rho_) {
+        auto rhotot_ = std::accumulate(std::begin(rho_), std::end(rho_), (decltype(rho_[0]))0.0);
+        return eval(model.alphar(T, rho_) * model.R * T * rhotot_);
+    };
+    return autodiff::hessian(hfunc, wrt(rhovecc), at(rhovecc), u, g); // evaluate the function value u, its gradient, and its Hessian matrix H
+}
+
+/***
+* \brief Calculate the Hessian of Psir = ar*rho w.r.t. the molar concentrations
+* 
+* Requires the use of multicomplex derivatives to calculate second partial derivatives
+*/
+template<typename Model, typename TType, typename RhoType>
+auto build_Psir_Hessian_mcx(const Model& model, const TType T, const RhoType& rho) {
+    // Double derivatives in each component's concentration
+    // N^N matrix (symmetric)
+
     // Lambda function for getting Psir with multicomplex concentrations
     auto func = [&model, &T](const std::vector<MultiComplex<double>>& rhovec) {
         auto N = rhovec.size();
diff --git a/src/test_autodiff.cpp b/src/test_autodiff.cpp
index de0718e..7bf7057 100644
--- a/src/test_autodiff.cpp
+++ b/src/test_autodiff.cpp
@@ -7,7 +7,6 @@
 
 #include "MultiComplex/MultiComplex.hpp"
 
-
 // autodiff include
 #include <autodiff/forward/dual.hpp>
 #include <autodiff/forward/dual/eigen.hpp>
diff --git a/src/trace_critical.cpp b/src/trace_critical.cpp
index 268c022..284cb1d 100644
--- a/src/trace_critical.cpp
+++ b/src/trace_critical.cpp
@@ -14,17 +14,20 @@ void trace() {
     auto T = Tc_K[0];
     const auto dT = 1;
     std::valarray<double> rhovec = { rhoc0, 0.0 };
+    auto tic0 = std::chrono::steady_clock::now();
     for (auto iter = 0; iter < 1000; ++iter){
         auto drhovecdT = get_drhovec_dT_crit(vdW, T, rhovec);
         rhovec += drhovecdT*dT;
         T += dT;
         int rr = 0;
         auto z0 = rhovec[0] / rhovec.sum();
-        std::cout << z0 <<  "," << rhovec[0] << "," << T << "," << get_splus(vdW, T, rhovec) << std::endl;
+        //std::cout << z0 <<  "," << rhovec[0] << "," << T << "," << get_splus(vdW, T, rhovec) << std::endl;
         if (z0 < 0) {
             break;
         }
     }
+    auto tic1 = std::chrono::steady_clock::now();
+    std::cout << std::chrono::duration<double>(tic1 - tic0).count() << " s to trace" << std::endl;
     int rr = 0;
 }
 int main() {   
-- 
GitLab