diff --git a/src/scheme/PolynomialReconstruction.cpp b/src/scheme/PolynomialReconstruction.cpp
index 0f3982c4f3b6816996906550821308757e251a18..3c257c2d9d5133fe82b3f13ecfdca5b1c3146915 100644
--- a/src/scheme/PolynomialReconstruction.cpp
+++ b/src/scheme/PolynomialReconstruction.cpp
@@ -185,9 +185,8 @@ PolynomialReconstruction::_build(
   auto xj = MeshDataManager::instance().getMeshData(mesh).xj();
   auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj();
 
-  auto cell_is_owned       = mesh.connectivity().cellIsOwned();
-  auto cell_type           = mesh.connectivity().cellType();
-  auto cell_to_face_matrix = mesh.connectivity().cellToFaceMatrix();
+  auto cell_is_owned = mesh.connectivity().cellIsOwned();
+  auto cell_type     = mesh.connectivity().cellType();
 
   auto full_stencil_size = [&](const CellId cell_id) {
     auto stencil_cell_list = stencil_array[cell_id];
@@ -270,6 +269,39 @@ PolynomialReconstruction::_build(
     std::make_shared<CellCenterReconstructionMatrixBuilder<MeshType>>(symmetry_origin_list, symmetry_normal_list,
                                                                       stencil_array, xj);
 
+  SmallArray<std::shared_ptr<ElementIntegralReconstructionMatrixBuilder<MeshType>>>
+    element_integral_reconstruction_matrix_builder_pool{A_pool.size()};
+
+  for (size_t t = 0; t < element_integral_reconstruction_matrix_builder_pool.size(); ++t) {
+    SmallArray<double>& inv_Vj_wq_detJ_ek = inv_Vj_wq_detJ_ek_pool[t];
+    SmallArray<double>& mean_j_of_ejk     = mean_j_of_ejk_pool[t];
+    SmallArray<double>& mean_i_of_ejk     = mean_i_of_ejk_pool[t];
+
+    element_integral_reconstruction_matrix_builder_pool[t] =
+      std::make_shared<ElementIntegralReconstructionMatrixBuilder<MeshType>>(*p_mesh, m_descriptor.degree(),
+                                                                             inv_Vj_wq_detJ_ek, mean_j_of_ejk,
+                                                                             mean_i_of_ejk, symmetry_origin_list,
+                                                                             symmetry_normal_list, stencil_array);
+  }
+
+  SmallArray<std::shared_ptr<BoundaryIntegralReconstructionMatrixBuilder<MeshType>>>
+    boundary_integral_reconstruction_matrix_builder_pool{A_pool.size()};
+
+  if constexpr (MeshType::Dimension == 2) {
+    for (size_t t = 0; t < boundary_integral_reconstruction_matrix_builder_pool.size(); ++t) {
+      SmallArray<double>& inv_Vj_alpha_p_1_wq_X_prime_orth_ek = inv_Vj_alpha_p_1_wq_X_prime_orth_ek_pool[t];
+      SmallArray<double>& mean_j_of_ejk                       = mean_j_of_ejk_pool[t];
+      SmallArray<double>& mean_i_of_ejk                       = mean_i_of_ejk_pool[t];
+
+      boundary_integral_reconstruction_matrix_builder_pool[t] =
+        std::make_shared<BoundaryIntegralReconstructionMatrixBuilder<MeshType>>(*p_mesh, m_descriptor.degree(),
+                                                                                inv_Vj_alpha_p_1_wq_X_prime_orth_ek,
+                                                                                mean_j_of_ejk, mean_i_of_ejk,
+                                                                                symmetry_origin_list,
+                                                                                symmetry_normal_list, stencil_array);
+    }
+  }
+
   parallel_for(
     mesh.numberOfCells(), PUGS_CLASS_LAMBDA(const CellId cell_j_id) {
       if (cell_is_owned[cell_j_id]) {
@@ -518,35 +550,12 @@ PolynomialReconstruction::_build(
           if ((m_descriptor.integrationMethodType() == IntegrationMethodType::boundary) and
               (MeshType::Dimension == 2)) {
             if constexpr (MeshType::Dimension == 2) {
-#warning incorporate in reconstruction_matrix_builder
-              SmallArray<double>& inv_Vj_alpha_p_1_wq_X_prime_orth_ek = inv_Vj_alpha_p_1_wq_X_prime_orth_ek_pool[t];
-              SmallArray<double>& mean_j_of_ejk                       = mean_j_of_ejk_pool[t];
-              SmallArray<double>& mean_i_of_ejk                       = mean_i_of_ejk_pool[t];
-
-              BoundaryIntegralReconstructionMatrixBuilder
-                boundary_integral_reconstruction_matrix_builder(*p_mesh, m_descriptor.degree(),
-                                                                inv_Vj_alpha_p_1_wq_X_prime_orth_ek, mean_j_of_ejk,
-                                                                mean_i_of_ejk, symmetry_origin_list,
-                                                                symmetry_normal_list, stencil_array);
-
-              boundary_integral_reconstruction_matrix_builder.build(cell_j_id, A);
-
+              boundary_integral_reconstruction_matrix_builder_pool[t]->build(cell_j_id, A);
             } else {
               throw NotImplementedError("invalid mesh dimension");
             }
           } else {
-
-#warning incorporate in reconstruction_matrix_builder
-            SmallArray<double>& inv_Vj_wq_detJ_ek = inv_Vj_wq_detJ_ek_pool[t];
-            SmallArray<double>& mean_j_of_ejk     = mean_j_of_ejk_pool[t];
-            SmallArray<double>& mean_i_of_ejk     = mean_i_of_ejk_pool[t];
-
-            ElementIntegralReconstructionMatrixBuilder
-              element_integral_reconstruction_matrix_builder(*p_mesh, m_descriptor.degree(), inv_Vj_wq_detJ_ek,
-                                                             mean_j_of_ejk, mean_i_of_ejk, symmetry_origin_list,
-                                                             symmetry_normal_list, stencil_array);
-
-            element_integral_reconstruction_matrix_builder.build(cell_j_id, A);
+            element_integral_reconstruction_matrix_builder_pool[t]->build(cell_j_id, A);
           }
         } else {
           throw UnexpectedError("invalid integration strategy");
diff --git a/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.hpp b/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.hpp
index 8e1ce86607ff8ed3f913307bca652701e14a3265..efb92d0db81af6be75026cfb9e926254f382b0d8 100644
--- a/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.hpp
+++ b/src/scheme/reconstruction_utils/ElementIntegralReconstructionMatrixBuilder.hpp
@@ -30,7 +30,7 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
   const size_t m_basis_dimension;
   const size_t m_polynomial_degree;
 
-  const SmallArray<double> m_inv_Vj_wq_detJ_ek;
+  const SmallArray<double> m_wq_detJ_ek;
   SmallArray<double> m_mean_j_of_ejk;
   SmallArray<double> m_mean_i_of_ejk;
 
@@ -45,13 +45,21 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
   const CellValue<const Rd> m_xj;
   const NodeValue<const Rd> m_xr;
 
+  // 2D
+  SmallArray<const size_t> m_y_row_index;
+
+  // 3D
+  SmallArray<const size_t> m_yz_row_index;
+  SmallArray<const size_t> m_z_triangle_index;
+  SmallArray<const size_t> m_yz_row_size;
+
   template <typename ConformTransformationT>
   void
   _computeEjkMean(const QuadratureFormula<1>& quadrature,
                   const ConformTransformationT& T,
                   const TinyVector<1>& Xj,
                   const double Vi,
-                  SmallArray<double>& mean_of_ejk)
+                  SmallArray<double>& mean_of_ejk) noexcept(NO_ASSERT)
   {
     mean_of_ejk.fill(0);
 
@@ -65,17 +73,21 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
       const double x_xj = X_Xj[0];
 
       {
-        size_t k                 = 0;
-        m_inv_Vj_wq_detJ_ek[k++] = wq * detT / Vi;
-        for (; k <= m_polynomial_degree; ++k) {
-          m_inv_Vj_wq_detJ_ek[k] = x_xj * m_inv_Vj_wq_detJ_ek[k - 1];
+        m_wq_detJ_ek[0] = wq * detT;
+        for (size_t k = 1; k <= m_polynomial_degree; ++k) {
+          m_wq_detJ_ek[k] = x_xj * m_wq_detJ_ek[k - 1];
         }
       }
 
       for (size_t k = 1; k < m_basis_dimension; ++k) {
-        mean_of_ejk[k - 1] += m_inv_Vj_wq_detJ_ek[k];
+        mean_of_ejk[k - 1] += m_wq_detJ_ek[k];
       }
     }
+
+    const double inv_Vi = 1. / Vi;
+    for (size_t k = 0; k < mean_of_ejk.size(); ++k) {
+      mean_of_ejk[k] *= inv_Vi;
+    }
   }
 
   template <typename ConformTransformationT>
@@ -84,7 +96,7 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
                   const ConformTransformationT& T,
                   const TinyVector<2>& Xj,
                   const double Vi,
-                  SmallArray<double>& mean_of_ejk)
+                  SmallArray<double>& mean_of_ejk) noexcept(NO_ASSERT)
   {
     mean_of_ejk.fill(0);
 
@@ -105,25 +117,29 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
       const double y_yj = X_Xj[1];
 
       {
-        size_t k                 = 0;
-        m_inv_Vj_wq_detJ_ek[k++] = wq * detT / Vi;
+        size_t k          = 0;
+        m_wq_detJ_ek[k++] = wq * detT;
         for (; k <= m_polynomial_degree; ++k) {
-          m_inv_Vj_wq_detJ_ek[k] = x_xj * m_inv_Vj_wq_detJ_ek[k - 1];
+          m_wq_detJ_ek[k] = x_xj * m_wq_detJ_ek[k - 1];
         }
 
         for (size_t i_y = 1; i_y <= m_polynomial_degree; ++i_y) {
-#warning store y_row index and size
-          const size_t begin_i_y_1 = ((i_y - 1) * (2 * m_polynomial_degree - i_y + 4)) / 2;
-          for (size_t l = 0; l <= m_polynomial_degree - i_y; ++l) {
-            m_inv_Vj_wq_detJ_ek[k++] = y_yj * m_inv_Vj_wq_detJ_ek[begin_i_y_1 + l];
+          const size_t begin_i_y_1 = m_y_row_index[i_y - 1];
+          for (size_t l = 0; l <= m_polynomial_degree - i_y; ++l, ++k) {
+            m_wq_detJ_ek[k] = y_yj * m_wq_detJ_ek[begin_i_y_1 + l];
           }
         }
       }
 
       for (size_t k = 1; k < m_basis_dimension; ++k) {
-        mean_of_ejk[k - 1] += m_inv_Vj_wq_detJ_ek[k];
+        mean_of_ejk[k - 1] += m_wq_detJ_ek[k];
       }
     }
+
+    const double inv_Vi = 1. / Vi;
+    for (size_t k = 0; k < mean_of_ejk.size(); ++k) {
+      mean_of_ejk[k] *= inv_Vi;
+    }
   }
 
   template <typename ConformTransformationT>
@@ -132,31 +148,8 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
                   const ConformTransformationT& T,
                   const TinyVector<3>& Xj,
                   const double Vi,
-                  SmallArray<double>& mean_of_ejk)
+                  SmallArray<double>& mean_of_ejk) noexcept(NO_ASSERT)
   {
-#warning Compute this once for all and rework design
-    SmallArray<size_t> m_yz_row_index((m_polynomial_degree + 2) * (m_polynomial_degree + 1) / 2 + 1);
-    SmallArray<size_t> m_z_triangle_index(m_polynomial_degree + 1);
-
-    {
-      size_t i_z  = 0;
-      size_t i_yz = 0;
-
-      m_yz_row_index[i_yz++] = 0;
-      for (ssize_t n = m_polynomial_degree + 1; n >= 1; --n) {
-        m_z_triangle_index[i_z++] = i_yz - 1;
-        for (ssize_t i = n; i >= 1; --i) {
-          m_yz_row_index[i_yz] = m_yz_row_index[i_yz - 1] + i;
-          ++i_yz;
-        }
-      }
-    }
-
-    SmallArray<size_t> m_yz_row_size{m_yz_row_index.size() - 1};
-    for (size_t i = 0; i < m_yz_row_size.size(); ++i) {
-      m_yz_row_size[i] = m_yz_row_index[i + 1] - m_yz_row_index[i];
-    }
-
     mean_of_ejk.fill(0);
 
     for (size_t i_q = 0; i_q < quadrature.numberOfPoints(); ++i_q) {
@@ -177,17 +170,17 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
       const double z_zj = X_Xj[2];
 
       {
-        size_t k                 = 0;
-        m_inv_Vj_wq_detJ_ek[k++] = wq * detT / Vi;
+        size_t k          = 0;
+        m_wq_detJ_ek[k++] = wq * detT;
         for (; k <= m_polynomial_degree; ++k) {
-          m_inv_Vj_wq_detJ_ek[k] = x_xj * m_inv_Vj_wq_detJ_ek[k - 1];
+          m_wq_detJ_ek[k] = x_xj * m_wq_detJ_ek[k - 1];
         }
 
         for (size_t i_y = 1; i_y <= m_polynomial_degree; ++i_y) {
           const size_t begin_i_y_1 = m_yz_row_index[i_y - 1];
           const size_t nb_monoms   = m_yz_row_size[i_y];
-          for (size_t l = 0; l < nb_monoms; ++l) {
-            m_inv_Vj_wq_detJ_ek[k++] = y_yj * m_inv_Vj_wq_detJ_ek[begin_i_y_1 + l];
+          for (size_t l = 0; l < nb_monoms; ++l, ++k) {
+            m_wq_detJ_ek[k] = y_yj * m_wq_detJ_ek[begin_i_y_1 + l];
           }
         }
 
@@ -198,17 +191,22 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
           for (size_t i_y = 0; i_y < nb_y; ++i_y) {
             const size_t begin_i_yz_1 = m_yz_row_index[index_z_1 + i_y];
             const size_t nb_monoms    = m_yz_row_size[index_z + i_y];
-            for (size_t l = 0; l < nb_monoms; ++l) {
-              m_inv_Vj_wq_detJ_ek[k++] = z_zj * m_inv_Vj_wq_detJ_ek[begin_i_yz_1 + l];
+            for (size_t l = 0; l < nb_monoms; ++l, ++k) {
+              m_wq_detJ_ek[k] = z_zj * m_wq_detJ_ek[begin_i_yz_1 + l];
             }
           }
         }
       }
 
       for (size_t k = 1; k < m_basis_dimension; ++k) {
-        mean_of_ejk[k - 1] += m_inv_Vj_wq_detJ_ek[k];
+        mean_of_ejk[k - 1] += m_wq_detJ_ek[k];
       }
     }
+
+    const double inv_Vi = 1. / Vi;
+    for (size_t k = 0; k < mean_of_ejk.size(); ++k) {
+      mean_of_ejk[k] *= inv_Vi;
+    }
   }
 
   void
@@ -514,7 +512,7 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
         polynomial_degree)},
       m_polynomial_degree{polynomial_degree},
 
-      m_inv_Vj_wq_detJ_ek{inv_Vj_wq_detJ_ek},
+      m_wq_detJ_ek{inv_Vj_wq_detJ_ek},
       m_mean_j_of_ejk{mean_j_of_ejk},
       m_mean_i_of_ejk{mean_i_of_ejk},
 
@@ -526,7 +524,48 @@ class PolynomialReconstruction::ElementIntegralReconstructionMatrixBuilder
       m_Vj{MeshDataManager::instance().getMeshData(mesh).Vj()},
       m_xj{MeshDataManager::instance().getMeshData(mesh).xj()},
       m_xr{mesh.xr()}
-  {}
+  {
+    if constexpr (MeshType::Dimension == 2) {
+      SmallArray<size_t> y_row_index(m_polynomial_degree + 2);
+
+      size_t i_y = 0;
+
+      y_row_index[i_y++] = 0;
+      for (ssize_t n = m_polynomial_degree + 1; n >= 1; --n) {
+        y_row_index[i_y] = y_row_index[i_y - 1] + n;
+        ++i_y;
+      }
+
+      m_y_row_index = y_row_index;
+
+    } else if constexpr (MeshType::Dimension == 3) {
+      SmallArray<size_t> yz_row_index((m_polynomial_degree + 2) * (m_polynomial_degree + 1) / 2 + 1);
+      SmallArray<size_t> z_triangle_index(m_polynomial_degree + 1);
+
+      {
+        size_t i_z  = 0;
+        size_t i_yz = 0;
+
+        yz_row_index[i_yz++] = 0;
+        for (ssize_t n = m_polynomial_degree + 1; n >= 1; --n) {
+          z_triangle_index[i_z++] = i_yz - 1;
+          for (ssize_t i = n; i >= 1; --i) {
+            yz_row_index[i_yz] = yz_row_index[i_yz - 1] + i;
+            ++i_yz;
+          }
+        }
+      }
+
+      SmallArray<size_t> yz_row_size{yz_row_index.size() - 1};
+      for (size_t i = 0; i < yz_row_size.size(); ++i) {
+        yz_row_size[i] = yz_row_index[i + 1] - yz_row_index[i];
+      }
+
+      m_yz_row_index     = yz_row_index;
+      m_z_triangle_index = z_triangle_index;
+      m_yz_row_size      = yz_row_size;
+    }
+  }
 
   ~ElementIntegralReconstructionMatrixBuilder() = default;
 };