diff --git a/include/teqp/derivs.hpp b/include/teqp/derivs.hpp
index 7f0ce9d38bbc334ce6961f32d900715ce1c4f021..154960f1ff95cde6ceadba361f8ebce382cfa9ba 100644
--- a/include/teqp/derivs.hpp
+++ b/include/teqp/derivs.hpp
@@ -81,6 +81,7 @@ struct wrt_helper {
     }
 };
 
+enum class AlphaWrapperOption {residual, idealgas};
 /**
 * \brief This class is used to wrap a model that exposes the generic 
 * functions alphar, alphaig, etc., and allow the desired member function to be
@@ -90,14 +91,14 @@ struct wrt_helper {
 * require the argument types to be known, and they are not known in this case
 * so we give the hard work of managing the argument types to the compiler
 */
-template<int i, class Model>
+template<AlphaWrapperOption o, class Model>
 struct AlphaCallWrapper {
     const Model& m_model;
     AlphaCallWrapper(const Model& model) : m_model(model) {};
 
     template <typename ... Args>
     auto alpha(const Args& ... args) const {
-        if constexpr (i == 0) {
+        if constexpr (o == AlphaWrapperOption::residual) {
             // The alphar method is REQUIRED to be implemented by all
             // models, so can just call it via perfect fowarding
             return m_model.alphar(std::forward<const Args>(args)...);
@@ -212,7 +213,7 @@ struct TDXDerivatives {
     */
     template<int iT, int iD, ADBackends be>
     static auto get_Arxy(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
-        auto wrapper = AlphaCallWrapper<0, decltype(model)>(model);
+        auto wrapper = AlphaCallWrapper<AlphaWrapperOption::residual, decltype(model)>(model);
         if constexpr (iT == 0 && iD == 0) {
             return wrapper.alpha(T, rho, molefrac);
         }
@@ -231,7 +232,7 @@ struct TDXDerivatives {
     */
     template<int iT, int iD, ADBackends be>
     static auto get_Aigxy(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
-        auto wrapper = AlphaCallWrapper<1, decltype(model)>(model);
+        auto wrapper = AlphaCallWrapper<AlphaWrapperOption::idealgas, decltype(model)>(model);
         if constexpr (iT == 0 && iD == 0) {
             return wrapper.alpha(T, rho, molefrac);
         }
@@ -338,7 +339,7 @@ struct TDXDerivatives {
     */
     template<int iT, ADBackends be = ADBackends::autodiff>
     static auto get_Arn0(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
-        auto wrapper = AlphaCallWrapper<0, decltype(model)>(model);
+        auto wrapper = AlphaCallWrapper<AlphaWrapperOption::residual, decltype(model)>(model);
         return get_Agenn0<iT, be>(wrapper, T, rho, molefrac);
     }
     
@@ -352,7 +353,7 @@ struct TDXDerivatives {
     */
     template<int iD, ADBackends be = ADBackends::autodiff>
     static auto get_Ar0n(const Model& model, const Scalar& T, const Scalar& rho, const VectorType& molefrac) {
-        auto wrapper = AlphaCallWrapper<0, decltype(model)>(model);
+        auto wrapper = AlphaCallWrapper<AlphaWrapperOption::residual, decltype(model)>(model);
         return get_Agen0n<iD, be>(wrapper, T, rho, molefrac);
     }
     
@@ -904,4 +905,30 @@ struct IsochoricDerivatives{
     }
 };
 
+template<int Nderivsmax, AlphaWrapperOption opt>
+class DerivativeHolderSquare{
+    
+public:
+    Eigen::Array<double, Nderivsmax+1, Nderivsmax+1> derivs;
+    
+    template<typename Model, typename Scalar, typename VecType>
+    DerivativeHolderSquare(const Model& model, const Scalar& T, const Scalar& rho, const VecType& z) {
+        using tdx = TDXDerivatives<decltype(model), Scalar, VecType>;
+        static_assert(Nderivsmax == 2, "It's gotta be 2 for now");
+        AlphaCallWrapper<opt, Model> wrapper(model);
+        
+        auto AX02 = tdx::template get_Agen0n<2>(wrapper, T, rho, z);
+        derivs(0, 0) = AX02[0];
+        derivs(0, 1) = AX02[1];
+        derivs(0, 2) = AX02[2];
+        
+        auto AX20 = tdx::template get_Agenn0<2>(wrapper, T, rho, z);
+        derivs(0, 0) = AX20[0];
+        derivs(1, 0) = AX20[1];
+        derivs(2, 0) = AX20[2];
+        
+        derivs(1, 1) = tdx::template get_Agenxy<1,1>(wrapper, T, rho, z);
+    }
+};
+
 }; // namespace teqp
diff --git a/interface/pybind11_wrapper.cpp b/interface/pybind11_wrapper.cpp
index 61e0d08d3bc013a8eb1c32196e2074232b42ed04..dcd96be9df907fdd75ae212bfabf7c3647832b29 100644
--- a/interface/pybind11_wrapper.cpp
+++ b/interface/pybind11_wrapper.cpp
@@ -164,6 +164,7 @@ void init_teqp(py::module& m) {
     auto alphaig = py::class_<IdealHelmholtz>(m, "IdealHelmholtz").def(py::init<const nlohmann::json&>());
     alphaig.def_static("convert_CoolProp_format", [](const std::string &path, int index){return convert_CoolProp_idealgas(path, index);});
     add_ig_derivatives<IdealHelmholtz>(m, alphaig);
+    alphaig.def("get_deriv_mat2", [](const IdealHelmholtz &ig, double T, double rho, const Eigen::ArrayXd& z){return DerivativeHolderSquare<2, AlphaWrapperOption::idealgas>(ig, T, rho, z).derivs;});
 
     add_vdW(m);
     add_PCSAFT(m);
diff --git a/interface/pybind11_wrapper.hpp b/interface/pybind11_wrapper.hpp
index e223e712795ed47c0c81c0d109bee5aad9629793..a9579fc05c3ec695c6efe3f9a15587eb917462e2 100644
--- a/interface/pybind11_wrapper.hpp
+++ b/interface/pybind11_wrapper.hpp
@@ -106,5 +106,7 @@ void add_derivatives(py::module &m, Wrapper &cls) {
     cls.def("get_Ar05n", &(tdx::template get_Ar0n<5>), py::arg("T"), py::arg("rho"), py::arg("molefrac").noconvert());
     cls.def("get_Ar06n", &(tdx::template get_Ar0n<6>), py::arg("T"), py::arg("rho"), py::arg("molefrac").noconvert());
     cls.def("get_neff", &(tdx::template get_neff<ADBackends::autodiff>), py::arg("T"), py::arg("rho"), py::arg("molefrac").noconvert());
+    
+    cls.def("get_deriv_mat2", [](const Model &model, double T, double rho, const Eigen::ArrayXd& z){return DerivativeHolderSquare<2, AlphaWrapperOption::residual>(model, T, rho, z).derivs;});
 
 }
diff --git a/src/bench_derivbox.cpp b/src/bench_derivbox.cpp
index 81ef2fff4ef451613a22d91d0dc828643e203b4b..233b18d1c4abc22af0be4f6576af82e9f69a6c52 100644
--- a/src/bench_derivbox.cpp
+++ b/src/bench_derivbox.cpp
@@ -8,32 +8,6 @@
 
 using namespace teqp;
 
-template<int Nderivsmax, int k>
-class DerivativeHolderSquare{
-    
-public:
-    Eigen::Array<double, Nderivsmax+1, Nderivsmax+1> derivs;
-    
-    template<typename Model, typename Scalar, typename VecType>
-    DerivativeHolderSquare(const Model& model, const Scalar& T, const Scalar& rho, const VecType& z) {
-        using tdx = TDXDerivatives<decltype(model), Scalar, VecType>;
-        static_assert(Nderivsmax == 2, "It's gotta be 2");
-        AlphaCallWrapper<k, Model> wrapper(model);
-        
-        auto AX02 = tdx::template get_Agen0n<2>(wrapper, T, rho, z);
-        derivs(0, 0) = AX02[0];
-        derivs(0, 1) = AX02[1];
-        derivs(0, 2) = AX02[2];
-        
-        auto AX20 = tdx::template get_Agenn0<2>(wrapper, T, rho, z);
-        derivs(0, 0) = AX20[0];
-        derivs(1, 0) = AX20[1];
-        derivs(2, 0) = AX20[2];
-        
-        derivs(1, 1) = tdx::template get_Agenxy<1,1>(wrapper, T, rho, z);
-    }
-};
-
 TEST_CASE("multifluid derivatives", "[mf]")
 {
     std::vector<std::string> names = { "Propane" };
@@ -52,10 +26,10 @@ TEST_CASE("multifluid derivatives", "[mf]")
     };
     
     BENCHMARK("All residual derivatives needed for first derivatives of h,s,u,p w.r.t. T&rho") {
-        return DerivativeHolderSquare<2,0>(model, T, rho, z).derivs;
+        return DerivativeHolderSquare<2,AlphaWrapperOption::residual>(model, T, rho, z).derivs;
     };
     
     BENCHMARK("All ideal-gas derivatives needed for first derivatives of h,s,u,p w.r.t. T&rho") {
-        return DerivativeHolderSquare<2,1>(aig, T, rho, z).derivs;
+        return DerivativeHolderSquare<2,AlphaWrapperOption::idealgas>(aig, T, rho, z).derivs;
     };
 }
diff --git a/src/tests/catch_test_alphaig.cxx b/src/tests/catch_test_alphaig.cxx
index a5230d242cce982b52cabe5f99bc45ebf94af092..8473c3978916a981075563db97a901a31fdaf522 100644
--- a/src/tests/catch_test_alphaig.cxx
+++ b/src/tests/catch_test_alphaig.cxx
@@ -29,7 +29,7 @@ TEST_CASE("alphaig derivative", "[alphaig]") {
     j.push_back(demo_pure_term(a_1, a_2));
     IdealHelmholtz ih(j);
     auto molefrac = (Eigen::ArrayXd(1) << 1.0).finished();
-    auto wih = AlphaCallWrapper<1, decltype(ih)>(ih);
+    auto wih = AlphaCallWrapper<AlphaWrapperOption::idealgas, decltype(ih)>(ih);
     wih.alpha(T, rho, molefrac);
     using tdx = TDXDerivatives<decltype(ih), double, Eigen::ArrayXd>;
     SECTION("All cross derivatives should be zero") {
@@ -59,8 +59,10 @@ TEST_CASE("Ammonia derivative", "[alphaig][NH3]") {
     nlohmann::json j = {{ {"R", 8.31446261815324}, {"terms", j0terms} }};
     IdealHelmholtz ih(j);
     auto molefrac = (Eigen::ArrayXd(1) << 1.0).finished();
-    auto wih = AlphaCallWrapper<1, decltype(ih)>(ih);
+    auto wih = AlphaCallWrapper<AlphaWrapperOption::idealgas, decltype(ih)>(ih);
     auto calc = wih.alpha(T, rho, molefrac);
     auto expected = -5.3492909452728545;
     REQUIRE(calc == Approx(expected));
+    
+    DerivativeHolderSquare<2, AlphaWrapperOption::idealgas> dhs(ih, T, rho, molefrac);
 }