diff --git a/include/teqp/algorithms/critical_tracing.hpp b/include/teqp/algorithms/critical_tracing.hpp
index 72c4e330dec18986c84a173884c8053c73fba9eb..bae1a547962e7f264f0b9d8e85014238c1514a57 100644
--- a/include/teqp/algorithms/critical_tracing.hpp
+++ b/include/teqp/algorithms/critical_tracing.hpp
@@ -36,12 +36,7 @@ struct CriticalTracing {
         return std::make_tuple(es.eigenvalues(), es.eigenvectors());
     }
 
-    struct EigenData {
-        Eigen::ArrayXd v0, v1, eigenvalues;
-        Eigen::MatrixXd eigenvectorscols;
-    };
-
-    static auto eigen_problem(const Model& model, const Scalar T, const VecType& rhovec, const VecType& alignment_v0 = {}) {
+    static auto eigen_problem(const Model& model, const Scalar T, const VecType& rhovec, const std::optional<VecType>& alignment_v0 = std::nullopt) {
 
         EigenData ed;
 
@@ -114,7 +109,7 @@ struct CriticalTracing {
         else {
             throw std::invalid_argument("More than one non-zero concentration value found; not currently supported");
         }
-        if (alignment_v0.size() > 0 && ed.eigenvectorscols.col(0).matrix().dot(alignment_v0.matrix()) < 0) {
+        if (alignment_v0 && ed.eigenvectorscols.col(0).matrix().dot(alignment_v0.value().matrix()) < 0) {
             ed.eigenvectorscols.col(0) *= -1;
         }
         
@@ -132,7 +127,7 @@ struct CriticalTracing {
         return eigen_problem(model, T, rhovec).eigenvalues[0];
     }
 
-    static auto get_derivs(const Model& model, const Scalar T, const VecType& rhovec, const VecType& alignment_v0 = {}) {
+    static auto get_derivs(const Model& model, const Scalar T, const VecType& rhovec, const std::optional<VecType>& alignment_v0 = std::nullopt) {
         auto molefrac = rhovec / rhovec.sum();
         auto R = model.R(molefrac);
 
@@ -163,7 +158,7 @@ struct CriticalTracing {
             return eval(model.alphar(T, rhotot, molefrac) * model.R(molefrac) * T * rhotot);
         };
         auto psir_derivs_ = derivatives(wrapper, wrt(varsigma), at(varsigma));
-        VecType psir_derivs; psir_derivs.resize(5);
+        Eigen::ArrayXd psir_derivs; psir_derivs.resize(5);
         for (auto i = 0; i < 5; ++i) { psir_derivs[i] = psir_derivs_[i]; }
 
 #else
@@ -179,7 +174,7 @@ struct CriticalTracing {
             return model.alphar(T, rhotot, molefrac) * model.R(molefrac) * T * rhotot;
         };
         auto psir_derivs_ = diff_mcx1(wrapper, 0.0, 4, true);
-        VecType psir_derivs; psir_derivs.resize(5);
+        Eigen::ArrayXd psir_derivs; psir_derivs.resize(5);
         for (auto i = 0; i < 5; ++i) { psir_derivs[i] = psir_derivs_[i]; }
 #endif
 
@@ -211,7 +206,7 @@ struct CriticalTracing {
 
         // The derivatives of total Psi w.r.t.sigma_1 (numerical for residual, analytic for ideal)
         // Returns a tuple, with residual, ideal, total dicts with of number of derivatives, value of derivative
-        auto all_derivs = get_derivs(model, T, rhovec);
+        auto all_derivs = get_derivs(model, T, rhovec, Eigen::ArrayXd());
         auto derivs = all_derivs.tot;
 
         // The temperature derivative of total Psi w.r.t.T from a centered finite difference in T
@@ -284,7 +279,7 @@ struct CriticalTracing {
     }
 
     static auto get_criticality_conditions(const Model& model, const Scalar T, const VecType& rhovec) {
-        auto derivs = get_derivs(model, T, rhovec);
+        auto derivs = get_derivs(model, T, rhovec, Eigen::ArrayXd());
         return (Eigen::ArrayXd(2) << derivs.tot[2], derivs.tot[3]).finished();
     }
 
@@ -341,7 +336,7 @@ struct CriticalTracing {
             auto T = x[0];
             Eigen::ArrayXd rhovec(2); rhovec << z0*x[1], (1-z0)*x[1];
             //auto z0new = rhovec[0] / rhovec.sum();
-            auto derivs = get_derivs(model, T, rhovec);
+            auto derivs = get_derivs(model, T, rhovec, {});
             // First two are residuals on critical point
             return (Eigen::ArrayXd(2) << derivs.tot[2], derivs.tot[3]).finished();
         };
@@ -746,11 +741,16 @@ struct CriticalTracing {
 
     /**
     * \brief Calculate dp/dT along the critical locus at given T, rhovec
+    * \f[
+    *     \rmderivsub{Y}{T}{\CRL} = \deriv{Y}{T}{\vec\rho}  + \sum_j \deriv{Y}{\rho_j}{T,\rho_{k\neq j}} \rmderivsub{\rho_j}{T}{\CRL}
+    * \f]
+    * where the derivatives on the RHS without the subscript $\CRL$ are homogeneous derivatives taken at the mixture statepoint, and are NOT along the critical curve.
     */
     static auto get_dp_dT_crit(const Model& model, const Scalar& T, const VecType& rhovec) {
         using id = IsochoricDerivatives<Model, Scalar, VecType>;
         auto dpdrhovec = id::get_dpdrhovec_constT(model, T, rhovec);
-        return id::get_dpdT_constrhovec(model, T, rhovec) + (dpdrhovec.matrix() * get_drhovec_dT_crit(model, T, rhovec).matrix()).array();
+        Scalar v = id::get_dpdT_constrhovec(model, T, rhovec) + (dpdrhovec.array()*get_drhovec_dT_crit(model, T, rhovec).array()).sum();
+        return v;
     }
 
 }; // namespace VecType
diff --git a/include/teqp/algorithms/critical_tracing_types.hpp b/include/teqp/algorithms/critical_tracing_types.hpp
index 48703d78533c36e75ef3d4e918357f414e601b8a..21d9192ba25221578d0548cebd6c3a3e3429e88d 100644
--- a/include/teqp/algorithms/critical_tracing_types.hpp
+++ b/include/teqp/algorithms/critical_tracing_types.hpp
@@ -24,4 +24,9 @@ struct TCABOptions {
     bool pure_endpoint_polish = false; ///< If true, if the last step crossed into negative concentrations, try to interpolate to find the pure fluid endpoint hiding in the data
 };
 
+struct EigenData {
+    Eigen::ArrayXd v0, v1, eigenvalues;
+    Eigen::MatrixXd eigenvectorscols;
+};
+
 }
diff --git a/include/teqp/cpp/teqpcpp.hpp b/include/teqp/cpp/teqpcpp.hpp
index e94cc37956256cf3bfd82e1f038179c00d987c12..334bb86c6ce07f04c15d2ecc1a050861da93d0af 100644
--- a/include/teqp/cpp/teqpcpp.hpp
+++ b/include/teqp/cpp/teqpcpp.hpp
@@ -87,10 +87,6 @@ namespace teqp {
             
             virtual double get_R(const EArrayd&) const = 0;
             
-            virtual nlohmann::json trace_critical_arclength_binary(const double T0, const EArrayd& rhovec0, const std::optional<std::string>&, const std::optional<TCABOptions> &) const = 0;
-            
-            virtual EArray33d get_deriv_mat2(const double T, double rho, const EArrayd& z) const = 0;
-            
             virtual double get_Arxy(const int, const int, const double, const double, const EArrayd&) const = 0;
             
             // Here X-Macros are used to create functions like get_Ar00, get_Ar01, ....
@@ -120,6 +116,8 @@ namespace teqp {
                 ISOCHORIC_matrix_args
             #undef X
             
+            virtual EArray33d get_deriv_mat2(const double T, double rho, const EArrayd& z ) const = 0;
+            
             virtual std::tuple<double, double> solve_pure_critical(const double T, const double rho, const std::optional<nlohmann::json>&) const = 0;
             virtual std::tuple<double, double> extrapolate_from_critical(const double Tc, const double rhoc, const double Tgiven) const = 0;
             virtual EArray2 pure_VLE_T(const double T, const double rhoL, const double rhoV, int maxiter) const = 0;
@@ -128,6 +126,12 @@ namespace teqp {
             virtual std::tuple<EArrayd, EArrayd> get_drhovecdT_psat(const double T, const REArrayd& rhovecL, const REArrayd& rhovecV) const = 0;
             virtual double get_dpsat_dTsat_isopleth(const double T, const REArrayd& rhovecL, const REArrayd& rhovecV) const = 0;
             
+            virtual nlohmann::json trace_critical_arclength_binary(const double T0, const EArrayd& rhovec0, const std::optional<std::string>&, const std::optional<TCABOptions> &) const = 0;
+            virtual EArrayd get_drhovec_dT_crit(const double T, const REArrayd& rhovec) const = 0;
+            virtual double get_dp_dT_crit(const double T, const REArrayd& rhovec) const = 0;
+            virtual EArray2 get_criticality_conditions(const double T, const REArrayd& rhovec) const = 0;
+            virtual EigenData eigen_problem(const double T, const REArrayd& rhovec, const std::optional<REArrayd>&) const = 0;
+            virtual double get_minimum_eigenvalue_Psi_Hessian(const double T, const REArrayd& rhovec) const = 0;
             
         };
         
diff --git a/interface/CPP/teqpcpp.cpp b/interface/CPP/teqpcpp.cpp
index 59f4c637de6d212969aad5872effbbae178eadc8..aeb5b343c0920e23378a92172409bcb93e7e7757 100644
--- a/interface/CPP/teqpcpp.cpp
+++ b/interface/CPP/teqpcpp.cpp
@@ -44,6 +44,37 @@ namespace teqp {
                     return crit::trace_critical_arclength_binary(model, T0, rhovec0, "");
                 }, m_model);
             }
+            EArrayd get_drhovec_dT_crit(const double T, const REArrayd& rhovec) const override {
+                return std::visit([&](const auto& model) {
+                    using crit = teqp::CriticalTracing<decltype(model), double, std::decay_t<decltype(rhovec)>>;
+                    return crit::get_drhovec_dT_crit(model, T, rhovec);
+                }, m_model);
+            }
+            double get_dp_dT_crit(const double T, const REArrayd& rhovec) const override {
+                return std::visit([&](const auto& model) {
+                    using crit = teqp::CriticalTracing<decltype(model), double, std::decay_t<decltype(rhovec)>>;
+                    return crit::get_dp_dT_crit(model, T, rhovec);
+                }, m_model);
+            }
+            EArray2 get_criticality_conditions(const double T, const REArrayd& rhovec) const override {
+                return std::visit([&](const auto& model) {
+                    using crit = teqp::CriticalTracing<decltype(model), double, std::decay_t<decltype(rhovec)>>;
+                    return crit::get_criticality_conditions(model, T, rhovec);
+                }, m_model);
+            }
+            EigenData eigen_problem(const double T, const REArrayd& rhovec, const std::optional<REArrayd>& alignment_v0) const override {
+                return std::visit([&](const auto& model) {
+                    using crit = teqp::CriticalTracing<decltype(model), double, std::decay_t<decltype(rhovec)>>;
+                    return crit::eigen_problem(model, T, rhovec, alignment_v0.value_or(Eigen::ArrayXd()));
+                }, m_model);
+            }
+            double get_minimum_eigenvalue_Psi_Hessian(const double T, const REArrayd& rhovec) const override {
+                return std::visit([&](const auto& model) {
+                    using crit = teqp::CriticalTracing<decltype(model), double, std::decay_t<decltype(rhovec)>>;
+                    return crit::get_minimum_eigenvalue_Psi_Hessian(model, T, rhovec);
+                }, m_model);
+            }
+            
             EArray2 pure_VLE_T(const double T, const double rhoL, const double rhoV, int maxiter) const override {
                 return std::visit([&](const auto& model) {
                     return teqp::pure_VLE_T(model, T, rhoL, rhoV, maxiter);
diff --git a/interface/pybind11_wrapper.cpp b/interface/pybind11_wrapper.cpp
index 7746032220d09d42fc4c5716fac4c3375cf2a7cf..99a637ac754a784a9083ac302cc41e3f7545a18c 100644
--- a/interface/pybind11_wrapper.cpp
+++ b/interface/pybind11_wrapper.cpp
@@ -227,25 +227,25 @@ void init_teqp(py::module& m) {
     
         // Routines related to binary mixture critical curve tracing
         .def("trace_critical_arclength_binary", &am::trace_critical_arclength_binary, "T0"_a, "rhovec0"_a, py::arg_v("path", std::nullopt, "None"), py::arg_v("options", std::nullopt, "None"))
-//        .def("get_criticality_conditions", &am::get_criticality_conditions)
-//        .def("eigen_problem", &am::eigen_problem)
-//        .def("get_minimum_eigenvalue_Psi_Hessian", &am::get_minimum_eigenvalue_Psi_Hessian)
-//        .def("get_drhovec_dT_crit", &am::get_drhovec_dT_crit)
-//        .def("get_dp_dT_crit", &am::get_dp_dT_crit)
+        .def("get_criticality_conditions", &am::get_criticality_conditions, "T"_a, "rhovec"_a.noconvert())
+        .def("eigen_problem", &am::eigen_problem, "T"_a, "rhovec"_a, py::arg_v("alignment_v0", std::nullopt, "None"))
+        .def("get_minimum_eigenvalue_Psi_Hessian", &am::get_minimum_eigenvalue_Psi_Hessian, "T"_a, "rhovec"_a.noconvert())
+        .def("get_drhovec_dT_crit", &am::get_drhovec_dT_crit, "T"_a, "rhovec"_a.noconvert())
+        .def("get_dp_dT_crit", &am::get_dp_dT_crit, "T"_a, "rhovec"_a.noconvert())
 
         .def("pure_VLE_T", &am::pure_VLE_T, "T"_a, "rhoL"_a, "rhoV"_a, "max_iter"_a)
 
         .def("get_drhovecdp_Tsat", &am::get_drhovecdp_Tsat, "T"_a, "rhovecL"_a.noconvert(), "rhovecV"_a.noconvert())
         .def("get_drhovecdT_psat", &am::get_drhovecdT_psat, "T"_a, "rhovecL"_a.noconvert(), "rhovecV"_a.noconvert())
         .def("get_dpsat_dTsat_isopleth", &am::get_dpsat_dTsat_isopleth, "T"_a, "rhovecL"_a.noconvert(), "rhovecV"_a.noconvert())
-//    .def("get_drhovecdp_Tsat", &get_drhovecdp_Tsat<Model, double, RAX>, "T"_a, "rhovecL"_a.noconvert(), "rhovecV"_a.noconvert())
-//    .def("trace_VLE_isotherm_binary", &trace_VLE_isotherm_binary<Model, double, Eigen::ArrayXd>, "T"_a, "rhovecL0"_a.noconvert(), "rhovecV0"_a.noconvert(), py::arg_v("options", std::nullopt, "None"))
-//    .def("get_drhovecdT_psat", &get_drhovecdT_psat<Model, double, RAX>, "T"_a, "rhovecL"_a.noconvert(), "rhovecV"_a.noconvert())
-//    .def("trace_VLE_isobar_binary", &trace_VLE_isobar_binary<Model, double, Eigen::ArrayXd>, "p"_a, "T0"_a, "rhovecL0"_a.noconvert(), "rhovecV0"_a.noconvert(), py::arg_v("options", std::nullopt, "None"))
-//    .def("get_dpsat_dTsat_isopleth", &get_dpsat_dTsat_isopleth<Model, double, RAX>, "T"_a, "rhovecL"_a.noconvert(), "rhovecV"_a.noconvert())
-//    .def("mix_VLLE_T", &mix_VLLE_T<Model, double, RAX>);
+    
+//        .def("mix_VLE_Tx", &mix_VLE_Tx<Model, double, RAX>)
+//        .def("mix_VLE_Tp", &mix_VLE_Tp<Model, double, RAX>, "T"_a, "p_given"_a, "rhovecL0"_a.noconvert(), "rhovecV0"_a.noconvert(), py::arg_v("flags", MixVLETpFlags{}, "None"))
+//        .def("mixture_VLE_px", &mixture_VLE_px<Model, double, RAX>, "p_spec"_a, "xmolar_spec"_a.noconvert(), "T0"_a, "rhovecL0"_a.noconvert(), "rhovecV0"_a.noconvert(), py::arg_v("flags", MixVLEpxFlags{}, "None"))
+//        .def("trace_VLE_isotherm_binary", &trace_VLE_isotherm_binary, "T"_a, "rhovecL0"_a.noconvert(), "rhovecV0"_a.noconvert(), py::arg_v("options", std::nullopt, "None"))
+//        .def("trace_VLE_isobar_binary", &trace_VLE_isobar_binary, "p"_a, "T0"_a, "rhovecL0"_a.noconvert(), "rhovecV0"_a.noconvert(), py::arg_v("options", std::nullopt, "None"))
+//        .def("mix_VLLE_T", &mix_VLLE_T<Model, double, RAX>);
 //        .def("find_VLLE_T_binary", &am::find_VLLE_T_binary, "traces"_a, py::arg_v("options", std::nullopt, "None"));
-        
     ;
     
     m.def("_make_model", &teqp::cppinterface::make_model);