diff --git a/src/scheme/VariationalSolver.cpp b/src/scheme/VariationalSolver.cpp
index 8ab8f549217fc30bb0824e312191c815df2033dc..cbd857dddb3ba467ce4675194865fe70ef4f64f0 100644
--- a/src/scheme/VariationalSolver.cpp
+++ b/src/scheme/VariationalSolver.cpp
@@ -166,7 +166,7 @@ variational_acoustic_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c_
     c.meshVariant()->variant());
 }
 
-template <MeshConcept MeshTypeT>
+template <MeshConcept MeshTypeT, size_t mesh_edges_degree>
 class VariationalSolverHandler::VariationalSolver final : public VariationalSolverHandler::IVariationalSolver
 {
  private:
@@ -254,7 +254,10 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
                                                                                mesh.xr(),
                                                                                mesh_node_boundary.nodeList());
 
-          if (hasFaceBoundary(mesh, bc_descriptor->boundaryDescriptor())) {
+          if constexpr (is_polygonal_mesh_v<MeshType>) {
+            bc_list.emplace_back(VelocityBoundaryCondition{mesh_node_boundary, node_value_list});
+          } else {
+            static_assert(is_polynomial_mesh_v<MeshType>);
             MeshFaceBoundary mesh_face_boundary = getMeshFaceBoundary(mesh, bc_descriptor->boundaryDescriptor());
 
             Table<const Rd> face_inner_node_value_list =
@@ -264,8 +267,6 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
 
             bc_list.emplace_back(VelocityBoundaryCondition{mesh_node_boundary, node_value_list,   //
                                                            mesh_face_boundary, face_inner_node_value_list});
-          } else {
-            bc_list.emplace_back(VelocityBoundaryCondition{mesh_node_boundary, node_value_list});
           }
         } else if (dirichlet_bc_descriptor.name() == "pressure") {
           const FunctionSymbolId pressure_id = dirichlet_bc_descriptor.rhsSymbolId();
@@ -280,7 +281,7 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
 
           Table<TinyVector<Dimension>> quadrature_points(mesh_face_boundary.faceList().size(), qf.numberOfPoints());
 
-          LineTransformationAccessor<MeshType, 2> transformation{mesh};
+          LineTransformationAccessor<MeshType, mesh_edges_degree> transformation{mesh};
 
           for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
             const FaceId face_id = face_list[i_face];
@@ -340,15 +341,15 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
     this->_applyVelocityBC(bc_list, mesh, velocity_bc_treatment, A, b);
   }
 
-  void _forcebcSymmetryBC(const BoundaryConditionList& bc_list, const MeshType& mesh, Vector<double>& U) const;
+  void _forcebcSymmetryBC(const BoundaryConditionList& bc_list, Vector<double>& U) const;
 
-  void _forcebcVelocityBC(const BoundaryConditionList& bc_list, const MeshType& mesh, Vector<double>& U) const;
+  void _forcebcVelocityBC(const BoundaryConditionList& bc_list, Vector<double>& U) const;
 
   void
-  _forcebcBoundaryConditions(const BoundaryConditionList& bc_list, const MeshType& mesh, Vector<double>& U) const
+  _forcebcBoundaryConditions(const BoundaryConditionList& bc_list, Vector<double>& U) const
   {
-    this->_forcebcSymmetryBC(bc_list, mesh, U);
-    this->_forcebcVelocityBC(bc_list, mesh, U);
+    this->_forcebcSymmetryBC(bc_list, U);
+    this->_forcebcVelocityBC(bc_list, U);
   }
 
   std::tuple<NodeValue<const Rd>, FaceArray<const Rd>, CellValue<const Rd>, CellValue<const double>>
@@ -362,9 +363,9 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
                  const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
                  std::optional<FunctionSymbolId> function_id) const
   {
-    std::shared_ptr mesh = getCommonMesh({rho_v, u_v, E_v})->get<MeshType>();
+    std::shared_ptr p_mesh = getCommonMesh({rho_v, u_v, E_v})->get<MeshType>();
 
-    auto xr = mesh->xr();
+    auto xr = p_mesh->xr();
 
     DiscreteScalarFunction rho = rho_v->get<DiscreteScalarFunction>();
     DiscreteVectorFunction u   = u_v->get<DiscreteVectorFunction>();
@@ -399,21 +400,21 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
       return (gamma - 1) * rho_epsilon;
     };
 
-    auto node_to_face_matrix = mesh->connectivity().nodeToFaceMatrix();
-    auto face_to_node_matrix = mesh->connectivity().faceToNodeMatrix();
+    auto node_to_face_matrix = p_mesh->connectivity().nodeToFaceMatrix();
+    auto face_to_node_matrix = p_mesh->connectivity().faceToNodeMatrix();
 
     m_face_indices = [&]() {
-      FaceArray<size_t> face_indices{mesh->connectivity(), mesh->degree() + 1};
+      FaceArray<size_t> face_indices{p_mesh->connectivity(), mesh_edges_degree + 1};
       {
-        for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
+        for (FaceId face_id = 0; face_id < p_mesh->numberOfFaces(); ++face_id) {
           auto face_nodes = face_to_node_matrix[face_id];
 
-          face_indices[face_id][0]              = face_nodes[0];
-          face_indices[face_id][mesh->degree()] = face_nodes[1];
+          face_indices[face_id][0]                 = face_nodes[0];
+          face_indices[face_id][mesh_edges_degree] = face_nodes[1];
         }
-        size_t cpt = mesh->numberOfNodes();
-        for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
-          for (size_t i_face_node = 1; i_face_node < mesh->degree(); ++i_face_node) {
+        size_t cpt = p_mesh->numberOfNodes();
+        for (FaceId face_id = 0; face_id < p_mesh->numberOfFaces(); ++face_id) {
+          for (size_t i_face_node = 1; i_face_node < mesh_edges_degree; ++i_face_node) {
             face_indices[face_id][i_face_node] = cpt++;
           }
         }
@@ -422,46 +423,48 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
     }();
 
     m_node_index = [&]() {
-      NodeValue<size_t> node_index{mesh->connectivity()};
+      NodeValue<size_t> node_index{p_mesh->connectivity()};
       {
-        for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
+        for (FaceId face_id = 0; face_id < p_mesh->numberOfFaces(); ++face_id) {
           auto face_nodes = face_to_node_matrix[face_id];
 
           node_index[face_nodes[0]] = m_face_indices[face_id][0];
-          node_index[face_nodes[1]] = m_face_indices[face_id][mesh->degree()];
+          node_index[face_nodes[1]] = m_face_indices[face_id][mesh_edges_degree];
         }
       }
       return node_index;
     }();
 
-    Array<int> non_zero(Dimension * (mesh->numberOfNodes() + mesh->numberOfEdges() * (mesh->degree() - 1)));
+    Array<int> non_zero(Dimension * (p_mesh->numberOfNodes() + p_mesh->numberOfEdges() * (mesh_edges_degree - 1)));
 
     parallel_for(
-      mesh->numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) {
+      p_mesh->numberOfNodes(), PUGS_LAMBDA(const NodeId node_id) {
         const size_t node_idx      = m_node_index[node_id];
-        const size_t node_non_zero = (node_to_face_matrix[node_id].size() * mesh->degree() + 1) * 2;
+        const size_t node_non_zero = (node_to_face_matrix[node_id].size() * mesh_edges_degree + 1) * 2;
 
         non_zero[2 * node_idx]     = node_non_zero;
         non_zero[2 * node_idx + 1] = node_non_zero;
       });
 
     parallel_for(
-      mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) {
-        for (size_t i = 1; i < mesh->degree(); ++i) {
+      p_mesh->numberOfFaces(), PUGS_LAMBDA(const FaceId face_id) {
+        for (size_t i = 1; i < mesh_edges_degree; ++i) {
           const size_t face_node_idx = m_face_indices[face_id][i];
 
-          const size_t face_node_non_zero = 2 * (mesh->degree() + 1);
+          const size_t face_node_non_zero = 2 * (mesh_edges_degree + 1);
 
           non_zero[2 * face_node_idx]     = face_node_non_zero;
           non_zero[2 * face_node_idx + 1] = face_node_non_zero;
         }
       });
 
-    CRSMatrixDescriptor A_descriptor(Dimension * (mesh->numberOfNodes() + mesh->numberOfEdges() * (mesh->degree() - 1)),
-                                     Dimension * (mesh->numberOfNodes() + mesh->numberOfEdges() * (mesh->degree() - 1)),
+    CRSMatrixDescriptor A_descriptor(Dimension *
+                                       (p_mesh->numberOfNodes() + p_mesh->numberOfEdges() * (mesh_edges_degree - 1)),
+                                     Dimension *
+                                       (p_mesh->numberOfNodes() + p_mesh->numberOfEdges() * (mesh_edges_degree - 1)),
                                      non_zero);
 
-    auto face_to_cell_matrix = mesh->connectivity().faceToCellMatrix();
+    auto face_to_cell_matrix = p_mesh->connectivity().faceToCellMatrix();
 
     const Rdxd I = identity;
 
@@ -478,19 +481,29 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
                                                                    return 0.5 * x[0] * (x[0] + 1);
                                                                  }};
 
+    const std::vector<std::function<double(R1)>> w_hat_set_P3 =
+      {[](R1 x) -> double { return -9. / 16 * (x[0] + 1. / 3) * (x[0] - 1. / 3) * (x[0] - 1); },   //
+       [](R1 x) -> double { return 27. / 16 * (x[0] + 1) * (x[0] - 1. / 3) * (x[0] - 1); },        //
+       [](R1 x) -> double { return -27. / 16 * (x[0] + 1) * (x[0] + 1. / 3) * (x[0] - 1); },       //
+       [](R1 x) -> double { return 9. / 16 * (x[0] + 1. / 3) * (x[0] - 1. / 3) * (x[0] + 1); }};
+
     std::vector<std::function<double(R1)>> w_hat_set;
-    if (mesh->degree() == 1) {
+    if constexpr (mesh_edges_degree == 1) {
       w_hat_set = w_hat_set_P1;
-    } else if (mesh->degree() == 2) {
+    } else if constexpr (mesh_edges_degree == 2) {
       w_hat_set = w_hat_set_P2;
+    } else if constexpr (mesh_edges_degree == 3) {
+      w_hat_set = w_hat_set_P3;
     } else {
-      throw NotImplementedError("degree > 2");
+      throw NotImplementedError("degree > 3");
     }
 
     const QuadratureFormula<1> qf =
       QuadratureManager::instance().getLineFormula(GaussQuadratureDescriptor(m_quadrature_degree));
 
-    for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
+    LineTransformationAccessor<MeshType, mesh_edges_degree> transformation{*p_mesh};
+
+    for (FaceId face_id = 0; face_id < p_mesh->numberOfFaces(); ++face_id) {
       auto cell_list = face_to_cell_matrix[face_id];
 
       double Z  = 0;
@@ -501,18 +514,7 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
         Za += a[cell_id];
       }
 
-      const Rd& x0 = mesh->xr()[face_to_node_matrix[face_id][0]];
-      const Rd& x2 = mesh->xr()[face_to_node_matrix[face_id][1]];
-
-      const Rd x1 = [&]() {
-        if (mesh->degree() == 2) {
-          return mesh->xl()[face_id][0];
-        } else {
-          return 0.5 * (x0 + x2);
-        }
-      }();
-
-      const LineParabolicTransformation<Dimension> t(x0, x1, x2);
+      auto t = transformation.getTransformation(face_id);
 
       for (size_t n0 = 0; n0 < w_hat_set.size(); ++n0) {
         const size_t r = m_face_indices[face_id][n0];
@@ -541,25 +543,15 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
       }
     }
 
-    const auto& face_local_numbers_in_their_cells = mesh->connectivity().faceLocalNumbersInTheirCells();
-    const auto& face_cell_is_reversed             = mesh->connectivity().cellFaceIsReversed();
+    const auto& face_local_numbers_in_their_cells = p_mesh->connectivity().faceLocalNumbersInTheirCells();
+    const auto& face_cell_is_reversed             = p_mesh->connectivity().cellFaceIsReversed();
 
-    Vector<double> b(Dimension * (mesh->numberOfNodes() + mesh->numberOfEdges() * (mesh->degree() - 1)));
+    Vector<double> b(Dimension * (p_mesh->numberOfNodes() + p_mesh->numberOfEdges() * (mesh_edges_degree - 1)));
     b.fill(0);
 
-    for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
-      const Rd& x0 = mesh->xr()[face_to_node_matrix[face_id][0]];
-      const Rd& x2 = mesh->xr()[face_to_node_matrix[face_id][1]];
+    for (FaceId face_id = 0; face_id < p_mesh->numberOfFaces(); ++face_id) {
+      auto t = transformation.getTransformation(face_id);
 
-      const Rd x1 = [&]() {
-        if (mesh->degree() == 2) {
-          return mesh->xl()[face_id][0];
-        } else {
-          return 0.5 * (x0 + x2);
-        }
-      }();
-
-      const LineParabolicTransformation<Dimension> t(x0, x1, x2);
       auto cell_list = face_to_cell_matrix[face_id];
 
       for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) {
@@ -596,9 +588,9 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
       }
     }
 
-    const BoundaryConditionList bc_list = this->_getBCList(*mesh, bc_descriptor_list);
+    const BoundaryConditionList bc_list = this->_getBCList(*p_mesh, bc_descriptor_list);
 
-    this->_applyBoundaryConditions(bc_list, *mesh, velocity_bc_treatment, A_descriptor, b);
+    this->_applyBoundaryConditions(bc_list, *p_mesh, velocity_bc_treatment, A_descriptor, b);
 
     CRSMatrix A = A_descriptor.getCRSMatrix();
 
@@ -607,14 +599,14 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
 
     LinearSolver solver;
     solver.solveLocalSystem(A, U, b);
-    this->_forcebcBoundaryConditions(bc_list, *mesh, U);
+    this->_forcebcBoundaryConditions(bc_list, U);
 
-    const auto& cell_to_face_matrix = mesh->connectivity().cellToFaceMatrix();
+    const auto& cell_to_face_matrix = p_mesh->connectivity().cellToFaceMatrix();
 
-    CellValue<Rd> momentum_fluxes{mesh->connectivity()};
-    CellValue<double> energy_fluxes{mesh->connectivity()};
+    CellValue<Rd> momentum_fluxes{p_mesh->connectivity()};
+    CellValue<double> energy_fluxes{p_mesh->connectivity()};
 
-    for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) {
+    for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
       Rd rho_u_j_fluxes     = zero;
       double rho_E_j_fluxes = 0;
 
@@ -622,18 +614,7 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
       for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
         const FaceId face_id = face_list[i_face];
 
-        const Rd& x0 = mesh->xr()[face_to_node_matrix[face_id][0]];
-        const Rd& x2 = mesh->xr()[face_to_node_matrix[face_id][1]];
-
-        const Rd x1 = [&]() {
-          if (mesh->degree() == 2) {
-            return mesh->xl()[face_id][0];
-          } else {
-            return 0.5 * (x0 + x2);
-          }
-        }();
-
-        const LineParabolicTransformation<Dimension> t(x0, x1, x2);
+        auto t = transformation.getTransformation(face_id);
 
         const double sign = face_cell_is_reversed(cell_id, i_face) ? -1 : 1;
 
@@ -680,33 +661,32 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
     }
 
     if (function_id.has_value()) {
-      auto Vj = MeshDataManager::instance().getMeshData(*mesh).Vj();
+      auto Vj = MeshDataManager::instance().getMeshData(*p_mesh).Vj();
 
       GaussLegendreQuadratureDescriptor quadrature(7);
-      CellValue<double> S(mesh->connectivity());
+      CellValue<double> S(p_mesh->connectivity());
 
-      IntegrateOnCells<double(Rd)>::integrateTo(function_id.value(), quadrature, *mesh, S);
+      IntegrateOnCells<double(Rd)>::integrateTo(function_id.value(), quadrature, *p_mesh, S);
 
-      for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) {
+      for (CellId cell_id = 0; cell_id < p_mesh->numberOfCells(); ++cell_id) {
         energy_fluxes[cell_id] -= S[cell_id];
       }
     }
 
-    NodeValue<Rd> ur(mesh->connectivity());
-    FaceArray<Rd> ul(mesh->connectivity(), mesh->degree() - 1);
+    NodeValue<Rd> ur(p_mesh->connectivity());
+    FaceArray<Rd> ul(p_mesh->connectivity(), mesh_edges_degree - 1);
 
-    for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
+    for (FaceId face_id = 0; face_id < p_mesh->numberOfFaces(); ++face_id) {
       for (size_t i = 0; i < Dimension; ++i) {
         ur[face_to_node_matrix[face_id][0]][i] = U[Dimension * m_face_indices[face_id][0] + i];
       }
       for (size_t i = 0; i < Dimension; ++i) {
-        for (size_t il = 0; il < mesh->degree() - 1; ++il) {
+        for (size_t il = 0; il < mesh_edges_degree - 1; ++il) {
           ul[face_id][il][i] = U[Dimension * m_face_indices[face_id][il + 1] + i];
         }
       }
       for (size_t i = 0; i < Dimension; ++i) {
-        ur[face_to_node_matrix[face_id][mesh->degree() - 1]][i] =
-          U[Dimension * m_face_indices[face_id][mesh->degree()] + i];
+        ur[face_to_node_matrix[face_id][1]][i] = U[Dimension * m_face_indices[face_id][mesh_edges_degree] + i];
       }
     }
 
@@ -747,20 +727,26 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
       new_E[cell_id] -= dt_over_Mj * energy_fluxes[cell_id];
     }
 
+    std::shared_ptr<const MeshType> new_mesh;
+
     NodeValue<Rd> new_xr = copy(mesh->xr());
-    FaceArray<Rd> new_xl = copy(mesh->xl());
 
     parallel_for(
       mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { new_xr[node_id] += dt * ur[node_id]; });
 
-    parallel_for(
-      mesh->numberOfFaces(), PUGS_LAMBDA(FaceId face_id) {
-        for (size_t i = 0; i < mesh->degree() - 1; ++i) {
-          new_xl[face_id][i] += dt * ul[face_id][i];
-        }
-      });
+    if constexpr (is_polygonal_mesh_v<MeshType>) {
+      new_mesh = std::make_shared<MeshType>(mesh->shared_connectivity(), new_xr);
+    } else if constexpr (is_polynomial_mesh_v<MeshType>) {
+      FaceArray<Rd> new_xl = copy(mesh->xl());
+      parallel_for(
+        mesh->numberOfFaces(), PUGS_LAMBDA(FaceId face_id) {
+          for (size_t i = 0; i < mesh_edges_degree - 1; ++i) {
+            new_xl[face_id][i] += dt * ul[face_id][i];
+          }
+        });
 
-    std::shared_ptr<const MeshType> new_mesh = std::make_shared<MeshType>(mesh->shared_connectivity(), new_xr, new_xl);
+      new_mesh = std::make_shared<MeshType>(mesh->shared_connectivity(), new_xr, new_xl);
+    }
 
     CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*new_mesh).Vj();
 
@@ -893,11 +879,12 @@ class VariationalSolverHandler::VariationalSolver final : public VariationalSolv
   ~VariationalSolver()                   = default;
 };
 
-template <MeshConcept MeshType>
+template <MeshConcept MeshType, size_t mesh_edges_degree>
 void
-VariationalSolverHandler::VariationalSolver<MeshType>::_applyPressureBC(const BoundaryConditionList& bc_list,
-                                                                        const MeshType& mesh,
-                                                                        Vector<double>& b) const
+VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::_applyPressureBC(
+  const BoundaryConditionList& bc_list,
+  const MeshType& mesh,
+  Vector<double>& b) const
 {
   for (const auto& boundary_condition : bc_list) {
     std::visit(
@@ -918,17 +905,24 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyPressureBC(const Bo
                [](R1 x) -> double { return -(x[0] - 1) * (x[0] + 1); },
                [](R1 x) -> double { return 0.5 * x[0] * (x[0] + 1); }};
 
+            const std::vector<std::function<double(R1)>> w_hat_set_P3 =
+              {[](R1 x) -> double { return -9. / 16 * (x[0] + 1. / 3) * (x[0] - 1. / 3) * (x[0] - 1); },   //
+               [](R1 x) -> double { return 27. / 16 * (x[0] + 1) * (x[0] - 1. / 3) * (x[0] - 1); },        //
+               [](R1 x) -> double { return -27. / 16 * (x[0] + 1) * (x[0] + 1. / 3) * (x[0] - 1); },       //
+               [](R1 x) -> double { return 9. / 16 * (x[0] + 1. / 3) * (x[0] - 1. / 3) * (x[0] + 1); }};
+
             std::vector<std::function<double(R1)>> w_hat_set;
-            if (mesh.degree() == 1) {
+            if constexpr (mesh_edges_degree == 1) {
               w_hat_set = w_hat_set_P1;
-            } else if (mesh.degree() == 2) {
+            } else if constexpr (mesh_edges_degree == 2) {
               w_hat_set = w_hat_set_P2;
+            } else if constexpr (mesh_edges_degree == 3) {
+              w_hat_set = w_hat_set_P3;
             } else {
-              throw NotImplementedError("degree > 2");
+              throw NotImplementedError("degree > 3");
             }
 
             const auto& face_to_cell_matrix = mesh.connectivity().faceToCellMatrix();
-            const auto& face_to_node_matrix = mesh.connectivity().faceToNodeMatrix();
 
             const Array<const FaceId>& face_list = bc.faceList();
             const Table<const double>& p_ext     = bc.valueList();
@@ -937,21 +931,13 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyPressureBC(const Bo
 
             const auto& face_cell_is_reversed = mesh.connectivity().cellFaceIsReversed();
 
+            LineTransformationAccessor<MeshType, mesh_edges_degree> transformation{mesh};
+
             for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
               FaceId face_id = face_list[i_face];
 
-              const Rd& x0 = mesh.xr()[face_to_node_matrix[face_id][0]];
-              const Rd& x2 = mesh.xr()[face_to_node_matrix[face_id][1]];
+              auto t = transformation.getTransformation(face_id);
 
-              const Rd x1 = [&]() {
-                if (mesh.degree() == 2) {
-                  return mesh.xl()[face_id][0];
-                } else {
-                  return 0.5 * (x0 + x2);
-                }
-              }();
-
-              const LineParabolicTransformation<Dimension> t(x0, x1, x2);
               auto cell_list = face_to_cell_matrix[face_id];
 
               for (size_t i_cell = 0; i_cell < cell_list.size(); ++i_cell) {
@@ -988,11 +974,11 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyPressureBC(const Bo
   }
 }
 
-template <MeshConcept MeshType>
+template <MeshConcept MeshType, size_t mesh_edges_degree>
 void
-VariationalSolverHandler::VariationalSolver<MeshType>::_forcebcSymmetryBC(const BoundaryConditionList& bc_list,
-                                                                          const MeshType& mesh,
-                                                                          Vector<double>& U) const
+VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::_forcebcSymmetryBC(
+  const BoundaryConditionList& bc_list,
+  Vector<double>& U) const
 {
   for (const auto& boundary_condition : bc_list) {
     std::visit(
@@ -1023,15 +1009,13 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_forcebcSymmetryBC(const
             }
           }
 
-          const size_t degree = mesh.degree();
-
           const Array<const FaceId>& face_list = bc.faceList();
 
           // treat inner nodes of the faces
           for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
             const FaceId face_id = face_list[i_face];
 
-            for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+            for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
               const size_t r = m_face_indices[face_id][r_hat];
 
               TinyVector<Dimension> ur;
@@ -1053,11 +1037,11 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_forcebcSymmetryBC(const
   }
 }
 
-template <MeshConcept MeshType>
+template <MeshConcept MeshType, size_t mesh_edges_degree>
 void
-VariationalSolverHandler::VariationalSolver<MeshType>::_forcebcVelocityBC(const BoundaryConditionList& bc_list,
-                                                                          const MeshType& mesh,
-                                                                          Vector<double>& U) const
+VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::_forcebcVelocityBC(
+  const BoundaryConditionList& bc_list,
+  Vector<double>& U) const
 {
   for (const auto& boundary_condition : bc_list) {
     std::visit(
@@ -1077,8 +1061,6 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_forcebcVelocityBC(const
             }
           }
 
-          const size_t degree = mesh.degree();
-
           const Array<const FaceId>& face_list              = bc.faceList();
           const Table<const Rd>& face_inner_node_value_list = bc.faceInnerNodeValueList();
 
@@ -1086,7 +1068,7 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_forcebcVelocityBC(const
           for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
             const FaceId face_id = face_list[i_face];
 
-            for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+            for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
               const size_t r = m_face_indices[face_id][r_hat];
 
               for (size_t i = 0; i < Dimension; ++i) {
@@ -1107,15 +1089,13 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_forcebcVelocityBC(const
             }
           }
 
-          const size_t degree = mesh.degree();
-
           const Array<const FaceId>& face_list = bc.faceList();
 
           // treat inner nodes of the faces
           for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
             const FaceId face_id = face_list[i_face];
 
-            for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+            for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
               const size_t r = m_face_indices[face_id][r_hat];
 
               for (size_t i = 0; i < Dimension; ++i) {
@@ -1129,12 +1109,13 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_forcebcVelocityBC(const
   }
 }
 
-template <MeshConcept MeshType>
+template <MeshConcept MeshType, size_t mesh_edges_degree>
 void
-VariationalSolverHandler::VariationalSolver<MeshType>::_applySymmetryBC(const BoundaryConditionList& bc_list,
-                                                                        const MeshType& mesh,
-                                                                        CRSMatrixDescriptor<double>& A_descriptor,
-                                                                        Vector<double>& b) const
+VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::_applySymmetryBC(
+  const BoundaryConditionList& bc_list,
+  const MeshType& mesh,
+  CRSMatrixDescriptor<double>& A_descriptor,
+  Vector<double>& b) const
 {
   for (const auto& boundary_condition : bc_list) {
     std::visit(
@@ -1182,13 +1163,11 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applySymmetryBC(const Bo
             }
           }
 
-          const size_t degree = mesh.degree();
-
           const Array<const FaceId>& face_list = bc.faceList();
           for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
             const FaceId face_id = face_list[i_face];
 
-            for (size_t i_hat = 1; i_hat < degree; ++i_hat) {
+            for (size_t i_hat = 1; i_hat < mesh_edges_degree; ++i_hat) {
               const size_t r = m_face_indices[face_id][i_hat];
 
               TinyMatrix<Dimension> Arr;
@@ -1231,7 +1210,7 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applySymmetryBC(const Bo
               const FaceId face_id = node_face_list[i_face];
               auto face_node_list  = face_to_node_matrix[face_id];
 
-              for (size_t i_hat = 0; i_hat <= degree; ++i_hat) {
+              for (size_t i_hat = 0; i_hat <= mesh_edges_degree; ++i_hat) {
                 const size_t s = m_face_indices[face_id][i_hat];
 
                 if (s != r) {
@@ -1256,10 +1235,10 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applySymmetryBC(const Bo
           for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
             const FaceId face_id = face_list[i_face];
 
-            for (size_t i_hat = 1; i_hat < degree; ++i_hat) {
+            for (size_t i_hat = 1; i_hat < mesh_edges_degree; ++i_hat) {
               const size_t r = m_face_indices[face_id][i_hat];
 
-              for (size_t j_hat = 0; j_hat <= degree; ++j_hat) {
+              for (size_t j_hat = 0; j_hat <= mesh_edges_degree; ++j_hat) {
                 const size_t s = m_face_indices[face_id][j_hat];
 
                 if (s != r) {
@@ -1286,9 +1265,9 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applySymmetryBC(const Bo
   }
 }
 
-template <MeshConcept MeshType>
+template <MeshConcept MeshType, size_t mesh_edges_degree>
 void
-VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
+VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::_applyVelocityBC(
   const BoundaryConditionList& bc_list,
   const MeshType& mesh,
   const VariationalSolverHandler::VelocityBCTreatment& velocity_bc_treatment,
@@ -1307,7 +1286,6 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
             const Array<const NodeId>& node_list = bc.nodeList();
             auto node_to_face_matrix             = mesh.connectivity().nodeToFaceMatrix();
             const Array<const FaceId>& face_list = bc.faceList();
-            const size_t degree                  = mesh.degree();
 
             const Array<const Rd>& node_value_list            = bc.nodeValueList();
             const Table<const Rd>& face_inner_node_value_list = bc.faceInnerNodeValueList();
@@ -1321,7 +1299,7 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
               for (size_t i_face = 0; i_face < node_face_list.size(); ++i_face) {
                 const FaceId face_id = node_face_list[i_face];
 
-                for (size_t s_hat = 0; s_hat <= degree; ++s_hat) {
+                for (size_t s_hat = 0; s_hat <= mesh_edges_degree; ++s_hat) {
                   const size_t s = m_face_indices[face_id][s_hat];
 
                   if (r != s) {
@@ -1345,9 +1323,9 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
             for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
               const FaceId face_id = face_list[i_face];
 
-              for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+              for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
                 const size_t r = m_face_indices[face_id][r_hat];
-                for (size_t s_hat = 0; s_hat <= degree; ++s_hat) {
+                for (size_t s_hat = 0; s_hat <= mesh_edges_degree; ++s_hat) {
                   const size_t s = m_face_indices[face_id][s_hat];
 
                   if (r != s) {
@@ -1377,7 +1355,7 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
               for (size_t i_face = 0; i_face < node_face_list.size(); ++i_face) {
                 const FaceId face_id = node_face_list[i_face];
 
-                for (size_t s_hat = 0; s_hat <= degree; ++s_hat) {
+                for (size_t s_hat = 0; s_hat <= mesh_edges_degree; ++s_hat) {
                   const size_t s = m_face_indices[face_id][s_hat];
 
                   if (r == s) {
@@ -1403,9 +1381,9 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
             for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
               const FaceId face_id = face_list[i_face];
 
-              for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+              for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
                 const size_t r = m_face_indices[face_id][r_hat];
-                for (size_t s_hat = 0; s_hat <= degree; ++s_hat) {
+                for (size_t s_hat = 0; s_hat <= mesh_edges_degree; ++s_hat) {
                   const size_t s = m_face_indices[face_id][s_hat];
 
                   if (r == s) {
@@ -1432,7 +1410,6 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
             const Array<const NodeId>& node_list = bc.nodeList();
             auto node_to_face_matrix             = mesh.connectivity().nodeToFaceMatrix();
             const Array<const FaceId>& face_list = bc.faceList();
-            const size_t degree                  = mesh.degree();
 
             // Treats vertices of the faces
             for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
@@ -1443,7 +1420,7 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
 
               for (size_t i_face = 0; i_face < node_faces.size(); ++i_face) {
                 const FaceId face_id = node_faces[i_face];
-                for (size_t s_hat = 0; s_hat <= degree; ++s_hat) {
+                for (size_t s_hat = 0; s_hat <= mesh_edges_degree; ++s_hat) {
                   const size_t s = m_face_indices[face_id][s_hat];
 
                   if (r == s) {
@@ -1469,9 +1446,9 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
             for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
               const FaceId face_id = face_list[i_face];
 
-              for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+              for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
                 const size_t r = m_face_indices[face_id][r_hat];
-                for (size_t s_hat = 0; s_hat <= degree; ++s_hat) {
+                for (size_t s_hat = 0; s_hat <= mesh_edges_degree; ++s_hat) {
                   const size_t s = m_face_indices[face_id][s_hat];
 
                   if (r == s) {
@@ -1513,11 +1490,10 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
               A_descriptor(Dimension * r + 1, Dimension * r + 1) += 1.e30;
             }
 
-            const size_t degree                  = mesh.degree();
             const Array<const FaceId>& face_list = bc.faceList();
             for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
               const FaceId face_id = face_list[i_face];
-              for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+              for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
                 const size_t r = m_face_indices[face_id][r_hat];
                 A_descriptor(Dimension * r, Dimension * r) += 1.e30;
                 A_descriptor(Dimension * r + 1, Dimension * r + 1) += 1.e30;
@@ -1536,7 +1512,7 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
 
             for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
               const FaceId face_id = face_list[i_face];
-              for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+              for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
                 const size_t value_index = r_hat - 1;   // nodal values on the face are not stored in this array
 
                 const size_t r = m_face_indices[face_id][r_hat];
@@ -1554,11 +1530,10 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
               A_descriptor(Dimension * r + 1, Dimension * r + 1) += 1.e30;
             }
 
-            const size_t degree                  = mesh.degree();
             const Array<const FaceId>& face_list = bc.faceList();
             for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
               const FaceId face_id = face_list[i_face];
-              for (size_t r_hat = 1; r_hat < degree; ++r_hat) {
+              for (size_t r_hat = 1; r_hat < mesh_edges_degree; ++r_hat) {
                 const size_t r = m_face_indices[face_id][r_hat];
                 A_descriptor(Dimension * r, Dimension * r) += 1.e30;
                 A_descriptor(Dimension * r + 1, Dimension * r + 1) += 1.e30;
@@ -1574,8 +1549,8 @@ VariationalSolverHandler::VariationalSolver<MeshType>::_applyVelocityBC(
   }
 }
 
-template <MeshConcept MeshType>
-class VariationalSolverHandler::VariationalSolver<MeshType>::FixedBoundaryCondition
+template <MeshConcept MeshType, size_t mesh_edges_degree>
+class VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::FixedBoundaryCondition
 {
  private:
   const MeshNodeBoundary m_mesh_node_boundary;
@@ -1605,8 +1580,8 @@ class VariationalSolverHandler::VariationalSolver<MeshType>::FixedBoundaryCondit
   ~FixedBoundaryCondition() = default;
 };
 
-template <MeshConcept MeshType>
-class VariationalSolverHandler::VariationalSolver<MeshType>::PressureBoundaryCondition
+template <MeshConcept MeshType, size_t mesh_edges_degree>
+class VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::PressureBoundaryCondition
 {
  private:
   const MeshFaceBoundary m_mesh_face_boundary;
@@ -1632,8 +1607,8 @@ class VariationalSolverHandler::VariationalSolver<MeshType>::PressureBoundaryCon
   ~PressureBoundaryCondition() = default;
 };
 
-template <MeshConcept MeshType>
-class VariationalSolverHandler::VariationalSolver<MeshType>::VelocityBoundaryCondition
+template <MeshConcept MeshType, size_t mesh_edges_degree>
+class VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::VelocityBoundaryCondition
 {
  private:
   const MeshNodeBoundary m_mesh_node_boundary;
@@ -1688,8 +1663,8 @@ class VariationalSolverHandler::VariationalSolver<MeshType>::VelocityBoundaryCon
   ~VelocityBoundaryCondition() = default;
 };
 
-template <MeshConcept MeshType>
-class VariationalSolverHandler::VariationalSolver<MeshType>::SymmetryBoundaryCondition
+template <MeshConcept MeshType, size_t mesh_edges_degree>
+class VariationalSolverHandler::VariationalSolver<MeshType, mesh_edges_degree>::SymmetryBoundaryCondition
 {
  public:
   using Rd = TinyVector<Dimension, double>;
@@ -1738,8 +1713,26 @@ VariationalSolverHandler::VariationalSolverHandler(const std::shared_ptr<const M
   std::visit(
     [&](auto&& mesh) {
       using MeshType = mesh_type_t<decltype(mesh)>;
-      if constexpr ((is_polynomial_mesh_v<MeshType>)and(MeshType::Dimension == 2)) {
-        m_acoustic_solver = std::make_unique<VariationalSolver<MeshType>>();
+      if constexpr ((is_polygonal_mesh_v<MeshType>)and(MeshType::Dimension == 2)) {
+        m_acoustic_solver = std::make_unique<VariationalSolver<MeshType, 1>>();
+      } else if constexpr ((is_polynomial_mesh_v<MeshType>)and(MeshType::Dimension == 2)) {
+        switch (mesh->degree()) {
+        case 1: {
+          m_acoustic_solver = std::make_unique<VariationalSolver<MeshType, 1>>();
+          break;
+        }
+        case 2: {
+          m_acoustic_solver = std::make_unique<VariationalSolver<MeshType, 2>>();
+          break;
+        }
+        case 3: {
+          m_acoustic_solver = std::make_unique<VariationalSolver<MeshType, 3>>();
+          break;
+        }
+        default: {
+          throw NotImplementedError("polynomial mesh of degree > 3 are not supported");
+        }
+        }
       } else {
         throw NormalError("unexpected mesh type");
       }
diff --git a/src/scheme/VariationalSolver.hpp b/src/scheme/VariationalSolver.hpp
index 85a2b158b4b9b70229c317ce2fde5f9db773b9d9..64bbb6b235c9c8d4ae8a1c70e0c25dc3846daa68 100644
--- a/src/scheme/VariationalSolver.hpp
+++ b/src/scheme/VariationalSolver.hpp
@@ -53,7 +53,7 @@ class VariationalSolverHandler
     virtual ~IVariationalSolver() = default;
   };
 
-  template <MeshConcept MeshTypeT>
+  template <MeshConcept MeshTypeT, size_t mesh_edges_degree>
   class VariationalSolver;
 
   std::unique_ptr<IVariationalSolver> m_acoustic_solver;