diff --git a/ProcessLib/BoundaryCondition/ConstraintDirichletBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/ConstraintDirichletBoundaryCondition.cpp
index 406c38c7e3abf8ab6ce3eafdec4ac14cc97aa132..8f18986a8a928cdd538eb546dba30cc2b78fe1e0 100644
--- a/ProcessLib/BoundaryCondition/ConstraintDirichletBoundaryCondition.cpp
+++ b/ProcessLib/BoundaryCondition/ConstraintDirichletBoundaryCondition.cpp
@@ -17,7 +17,7 @@
 #include "MeshLib/MeshSearch/NodeSearch.h"  // for getUniqueNodes
 #include "MeshLib/Node.h"
 #include "ParameterLib/Utils.h"
-#include "ProcessLib/Utils/CreateLocalAssemblers.h"
+#include "ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h"
 
 namespace ProcessLib
 {
@@ -100,7 +100,7 @@ ConstraintDirichletBoundaryCondition::ConstraintDirichletBoundaryCondition(
 
     const int shape_function_order = 1;
 
-    ProcessLib::createLocalAssemblers<
+    BoundaryConditionOrSourceTerm::createLocalAssemblers<
         ConstraintDirichletBoundaryConditionLocalAssembler>(
         _bulk_mesh.getDimension(), _bc_mesh.getElements(), *_dof_table_boundary,
         shape_function_order, _local_assemblers, _bc_mesh.isAxiallySymmetric(),
diff --git a/ProcessLib/BoundaryCondition/GenericNaturalBoundaryCondition-impl.h b/ProcessLib/BoundaryCondition/GenericNaturalBoundaryCondition-impl.h
index 0c91154d7c2f9a6d7de8e3e456c52c474642dfaf..dfd07225c6f4d23179df06a81cdd489a44fb48d9 100644
--- a/ProcessLib/BoundaryCondition/GenericNaturalBoundaryCondition-impl.h
+++ b/ProcessLib/BoundaryCondition/GenericNaturalBoundaryCondition-impl.h
@@ -9,7 +9,7 @@
  */
 
 #include "GenericNaturalBoundaryConditionLocalAssembler.h"
-#include "ProcessLib/Utils/CreateLocalAssemblers.h"
+#include "ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h"
 
 namespace ProcessLib
 {
@@ -65,7 +65,8 @@ GenericNaturalBoundaryCondition<BoundaryConditionData,
     _dof_table_boundary.reset(dof_table_bulk.deriveBoundaryConstrainedMap(
         variable_id, {component_id}, std::move(bc_mesh_subset)));
 
-    createLocalAssemblers<LocalAssemblerImplementation>(
+    BoundaryConditionOrSourceTerm::createLocalAssemblers<
+        LocalAssemblerImplementation>(
         global_dim, _bc_mesh.getElements(), *_dof_table_boundary,
         shapefunction_order, _local_assemblers, _bc_mesh.isAxiallySymmetric(),
         integration_order, _data);
diff --git a/ProcessLib/BoundaryCondition/NormalTractionBoundaryCondition-impl.h b/ProcessLib/BoundaryCondition/NormalTractionBoundaryCondition-impl.h
index 28706ab75f2bb66b4c686ca9134849bd4bdd2d83..460fdc8d2f70957e62504e8c28ca08d7431d6665 100644
--- a/ProcessLib/BoundaryCondition/NormalTractionBoundaryCondition-impl.h
+++ b/ProcessLib/BoundaryCondition/NormalTractionBoundaryCondition-impl.h
@@ -13,10 +13,9 @@
 #include <numeric>
 
 #include "MeshLib/MeshSearch/NodeSearch.h"
-#include "ParameterLib/Utils.h"
-#include "ProcessLib/Utils/CreateLocalAssemblers.h"
-
 #include "NormalTractionBoundaryConditionLocalAssembler.h"
+#include "ParameterLib/Utils.h"
+#include "ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h"
 
 namespace ProcessLib
 {
@@ -52,7 +51,8 @@ NormalTractionBoundaryCondition<GlobalDim, LocalAssemblerImplementation>::
     _dof_table_boundary.reset(dof_table_bulk.deriveBoundaryConstrainedMap(
         variable_id, component_ids, std::move(bc_mesh_subset)));
 
-    createLocalAssemblers<GlobalDim, LocalAssemblerImplementation>(
+    BoundaryConditionOrSourceTerm::detail::createLocalAssemblers<
+        GlobalDim, LocalAssemblerImplementation>(
         *_dof_table_boundary, shapefunction_order, _bc_mesh.getElements(),
         _local_assemblers, _bc_mesh.isAxiallySymmetric(), _integration_order,
         _pressure);
diff --git a/ProcessLib/BoundaryCondition/Python/PythonBoundaryCondition.cpp b/ProcessLib/BoundaryCondition/Python/PythonBoundaryCondition.cpp
index 1ba9c7ecad38e2ce295978192dcc288fe9d47f0c..deed7068845ef7cdd7c238123797804d96588748 100644
--- a/ProcessLib/BoundaryCondition/Python/PythonBoundaryCondition.cpp
+++ b/ProcessLib/BoundaryCondition/Python/PythonBoundaryCondition.cpp
@@ -16,7 +16,7 @@
 
 #include "BaseLib/ConfigTree.h"
 #include "MeshLib/MeshSearch/NodeSearch.h"
-#include "ProcessLib/Utils/CreateLocalAssemblers.h"
+#include "ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h"
 #include "PythonBoundaryConditionLocalAssembler.h"
 
 namespace
@@ -75,7 +75,8 @@ PythonBoundaryCondition::PythonBoundaryCondition(
     _dof_table_boundary = _bc_data.dof_table_bulk.deriveBoundaryConstrainedMap(
         std::move(bc_mesh_subset));
 
-    createLocalAssemblers<PythonBoundaryConditionLocalAssembler>(
+    BoundaryConditionOrSourceTerm::createLocalAssemblers<
+        PythonBoundaryConditionLocalAssembler>(
         global_dim, _bc_data.boundary_mesh.getElements(), *_dof_table_boundary,
         shapefunction_order, _local_assemblers,
         _bc_data.boundary_mesh.isAxiallySymmetric(), integration_order,
diff --git a/ProcessLib/CMakeLists.txt b/ProcessLib/CMakeLists.txt
index 2c417a1d6d8e1aaa246deb9b984e299074daec8a..f1b2e308d5da780a973698c7bfa3bc245e2caea9 100644
--- a/ProcessLib/CMakeLists.txt
+++ b/ProcessLib/CMakeLists.txt
@@ -17,6 +17,7 @@ append_source_files(SOURCES SurfaceFlux)
 append_source_files(SOURCES Output)
 append_source_files(SOURCES SourceTerms)
 append_source_files(SOURCES Utils)
+append_source_files(SOURCES Utils/ForBoundaryConditionOrSourceTerm)
 
 ogs_add_library(ProcessLib ${SOURCES})
 
diff --git a/ProcessLib/SourceTerms/Python/PythonSourceTerm.cpp b/ProcessLib/SourceTerms/Python/PythonSourceTerm.cpp
index 35b4bbc35fa7ba89d60e52854a07c2f097a108fb..12cb687bd2087dda6850bbbdff03c77f8964c5ef 100644
--- a/ProcessLib/SourceTerms/Python/PythonSourceTerm.cpp
+++ b/ProcessLib/SourceTerms/Python/PythonSourceTerm.cpp
@@ -16,7 +16,7 @@
 
 #include "MeshLib/MeshSearch/NodeSearch.h"
 #include "NumLib/DOF/LocalToGlobalIndexMap.h"
-#include "ProcessLib/Utils/CreateLocalAssemblers.h"
+#include "ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h"
 #include "PythonSourceTermLocalAssembler.h"
 
 namespace
@@ -71,7 +71,8 @@ PythonSourceTerm::PythonSourceTerm(
       _source_term_data(std::move(source_term_data)),
       _flush_stdout(flush_stdout)
 {
-    createLocalAssemblers<PythonSourceTermLocalAssembler>(
+    BoundaryConditionOrSourceTerm::createLocalAssemblers<
+        PythonSourceTermLocalAssembler>(
         global_dim, _source_term_data.source_term_mesh.getElements(),
         *_source_term_dof_table, shapefunction_order, _local_assemblers,
         _source_term_data.source_term_mesh.isAxiallySymmetric(),
diff --git a/ProcessLib/SourceTerms/VolumetricSourceTerm.cpp b/ProcessLib/SourceTerms/VolumetricSourceTerm.cpp
index 6901d7537c80e74beacb3b324772d3c2e847b254..62be8d56432bdb5a0d6684e8067e50cd633a9348 100644
--- a/ProcessLib/SourceTerms/VolumetricSourceTerm.cpp
+++ b/ProcessLib/SourceTerms/VolumetricSourceTerm.cpp
@@ -10,7 +10,7 @@
 
 #include "VolumetricSourceTerm.h"
 
-#include "ProcessLib/Utils/CreateLocalAssemblers.h"
+#include "ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h"
 
 namespace ProcessLib
 {
@@ -22,7 +22,8 @@ VolumetricSourceTerm::VolumetricSourceTerm(
     : SourceTerm(std::move(source_term_dof_table)),
       _source_term_parameter(source_term_parameter)
 {
-    ProcessLib::createLocalAssemblers<VolumetricSourceTermLocalAssembler>(
+    BoundaryConditionOrSourceTerm::createLocalAssemblers<
+        VolumetricSourceTermLocalAssembler>(
         bulk_mesh_dimension, source_term_mesh.getElements(),
         *_source_term_dof_table, shapefunction_order, _local_assemblers,
         source_term_mesh.isAxiallySymmetric(), integration_order,
diff --git a/ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h b/ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h
new file mode 100644
index 0000000000000000000000000000000000000000..b12f7808662f9126d5b55ec30c3c6e4b4abe150d
--- /dev/null
+++ b/ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/CreateLocalAssemblers.h
@@ -0,0 +1,101 @@
+/**
+ * \file
+ * \copyright
+ * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ */
+
+#pragma once
+
+#include <vector>
+
+#include "BaseLib/Logging.h"
+#include "LocalDataInitializer.h"
+#include "NumLib/DOF/LocalToGlobalIndexMap.h"
+
+namespace ProcessLib
+{
+namespace BoundaryConditionOrSourceTerm
+{
+namespace detail
+{
+template <int GlobalDim,
+          template <typename, typename, int> class LocalAssemblerImplementation,
+          typename LocalAssemblerInterface, typename... ExtraCtorArgs>
+void createLocalAssemblers(
+    NumLib::LocalToGlobalIndexMap const& dof_table,
+    const unsigned shapefunction_order,
+    std::vector<MeshLib::Element*> const& mesh_elements,
+    std::vector<std::unique_ptr<LocalAssemblerInterface>>& local_assemblers,
+    ExtraCtorArgs&&... extra_ctor_args)
+{
+    static_assert(
+        GlobalDim == 1 || GlobalDim == 2 || GlobalDim == 3,
+        "Meshes with dimension greater than three are not supported.");
+    // Shape matrices initializer
+    using LocalDataInitializer =
+        LocalDataInitializer<LocalAssemblerInterface,
+                             LocalAssemblerImplementation, GlobalDim,
+                             ExtraCtorArgs...>;
+
+    DBUG("Create local assemblers.");
+    // Populate the vector of local assemblers.
+    local_assemblers.resize(mesh_elements.size());
+
+    LocalDataInitializer initializer(dof_table, shapefunction_order);
+
+    DBUG("Calling local assembler builder for all mesh elements.");
+    GlobalExecutor::transformDereferenced(
+        initializer, mesh_elements, local_assemblers,
+        std::forward<ExtraCtorArgs>(extra_ctor_args)...);
+}
+}  // namespace detail
+/*! Creates local assemblers for each element of the given \c mesh.
+ *
+ * \tparam LocalAssemblerImplementation the individual local assembler type
+ * \tparam LocalAssemblerInterface the general local assembler interface
+ * \tparam ExtraCtorArgs types of additional constructor arguments.
+ *         Those arguments will be passed to the constructor of
+ *         \c LocalAssemblerImplementation.
+ *
+ * The first two template parameters cannot be deduced from the arguments.
+ * Therefore they always have to be provided manually.
+ */
+template <template <typename, typename, int> class LocalAssemblerImplementation,
+          typename LocalAssemblerInterface, typename... ExtraCtorArgs>
+void createLocalAssemblers(
+    const unsigned dimension,
+    std::vector<MeshLib::Element*> const& mesh_elements,
+    NumLib::LocalToGlobalIndexMap const& dof_table,
+    const unsigned shapefunction_order,
+    std::vector<std::unique_ptr<LocalAssemblerInterface>>& local_assemblers,
+    ExtraCtorArgs&&... extra_ctor_args)
+{
+    DBUG("Create local assemblers.");
+
+    switch (dimension)
+    {
+        case 1:
+            detail::createLocalAssemblers<1, LocalAssemblerImplementation>(
+                dof_table, shapefunction_order, mesh_elements, local_assemblers,
+                std::forward<ExtraCtorArgs>(extra_ctor_args)...);
+            break;
+        case 2:
+            detail::createLocalAssemblers<2, LocalAssemblerImplementation>(
+                dof_table, shapefunction_order, mesh_elements, local_assemblers,
+                std::forward<ExtraCtorArgs>(extra_ctor_args)...);
+            break;
+        case 3:
+            detail::createLocalAssemblers<3, LocalAssemblerImplementation>(
+                dof_table, shapefunction_order, mesh_elements, local_assemblers,
+                std::forward<ExtraCtorArgs>(extra_ctor_args)...);
+            break;
+        default:
+            OGS_FATAL(
+                "Meshes with dimension greater than three are not supported.");
+    }
+}
+}  // namespace BoundaryConditionOrSourceTerm
+}  // namespace ProcessLib
diff --git a/ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/LocalDataInitializer.h b/ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/LocalDataInitializer.h
new file mode 100644
index 0000000000000000000000000000000000000000..032af2890b6b911177875cd52b2d48169a7bd6d5
--- /dev/null
+++ b/ProcessLib/Utils/ForBoundaryConditionOrSourceTerm/LocalDataInitializer.h
@@ -0,0 +1,401 @@
+/**
+ * \file
+ * \copyright
+ * Copyright (c) 2012-2021, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/project/license
+ *
+ */
+
+#pragma once
+
+#include <functional>
+#include <memory>
+#include <type_traits>
+#include <typeindex>
+#include <typeinfo>
+#include <unordered_map>
+
+#include "MeshLib/Elements/Elements.h"
+#include "NumLib/DOF/LocalToGlobalIndexMap.h"
+#include "NumLib/Fem/Integration/GaussLegendreIntegrationPolicy.h"
+
+#ifndef OGS_MAX_ELEMENT_DIM
+static_assert(false, "The macro OGS_MAX_ELEMENT_DIM is undefined.");
+#endif
+
+#ifndef OGS_MAX_ELEMENT_ORDER
+static_assert(false, "The macro OGS_MAX_ELEMENT_ORDER is undefined.");
+#endif
+
+// The following macros decide which element types will be compiled, i.e.
+// which element types will be available for use in simulations.
+
+#ifdef OGS_ENABLE_ELEMENT_SIMPLEX
+#define ENABLED_ELEMENT_TYPE_SIMPLEX 1u
+#else
+#define ENABLED_ELEMENT_TYPE_SIMPLEX 0u
+#endif
+
+#ifdef OGS_ENABLE_ELEMENT_CUBOID
+#define ENABLED_ELEMENT_TYPE_CUBOID 1u << 1
+#else
+#define ENABLED_ELEMENT_TYPE_CUBOID 0u
+#endif
+
+#ifdef OGS_ENABLE_ELEMENT_PRISM
+#define ENABLED_ELEMENT_TYPE_PRISM 1u << 2
+#else
+#define ENABLED_ELEMENT_TYPE_PRISM 0u
+#endif
+
+#ifdef OGS_ENABLE_ELEMENT_PYRAMID
+#define ENABLED_ELEMENT_TYPE_PYRAMID 1u << 3
+#else
+#define ENABLED_ELEMENT_TYPE_PYRAMID 0u
+#endif
+
+// Dependent element types.
+// Faces of tets, pyramids and prisms are triangles
+#define ENABLED_ELEMENT_TYPE_TRI                                       \
+    ((ENABLED_ELEMENT_TYPE_SIMPLEX) | (ENABLED_ELEMENT_TYPE_PYRAMID) | \
+     (ENABLED_ELEMENT_TYPE_PRISM))
+// Faces of hexes, pyramids and prisms are quads
+#define ENABLED_ELEMENT_TYPE_QUAD                                     \
+    ((ENABLED_ELEMENT_TYPE_CUBOID) | (ENABLED_ELEMENT_TYPE_PYRAMID) | \
+     (ENABLED_ELEMENT_TYPE_PRISM))
+// Faces of triangles and quads are lines
+#define ENABLED_ELEMENT_TYPE_LINE \
+    ((ENABLED_ELEMENT_TYPE_TRI) | (ENABLED_ELEMENT_TYPE_QUAD))
+
+// All enabled element types
+#define OGS_ENABLED_ELEMENTS                                          \
+    ((ENABLED_ELEMENT_TYPE_SIMPLEX) | (ENABLED_ELEMENT_TYPE_CUBOID) | \
+     (ENABLED_ELEMENT_TYPE_PYRAMID) | (ENABLED_ELEMENT_TYPE_PRISM))
+
+// Include only what is needed (Well, the conditions are not sharp).
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0
+#include "NumLib/Fem/ShapeFunction/ShapeLine2.h"
+#include "NumLib/Fem/ShapeFunction/ShapeLine3.h"
+#include "NumLib/Fem/ShapeFunction/ShapePoint1.h"
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_SIMPLEX) != 0
+#include "NumLib/Fem/ShapeFunction/ShapeTet10.h"
+#include "NumLib/Fem/ShapeFunction/ShapeTet4.h"
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_TRI) != 0
+#include "NumLib/Fem/ShapeFunction/ShapeTri3.h"
+#include "NumLib/Fem/ShapeFunction/ShapeTri6.h"
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_CUBOID) != 0
+#include "NumLib/Fem/ShapeFunction/ShapeHex20.h"
+#include "NumLib/Fem/ShapeFunction/ShapeHex8.h"
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_QUAD) != 0
+#include "NumLib/Fem/ShapeFunction/ShapeQuad4.h"
+#include "NumLib/Fem/ShapeFunction/ShapeQuad8.h"
+#include "NumLib/Fem/ShapeFunction/ShapeQuad9.h"
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PRISM) != 0
+#include "NumLib/Fem/ShapeFunction/ShapePrism15.h"
+#include "NumLib/Fem/ShapeFunction/ShapePrism6.h"
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PYRAMID) != 0
+#include "NumLib/Fem/ShapeFunction/ShapePyra13.h"
+#include "NumLib/Fem/ShapeFunction/ShapePyra5.h"
+#endif
+
+namespace ProcessLib
+{
+namespace BoundaryConditionOrSourceTerm
+{
+/// The LocalDataInitializer is a functor creating a local assembler data with
+/// corresponding to the mesh element type shape functions and calling
+/// initialization of the new local assembler data.
+/// For example for MeshLib::Quad a local assembler data with template argument
+/// NumLib::ShapeQuad4 is created.
+template <typename LocalAssemblerInterface,
+          template <typename, typename, int> class LocalAssemblerData,
+          int GlobalDim, typename... ConstructorArgs>
+class LocalDataInitializer final
+{
+public:
+    using LADataIntfPtr = std::unique_ptr<LocalAssemblerInterface>;
+
+    LocalDataInitializer(NumLib::LocalToGlobalIndexMap const& dof_table,
+                         const unsigned shapefunction_order)
+        : _dof_table(dof_table)
+    {
+        if (shapefunction_order < 1 || 2 < shapefunction_order)
+            OGS_FATAL("The given shape function order {:d} is not supported",
+                      shapefunction_order);
+
+        if (shapefunction_order == 1)
+        {
+            // /// Lines and points ///////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 0 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Point))] =
+                makeLocalAssemblerBuilder<NumLib::ShapePoint1>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 1 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Line))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeLine2>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 1 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Line3))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeLine2>();
+#endif
+
+            // /// Quads and Hexahedra ///////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_QUAD) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 2 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Quad))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeQuad4>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_CUBOID) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Hex))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeHex8>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_QUAD) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 2 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Quad8))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeQuad4>();
+            _builder[std::type_index(typeid(MeshLib::Quad9))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeQuad4>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_CUBOID) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Hex20))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeHex8>();
+#endif
+
+            // /// Simplices ////////////////////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_TRI) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 2 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Tri))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeTri3>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_SIMPLEX) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Tet))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeTet4>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_TRI) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 2 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Tri6))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeTri3>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_SIMPLEX) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Tet10))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeTet4>();
+#endif
+
+            // /// Prisms ////////////////////////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PRISM) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Prism))] =
+                makeLocalAssemblerBuilder<NumLib::ShapePrism6>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PRISM) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Prism15))] =
+                makeLocalAssemblerBuilder<NumLib::ShapePrism6>();
+#endif
+
+            // /// Pyramids //////////////////////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PYRAMID) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Pyramid))] =
+                makeLocalAssemblerBuilder<NumLib::ShapePyra5>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PYRAMID) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Pyramid13))] =
+                makeLocalAssemblerBuilder<NumLib::ShapePyra5>();
+#endif
+        }
+        else if (shapefunction_order == 2)
+        {
+// /// Lines and points ///////////////////////////////////
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 0 && OGS_MAX_ELEMENT_ORDER >= 1
+            _builder[std::type_index(typeid(MeshLib::Point))] =
+                makeLocalAssemblerBuilder<NumLib::ShapePoint1>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 1 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Line3))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeLine3>();
+#endif
+
+            // /// Quads and Hexahedra ///////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_QUAD) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 2 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Quad8))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeQuad8>();
+            _builder[std::type_index(typeid(MeshLib::Quad9))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeQuad9>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_CUBOID) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Hex20))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeHex20>();
+#endif
+
+            // /// Simplices ////////////////////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_TRI) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 2 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Tri6))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeTri6>();
+#endif
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_SIMPLEX) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Tet10))] =
+                makeLocalAssemblerBuilder<NumLib::ShapeTet10>();
+#endif
+
+            // /// Prisms ////////////////////////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PRISM) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Prism15))] =
+                makeLocalAssemblerBuilder<NumLib::ShapePrism15>();
+#endif
+
+            // /// Pyramids //////////////////////////////////////////////////
+
+#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_PYRAMID) != 0 && \
+    OGS_MAX_ELEMENT_DIM >= 3 && OGS_MAX_ELEMENT_ORDER >= 2
+            _builder[std::type_index(typeid(MeshLib::Pyramid13))] =
+                makeLocalAssemblerBuilder<NumLib::ShapePyra13>();
+#endif
+        }
+    }
+
+    /// Returns data pointer to the newly created local assembler data.
+    ///
+    /// \attention
+    /// The index \c id is not necessarily the mesh item's id. Especially when
+    /// having multiple meshes it will differ from the latter.
+    LADataIntfPtr operator()(std::size_t const id,
+                             MeshLib::Element const& mesh_item,
+                             ConstructorArgs&&... args) const
+    {
+        auto const type_idx = std::type_index(typeid(mesh_item));
+        auto const it = _builder.find(type_idx);
+
+        if (it != _builder.end())
+        {
+            auto const num_local_dof = _dof_table.getNumberOfElementDOF(id);
+            return it->second(mesh_item, num_local_dof,
+                              std::forward<ConstructorArgs>(args)...);
+        }
+        OGS_FATAL(
+            "You are trying to build a local assembler for an unknown mesh "
+            "element type ({:s})."
+            " Maybe you have disabled this mesh element type in your build "
+            "configuration.",
+            type_idx.name());
+    }
+
+private:
+    using LADataBuilder =
+        std::function<LADataIntfPtr(MeshLib::Element const& e,
+                                    std::size_t const local_matrix_size,
+                                    ConstructorArgs&&...)>;
+
+    template <typename ShapeFunction>
+    using IntegrationMethod = typename NumLib::GaussLegendreIntegrationPolicy<
+        typename ShapeFunction::MeshElement>::IntegrationMethod;
+
+    template <typename ShapeFunction>
+    using LAData =
+        LocalAssemblerData<ShapeFunction, IntegrationMethod<ShapeFunction>,
+                           GlobalDim>;
+
+    /// A helper forwarding to the correct version of makeLocalAssemblerBuilder
+    /// depending whether the global dimension is less than the shape function's
+    /// dimension or not.
+    template <typename ShapeFunction>
+    static LADataBuilder makeLocalAssemblerBuilder()
+    {
+        return makeLocalAssemblerBuilder<ShapeFunction>(
+            static_cast<std::integral_constant<
+                bool, (GlobalDim >= ShapeFunction::DIM)>*>(nullptr));
+    }
+
+    /// Mapping of element types to local assembler constructors.
+    std::unordered_map<std::type_index, LADataBuilder> _builder;
+
+    NumLib::LocalToGlobalIndexMap const& _dof_table;
+
+    // local assembler builder implementations.
+private:
+    /// Generates a function that creates a new LocalAssembler of type
+    /// LAData<ShapeFunction>. Only functions with shape function's dimension
+    /// less or equal to the global dimension are instantiated, e.g.  following
+    /// combinations of shape functions and global dimensions: (Line2, 1),
+    /// (Line2, 2), (Line2, 3), (Hex20, 3) but not (Hex20, 2) or (Hex20, 1).
+    template <typename ShapeFunction>
+    static LADataBuilder makeLocalAssemblerBuilder(std::true_type* /*unused*/)
+    {
+        return [](MeshLib::Element const& e,
+                  std::size_t const local_matrix_size,
+                  ConstructorArgs&&... args)
+        {
+            return LADataIntfPtr{new LAData<ShapeFunction>{
+                e, local_matrix_size, std::forward<ConstructorArgs>(args)...}};
+        };
+    }
+
+    /// Returns nullptr for shape functions whose dimensions are less than the
+    /// global dimension.
+    template <typename ShapeFunction>
+    static LADataBuilder makeLocalAssemblerBuilder(std::false_type* /*unused*/)
+    {
+        return nullptr;
+    }
+};
+
+}  // namespace BoundaryConditionOrSourceTerm
+}  // namespace ProcessLib
+#undef ENABLED_ELEMENT_TYPE_SIMPLEX
+#undef ENABLED_ELEMENT_TYPE_CUBOID
+#undef ENABLED_ELEMENT_TYPE_PYRAMID
+#undef ENABLED_ELEMENT_TYPE_PRISM
+#undef ENABLED_ELEMENT_TYPE_LINE
+#undef ENABLED_ELEMENT_TYPE_TRI
+#undef ENABLED_ELEMENT_TYPE_QUAD
+#undef OGS_ENABLED_ELEMENTS
diff --git a/ProcessLib/Utils/LocalDataInitializer.h b/ProcessLib/Utils/LocalDataInitializer.h
index 52a3cf317a93d8763ab9ad224b5d8214cbbd90e1..df1733e6dd2359191a0cc68b79502b2ff15f5d25 100644
--- a/ProcessLib/Utils/LocalDataInitializer.h
+++ b/ProcessLib/Utils/LocalDataInitializer.h
@@ -78,7 +78,6 @@ static_assert(false, "The macro OGS_MAX_ELEMENT_ORDER is undefined.");
 #if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0
 #include "NumLib/Fem/ShapeFunction/ShapeLine2.h"
 #include "NumLib/Fem/ShapeFunction/ShapeLine3.h"
-#include "NumLib/Fem/ShapeFunction/ShapePoint1.h"
 #endif
 
 #if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_SIMPLEX) != 0
@@ -139,11 +138,6 @@ public:
         {
 // /// Lines and points ///////////////////////////////////
 
-#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
-    OGS_MAX_ELEMENT_DIM >= 0 && OGS_MAX_ELEMENT_ORDER >= 1
-            _builder[std::type_index(typeid(MeshLib::Point))] =
-                makeLocalAssemblerBuilder<NumLib::ShapePoint1>();
-#endif
 
 #if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
     OGS_MAX_ELEMENT_DIM >= 1 && OGS_MAX_ELEMENT_ORDER >= 1
@@ -241,12 +235,6 @@ public:
         }
         else if (shapefunction_order == 2)
         {
-// /// Lines and points ///////////////////////////////////
-#if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
-    OGS_MAX_ELEMENT_DIM >= 0 && OGS_MAX_ELEMENT_ORDER >= 1
-            _builder[std::type_index(typeid(MeshLib::Point))] =
-                makeLocalAssemblerBuilder<NumLib::ShapePoint1>();
-#endif
 
 #if (OGS_ENABLED_ELEMENTS & ENABLED_ELEMENT_TYPE_LINE) != 0 && \
     OGS_MAX_ELEMENT_DIM >= 1 && OGS_MAX_ELEMENT_ORDER >= 2