diff --git a/NumLib/Fem/InitShapeMatrices.h b/NumLib/Fem/InitShapeMatrices.h
index ab5f8feba2104ac73ce95a0ed223326554073e69..fb2781741bccc188dba1bd10fe54b0fbf32aaa53 100644
--- a/NumLib/Fem/InitShapeMatrices.h
+++ b/NumLib/Fem/InitShapeMatrices.h
@@ -18,11 +18,11 @@ namespace NumLib
 {
 template <typename ShapeFunction, typename ShapeMatricesType, int GlobalDim,
           ShapeMatrixType SelectedShapeMatrixType = ShapeMatrixType::ALL,
-          typename IntegrationMethod>
+          typename PointContainer>
 std::vector<typename ShapeMatricesType::ShapeMatrices,
             Eigen::aligned_allocator<typename ShapeMatricesType::ShapeMatrices>>
-initShapeMatrices(MeshLib::Element const& e, bool is_axially_symmetric,
-                  IntegrationMethod const& integration_method)
+computeShapeMatrices(MeshLib::Element const& e, bool const is_axially_symmetric,
+                     PointContainer const& points)
 {
     std::vector<
         typename ShapeMatricesType::ShapeMatrices,
@@ -32,22 +32,41 @@ initShapeMatrices(MeshLib::Element const& e, bool is_axially_symmetric,
     auto const fe =
         createIsoparametricFiniteElement<ShapeFunction, ShapeMatricesType>(e);
 
-    unsigned const n_integration_points =
-        integration_method.getNumberOfPoints();
-
-    shape_matrices.reserve(n_integration_points);
-    for (unsigned ip = 0; ip < n_integration_points; ++ip)
+    shape_matrices.reserve(points.size());
+    for (auto const& p : points)
     {
         shape_matrices.emplace_back(ShapeFunction::DIM, GlobalDim,
                                     ShapeFunction::NPOINTS);
-        fe.computeShapeFunctions(
-            integration_method.getWeightedPoint(ip).getCoords(),
-            shape_matrices[ip], GlobalDim, is_axially_symmetric);
+        fe.template computeShapeFunctions<SelectedShapeMatrixType>(
+            p.getCoords(), shape_matrices.back(), GlobalDim,
+            is_axially_symmetric);
     }
 
     return shape_matrices;
 }
 
+template <typename ShapeFunction, typename ShapeMatricesType, int GlobalDim,
+          ShapeMatrixType SelectedShapeMatrixType = ShapeMatrixType::ALL,
+          typename IntegrationMethod>
+std::vector<typename ShapeMatricesType::ShapeMatrices,
+            Eigen::aligned_allocator<typename ShapeMatricesType::ShapeMatrices>>
+initShapeMatrices(MeshLib::Element const& e, bool const is_axially_symmetric,
+                  IntegrationMethod const& integration_method)
+{
+    int const n_integration_points = integration_method.getNumberOfPoints();
+
+    std::vector<typename IntegrationMethod::WeightedPoint> points;
+    points.reserve(n_integration_points);
+    for (int ip = 0; ip < n_integration_points; ++ip)
+    {
+        points.push_back(integration_method.getWeightedPoint(ip));
+    }
+
+    return computeShapeMatrices<ShapeFunction, ShapeMatricesType, GlobalDim,
+                                SelectedShapeMatrixType>(
+        e, is_axially_symmetric, points);
+}
+
 template <typename ShapeFunction, typename ShapeMatricesType>
 double interpolateXCoordinate(
     MeshLib::Element const& e,
diff --git a/NumLib/Fem/Integration/IntegrationGaussLegendrePrism.h b/NumLib/Fem/Integration/IntegrationGaussLegendrePrism.h
index e87e50baead3275754c299f7e6b65b84492e4dca..9dc77292531b5259f61c7201dcc31076ac447328 100644
--- a/NumLib/Fem/Integration/IntegrationGaussLegendrePrism.h
+++ b/NumLib/Fem/Integration/IntegrationGaussLegendrePrism.h
@@ -21,9 +21,9 @@ namespace NumLib
  */
 class IntegrationGaussLegendrePrism
 {
+public:
     using WeightedPoint = MathLib::TemplateWeightedPoint<double, double, 3>;
 
-public:
     /**
      * Construct this object with the given integration order
      *
diff --git a/NumLib/Fem/Integration/IntegrationGaussLegendrePyramid.h b/NumLib/Fem/Integration/IntegrationGaussLegendrePyramid.h
index f02fe46e7d853b8d6e9f60c497a2e6f9b1d2d2a3..4e3aee5e1f0791ae3b421bd627e2366eff01986e 100644
--- a/NumLib/Fem/Integration/IntegrationGaussLegendrePyramid.h
+++ b/NumLib/Fem/Integration/IntegrationGaussLegendrePyramid.h
@@ -20,9 +20,9 @@ namespace NumLib
  */
 class IntegrationGaussLegendrePyramid
 {
+public:
     using WeightedPoint = MathLib::TemplateWeightedPoint<double, double, 3>;
 
-public:
     /**
      * Construct this object with the given integration order
      *
diff --git a/NumLib/Fem/Integration/IntegrationGaussLegendreRegular.h b/NumLib/Fem/Integration/IntegrationGaussLegendreRegular.h
index ab9c7e26bad2a4859c04ee43fff14ade5404b960..1f3f55991b9244624ab1f16a0679ee827578b789 100644
--- a/NumLib/Fem/Integration/IntegrationGaussLegendreRegular.h
+++ b/NumLib/Fem/Integration/IntegrationGaussLegendreRegular.h
@@ -27,10 +27,10 @@ namespace NumLib
 template <unsigned N_DIM>
 class IntegrationGaussLegendreRegular
 {
+public:
     using WeightedPoint =
         typename MathLib::TemplateWeightedPoint<double, double, N_DIM>;
 
-public:
     /// Create IntegrationGaussLegendreRegular of the given Gauss-Legendre
     /// integration order.
     ///
diff --git a/NumLib/Fem/Integration/IntegrationGaussLegendreTet.h b/NumLib/Fem/Integration/IntegrationGaussLegendreTet.h
index 2fd50e2457bdda409b7c7e6ff278efc882133bd4..a797e4e7cd70f87dbe88c174112ec18ff4c1ff84 100644
--- a/NumLib/Fem/Integration/IntegrationGaussLegendreTet.h
+++ b/NumLib/Fem/Integration/IntegrationGaussLegendreTet.h
@@ -20,9 +20,9 @@ namespace NumLib
  */
 class IntegrationGaussLegendreTet
 {
+public:
     using WeightedPoint = MathLib::TemplateWeightedPoint<double, double, 3>;
 
-public:
     /**
      * Construct this object with the given integration order
      *
diff --git a/NumLib/Fem/Integration/IntegrationGaussLegendreTri.h b/NumLib/Fem/Integration/IntegrationGaussLegendreTri.h
index f472b1430b7ad87d6d5135e15af02cfcd898e075..3ab76037dceb181b5662ff61b78a5317874c997a 100644
--- a/NumLib/Fem/Integration/IntegrationGaussLegendreTri.h
+++ b/NumLib/Fem/Integration/IntegrationGaussLegendreTri.h
@@ -35,9 +35,9 @@ namespace NumLib
  */
 class IntegrationGaussLegendreTri
 {
+public:
     using WeightedPoint = MathLib::TemplateWeightedPoint<double, double, 2>;
 
-public:
     /**
      * Construct this object with the given integration order
      *
diff --git a/NumLib/Fem/Integration/IntegrationPoint.h b/NumLib/Fem/Integration/IntegrationPoint.h
index fdb72ee33752047b609a03bf8c55ec209a523214..a6cd0f08fbb0f3677ac57de6fcaec99dabc9a882 100644
--- a/NumLib/Fem/Integration/IntegrationPoint.h
+++ b/NumLib/Fem/Integration/IntegrationPoint.h
@@ -20,9 +20,9 @@ namespace NumLib
 /// It is only needed to satisfy the common integration rule concepts.
 class IntegrationPoint
 {
+public:
     using WeightedPoint = MathLib::TemplateWeightedPoint<double, double, 1>;
 
-public:
     /// IntegrationPoint constructor for given order.
     explicit IntegrationPoint(unsigned /* order */)
     {
diff --git a/NumLib/Function/Interpolation.h b/NumLib/Function/Interpolation.h
index 06408b1939bd3d39c3aeef0949efdd71b3fe9eb4..0d6bb7b6ae661a1e313062e8cce6a358e07bf904 100644
--- a/NumLib/Function/Interpolation.h
+++ b/NumLib/Function/Interpolation.h
@@ -15,6 +15,7 @@
 
 #include "NumLib/Fem/CoordinatesMapping/NaturalNodeCoordinates.h"
 #include "NumLib/Fem/FiniteElement/TemplateIsoparametric.h"
+#include "NumLib/Fem/InitShapeMatrices.h"
 
 namespace NumLib
 {
@@ -108,11 +109,7 @@ void interpolateToHigherOrderNodes(
 
     using SF = LowerOrderShapeFunction;
     using ShapeMatricesType = ShapeMatrixPolicyType<SF, GlobalDim>;
-    using ShapeMatrices = typename ShapeMatricesType::ShapeMatrices;
 
-    auto const fe =
-        NumLib::createIsoparametricFiniteElement<SF, ShapeMatricesType>(
-            element);
     int const number_base_nodes = element.getNumberOfBaseNodes();
     int const number_all_nodes = element.getNumberOfNodes();
 
@@ -123,21 +120,32 @@ void interpolateToHigherOrderNodes(
         interpolated_values_global_vector[global_index] = node_values[n];
     }
 
-    // Shape matrices storage reused in the interpolation loop.
-    ShapeMatrices shape_matrices{SF::DIM, GlobalDim, SF::NPOINTS};
-
+    //
     // Interpolate values for higher order nodes.
-    for (int n = number_base_nodes; n < number_all_nodes; ++n)
+    //
+
+    int const number_higher_order_nodes = number_all_nodes - number_base_nodes;
+    std::vector<MathLib::Point3d> higher_order_nodes;
+    higher_order_nodes.reserve(number_higher_order_nodes);
+    for (int n = 0; n < number_higher_order_nodes; ++n)
     {
-        // Evaluated at higher order nodes' coordinates.
-        fe.template computeShapeFunctions<ShapeMatrixType::N>(
-            NaturalCoordinates<HigherOrderMeshElementType>::coordinates[n]
-                .data(),
-            shape_matrices, GlobalDim, is_axially_symmetric);
+        higher_order_nodes.emplace_back(
+            NaturalCoordinates<HigherOrderMeshElementType>::coordinates
+                [number_base_nodes + n]);
+    }
 
-        std::size_t const global_index = element.getNodeIndex(n);
+    // Shape matrices evaluated at higher order nodes' coordinates.
+    auto const shape_matrices =
+        computeShapeMatrices<SF, ShapeMatricesType, GlobalDim,
+                             ShapeMatrixType::N>(element, is_axially_symmetric,
+                                                 higher_order_nodes);
+
+    for (int n = 0; n < number_higher_order_nodes; ++n)
+    {
+        std::size_t const global_index =
+            element.getNodeIndex(number_base_nodes + n);
         interpolated_values_global_vector[global_index] =
-            shape_matrices.N * node_values;
+            shape_matrices[n].N * node_values;
     }
 }
 
diff --git a/ProcessLib/ComponentTransport/ComponentTransportFEM.h b/ProcessLib/ComponentTransport/ComponentTransportFEM.h
index 2c3b5f5d5162e0dc9f9f3f8f4489271502dcdf8b..235e8d0f147e63fe9538428492eddeed434d9ddb 100644
--- a/ProcessLib/ComponentTransport/ComponentTransportFEM.h
+++ b/ProcessLib/ComponentTransport/ComponentTransportFEM.h
@@ -854,21 +854,14 @@ public:
         auto const local_C = Eigen::Map<const NodalVectorType>(
             &local_x[first_concentration_index], concentration_size);
 
-        // eval shape matrices at given point
-        auto const shape_matrices = [&]() {
-            auto const fe = NumLib::createIsoparametricFiniteElement<
-                ShapeFunction, ShapeMatricesType>(_element);
-
-            typename ShapeMatricesType::ShapeMatrices sm(
-                ShapeFunction::DIM, GlobalDim, ShapeFunction::NPOINTS);
-
-            // Note: Axial symmetry is set to false here, because we only need
-            // dNdx here, which is not affected by axial symmetry.
-            fe.template computeShapeFunctions<NumLib::ShapeMatrixType::DNDX>(
-                pnt_local_coords.getCoords(), sm, GlobalDim, false);
-
-            return sm;
-        }();
+        // Eval shape matrices at given point
+        // Note: Axial symmetry is set to false here, because we only need dNdx
+        // here, which is not affected by axial symmetry.
+        auto const shape_matrices =
+            NumLib::computeShapeMatrices<ShapeFunction, ShapeMatricesType,
+                                         GlobalDim>(
+                _element, false /*is_axially_symmetric*/,
+                std::array{pnt_local_coords})[0];
 
         ParameterLib::SpatialPosition pos;
         pos.setElementID(_element.getID());
diff --git a/ProcessLib/HT/HTFEM.h b/ProcessLib/HT/HTFEM.h
index 701d448e400a11492301f1a26807013def616d8b..643a114e91772a6fc6e8a40dbd86d06198671961 100644
--- a/ProcessLib/HT/HTFEM.h
+++ b/ProcessLib/HT/HTFEM.h
@@ -95,17 +95,14 @@ public:
                             double const t,
                             std::vector<double> const& local_x) const override
     {
-        // eval dNdx and invJ at given point
-        auto const fe = NumLib::createIsoparametricFiniteElement<
-            ShapeFunction, ShapeMatricesType>(_element);
-
-        typename ShapeMatricesType::ShapeMatrices shape_matrices(
-            ShapeFunction::DIM, GlobalDim, ShapeFunction::NPOINTS);
-
+        // Eval shape matrices at given point
         // Note: Axial symmetry is set to false here, because we only need dNdx
         // here, which is not affected by axial symmetry.
-        fe.computeShapeFunctions(pnt_local_coords.getCoords(), shape_matrices,
-                                 GlobalDim, false);
+        auto const shape_matrices =
+            NumLib::computeShapeMatrices<ShapeFunction, ShapeMatricesType,
+                                         GlobalDim>(
+                _element, false /*is_axially_symmetric*/,
+                std::array{pnt_local_coords})[0];
 
         ParameterLib::SpatialPosition pos;
         pos.setElementID(this->_element.getID());
diff --git a/ProcessLib/LiquidFlow/LiquidFlowLocalAssembler-impl.h b/ProcessLib/LiquidFlow/LiquidFlowLocalAssembler-impl.h
index 5b4922097f54afd8b57e1aaa7cd15fa4c07471c9..56e483bea270400306dfe5fc1ba3ad5a837e0324 100644
--- a/ProcessLib/LiquidFlow/LiquidFlowLocalAssembler-impl.h
+++ b/ProcessLib/LiquidFlow/LiquidFlowLocalAssembler-impl.h
@@ -76,18 +76,13 @@ LiquidFlowLocalAssembler<ShapeFunction, IntegrationMethod, GlobalDim>::getFlux(
     // extension of getFlux interface
     double const dt = std::numeric_limits<double>::quiet_NaN();
 
-    // eval dNdx and invJ at p
-    auto const fe =
-        NumLib::createIsoparametricFiniteElement<ShapeFunction,
-                                                 ShapeMatricesType>(_element);
-
-    typename ShapeMatricesType::ShapeMatrices shape_matrices(
-        ShapeFunction::DIM, GlobalDim, ShapeFunction::NPOINTS);
-
     // Note: Axial symmetry is set to false here, because we only need dNdx
     // here, which is not affected by axial symmetry.
-    fe.computeShapeFunctions(p_local_coords.getCoords(), shape_matrices,
-                             GlobalDim, false);
+    auto const shape_matrices =
+        NumLib::computeShapeMatrices<ShapeFunction, ShapeMatricesType,
+                                     GlobalDim>(_element,
+                                                false /*is_axially_symmetric*/,
+                                                std::array{p_local_coords})[0];
 
     // create pos object to access the correct media property
     ParameterLib::SpatialPosition pos;
diff --git a/ProcessLib/SteadyStateDiffusion/SteadyStateDiffusionFEM.h b/ProcessLib/SteadyStateDiffusion/SteadyStateDiffusionFEM.h
index 2bcbabbc3b88d13422764267b7118cba6d1b5e2f..4cb5664408e09044fd62e110099a3d2df368942f 100644
--- a/ProcessLib/SteadyStateDiffusion/SteadyStateDiffusionFEM.h
+++ b/ProcessLib/SteadyStateDiffusion/SteadyStateDiffusionFEM.h
@@ -136,17 +136,14 @@ public:
         // extension of getFlux interface
         double const dt = std::numeric_limits<double>::quiet_NaN();
 
-        // eval dNdx and invJ at p
-        auto const fe = NumLib::createIsoparametricFiniteElement<
-            ShapeFunction, ShapeMatricesType>(_element);
-
-        typename ShapeMatricesType::ShapeMatrices shape_matrices(
-            ShapeFunction::DIM, GlobalDim, ShapeFunction::NPOINTS);
-
+        // Eval shape matrices at given point
         // Note: Axial symmetry is set to false here, because we only need dNdx
         // here, which is not affected by axial symmetry.
-        fe.computeShapeFunctions(p_local_coords.getCoords(), shape_matrices,
-                                 GlobalDim, false);
+        auto const shape_matrices =
+            NumLib::computeShapeMatrices<ShapeFunction, ShapeMatricesType,
+                                         GlobalDim>(
+                _element, false /*is_axially_symmetric*/,
+                std::array{p_local_coords})[0];
 
         // fetch hydraulic conductivity
         ParameterLib::SpatialPosition pos;
diff --git a/Tests/NumLib/NaturalNodeCoordinates.cpp b/Tests/NumLib/NaturalNodeCoordinates.cpp
index 6166382d3470cf54d62b90fd5aeb922e714a4f11..93d44ad9310ce578c6cfb922ffb761d9f7543442 100644
--- a/Tests/NumLib/NaturalNodeCoordinates.cpp
+++ b/Tests/NumLib/NaturalNodeCoordinates.cpp
@@ -7,15 +7,16 @@
  *
  */
 
+#include "NumLib/Fem/CoordinatesMapping/NaturalNodeCoordinates.h"
+
 #include <gtest/gtest.h>
 
 #include <vector>
 
 #include "MeshLib/ElementCoordinatesMappingLocal.h"
-
-#include "NumLib/Fem/CoordinatesMapping/NaturalNodeCoordinates.h"
 #include "NumLib/Fem/CoordinatesMapping/ShapeMatrices.h"
 #include "NumLib/Fem/FiniteElement/C0IsoparametricElements.h"
+#include "NumLib/Fem/InitShapeMatrices.h"
 #include "NumLib/Fem/Integration/GaussLegendreIntegrationPolicy.h"
 #include "NumLib/Fem/ShapeMatrixPolicy.h"
 
@@ -25,8 +26,6 @@ template <typename ShapeFunction, int GlobalDim>
 bool test(MeshLib::Element const& element)
 {
     using ShapeMatricesType = ShapeMatrixPolicyType<ShapeFunction, GlobalDim>;
-    using FemType =
-        NumLib::TemplateIsoparametric<ShapeFunction, ShapeMatricesType>;
 
     // Test if the cast is possible.
     bool const dynamic_cast_failed =
@@ -37,29 +36,31 @@ bool test(MeshLib::Element const& element)
     {
         return false;
     }
-    FemType fe{
-        static_cast<typename ShapeFunction::MeshElement const&>(element)};
-
-    bool result = true;
 
     // For each node evaluate the shape functions at natural coordinates and
     // test if only the corresponding shape function has value 1 and all others
     // must return 0.
     int const number_nodes = element.getNumberOfNodes();
+    std::vector<MathLib::Point3d> points;
+    points.reserve(number_nodes);
     for (int n = 0; n < number_nodes; ++n)
     {
         // Evaluate shape matrices at natural coordinates.
-        typename ShapeMatricesType::ShapeMatrices shape_matrices{
-            ShapeFunction::DIM, GlobalDim, ShapeFunction::NPOINTS};
         // Compute only N, because for pyramid the detJ becomes zero at the
         // apex, and we only use N in the following test anyway.
-        fe.template computeShapeFunctions<NumLib::ShapeMatrixType::N>(
+        points.emplace_back(
             NumLib::NaturalCoordinates<
-                typename ShapeFunction::MeshElement>::coordinates[n]
-                .data(),
-            shape_matrices, GlobalDim, false /* axial symmetry */);
+                typename ShapeFunction::MeshElement>::coordinates[n]);
+    }
+    auto const shape_matrices =
+        NumLib::computeShapeMatrices<ShapeFunction, ShapeMatricesType,
+                                     GlobalDim, NumLib::ShapeMatrixType::N>(
+            element, false /*is_axially_symmetric*/, points);
 
-        auto const& N = shape_matrices.N;
+    bool result = true;
+    for (int n = 0; n < number_nodes; ++n)
+    {
+        auto const& N = shape_matrices[n].N;
         for (int p = 0; p < static_cast<int>(ShapeFunction::NPOINTS); ++p)
         {
             if (p == n)
diff --git a/Tests/NumLib/TestFe.cpp b/Tests/NumLib/TestFe.cpp
index 395f0b369508a3ae99e9bf43797a18baa08baf3b..d7b935057960c2aff0060a4f31686e5d37067578 100644
--- a/Tests/NumLib/TestFe.cpp
+++ b/Tests/NumLib/TestFe.cpp
@@ -265,22 +265,22 @@ TYPED_TEST(NumLibFemIsoTest, CheckMassLaplaceMatrices)
 TYPED_TEST(NumLibFemIsoTest, CheckGaussLegendreIntegrationLevel)
 {
     // Refer to typedefs in the fixture
-    using FeType = typename TestFixture::FeType;
     using NodalMatrix = typename TestFixture::NodalMatrix;
-    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
 
-    // create a finite element object with gauss quadrature level 2
-    FeType fe(*this->mesh_element);
+    auto shape_matrices =
+        NumLib::initShapeMatrices<typename TestFixture::ShapeFunction,
+                                  typename TestFixture::ShapeMatrixTypes,
+                                  TestFixture::global_dim>(
+            *this->mesh_element, false /*is_axially_symmetric*/,
+            this->integration_method);
 
     // evaluate a mass matrix
     NodalMatrix M(this->e_nnodes, this->e_nnodes);
     M.setZero();
-    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);
     ASSERT_EQ(TestFixture::n_sample_pt_order2, this->integration_method.getNumberOfPoints());
     for (std::size_t i=0; i < this->integration_method.getNumberOfPoints(); i++) {
-        shape.setZero();
+        auto const& shape = shape_matrices[i];
         auto wp = this->integration_method.getWeightedPoint(i);
-        fe.computeShapeFunctions(wp.getCoords(), shape);
         M.noalias() += shape.N * shape.N.transpose() * shape.detJ * wp.getWeight();
     }
     //std::cout << "M=\n" << M << std::endl;
@@ -290,10 +290,17 @@ TYPED_TEST(NumLibFemIsoTest, CheckGaussLegendreIntegrationLevel)
     this->integration_method.setIntegrationOrder(3);
     M *= .0;
     ASSERT_EQ(TestFixture::n_sample_pt_order3, this->integration_method.getNumberOfPoints());
+
+    shape_matrices =
+        NumLib::initShapeMatrices<typename TestFixture::ShapeFunction,
+                                  typename TestFixture::ShapeMatrixTypes,
+                                  TestFixture::global_dim>(
+            *this->mesh_element, false /*is_axially_symmetric*/,
+            this->integration_method);
+
     for (std::size_t i=0; i < this->integration_method.getNumberOfPoints(); i++) {
-        shape.setZero();
+        auto const& shape = shape_matrices[i];
         auto wp = this->integration_method.getWeightedPoint(i);
-        fe.computeShapeFunctions(wp.getCoords(), shape);
         M.noalias() += shape.N * shape.N.transpose() * shape.detJ * wp.getWeight();
     }
     //std::cout << "M=\n" << M << std::endl;
diff --git a/Tests/NumLib/TestGradShapeFunction.cpp b/Tests/NumLib/TestGradShapeFunction.cpp
index d8457ecc3febb9d77c326c5c3d182931a4ef6925..daaf40b3f50f164f284399740875e9ff7f20c9b1 100644
--- a/Tests/NumLib/TestGradShapeFunction.cpp
+++ b/Tests/NumLib/TestGradShapeFunction.cpp
@@ -14,36 +14,33 @@
 
 #include <gtest/gtest.h>
 
-#include <vector>
-#include <cmath>
-
 #include <Eigen/Eigen>
+#include <cmath>
+#include <vector>
 
-#include "MeshLib/ElementCoordinatesMappingLocal.h"
-#include "MeshLib/CoordinateSystem.h"
-
-#include "NumLib/Fem/CoordinatesMapping/ShapeMatrices.h"
-#include "NumLib/Fem/FiniteElement/C0IsoparametricElements.h"
-#include "NumLib/Fem/Integration/GaussLegendreIntegrationPolicy.h"
-#include "NumLib/Fem/ShapeMatrixPolicy.h"
-
+#include "FeTestData/TestFeHEX20.h"
+#include "FeTestData/TestFeHEX8.h"
 #include "FeTestData/TestFeLINE2.h"
 #include "FeTestData/TestFeLINE2Y.h"
 #include "FeTestData/TestFeLINE3.h"
-#include "FeTestData/TestFeTRI3.h"
-#include "FeTestData/TestFeTRI6.h"
+#include "FeTestData/TestFePRISM15.h"
+#include "FeTestData/TestFePRISM6.h"
+#include "FeTestData/TestFePYRA13.h"
+#include "FeTestData/TestFePYRA5.h"
 #include "FeTestData/TestFeQUAD4.h"
 #include "FeTestData/TestFeQUAD8.h"
 #include "FeTestData/TestFeQUAD9.h"
-#include "FeTestData/TestFeHEX8.h"
-#include "FeTestData/TestFeHEX20.h"
-#include "FeTestData/TestFeTET4.h"
 #include "FeTestData/TestFeTET10.h"
-#include "FeTestData/TestFePRISM6.h"
-#include "FeTestData/TestFePRISM15.h"
-#include "FeTestData/TestFePYRA5.h"
-#include "FeTestData/TestFePYRA13.h"
-
+#include "FeTestData/TestFeTET4.h"
+#include "FeTestData/TestFeTRI3.h"
+#include "FeTestData/TestFeTRI6.h"
+#include "MeshLib/CoordinateSystem.h"
+#include "MeshLib/ElementCoordinatesMappingLocal.h"
+#include "NumLib/Fem/CoordinatesMapping/ShapeMatrices.h"
+#include "NumLib/Fem/FiniteElement/C0IsoparametricElements.h"
+#include "NumLib/Fem/InitShapeMatrices.h"
+#include "NumLib/Fem/Integration/GaussLegendreIntegrationPolicy.h"
+#include "NumLib/Fem/ShapeMatrixPolicy.h"
 #include "Tests/TestTools.h"
 
 using namespace NumLib;
@@ -110,11 +107,6 @@ public:
     // Finite element type
     template <typename X>
     using ShapeMatrixPolicy = typename T::template ShapeMatrixPolicy<X>;
-    using FeType =
-        typename TestFeType::template FeType<ShapeMatrixPolicy>::type;
-
-    // Shape matrix data type
-    using ShapeMatricesType = typename ShapeMatrixTypes::ShapeMatrices;
     using MeshElementType = typename TestFeType::MeshElementType;
 
     static const unsigned dim = TestFeType::dim;
@@ -182,23 +174,21 @@ TYPED_TEST_CASE(GradShapeFunctionTest, TestTypes);
 TYPED_TEST(GradShapeFunctionTest,
            CheckGradShapeFunctionByComputingElementVolume)
 {
-    // Refer to typedefs in the fixture
-    using FeType = typename TestFixture::FeType;
-    using ShapeMatricesType = typename TestFixture::ShapeMatricesType;
-
-    // create a finite element object
-    FeType fe(*this->mesh_element);
+    auto const shape_matrices =
+        NumLib::initShapeMatrices<typename TestFixture::ShapeFunction,
+                                  typename TestFixture::ShapeMatrixTypes,
+                                  TestFixture::global_dim,
+                                  ShapeMatrixType::N_J>(
+            *this->mesh_element, false /*is_axially_symmetric*/,
+            this->integration_method);
 
     // Compute element volume numerically as V_e = int {1}dA_e
     double computed_element_volume = 0.;
-    ShapeMatricesType shape(this->dim, this->global_dim, this->e_nnodes);
     for (std::size_t i = 0; i < this->integration_method.getNumberOfPoints();
          i++)
     {
-        shape.setZero();
+        auto const& shape = shape_matrices[i];
         auto wp = this->integration_method.getWeightedPoint(i);
-        fe.template computeShapeFunctions<ShapeMatrixType::N_J>(
-            wp.getCoords(), shape, this->global_dim, false);
         computed_element_volume += shape.detJ * wp.getWeight();
     }