diff --git a/src/algebra/IntegrationTools.hpp b/src/algebra/IntegrationTools.hpp
index bdf6de6929f194696b0f467ea7af45ded1b52e62..756fe09b9b4a2428a5649f37f6007ae9404298ca 100644
--- a/src/algebra/IntegrationTools.hpp
+++ b/src/algebra/IntegrationTools.hpp
@@ -1,15 +1,13 @@
 #ifndef INTEGRATION_TOOLS_HPP
 #define INTEGRATION_TOOLS_HPP
 
-#include <iostream>
-
+#include <language/utils/EvaluateAtPoints.hpp>
 #include <utils/Exceptions.hpp>
 #include <utils/PugsAssert.hpp>
 #include <utils/PugsMacros.hpp>
+#include <utils/Types.hpp>
 
 #include <cmath>
-#include <language/utils/EvaluateAtPoints.hpp>
-#include <utils/Types.hpp>
 
 enum class QuadratureType : int8_t
 {
@@ -21,15 +19,362 @@ enum class QuadratureType : int8_t
   QT__end
 };
 
-template <size_t Order>
-class IntegrationMethod
+template <size_t Dimension>
+class QuadratureBase
+{
+ protected:
+  size_t m_order;
+  SmallArray<const TinyVector<Dimension>> m_point_list;
+  SmallArray<const double> m_weight_list;
+
+  virtual void _buildPointAndWeightLists() = 0;
+
+ public:
+  size_t
+  numberOfPoints() const
+  {
+    Assert(m_point_list.size() == m_weight_list.size());
+    return m_point_list.size();
+  }
+
+  const SmallArray<const TinyVector<Dimension>>&
+  pointList() const
+  {
+    return m_point_list;
+  }
+
+  const SmallArray<const double>&
+  weightList() const
+  {
+    return m_weight_list;
+  }
+
+  QuadratureBase(QuadratureBase&&)      = default;
+  QuadratureBase(const QuadratureBase&) = default;
+
+ protected:
+  explicit QuadratureBase(const size_t order) : m_order{order} {}
+
+ public:
+  QuadratureBase()          = delete;
+  virtual ~QuadratureBase() = default;
+};
+
+template <size_t Dimension>
+class TensorialGaussLegendre final : public QuadratureBase<Dimension>
 {
+ private:
+  void _buildPointAndWeightLists();
+
  public:
-  //  PUGS_INLINE virtual T integrate(const FunctionSymbolId& function, const double& a, const double& b) = 0;
+  TensorialGaussLegendre(TensorialGaussLegendre&&)      = default;
+  TensorialGaussLegendre(const TensorialGaussLegendre&) = default;
+
+  explicit TensorialGaussLegendre(const size_t order) : QuadratureBase<Dimension>(order)
+  {
+    this->_buildPointAndWeightLists();
+  }
+
+  TensorialGaussLegendre()  = delete;
+  ~TensorialGaussLegendre() = default;
+};
+
+template <>
+void
+TensorialGaussLegendre<1>::_buildPointAndWeightLists()
+{
+  const size_t nb_points = m_order / 2 + 1;
+
+  SmallArray<TinyVector<1>> point_list(nb_points);
+  SmallArray<double> weight_list(nb_points);
+
+  switch (m_order) {
+  case 0:
+  case 1: {
+    point_list[0] = 0;
+
+    weight_list[0] = 2;
+    break;
+  }
+  case 2:
+  case 3: {
+    point_list[0] = -0.5773502691896257645091488;
+    point_list[1] = +0.5773502691896257645091488;
+
+    weight_list[0] = 1;
+    weight_list[1] = 1;
+    break;
+  }
+  case 4:
+  case 5: {
+    point_list[0] = -0.7745966692414833770358531;
+    point_list[1] = 0;
+    point_list[2] = +0.7745966692414833770358531;
+
+    weight_list[0] = 0.5555555555555555555555556;
+    weight_list[1] = 0.8888888888888888888888889;
+    weight_list[2] = 0.5555555555555555555555556;
+    break;
+  }
+  case 6:
+  case 7: {
+    point_list[0] = -0.8611363115940525752239465;
+    point_list[1] = -0.3399810435848562648026658;
+    point_list[2] = +0.3399810435848562648026658;
+    point_list[3] = +0.8611363115940525752239465;
+
+    weight_list[0] = 0.3478548451374538573730639;
+    weight_list[1] = 0.6521451548625461426269361;
+    weight_list[2] = 0.6521451548625461426269361;
+    weight_list[3] = 0.3478548451374538573730639;
+    break;
+  }
+  case 8:
+  case 9: {
+    point_list[0] = -0.9061798459386639927976269;
+    point_list[1] = -0.5384693101056830910363144;
+    point_list[2] = 0;
+    point_list[3] = +0.5384693101056830910363144;
+    point_list[4] = +0.9061798459386639927976269;
+
+    weight_list[0] = 0.2369268850561890875142640;
+    weight_list[1] = 0.4786286704993664680412915;
+    weight_list[2] = 0.5688888888888888888888889;
+    weight_list[3] = 0.4786286704993664680412915;
+    weight_list[4] = 0.2369268850561890875142640;
+    break;
+  }
+  case 10:
+  case 11: {
+    point_list[0] = -0.9324695142031520278123016;
+    point_list[1] = -0.6612093864662645136613996;
+    point_list[2] = -0.2386191860831969086305017;
+    point_list[3] = +0.2386191860831969086305017;
+    point_list[4] = +0.6612093864662645136613996;
+    point_list[5] = +0.9324695142031520278123016;
+
+    weight_list[0] = 0.1713244923791703450402961;
+    weight_list[1] = 0.3607615730481386075698335;
+    weight_list[2] = 0.4679139345726910473898703;
+    weight_list[3] = 0.4679139345726910473898703;
+    weight_list[4] = 0.3607615730481386075698335;
+    weight_list[5] = 0.1713244923791703450402961;
+    break;
+  }
+  case 12:
+  case 13: {
+    point_list[0] = -0.9491079123427585245261897;
+    point_list[1] = -0.7415311855993944398638648;
+    point_list[2] = -0.4058451513773971669066064;
+    point_list[3] = 0;
+    point_list[4] = +0.4058451513773971669066064;
+    point_list[5] = +0.7415311855993944398638648;
+    point_list[6] = +0.9491079123427585245261897;
+
+    weight_list[0] = 0.1294849661688696932706114;
+    weight_list[1] = 0.2797053914892766679014678;
+    weight_list[2] = 0.3818300505051189449503698;
+    weight_list[3] = 0.4179591836734693877551020;
+    weight_list[4] = 0.3818300505051189449503698;
+    weight_list[5] = 0.2797053914892766679014678;
+    weight_list[6] = 0.1294849661688696932706114;
+    break;
+  }
+  case 14:
+  case 15: {
+    point_list[0] = -0.9602898564975362316835609;
+    point_list[1] = -0.7966664774136267395915539;
+    point_list[2] = -0.5255324099163289858177390;
+    point_list[3] = -0.1834346424956498049394761;
+    point_list[4] = +0.1834346424956498049394761;
+    point_list[5] = +0.5255324099163289858177390;
+    point_list[6] = +0.7966664774136267395915539;
+    point_list[7] = +0.9602898564975362316835609;
+
+    weight_list[0] = 0.1012285362903762591525314;
+    weight_list[1] = 0.2223810344533744705443560;
+    weight_list[2] = 0.3137066458778872873379622;
+    weight_list[3] = 0.3626837833783619829651504;
+    weight_list[4] = 0.3626837833783619829651504;
+    weight_list[5] = 0.3137066458778872873379622;
+    weight_list[6] = 0.2223810344533744705443560;
+    weight_list[7] = 0.1012285362903762591525314;
+    break;
+  }
+  case 16:
+  case 17: {
+    point_list[0] = -0.9681602395076260898355762;
+    point_list[1] = -0.8360311073266357942994298;
+    point_list[2] = -0.6133714327005903973087020;
+    point_list[3] = -0.3242534234038089290385380;
+    point_list[4] = 0;
+    point_list[5] = +0.3242534234038089290385380;
+    point_list[6] = +0.6133714327005903973087020;
+    point_list[7] = +0.8360311073266357942994298;
+    point_list[8] = +0.9681602395076260898355762;
+
+    weight_list[0] = 0.0812743883615744119718922;
+    weight_list[1] = 0.1806481606948574040584720;
+    weight_list[2] = 0.2606106964029354623187429;
+    weight_list[3] = 0.3123470770400028400686304;
+    weight_list[4] = 0.3302393550012597631645251;
+    weight_list[5] = 0.3123470770400028400686304;
+    weight_list[6] = 0.2606106964029354623187429;
+    weight_list[7] = 0.1806481606948574040584720;
+    weight_list[8] = 0.0812743883615744119718922;
+    break;
+  }
+  case 18:
+  case 19: {
+    point_list[0] = -0.9739065285171717200779640;
+    point_list[1] = -0.8650633666889845107320967;
+    point_list[2] = -0.6794095682990244062343274;
+    point_list[3] = -0.4333953941292471907992659;
+    point_list[4] = -0.1488743389816312108848260;
+    point_list[5] = +0.1488743389816312108848260;
+    point_list[6] = +0.4333953941292471907992659;
+    point_list[7] = +0.6794095682990244062343274;
+    point_list[8] = +0.8650633666889845107320967;
+    point_list[9] = +0.9739065285171717200779640;
+
+    weight_list[0] = 0.0666713443086881375935688;
+    weight_list[1] = 0.1494513491505805931457763;
+    weight_list[2] = 0.2190863625159820439955349;
+    weight_list[3] = 0.2692667193099963550912269;
+    weight_list[4] = 0.2955242247147528701738930;
+    weight_list[5] = 0.2955242247147528701738930;
+    weight_list[6] = 0.2692667193099963550912269;
+    weight_list[7] = 0.2190863625159820439955349;
+    weight_list[8] = 0.1494513491505805931457763;
+    weight_list[9] = 0.0666713443086881375935688;
+    break;
+  }
+  case 20:
+  case 21: {
+    point_list[0]  = -0.9782286581460569928039380;
+    point_list[1]  = -0.8870625997680952990751578;
+    point_list[2]  = -0.7301520055740493240934163;
+    point_list[3]  = -0.5190961292068118159257257;
+    point_list[4]  = -0.2695431559523449723315320;
+    point_list[5]  = 0;
+    point_list[6]  = +0.2695431559523449723315320;
+    point_list[7]  = +0.5190961292068118159257257;
+    point_list[8]  = +0.7301520055740493240934163;
+    point_list[9]  = +0.8870625997680952990751578;
+    point_list[10] = +0.9782286581460569928039380;
+
+    weight_list[0]  = 0.0556685671161736664827537;
+    weight_list[1]  = 0.1255803694649046246346940;
+    weight_list[2]  = 0.1862902109277342514260980;
+    weight_list[3]  = 0.2331937645919904799185237;
+    weight_list[4]  = 0.2628045445102466621806889;
+    weight_list[5]  = 0.2729250867779006307144835;
+    weight_list[6]  = 0.2628045445102466621806889;
+    weight_list[7]  = 0.2331937645919904799185237;
+    weight_list[8]  = 0.1862902109277342514260980;
+    weight_list[9]  = 0.1255803694649046246346940;
+    weight_list[10] = 0.0556685671161736664827537;
+    break;
+  }
+  case 22:
+  case 23: {
+    point_list[0]  = -0.9815606342467192506905491;
+    point_list[1]  = -0.9041172563704748566784659;
+    point_list[2]  = -0.7699026741943046870368938;
+    point_list[3]  = -0.5873179542866174472967024;
+    point_list[4]  = -0.3678314989981801937526915;
+    point_list[5]  = -0.1252334085114689154724414;
+    point_list[6]  = +0.1252334085114689154724414;
+    point_list[7]  = +0.3678314989981801937526915;
+    point_list[8]  = +0.5873179542866174472967024;
+    point_list[9]  = +0.7699026741943046870368938;
+    point_list[10] = +0.9041172563704748566784659;
+    point_list[11] = +0.9815606342467192506905491;
+
+    weight_list[0]  = 0.0471753363865118271946160;
+    weight_list[1]  = 0.1069393259953184309602547;
+    weight_list[2]  = 0.1600783285433462263346525;
+    weight_list[3]  = 0.2031674267230659217490645;
+    weight_list[4]  = 0.2334925365383548087608499;
+    weight_list[5]  = 0.2491470458134027850005624;
+    weight_list[6]  = 0.2491470458134027850005624;
+    weight_list[7]  = 0.2334925365383548087608499;
+    weight_list[8]  = 0.2031674267230659217490645;
+    weight_list[9]  = 0.1600783285433462263346525;
+    weight_list[10] = 0.1069393259953184309602547;
+    weight_list[11] = 0.0471753363865118271946160;
+    break;
+  }
+  default: {
+    throw UnexpectedError("Gauss-Legendre quadratures handle orders up to 23");
+    break;
+  }
+  }
+
+  m_point_list  = point_list;
+  m_weight_list = weight_list;
+}
 
-  PUGS_INLINE virtual Array<TinyVector<1>> quadraturePoints(const double& a, const double& b) = 0;
-  PUGS_INLINE virtual size_t numberOfPoints()                                                 = 0;
-  PUGS_INLINE virtual Array<double> weights()                                                 = 0;
+template <>
+void
+TensorialGaussLegendre<2>::_buildPointAndWeightLists()
+{
+  const size_t nb_points_1d = this->m_order / 2 + 1;
+  const size_t nb_points    = nb_points_1d * nb_points_1d;
+
+  SmallArray<TinyVector<2>> point_list(nb_points);
+  SmallArray<double> weight_list(nb_points);
+
+  TensorialGaussLegendre<1> gauss_legendre_1d(m_order);
+  const auto& point_list_1d  = gauss_legendre_1d.pointList();
+  const auto& weight_list_1d = gauss_legendre_1d.weightList();
+
+  size_t l = 0;
+  for (size_t i = 0; i < nb_points_1d; ++i) {
+    for (size_t j = 0; j < nb_points_1d; ++j, ++l) {
+      point_list[l]  = TinyVector<2>{point_list_1d[i][0], point_list_1d[j][0]};
+      weight_list[l] = weight_list_1d[i] * weight_list_1d[j];
+    }
+  }
+
+  this->m_point_list  = point_list;
+  this->m_weight_list = weight_list;
+}
+
+template <>
+void
+TensorialGaussLegendre<3>::_buildPointAndWeightLists()
+{
+  const size_t nb_points_1d = this->m_order / 2 + 1;
+  const size_t nb_points    = nb_points_1d * nb_points_1d * nb_points_1d;
+
+  SmallArray<TinyVector<3>> point_list(nb_points);
+  SmallArray<double> weight_list(nb_points);
+
+  TensorialGaussLegendre<1> gauss_legendre_1d(m_order);
+  const auto& point_list_1d  = gauss_legendre_1d.pointList();
+  const auto& weight_list_1d = gauss_legendre_1d.weightList();
+
+  size_t l = 0;
+  for (size_t i = 0; i < nb_points_1d; ++i) {
+    for (size_t j = 0; j < nb_points_1d; ++j) {
+      for (size_t k = 0; k < nb_points_1d; ++k, ++l) {
+        point_list[l]  = TinyVector<3>{point_list_1d[i][0], point_list_1d[j][0], point_list_1d[k][0]};
+        weight_list[l] = weight_list_1d[i] * weight_list_1d[j] * weight_list_1d[k];
+      }
+    }
+  }
+
+  this->m_point_list  = point_list;
+  this->m_weight_list = weight_list;
+}
+
+class IntegrationMethod
+{
+ public:
+  PUGS_INLINE virtual SmallArray<TinyVector<1>> quadraturePoints(const double& a, const double& b) = 0;
+  PUGS_INLINE virtual size_t numberOfPoints()                                                      = 0;
+  PUGS_INLINE virtual SmallArray<double> weights()                                                 = 0;
   // One does not use the '=default' constructor to avoid
   // (zero-initialization) performances issues
   PUGS_INLINE
@@ -45,16 +390,16 @@ class IntegrationMethod
 };
 
 template <size_t Order>
-class IntegrationMethodLobatto : public IntegrationMethod<Order>
+class IntegrationMethodLobatto : public IntegrationMethod
 {
  private:
   static constexpr size_t number_points = (Order < 4 ? 3 : (Order < 6 ? 4 : (Order < 8 ? 5 : Order < 10 ? 6 : 7)));
-  Array<double> m_weights;
-  Array<TinyVector<1>> m_quadrature_positions;
-  PUGS_INLINE Array<TinyVector<1>>
+  SmallArray<double> m_weights;
+  SmallArray<TinyVector<1>> m_quadrature_positions;
+  PUGS_INLINE SmallArray<TinyVector<1>>
   translateQuadraturePoints(const double& a, const double& b)
   {
-    Array<TinyVector<1>> points{number_points};
+    SmallArray<TinyVector<1>> points{number_points};
     double length = b - a;
     for (size_t i = 0; i < m_quadrature_positions.size(); i++) {
       TinyVector<1> qpos{m_quadrature_positions[i]};
@@ -64,7 +409,7 @@ class IntegrationMethodLobatto : public IntegrationMethod<Order>
   }
 
   PUGS_INLINE
-  constexpr void
+  void
   fillArrayLobatto()
   {
     switch (Order) {
@@ -180,7 +525,7 @@ class IntegrationMethodLobatto : public IntegrationMethod<Order>
   }
 
   PUGS_INLINE
-  Array<TinyVector<1>>
+  SmallArray<TinyVector<1>>
   quadraturePoints(const double& a, const double& b)
   {
     return translateQuadraturePoints(a, b);
@@ -192,7 +537,7 @@ class IntegrationMethodLobatto : public IntegrationMethod<Order>
     return number_points;
   }
   PUGS_INLINE
-  Array<double>
+  SmallArray<double>
   weights()
   {
     return m_weights;
@@ -209,16 +554,16 @@ class IntegrationMethodLobatto : public IntegrationMethod<Order>
 };
 
 template <size_t Order>
-class IntegrationMethodLegendre : public IntegrationMethod<Order>
+class IntegrationMethodLegendre : public IntegrationMethod
 {
  private:
   static constexpr size_t number_points = (Order < 4 ? 2 : (Order < 6 ? 3 : (Order < 8 ? 4 : 5)));
-  Array<double> m_weights;
-  Array<TinyVector<1>> m_quadrature_positions;
-  PUGS_INLINE Array<TinyVector<1>>
+  SmallArray<double> m_weights;
+  SmallArray<TinyVector<1>> m_quadrature_positions;
+  PUGS_INLINE SmallArray<TinyVector<1>>
   translateQuadraturePoints(const double& a, const double& b)
   {
-    Array<TinyVector<1>> points{number_points};
+    SmallArray<TinyVector<1>> points{number_points};
     double length = b - a;
     for (size_t i = 0; i < m_quadrature_positions.size(); i++) {
       TinyVector<1> qpos{m_quadrature_positions[i]};
@@ -228,78 +573,81 @@ class IntegrationMethodLegendre : public IntegrationMethod<Order>
   }
 
   PUGS_INLINE
-  constexpr void
+  void
   fillArrayLegendre()
   {
-    switch (Order) {
-    case 0:
-    case 1:
-    case 2:
-    case 3: {
-      double oneovsqrt3         = 1. / std::sqrt(3);
-      m_quadrature_positions[0] = -oneovsqrt3;
-      m_quadrature_positions[1] = oneovsqrt3;
-      m_weights[0]              = 1;
-      m_weights[1]              = 1;
-      // m_quadrature_positions.fill({-1, 0, 1});
-      // m_weights.fill({oneov3, 4 * oneov3, oneov3});
-      break;
-    }
-    case 4:
-    case 5: {
-      double oneover9           = 1. / 9;
-      double coef               = std::sqrt(3. / 5.);
-      m_quadrature_positions[0] = -coef;
-      m_quadrature_positions[1] = 0;
-      m_quadrature_positions[2] = coef;
-      m_weights[0]              = 5 * oneover9;
-      m_weights[1]              = 8 * oneover9;
-      m_weights[2]              = 5 * oneover9;
-      break;
-    }
-    case 6:
-    case 7: {
-      double oneov36 = 1. / 36.;
-      double coef1   = std::sqrt(3. / 7. - 2. / 7. * std::sqrt(6. / 5.));
-      double coef2   = std::sqrt(3. / 7. + 2. / 7. * std::sqrt(6. / 5.));
-      double coef3   = 18. + std::sqrt(30.);
-      double coef4   = 18. - std::sqrt(30.);
-
-      m_quadrature_positions[0] = -coef2;
-      m_quadrature_positions[1] = -coef1;
-      m_quadrature_positions[2] = coef1;
-      m_quadrature_positions[3] = coef2;
-      m_weights[0]              = coef4 * oneov36;
-      m_weights[1]              = coef3 * oneov36;
-      m_weights[2]              = coef3 * oneov36;
-      m_weights[3]              = coef4 * oneov36;
-      break;
-    }
-    case 8:
-    case 9: {
-      double oneov900           = 1. / 900.;
-      double oneov225           = 1. / 225.;
-      double coef1              = 1. / 3. * std::sqrt(5. - 2. * std::sqrt(10. / 7.));
-      double coef2              = 1. / 3. * std::sqrt(5. + 2. * std::sqrt(10. / 7.));
-      double coef3              = 322. + 13. * std::sqrt(70.);
-      double coef4              = 322. - 13. * std::sqrt(70.);
-      m_quadrature_positions[0] = -coef2;
-      m_quadrature_positions[1] = -coef1;
-      m_quadrature_positions[2] = 0;
-      m_quadrature_positions[3] = coef1;
-      m_quadrature_positions[4] = coef2;
-      m_weights[0]              = coef4 * oneov900;
-      m_weights[1]              = coef3 * oneov900;
-      m_weights[2]              = 128. * oneov225;
-      m_weights[3]              = coef3 * oneov900;
-      m_weights[4]              = coef4 * oneov900;
-      break;
-    }
-    default: {
-      throw UnexpectedError("Gauss-Legendre quadratures handle orders up to 9.");
-      break;
-    }
-    }
+    TensorialGaussLegendre<1> tensorial_gauss_legendre(Order);
+    copy_to(tensorial_gauss_legendre.pointList(), m_quadrature_positions);
+    copy_to(tensorial_gauss_legendre.weightList(), m_weights);
+    // switch (Order) {
+    // case 0:
+    // case 1:
+    // case 2:
+    // case 3: {
+    //   double oneovsqrt3         = 1. / std::sqrt(3);
+    //   m_quadrature_positions[0] = -oneovsqrt3;
+    //   m_quadrature_positions[1] = oneovsqrt3;
+    //   m_weights[0]              = 1;
+    //   m_weights[1]              = 1;
+    //   // m_quadrature_positions.fill({-1, 0, 1});
+    //   // m_weights.fill({oneov3, 4 * oneov3, oneov3});
+    //   break;
+    // }
+    // case 4:
+    // case 5: {
+    //   double oneover9           = 1. / 9;
+    //   double coef               = std::sqrt(3. / 5.);
+    //   m_quadrature_positions[0] = -coef;
+    //   m_quadrature_positions[1] = 0;
+    //   m_quadrature_positions[2] = coef;
+    //   m_weights[0]              = 5 * oneover9;
+    //   m_weights[1]              = 8 * oneover9;
+    //   m_weights[2]              = 5 * oneover9;
+    //   break;
+    // }
+    // case 6:
+    // case 7: {
+    //   double oneov36 = 1. / 36.;
+    //   double coef1   = std::sqrt(3. / 7. - 2. / 7. * std::sqrt(6. / 5.));
+    //   double coef2   = std::sqrt(3. / 7. + 2. / 7. * std::sqrt(6. / 5.));
+    //   double coef3   = 18. + std::sqrt(30.);
+    //   double coef4   = 18. - std::sqrt(30.);
+
+    //   m_quadrature_positions[0] = -coef2;
+    //   m_quadrature_positions[1] = -coef1;
+    //   m_quadrature_positions[2] = coef1;
+    //   m_quadrature_positions[3] = coef2;
+    //   m_weights[0]              = coef4 * oneov36;
+    //   m_weights[1]              = coef3 * oneov36;
+    //   m_weights[2]              = coef3 * oneov36;
+    //   m_weights[3]              = coef4 * oneov36;
+    //   break;
+    // }
+    // case 8:
+    // case 9: {
+    //   double oneov900           = 1. / 900.;
+    //   double oneov225           = 1. / 225.;
+    //   double coef1              = 1. / 3. * std::sqrt(5. - 2. * std::sqrt(10. / 7.));
+    //   double coef2              = 1. / 3. * std::sqrt(5. + 2. * std::sqrt(10. / 7.));
+    //   double coef3              = 322. + 13. * std::sqrt(70.);
+    //   double coef4              = 322. - 13. * std::sqrt(70.);
+    //   m_quadrature_positions[0] = -coef2;
+    //   m_quadrature_positions[1] = -coef1;
+    //   m_quadrature_positions[2] = 0;
+    //   m_quadrature_positions[3] = coef1;
+    //   m_quadrature_positions[4] = coef2;
+    //   m_weights[0]              = coef4 * oneov900;
+    //   m_weights[1]              = coef3 * oneov900;
+    //   m_weights[2]              = 128. * oneov225;
+    //   m_weights[3]              = coef3 * oneov900;
+    //   m_weights[4]              = coef4 * oneov900;
+    //   break;
+    // }
+    // default: {
+    //   throw UnexpectedError("Gauss-Legendre quadratures handle orders up to 9.");
+    //   break;
+    // }
+    // }
   }
 
  public:
@@ -314,7 +662,7 @@ class IntegrationMethodLegendre : public IntegrationMethod<Order>
   }
 
   PUGS_INLINE
-  Array<TinyVector<1>>
+  SmallArray<TinyVector<1>>
   quadraturePoints(const double& a, const double& b)
   {
     return translateQuadraturePoints(a, b);
@@ -326,7 +674,7 @@ class IntegrationMethodLegendre : public IntegrationMethod<Order>
     return number_points;
   }
   PUGS_INLINE
-  Array<double>
+  SmallArray<double>
   weights()
   {
     return m_weights;
@@ -350,17 +698,18 @@ class IntegrationTools
 
  private:
   //  T m_values[N];
-  std::shared_ptr<IntegrationMethod<Order>> m_integration_method;
+  std::shared_ptr<IntegrationMethod> m_integration_method;
   size_t N;
 
  public:
   PUGS_INLINE T
   integrate(const FunctionSymbolId& function, const double& a, const double& b) const
   {
-    T result                             = 0;
-    Array<const TinyVector<1>> positions = quadraturePoints(a, b);
-    Array<double> weights                = m_integration_method->weights();
-    Array<T> values                      = EvaluateAtPoints<double(const TinyVector<1>)>::evaluate(function, positions);
+    T result                                  = 0;
+    SmallArray<const TinyVector<1>> positions = quadraturePoints(a, b);
+    SmallArray<double> weights                = m_integration_method->weights();
+    SmallArray<T> values(positions.size());
+    EvaluateAtPoints<double(const TinyVector<1>)>::evaluateTo(function, positions, values);
     Assert(positions.size() == weights.size(), "Wrong number of quadrature points and/or weights in Gauss quadrature");
     for (size_t i = 0; i < values.size(); ++i) {
       result += weights[i] * values[i];
@@ -368,14 +717,15 @@ class IntegrationTools
     return (b - a) / 2 * result;
   }
 
-  PUGS_INLINE Array<T>
-  integrateFunction(const FunctionSymbolId& function, const Array<TinyVector<1>>& vertices) const
+  PUGS_INLINE SmallArray<T>
+  integrateFunction(const FunctionSymbolId& function, const SmallArray<TinyVector<1>>& vertices) const
   {
-    Array<const TinyVector<1>> positions = quadraturePoints(vertices);
-    Array<T> result{vertices.size() - 1};
-    Array<double> interval_size{vertices.size() - 1};
-    Array<double> weights = m_integration_method->weights();
-    Array<T> values       = EvaluateAtPoints<double(const TinyVector<1>)>::evaluate(function, positions);
+    SmallArray<const TinyVector<1>> positions = quadraturePoints(vertices);
+    SmallArray<T> result{vertices.size() - 1};
+    SmallArray<double> interval_size{vertices.size() - 1};
+    SmallArray<double> weights = m_integration_method->weights();
+    SmallArray<T> values(positions.size());
+    EvaluateAtPoints<double(const TinyVector<1>)>::evaluateTo(function, positions, values);
 
     for (size_t i = 0; i < interval_size.size(); ++i) {
       interval_size[i] = vertices[i + 1][0] - vertices[i][0];
@@ -391,27 +741,31 @@ class IntegrationTools
   PUGS_INLINE T
   testIntegrate(const double& a, const double& b) const
   {
-    T result                       = 0;
-    Array<TinyVector<1>> positions = quadraturePoints(a, b);
-    Array<double> weights          = m_integration_method->weights();
-    Array<T> values(weights.size());
+    T result                            = 0;
+    SmallArray<TinyVector<1>> positions = quadraturePoints(a, b);
+
+    SmallArray<double> weights = m_integration_method->weights();
+
+    SmallArray<T> values(weights.size());
     for (size_t j = 0; j < weights.size(); ++j) {
-      values[j] = std::pow(positions[j][0], 3);
+      values[j] = std::pow(positions[j][0], 3.);
     }
+
     Assert(positions.size() == weights.size(), "Wrong number of quadrature points and/or weights in Gauss quadrature");
     for (size_t i = 0; i < values.size(); ++i) {
       result += weights[i] * values[i];
     }
-    return (b - a) / 2 * result;
+
+    return 0.5 * (b - a) * result;
   }
 
-  PUGS_INLINE Array<T>
-  testIntegrateFunction(const Array<TinyVector<1>>& vertices) const
+  PUGS_INLINE SmallArray<T>
+  testIntegrateFunction(const SmallArray<TinyVector<1>>& vertices) const
   {
-    Array<TinyVector<1>> positions = quadraturePoints(vertices);
-    Array<double> interval_size{vertices.size() - 1};
-    Array<double> weights = m_integration_method->weights();
-    Array<T> values(positions.size());
+    SmallArray<TinyVector<1>> positions = quadraturePoints(vertices);
+    SmallArray<double> interval_size{vertices.size() - 1};
+    SmallArray<double> weights = m_integration_method->weights();
+    SmallArray<T> values(positions.size());
     for (size_t j = 0; j < positions.size(); ++j) {
       values[j] = std::pow(positions[j][0], 3);
     }
@@ -419,7 +773,7 @@ class IntegrationTools
     for (size_t i = 0; i < interval_size.size(); ++i) {
       interval_size[i] = vertices[i + 1][0] - vertices[i][0];
     }
-    Array<T> result{vertices.size() - 1};
+    SmallArray<T> result{vertices.size() - 1};
     if constexpr (std::is_arithmetic_v<T>) {
       result.fill(0);
     } else if constexpr (is_tiny_vector_v<T> or is_tiny_matrix_v<T>) {
@@ -435,19 +789,19 @@ class IntegrationTools
     return result;
   }
 
-  PUGS_INLINE Array<TinyVector<1>>
+  PUGS_INLINE SmallArray<TinyVector<1>>
   quadraturePoints(const double& a, const double& b) const
   {
     return m_integration_method->quadraturePoints(a, b);
   }
 
   PUGS_INLINE
-  Array<TinyVector<1>>
-  quadraturePoints(const Array<TinyVector<1>>& positions) const
+  SmallArray<TinyVector<1>>
+  quadraturePoints(const SmallArray<TinyVector<1>>& positions) const
   {
     size_t number_of_intervals = positions.size() - 1;
     size_t quadrature_size     = m_integration_method->numberOfPoints();
-    Array<TinyVector<1>> quadratures{quadrature_size * number_of_intervals};
+    SmallArray<TinyVector<1>> quadratures{quadrature_size * number_of_intervals};
     for (size_t j = 0; j < number_of_intervals; ++j) {
       double a                    = positions[j][0];
       double b                    = positions[j + 1][0];
@@ -459,7 +813,7 @@ class IntegrationTools
     return quadratures;
   }
 
-  PUGS_INLINE Array<double>
+  PUGS_INLINE SmallArray<double>
   weights() const
   {
     return m_integration_method->weights();
diff --git a/tests/test_FunctionEvaluation.cpp b/tests/test_FunctionEvaluation.cpp
index a7a79d156bba68e959aef9bfb40815960c2ca4c6..88c9e552af82fdfecc1d2da1a78cbefd2ffae969 100644
--- a/tests/test_FunctionEvaluation.cpp
+++ b/tests/test_FunctionEvaluation.cpp
@@ -24,19 +24,76 @@ TEST_CASE("EvaluateAtPoints", "[integration]")
   SECTION("Instantiation")
   {
     // positions[0] = 1;
-    Array<double> result(1);
+    SmallArray<double> result(1);
     //    result = EvaluateAtPoints<double(TinyVector<1>)>::evaluate(f, positions);
     //    REQUIRE(result[0] == 1);
   }
 }
 
+TEST_CASE("QuadratureFormula", "[analysis]")
+{
+  SECTION("TensorialGaussLegendre")
+  {
+    auto integrate = [](auto f, auto quadrature_formula, const double a, const double b) {
+      auto point_list  = quadrature_formula.pointList();
+      auto weight_list = quadrature_formula.weightList();
+
+      auto x = [&a, &b](auto x_hat) { return 0.5 * (b - a) * (x_hat + 1); };
+
+      auto value = weight_list[0] * f(x(point_list[0]));
+      for (size_t i = 1; i < weight_list.size(); ++i) {
+        value += weight_list[i] * f(x(point_list[i]));
+      }
+      return 0.5 * (b - a) * value;
+    };
+
+    auto p0 = [](const TinyVector<1>&) { return 3; };
+    auto p1 = [](const TinyVector<1>& X) {
+      const double x = X[0];
+      return 2 * x + 1;
+    };
+    auto p2 = [](const TinyVector<1>& X) {
+      const double x = X[0];
+      return 3 * x * x + 2 * x + 1;
+    };
+
+    SECTION("exact integration")
+    {
+      SECTION("order 0 and 1")
+      {
+        TensorialGaussLegendre<1> l0(0);
+        TensorialGaussLegendre<1> l1(1);
+
+        REQUIRE(l0.numberOfPoints() == 1);
+        REQUIRE(l1.numberOfPoints() == 1);
+
+        REQUIRE(integrate(p0, l1, 0.5, 1) == Catch::Approx(1.5));
+        REQUIRE(integrate(p1, l1, 0, 1) == Catch::Approx(2));
+      }
+
+      SECTION("order 2 and 3")
+      {
+        TensorialGaussLegendre<1> l2(2);
+        TensorialGaussLegendre<1> l3(3);
+
+        REQUIRE(l2.numberOfPoints() == 2);
+        REQUIRE(l3.numberOfPoints() == 2);
+
+        REQUIRE(integrate(p0, l3, 0.5, 1) == Catch::Approx(1.5));
+        REQUIRE(integrate(p1, l3, 0, 1) == Catch::Approx(2));
+        REQUIRE(integrate(p2, l3, 0, 1) == Catch::Approx(3));
+      }
+    }
+  }
+}
+
 TEST_CASE("IntegrationTools", "[integration]")
 {
   IntegrationTools<2> integrationtools(QuadratureType::gausslobatto);
   double a = 1;
   double b = 2;
 
-  Array<TinyVector<1>> vertices(4);
+  SmallArray<TinyVector<1>> vertices(4);
   for (size_t i = 0; i < 4; i++) {
     vertices[0] = {a};
     vertices[1] = {b};
@@ -50,19 +107,21 @@ TEST_CASE("IntegrationTools", "[integration]")
   }
   SECTION("QuadraturePoints")
   {
-    Array<TinyVector<1>> quadratures = integrationtools.quadraturePoints(a, b);
-    REQUIRE(((quadratures[0] == 1) and (quadratures[1] == 1.5) and (quadratures[2] == 2)));
+    SmallArray<TinyVector<1>> quadratures = integrationtools.quadraturePoints(a, b);
+    REQUIRE(quadratures[0] == 1);
+    REQUIRE(quadratures[1] == 1.5);
+    REQUIRE(quadratures[2] == 2);
   }
   SECTION("Weights")
   {
-    Array<double> weights = integrationtools.weights();
+    SmallArray<double> weights = integrationtools.weights();
     REQUIRE(((weights[0] == 1. / 3.) and (weights[1] == 4. / 3.) and (weights[2] == 1. / 3.)));
   }
   SECTION("TestOrder3")
   {
     double result = integrationtools.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtools.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtools.testIntegrateFunction(vertices);
     REQUIRE(results.size() == 3);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
@@ -73,7 +132,7 @@ TEST_CASE("IntegrationTools", "[integration]")
   {
     double result = integrationtools5.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtools.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtools.testIntegrateFunction(vertices);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
     REQUIRE(results[2] == Catch::Approx((-0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
@@ -83,7 +142,7 @@ TEST_CASE("IntegrationTools", "[integration]")
   {
     double result = integrationtools7.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtools.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtools.testIntegrateFunction(vertices);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
     REQUIRE(results[2] == Catch::Approx((-0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
@@ -93,7 +152,7 @@ TEST_CASE("IntegrationTools", "[integration]")
   {
     double result = integrationtools9.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtools.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtools.testIntegrateFunction(vertices);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
     REQUIRE(results[2] == Catch::Approx((-0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
@@ -103,7 +162,7 @@ TEST_CASE("IntegrationTools", "[integration]")
   {
     double result = integrationtools11.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtools.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtools.testIntegrateFunction(vertices);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
     REQUIRE(results[2] == Catch::Approx((-0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
@@ -119,7 +178,7 @@ TEST_CASE("IntegrationTools", "[integration]")
   {
     double result = integrationtoolslegendre.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtoolslegendre.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtoolslegendre.testIntegrateFunction(vertices);
     REQUIRE(results.size() == 3);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
@@ -130,7 +189,7 @@ TEST_CASE("IntegrationTools", "[integration]")
   {
     double result = integrationtoolslegendre5.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtoolslegendre5.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtoolslegendre5.testIntegrateFunction(vertices);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
     REQUIRE(results[2] == Catch::Approx((-0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
@@ -140,7 +199,7 @@ TEST_CASE("IntegrationTools", "[integration]")
   {
     double result = integrationtoolslegendre7.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtoolslegendre7.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtoolslegendre7.testIntegrateFunction(vertices);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
     REQUIRE(results[2] == Catch::Approx((-0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
@@ -150,7 +209,7 @@ TEST_CASE("IntegrationTools", "[integration]")
   {
     double result = integrationtoolslegendre9.testIntegrate(a, b);
     REQUIRE(result == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
-    Array<double> results = integrationtoolslegendre9.testIntegrateFunction(vertices);
+    SmallArray<double> results = integrationtoolslegendre9.testIntegrateFunction(vertices);
     REQUIRE(results[0] == Catch::Approx((0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));
     REQUIRE(results[1] == 0);
     REQUIRE(results[2] == Catch::Approx((-0.25 * (std::pow(2, 4) - std::pow(1, 4)))).epsilon(1E-14));