diff --git a/include/teqp/models/multifluid.hpp b/include/teqp/models/multifluid.hpp
index 40441dc03d1c25be69dd6c1ab14114793f88ff01..953fc11e6d4c2f79460199a97a26a03715b4f318 100644
--- a/include/teqp/models/multifluid.hpp
+++ b/include/teqp/models/multifluid.hpp
@@ -8,7 +8,6 @@
 #include <cmath>
 #include <optional>
 #include <variant>
-#include <set>
 
 #include "teqp/types.hpp"
 #include "MultiComplex/MultiComplex.hpp"
@@ -268,114 +267,137 @@ public:
     template<typename MoleFractions> auto get_rhor(const MoleFractions& molefracs) const { return 1.0 / Y(molefracs, vc, betaV, Yv); }
 };
 
-class MultiFluidDepartureFunction {
-public:
-    enum class types { NOTSETTYPE, GERG2004, GaussianExponential, NoDeparture };
-private:
-    types type = types::NOTSETTYPE;
-public:
-    Eigen::ArrayXd n, t, d, c, l, eta, beta, gamma, epsilon;
+inline auto get_departure_function_matrix(const std::string& coolprop_root, const nlohmann::json& BIPcollection, const std::vector<std::string>& components, const nlohmann::json& flags) {
 
-    void set_type(const std::string& kind) {
-        if (kind == "GERG-2004" || kind == "GERG-2008") {
-            type = types::GERG2004;
-        }
-        else if (kind == "Gaussian+Exponential") {
-            type = types::GaussianExponential;
+    // Allocate the matrix with default models
+    std::vector<std::vector<DepartureTerms>> funcs(components.size()); for (auto i = 0; i < funcs.size(); ++i) { funcs[i].resize(funcs.size()); }
+
+    // Load the collection of data on departure functions
+    auto depcollection = nlohmann::json::parse(std::ifstream(coolprop_root + "/dev/mixtures/mixture_departure_functions.json"));
+    auto get_departure_json = [&depcollection](const std::string& Name) {
+        for (auto& el : depcollection) {
+            if (el["Name"] == Name) { return el; }
         }
-        else if (kind == "none") {
-            type = types::NoDeparture;
+        throw std::invalid_argument("Bad argument");
+    };
+
+    auto build_power = [&](auto term) {
+        std::size_t N = term["n"].size();
+
+        PowerEOSTerm eos;
+
+        auto eigorzero = [&term, &N](const std::string& name) -> Eigen::ArrayXd {
+            if (!term[name].empty()) {
+                return toeig(term[name]);
+            }
+            else {
+                return Eigen::ArrayXd::Zero(N);
+            }
+        };
+
+
+        eos.n = eigorzero("n");
+        eos.t = eigorzero("t");
+        eos.d = eigorzero("d");
+
+        Eigen::ArrayXd c(N), l(N); c.setZero();
+        if (term["l"].empty()) {
+            // exponential part not included
+            l.setZero();
         }
         else {
-            throw std::invalid_argument("Bad type:" + kind);
-        }
-    }
-
-    template<typename TauType, typename DeltaType>
-    auto alphar(const TauType& tau, const DeltaType& delta) const {
-        switch (type) {
-        case (types::GaussianExponential):
-            return forceeval((n * exp(t*log(tau) + d*log(delta)-c*pow(delta, l)-eta * (delta - epsilon).square() - beta * (tau - gamma).square())).sum());
-        case (types::GERG2004):
-            return forceeval((n * exp(t*log(tau) + d*log(delta) -eta * (delta - epsilon).square() - beta * (delta - gamma))).sum()); 
-        case (types::NoDeparture):
-            return forceeval(0.0*(tau*delta));
-        default:
-            throw - 1;
+            l = toeig(term["l"]);
+            // l is included, use it to build c; c_i = 1 if l_i > 0, zero otherwise
+            for (auto i = 0; i < c.size(); ++i) {
+                if (l[i] > 0) {
+                    c[i] = 1.0;
+                }
+            }
         }
-    }
-};
+        eos.c = c;
+        eos.l = l;
 
-inline auto get_departure_function_matrix(const std::string& coolprop_root, const nlohmann::json& BIPcollection, const std::vector<std::string>& components, const nlohmann::json& flags) {
+        eos.l_i = eos.l.cast<int>();
 
-    // Allocate the matrix with default models
-    std::vector<std::vector<MultiFluidDepartureFunction>> funcs(components.size()); for (auto i = 0; i < funcs.size(); ++i) { funcs[i].resize(funcs.size()); }
+        if (((eos.l_i.cast<double>() - eos.l).cwiseAbs() > 0.0).any()) {
+            throw std::invalid_argument("Non-integer entry in l found");
+        }
 
-    auto depcollection = nlohmann::json::parse(std::ifstream(coolprop_root + "/dev/mixtures/mixture_departure_functions.json"));
+        return eos;
+    };
 
-    auto get_departure_function = [&depcollection](const std::string& Name) {
-        for (auto& el : depcollection) {
-            if (el["Name"] == Name) { return el; }
+    auto build_gaussian = [&](auto &term) {
+        GaussianEOSTerm eos;
+        eos.n = toeig(term["n"]);
+        eos.t = toeig(term["t"]);
+        eos.d = toeig(term["d"]);
+        eos.eta = toeig(term["eta"]);
+        eos.beta = toeig(term["beta"]);
+        eos.gamma = toeig(term["gamma"]);
+        eos.epsilon = toeig(term["epsilon"]);
+        if (!all_same_length(term, { "n","t","d","eta","beta","gamma","epsilon" })) {
+            throw std::invalid_argument("Lengths are not all identical in Gaussian term");
         }
-        throw std::invalid_argument("Bad argument");
+        return eos;
+    };
+    auto build_GERG2004 = [&](const auto& term, auto &dep) {
+        if (!all_same_length(term, { "n","t","d","eta","beta","gamma","epsilon" })) {
+            throw std::invalid_argument("Lengths are not all identical in Gaussian term");
+        }
+        auto Npower = term["Npower"];
+        auto NGERG = term["n"].size()- Npower;
+        
+        PowerEOSTerm eos;
+        eos.n = toeig(term["n"]).head(Npower);
+        eos.t = toeig(term["t"]).head(Npower);
+        eos.d = toeig(term["d"]).head(Npower);
+        if (term.contains("l")) {
+            eos.l = toeig(term["l"]).head(Npower);
+        }
+        else {
+            eos.l = 0.0 * eos.n;
+        }
+        eos.c = (eos.l > 0).cast<int>().cast<double>();
+        eos.l_i = eos.l.cast<int>();
+        dep.add_term(eos);
+
+        GERG2004EOSTerm e;
+        e.n = toeig(term["n"]).tail(NGERG);
+        e.t = toeig(term["t"]).tail(NGERG);
+        e.d = toeig(term["d"]).tail(NGERG);
+        e.eta = toeig(term["eta"]).tail(NGERG);
+        e.beta = toeig(term["beta"]).tail(NGERG);
+        e.gamma = toeig(term["gamma"]).tail(NGERG);
+        e.epsilon = toeig(term["epsilon"]).tail(NGERG);
+        dep.add_term(e);
+    };
+    auto get_function = [&](auto& funcname) {
+        auto j = get_departure_json(funcname); 
+        auto type = j["type"];
+        DepartureTerms dep;
+        if (type == "Exponential") {
+            dep.add_term(build_power(j));
+        }
+        else if(type == "GERG-2004" || type == "GERG-2008") {
+            build_GERG2004(j, dep);
+        }
+        else {
+            throw std::invalid_argument("Bad term type, should not get here");
+        }
+        return dep;
     };
 
     for (auto i = 0; i < funcs.size(); ++i) {
         for (auto j = i + 1; j < funcs.size(); ++j) {
             auto BIP = MultiFluidReducingFunction::get_BIPdep(BIPcollection, { components[i], components[j] }, flags);
-            auto function = BIP["function"];
-            if (!function.empty()) {
-
-                auto info = get_departure_function(function);
-                auto N = info["n"].size();
-
-                auto toeig = [](const std::vector<double>& v) -> Eigen::ArrayXd { return Eigen::Map<const Eigen::ArrayXd>(&(v[0]), v.size()); };
-                auto eigorempty = [&info, &toeig, &N](const std::string& name) -> Eigen::ArrayXd {
-                    if (!info[name].empty()) {
-                        return toeig(info[name]);
-                    }
-                    else {
-                        return Eigen::ArrayXd::Zero(N);
-                    }
-                };
-
-                MultiFluidDepartureFunction f;
-                f.set_type(info["type"]);
-                f.n = toeig(info["n"]);
-                f.t = toeig(info["t"]);
-                f.d = toeig(info["d"]);
-
-                f.eta = eigorempty("eta");
-                f.beta = eigorempty("beta");
-                f.gamma = eigorempty("gamma");
-                f.epsilon = eigorempty("epsilon");
-
-                Eigen::ArrayXd c(f.n.size()), l(f.n.size()); c.setZero();
-                if (info["l"].empty()) {
-                    // exponential part not included
-                    l.setZero();
-                }
-                else {
-                    l = toeig(info["l"]);
-                    // l is included, use it to build c; c_i = 1 if l_i > 0, zero otherwise
-                    for (auto i = 0; i < c.size(); ++i) {
-                        if (l[i] > 0) {
-                            c[i] = 1.0;
-                        }
-                    }
-                }
-
-                f.l = l;
-                f.c = c;
-                funcs[i][j] = f;
-                funcs[j][i] = f;
-                int rr = 0;
+            std::string funcname = BIP["function"];
+            if (!funcname.empty()) {
+                funcs[i][j] = get_function(funcname);
+                funcs[j][i] = get_function(funcname);
             }
             else {
-                MultiFluidDepartureFunction f;
-                f.set_type("none");
-                funcs[i][j] = f;
-                funcs[j][i] = f;
+                funcs[i][j].add_term(NullEOSTerm());
+                funcs[j][i].add_term(NullEOSTerm());
             }
         }
     }
@@ -447,25 +469,6 @@ auto pow(const mcx::MultiComplex<T> &x, const Eigen::ArrayXd& e) {
     return o;
 }
 
-template<class T>
-struct PowIUnaryFunctor {
-    const T m_base;
-    PowIUnaryFunctor(T base) : m_base(base) {};
-    typedef T result_type;
-    result_type operator()(const int& e) const{
-        switch (e) {
-        case 0:
-            return 1.0;
-        case 1:
-            return m_base;
-        case 2:
-            return m_base * m_base;
-        default:
-            return powi(m_base, e);
-        }
-    }
-};
-
 inline auto get_EOS_terms(const std::string& coolprop_root, const std::string& name)
 {
     using namespace nlohmann;
@@ -486,14 +489,6 @@ inline auto get_EOS_terms(const std::string& coolprop_root, const std::string& n
         }
     }
 
-    auto toeig = [](const std::vector<double>& v) -> Eigen::ArrayXd { return Eigen::Map<const Eigen::ArrayXd>(&(v[0]), v.size()); };    
-
-    auto all_same_length = [](const nlohmann::json& j, const std::vector<std::string>& ks) {
-        std::set<int> lengths; 
-        for (auto k : ks) { lengths.insert(j[k].size()); }
-        return lengths.size() == 1;
-    };
-
     EOSTerms container;
 
     auto build_power = [&](auto term) {
@@ -501,7 +496,7 @@ inline auto get_EOS_terms(const std::string& coolprop_root, const std::string& n
 
         PowerEOSTerm eos;
 
-        auto eigorzero = [&term, &toeig, &N](const std::string& name) -> Eigen::ArrayXd {
+        auto eigorzero = [&term, &N](const std::string& name) -> Eigen::ArrayXd {
             if (!term[name].empty()) {
                 return toeig(term[name]);
             }
diff --git a/include/teqp/models/multifluid_eosterms.hpp b/include/teqp/models/multifluid_eosterms.hpp
index 80547d27a09f68ff6e114c4ce9e0205204cc134b..0b6c08b3b8042ae3db973f7cff016bbb876a536e 100644
--- a/include/teqp/models/multifluid_eosterms.hpp
+++ b/include/teqp/models/multifluid_eosterms.hpp
@@ -38,9 +38,22 @@ public:
     }
 };
 
+/**
+\f$ \alpha^r = \displaystyle\sum_i n_i \tau^{t_i}\delta^ {d_i} \exp(-\eta_i(\delta-\epsilon_i)^2 -\beta_i(\delta-\gamma_i) }\f$
+*/
+class GERG2004EOSTerm {
+public:
+    Eigen::ArrayXd n, t, d, eta, beta, gamma, epsilon;
+
+    template<typename TauType, typename DeltaType>
+    auto alphar(const TauType& tau, const DeltaType& delta) const {
+        return forceeval((n * exp(t * log(tau) + d * log(delta) - eta * (delta - epsilon).square() - beta * (tau - gamma).square())).sum());
+    }
+};
+
 
 /**
-\f$ \alpha^ r = \displaystyle\sum_i n_i \delta^ { d_i } \tau^ { t_i } \exp(-\delta^ { l_i } - \tau^ { m_i })\f$
+\f$ \alpha^r = \displaystyle\sum_i n_i \delta^ { d_i } \tau^ { t_i } \exp(-\delta^ { l_i } - \tau^ { m_i })\f$
 */
 class Lemmon2005EOSTerm {
 public:
@@ -54,7 +67,7 @@ public:
 };
 
 /**
-\f$ \alpha^ r = \displaystyle\sum_i n_i \tau^{t_i}\delta^ {d_i} \exp(-\eta_i(\delta-\epsilon_i)^2 + \frac{1}{\beta_i(\tau-\gamma_i)^2+b_i}\f$
+\f$ \alpha^r = \displaystyle\sum_i n_i \tau^{t_i}\delta^ {d_i} \exp(-\eta_i(\delta-\epsilon_i)^2 + \frac{1}{\beta_i(\tau-\gamma_i)^2+b_i}\f$
 */
 class GaoBEOSTerm {
 public:
@@ -67,6 +80,17 @@ public:
     }
 };
 
+/**
+\f$ \alpha^r = 0\f$
+*/
+class NullEOSTerm {
+public:
+    template<typename TauType, typename DeltaType>
+    auto alphar(const TauType& tau, const DeltaType& delta) const {
+        return static_cast<std::common_type_t<TauType, DeltaType>>(0.0);
+    }
+};
+
 class NonAnalyticEOSTerm {
 public:
     Eigen::ArrayXd A, B, C, D, a, b, beta, n;
@@ -81,17 +105,24 @@ public:
         auto theta = ((1.0 - tau) + A * pow(delta_min1_sq, k)).eval();
         auto Delta = (theta.square() + B * pow(delta_min1_sq, a)).eval();
 
-        return forceeval((n * pow(Delta, b) * delta * Psi).eval().sum());
+        auto outval = forceeval((n * pow(Delta, b) * delta * Psi).eval().sum());
+
+        // If we are really, really close to the critical point (tau=delta=1), then the term will become undefined, so let's just return 0 in that case
+        double dbl = getbaseval(outval);
+        if (std::isfinite(dbl)) {
+            return outval;
+        }
+        else {
+            return static_cast<decltype(outval)>(0.0);
+        }
     }
 };
 
 
-
 template<typename... Args>
-class EOSTermContainer {
-public:
-    using varEOSTerms = std::variant<Args...>;
+class EOSTermContainer {  
 private:
+    using varEOSTerms = std::variant<Args...>;
     std::vector<varEOSTerms> coll;
 public:
 
@@ -107,18 +138,12 @@ public:
         std::common_type_t <Tau, Delta> ar = 0.0;
         for (const auto& term : coll) {
             auto contrib = std::visit([&](auto& t) { return t.alphar(tau, delta); }, term);
-            if (std::holds_alternative<NonAnalyticEOSTerm>(term)) {
-                double dbl = getbaseval(abs(contrib));
-                if (std::isfinite(dbl)) {
-                    ar = ar + contrib;
-                }
-            }
-            else {
-                ar = ar + contrib;
-            }
+            ar = ar + contrib;
         }
         return ar;
     }
 };
 
-using EOSTerms = EOSTermContainer<PowerEOSTerm, GaussianEOSTerm, NonAnalyticEOSTerm, Lemmon2005EOSTerm, GaoBEOSTerm, ExponentialEOSTerm>;
\ No newline at end of file
+using EOSTerms = EOSTermContainer<PowerEOSTerm, GaussianEOSTerm, NonAnalyticEOSTerm, Lemmon2005EOSTerm, GaoBEOSTerm, ExponentialEOSTerm>;
+
+using DepartureTerms = EOSTermContainer<PowerEOSTerm, GaussianEOSTerm, GERG2004EOSTerm, NullEOSTerm>;
\ No newline at end of file
diff --git a/include/teqp/types.hpp b/include/teqp/types.hpp
index f315d2116760a3bae1e1bfa1086bbbc03f0cc585..a9644a9fba018719ce5d850647ebe1f9d7d2debd 100644
--- a/include/teqp/types.hpp
+++ b/include/teqp/types.hpp
@@ -1,7 +1,10 @@
 #pragma once
 
+#include "nlohmann/json.hpp"
+
 #include <vector>
 #include <valarray>
+#include <set>
 
 // Registration of types that are considered to be containers
 // See https://stackoverflow.com/a/12045843
@@ -28,14 +31,29 @@ auto forceeval(T&& expr)
     }
 }
 
+// See https://stackoverflow.com/a/41438758
+template<typename T> struct is_complex_t : public std::false_type {};
+template<typename T> struct is_complex_t<std::complex<T>> : public std::true_type {};
+
 template<typename T>
-auto getbaseval(T&& expr)
+auto getbaseval(const T& expr)
 {
     using namespace autodiff::detail;
     if constexpr (isDual<T> || isExpr<T>) {
         return val(expr);
     }
+    else if constexpr (is_complex_t<T>()) {
+        return expr.real();
+    }
     else {
         return expr;
     }
-}
\ No newline at end of file
+}
+
+auto toeig = [](const std::vector<double>& v) -> Eigen::ArrayXd { return Eigen::Map<const Eigen::ArrayXd>(&(v[0]), v.size()); };
+
+auto all_same_length = [](const nlohmann::json& j, const std::vector<std::string>& ks) {
+    std::set<int> lengths;
+    for (auto k : ks) { lengths.insert(j[k].size()); }
+    return lengths.size() == 1;
+};