diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt
index ee7b44b7da15f559f0d57dc4d5a5545157253e97..135500f6389fd1e8fcf6b6d982a42b294cc43a65 100644
--- a/src/scheme/CMakeLists.txt
+++ b/src/scheme/CMakeLists.txt
@@ -38,5 +38,6 @@ add_library(
 
 target_link_libraries(
   PugsScheme
+  PugsAnalysis
   ${HIGHFIVE_TARGET}
 )
diff --git a/src/scheme/DiscreteFunctionDPkVector.hpp b/src/scheme/DiscreteFunctionDPkVector.hpp
index 2fefc078b192304ab0a80b63782986867e13c3d8..e8ac729f4b3e002f8c1c3b2c1cdcbd5f4aef3f77 100644
--- a/src/scheme/DiscreteFunctionDPkVector.hpp
+++ b/src/scheme/DiscreteFunctionDPkVector.hpp
@@ -139,6 +139,16 @@ class DiscreteFunctionDPkVector
     return m_by_cell_coefficients[cell_id];
   }
 
+  PUGS_INLINE auto
+  componentCoefficients(const CellId cell_id, size_t i_component) const noexcept(NO_ASSERT)
+  {
+    Assert(m_mesh_v.use_count() > 0, "DiscreteFunctionDPkVector is not built");
+    Assert(i_component < m_number_of_components, "incorrect component number");
+
+    return ComponentCoefficientView{&m_by_cell_coefficients[cell_id][i_component * m_nb_coefficients_per_component],
+                                    m_nb_coefficients_per_component};
+  }
+
   PUGS_FORCEINLINE BasisView
   operator()(const CellId cell_id, size_t i_component) const noexcept(NO_ASSERT)
   {
diff --git a/src/scheme/EulerKineticSolverMultiD.cpp b/src/scheme/EulerKineticSolverMultiD.cpp
index 3ea60272a74641a139f9acfb34174554e770c4bd..4022bfda3422af3d18f9281b254d108b9ede1a51 100644
--- a/src/scheme/EulerKineticSolverMultiD.cpp
+++ b/src/scheme/EulerKineticSolverMultiD.cpp
@@ -275,7 +275,7 @@ class EulerKineticSolverMultiD
         }
         auto node_boundary = getMeshNodeBoundary(mesh, bc_descriptor->boundaryDescriptor());
 
-        Array<size_t> is_boundary_cell{p_mesh->numberOfCells()};
+        CellValue<size_t> is_boundary_cell{p_mesh->connectivity()};
 
         is_boundary_cell.fill(0);
 
@@ -506,7 +506,7 @@ class EulerKineticSolverMultiD
 
   template <typename T>
   NodeArray<T>
-  compute_Flux1(CellArray<T>& Fn)
+  compute_Flux1_glace(const CellArray<const T>& Fn, NodeValue<bool> is_symmetry_boundary_node)
   {
     if constexpr (Dimension > 1) {
       const NodeValuePerCell<const TinyVector<Dimension>> njr = MeshDataManager::instance().getMeshData(m_mesh).njr();
@@ -534,12 +534,12 @@ class EulerKineticSolverMultiD
 
               double li_njr = dot(m_lambda_vector[i_wave], njr(cell_id, i_node));
               if (li_njr > 0) {
-                Fr[node_id][i_wave] += Fn[cell_id][i_wave] * li_njr;
+                Fr[node_id][i_wave] += li_njr * Fn[cell_id][i_wave];
                 sum_li_njr += li_njr;
               }
             }
-            if (sum_li_njr != 0) {
-              Fr[node_id][i_wave] /= sum_li_njr;
+            if ((sum_li_njr != 0) and (not is_symmetry_boundary_node[node_id])) {
+              Fr[node_id][i_wave] = 1. / sum_li_njr * Fr[node_id][i_wave];
             }
           }
         });
@@ -552,7 +552,7 @@ class EulerKineticSolverMultiD
 
   template <typename T>
   FaceArrayPerNode<T>
-  compute_Flux1_eucchlyd(CellArray<T> Fn)
+  compute_Flux1_eucclhyd(const CellArray<const T>& Fn, NodeValue<bool> is_symmetry_boundary_node)
   {
     if constexpr (Dimension > 1) {
       const NodeValuePerFace<const TinyVector<Dimension>> nlr = MeshDataManager::instance().getMeshData(m_mesh).nlr();
@@ -594,12 +594,12 @@ class EulerKineticSolverMultiD
                 double li_nlr = sign * dot(m_lambda_vector[i_wave], n_face);
 
                 if (li_nlr > 0) {
-                  Flr[node_id][i_face][i_wave] += Fn[cell_id][i_wave] * li_nlr;
+                  Flr[node_id][i_face][i_wave] += li_nlr * Fn[cell_id][i_wave];
                   sum += li_nlr;
                 }
               }
-              if (sum != 0) {
-                Flr[node_id][i_face][i_wave] /= sum;
+              if ((sum != 0) and (not is_symmetry_boundary_node[node_id])) {
+                Flr[node_id][i_face][i_wave] = 1. / sum * Flr[node_id][i_face][i_wave];
               }
             }
           }
@@ -653,16 +653,16 @@ class EulerKineticSolverMultiD
   }
 
   void
-  apply_bc(FaceArray<double> Fl_rho,
-           FaceArray<TinyVector<Dimension>> Fl_rho_u,
-           FaceArray<double> Fl_rho_E,
-           const CellValue<const double> rho,
-           const CellValue<const TinyVector<Dimension>> rho_u,
-           const CellValue<const double> rho_E,
-           const CellArray<const double> Fn_rho,
-           const CellArray<const TinyVector<Dimension>> Fn_rho_u,
-           const CellArray<const double> Fn_rho_E,
-           const BoundaryConditionList& bc_list)
+  apply_face_bc(FaceArray<double> Fl_rho,
+                FaceArray<TinyVector<Dimension>> Fl_rho_u,
+                FaceArray<double> Fl_rho_E,
+                const CellValue<const double> rho,
+                const CellValue<const TinyVector<Dimension>> rho_u,
+                const CellValue<const double> rho_E,
+                const CellArray<const double> Fn_rho,
+                const CellArray<const TinyVector<Dimension>> Fn_rho_u,
+                const CellArray<const double> Fn_rho_E,
+                const BoundaryConditionList& bc_list)
   {
     const size_t nb_waves                         = m_lambda_vector.size();
     const auto& face_local_numbers_in_their_cells = p_mesh->connectivity().faceLocalNumbersInTheirCells();
@@ -822,27 +822,297 @@ class EulerKineticSolverMultiD
     }
   }
 
-  DiscreteFunctionP0Vector<double>
-  compute_deltaLFn(NodeArray<double> Fr)
+  void
+  apply_glace_bc(NodeArray<double> Fr_rho,
+                 NodeArray<TinyVector<Dimension>> Fr_rho_u,
+                 NodeArray<double> Fr_rho_E,
+                 const CellValue<const double> rho,
+                 const CellValue<const TinyVector<Dimension>> rho_u,
+                 const CellValue<const double> rho_E,
+                 const BoundaryConditionList& bc_list)
+  {
+    const size_t nb_waves                                   = m_lambda_vector.size();
+    const auto& node_local_numbers_in_their_cells           = p_mesh->connectivity().nodeLocalNumbersInTheirCells();
+    const auto& node_to_cell_matrix                         = p_mesh->connectivity().nodeToCellMatrix();
+    const NodeValuePerCell<const TinyVector<Dimension>> njr = MeshDataManager::instance().getMeshData(m_mesh).njr();
+
+    TinyVector<MeshType::Dimension> inv_S = zero;
+    for (size_t d = 0; d < MeshType::Dimension; ++d) {
+      for (size_t i = 0; i < nb_waves; ++i) {
+        inv_S[d] += m_lambda_vector[i][d] * m_lambda_vector[i][d];
+      }
+      inv_S[d] = 1. / inv_S[d];
+    }
+
+    NodeValue<bool> node_is_done{p_mesh->connectivity()};
+    node_is_done.fill(false);
+
+    for (auto&& bc_v : bc_list) {
+      std::visit(
+        [=, this](auto&& bc) {
+          using BCType = std::decay_t<decltype(bc)>;
+          if constexpr (std::is_same_v<BCType, SymmetryBoundaryCondition>) {
+            auto node_list          = bc.nodeList();
+            auto n                  = bc.outgoingNormal();
+            auto nxn                = tensorProduct(n, n);
+            TinyMatrix<Dimension> I = identity;
+            auto txt                = I - nxn;
+
+            //             for (size_t i_cell = 0; i_cell < node_to_cell.size(); ++i_cell) {
+            //   const CellId cell_id      = node_to_cell[i_cell];
+            //   const unsigned int i_node = node_local_number_in_its_cell[i_cell];
+
+            //   double li_njr = dot(m_lambda_vector[i_wave], njr(cell_id, i_node));
+            //   if (li_njr > 0) {
+            //     Fr[node_id][i_wave] += Fn[cell_id][i_wave] * li_njr;
+            //     sum_li_njr += li_njr;
+            //   }
+            // }
+            // if (sum_li_njr != 0) {
+            //   Fr[node_id][i_wave] /= sum_li_njr;
+            // }
+
+            for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
+              const NodeId node_id = node_list[i_node];
+              if (not node_is_done[node_id]) {
+                for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+                  const auto& node_local_number_in_its_cell = node_local_numbers_in_their_cells.itemArray(node_id);
+                  const auto& node_to_cell                  = node_to_cell_matrix[node_id];
+
+                  double sum_li_njr = 0;
+
+                  for (size_t i_cell = 0; i_cell < node_to_cell.size(); ++i_cell) {
+                    const CellId cell_id     = node_to_cell[i_cell];
+                    const size_t i_node_cell = node_local_number_in_its_cell[i_cell];
+
+                    double li_njr = dot(m_lambda_vector[i_wave], njr(cell_id, i_node_cell));
+
+                    if (li_njr > 0) {
+                      sum_li_njr += li_njr;
+                    }
+
+                    TinyVector<Dimension> njr_prime = txt * njr(cell_id, i_node_cell) - nxn * njr(cell_id, i_node_cell);
+                    double li_njr_prime             = dot(m_lambda_vector[i_wave], njr_prime);
+
+                    if (li_njr_prime > 0) {
+                      double rhoj_prime                  = rho[cell_id];
+                      TinyVector<Dimension> rho_uj_prime = txt * rho_u[cell_id] - nxn * rho_u[cell_id];
+                      double rho_Ej_prime                = rho_E[cell_id];
+
+                      double rho_e = rho_E[cell_id] - 0.5 * (1. / rho[cell_id]) * dot(rho_u[cell_id], rho_u[cell_id]);
+                      double p     = (m_gamma - 1) * rho_e;
+
+                      TinyVector<Dimension> A_rho_prime = rho_uj_prime;
+                      TinyMatrix<Dimension> A_rho_u_prime =
+                        1. / rhoj_prime * tensorProduct(rho_uj_prime, rho_uj_prime) + p * I;
+                      TinyVector<Dimension> A_rho_E_prime = (rho_Ej_prime + p) / rhoj_prime * rho_uj_prime;
+
+                      double Fn_rho_prime                  = rhoj_prime / nb_waves;
+                      TinyVector<Dimension> Fn_rho_u_prime = 1. / nb_waves * rho_uj_prime;
+                      double Fn_rho_E_prime                = rho_Ej_prime / nb_waves;
+
+                      for (size_t d1 = 0; d1 < Dimension; ++d1) {
+                        Fn_rho_prime += inv_S[d1] * m_lambda_vector[i_wave][d1] * A_rho_prime[d1];
+                        for (size_t d2 = 0; d2 < Dimension; ++d2) {
+                          Fn_rho_u_prime[d1] += inv_S[d2] * m_lambda_vector[i_wave][d2] * A_rho_u_prime(d2, d1);
+                        }
+                        Fn_rho_E_prime += inv_S[d1] * m_lambda_vector[i_wave][d1] * A_rho_E_prime[d1];
+                      }
+
+                      Fr_rho[node_id][i_wave] += Fn_rho_prime * li_njr_prime;
+                      Fr_rho_u[node_id][i_wave] += 1. / li_njr_prime * Fn_rho_u_prime;
+                      Fr_rho_E[node_id][i_wave] += Fn_rho_E_prime * li_njr_prime;
+
+                      sum_li_njr += li_njr_prime;
+                    }
+                  }
+                  if (sum_li_njr != 0) {
+                    Fr_rho[node_id][i_wave] /= sum_li_njr;
+                    Fr_rho_u[node_id][i_wave] = 1. / sum_li_njr * Fr_rho_u[node_id][i_wave];
+                    Fr_rho_E[node_id][i_wave] /= sum_li_njr;
+                  }
+                }
+                node_is_done[node_id] = true;
+              }
+            }
+          }
+        },
+        bc_v);
+    }
+  }
+
+  void
+  apply_eucclhyd_bc(FaceArrayPerNode<double> Flr_rho,
+                    FaceArrayPerNode<TinyVector<Dimension>> Flr_rho_u,
+                    FaceArrayPerNode<double> Flr_rho_E,
+                    const CellValue<const double> rho,
+                    const CellValue<const TinyVector<Dimension>> rho_u,
+                    const CellValue<const double> rho_E,
+                    const BoundaryConditionList& bc_list)
+  {
+    const size_t nb_waves = m_lambda_vector.size();
+
+    // const NodeValuePerCell<const TinyVector<Dimension>> njr = MeshDataManager::instance().getMeshData(m_mesh).njr();
+    const auto& face_local_numbers_in_their_cells           = p_mesh->connectivity().faceLocalNumbersInTheirCells();
+    const auto& face_local_numbers_in_their_nodes           = p_mesh->connectivity().faceLocalNumbersInTheirNodes();
+    const auto& face_to_node_matrix                         = p_mesh->connectivity().faceToNodeMatrix();
+    const auto& face_to_cell_matrix                         = p_mesh->connectivity().faceToCellMatrix();
+    const NodeValuePerFace<const TinyVector<Dimension>> nlr = MeshDataManager::instance().getMeshData(m_mesh).nlr();
+    const auto& face_cell_is_reversed                       = p_mesh->connectivity().cellFaceIsReversed();
+
+    TinyVector<MeshType::Dimension> inv_S = zero;
+    for (size_t d = 0; d < MeshType::Dimension; ++d) {
+      for (size_t i = 0; i < nb_waves; ++i) {
+        inv_S[d] += m_lambda_vector[i][d] * m_lambda_vector[i][d];
+      }
+      inv_S[d] = 1. / inv_S[d];
+    }
+
+    FaceArrayPerNode<double> sum_li_nlr(m_mesh.connectivity(), nb_waves);
+    sum_li_nlr.fill(0);
+
+    for (auto&& bc_v : bc_list) {
+      std::visit(
+        [=, this](auto&& bc) {
+          using BCType = std::decay_t<decltype(bc)>;
+          if constexpr (std::is_same_v<BCType, SymmetryBoundaryCondition>) {
+            auto face_list          = bc.faceList();
+            auto n                  = bc.outgoingNormal();
+            auto nxn                = tensorProduct(n, n);
+            TinyMatrix<Dimension> I = identity;
+            auto txt                = I - nxn;
+
+            for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
+              const FaceId face_id = face_list[i_face];
+
+              const auto& face_to_node                  = face_to_node_matrix[face_id];
+              const auto& face_local_number_in_its_cell = face_local_numbers_in_their_cells.itemArray(face_id);
+              const auto& face_to_cell                  = face_to_cell_matrix[face_id];
+
+              for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+                for (size_t i_node = 0; i_node < face_to_node.size(); ++i_node) {
+                  const NodeId node_id = face_to_node[i_node];
+
+                  const auto& face_local_number_in_its_node = face_local_numbers_in_their_nodes.itemArray(face_id);
+                  const size_t i_face_node                  = face_local_number_in_its_node[i_node];
+
+                  for (size_t i_cell = 0; i_cell < face_to_cell.size(); ++i_cell) {
+                    const CellId cell_id     = face_to_cell[i_cell];
+                    const size_t i_face_cell = face_local_number_in_its_cell[i_cell];
+
+                    TinyVector<Dimension> n_face = nlr(face_id, i_node);
+                    const double sign            = face_cell_is_reversed(cell_id, i_face_cell) ? -1 : 1;
+
+                    TinyVector<Dimension> nlr_prime = txt * n_face - nxn * n_face;
+                    double li_nlr_prime             = sign * dot(m_lambda_vector[i_wave], nlr_prime);
+                    double li_nlr                   = sign * dot(m_lambda_vector[i_wave], n_face);
+
+                    if (li_nlr > 0) {
+                      sum_li_nlr[node_id][i_face_node][i_wave] += li_nlr;
+                    }
+
+                    if (li_nlr_prime > 0) {
+                      double rhoj_prime                  = rho[cell_id];
+                      TinyVector<Dimension> rho_uj_prime = txt * rho_u[cell_id] - nxn * rho_u[cell_id];
+                      double rho_Ej_prime                = rho_E[cell_id];
+
+                      double rho_e = rho_E[cell_id] - 0.5 * (1. / rho[cell_id]) * dot(rho_u[cell_id], rho_u[cell_id]);
+                      double p     = (m_gamma - 1) * rho_e;
+
+                      TinyVector<Dimension> A_rho_prime = rho_uj_prime;
+                      TinyMatrix<Dimension> A_rho_u_prime =
+                        1. / rhoj_prime * tensorProduct(rho_uj_prime, rho_uj_prime) + p * I;
+                      TinyVector<Dimension> A_rho_E_prime = (rho_Ej_prime + p) / rhoj_prime * rho_uj_prime;
+
+                      double Fn_rho_prime                  = rhoj_prime / nb_waves;
+                      TinyVector<Dimension> Fn_rho_u_prime = 1. / nb_waves * rho_uj_prime;
+                      double Fn_rho_E_prime                = rho_Ej_prime / nb_waves;
+
+                      for (size_t d1 = 0; d1 < Dimension; ++d1) {
+                        Fn_rho_prime += inv_S[d1] * m_lambda_vector[i_wave][d1] * A_rho_prime[d1];
+                        for (size_t d2 = 0; d2 < Dimension; ++d2) {
+                          Fn_rho_u_prime[d1] += inv_S[d2] * m_lambda_vector[i_wave][d2] * A_rho_u_prime(d2, d1);
+                        }
+                        Fn_rho_E_prime += inv_S[d1] * m_lambda_vector[i_wave][d1] * A_rho_E_prime[d1];
+                      }
+                      Flr_rho[node_id][i_face_node][i_wave] += Fn_rho_prime * li_nlr_prime;
+                      Flr_rho_u[node_id][i_face_node][i_wave] += li_nlr_prime * Fn_rho_u_prime;
+                      Flr_rho_E[node_id][i_face_node][i_wave] += Fn_rho_E_prime * li_nlr_prime;
+
+                      sum_li_nlr[node_id][i_face_node][i_wave] += li_nlr_prime;
+                    }
+                  }
+                }
+              }
+            }
+          }
+        },
+        bc_v);
+    }
+
+    for (auto&& bc_v : bc_list) {
+      std::visit(
+        [=](auto&& bc) {
+          using BCType = std::decay_t<decltype(bc)>;
+          if constexpr (std::is_same_v<BCType, SymmetryBoundaryCondition>) {
+            auto 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];
+
+              const auto& face_to_node = face_to_node_matrix[face_id];
+
+              for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+                for (size_t i_node = 0; i_node < face_to_node.size(); ++i_node) {
+                  const NodeId node_id = face_to_node[i_node];
+
+                  const auto& face_local_number_in_its_node = face_local_numbers_in_their_nodes.itemArray(face_id);
+                  const size_t i_face_node                  = face_local_number_in_its_node[i_node];
+
+                  if (sum_li_nlr[node_id][i_face_node][i_wave] != 0) {
+                    Flr_rho[node_id][i_face_node][i_wave] =
+                      1. / sum_li_nlr[node_id][i_face_node][i_wave] * Flr_rho[node_id][i_face_node][i_wave];
+                    Flr_rho_u[node_id][i_face_node][i_wave] =
+                      1. / sum_li_nlr[node_id][i_face_node][i_wave] * Flr_rho_u[node_id][i_face_node][i_wave];
+                    Flr_rho_E[node_id][i_face_node][i_wave] =
+                      1. / sum_li_nlr[node_id][i_face_node][i_wave] * Flr_rho[node_id][i_face_node][i_wave];
+                  }
+                }
+              }
+            }
+          }
+        },
+        bc_v);
+    }
+  }
+
+  template <typename T>
+  CellArray<T>
+  compute_deltaLFn_glace(NodeArray<T> Fr)
   {
     if constexpr (Dimension > 1) {
       const NodeValuePerCell<const TinyVector<Dimension>> Cjr = MeshDataManager::instance().getMeshData(m_mesh).Cjr();
       const size_t nb_waves                                   = m_lambda_vector.size();
-      DiscreteFunctionP0Vector<double> deltaLFn(p_mesh, nb_waves);
+      CellArray<T> deltaLFn(p_mesh->connectivity(), nb_waves);
 
       const auto& cell_to_node_matrix = p_mesh->connectivity().cellToNodeMatrix();
 
+      if constexpr (is_tiny_vector_v<T>) {
+        deltaLFn.fill(zero);
+      } else {
+        deltaLFn.fill(0.);
+      }
+
       parallel_for(
         p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
           const auto& cell_to_node = cell_to_node_matrix[cell_id];
 
           for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
-            deltaLFn[cell_id][i_wave] = 0;
             for (size_t i_node = 0; i_node < cell_to_node.size(); ++i_node) {
               const NodeId node_id = cell_to_node[i_node];
 
               double li_Cjr = dot(m_lambda_vector[i_wave], Cjr(cell_id, i_node));
-              deltaLFn[cell_id][i_wave] += Fr[node_id][i_wave] * li_Cjr;
+              deltaLFn[cell_id][i_wave] += li_Cjr * Fr[node_id][i_wave];
             }
           }
         });
@@ -852,12 +1122,19 @@ class EulerKineticSolverMultiD
     }
   }
 
-  DiscreteFunctionP0Vector<double>
-  compute_deltaLFn_eucclhyd(FaceArrayPerNode<double> Fr)
+  template <typename T>
+  CellArray<T>
+  compute_deltaLFn_eucclhyd(FaceArrayPerNode<T> Flr)
   {
     if constexpr (Dimension > 1) {
       const size_t nb_waves = m_lambda_vector.size();
-      DiscreteFunctionP0Vector<double> deltaLFn(p_mesh, nb_waves);
+      CellArray<T> deltaLFn(p_mesh->connectivity(), nb_waves);
+
+      if constexpr (is_tiny_vector_v<T>) {
+        deltaLFn.fill(zero);
+      } else {
+        deltaLFn.fill(0.);
+      }
 
       const NodeValuePerFace<const TinyVector<Dimension>> Nlr = MeshDataManager::instance().getMeshData(m_mesh).Nlr();
 
@@ -871,8 +1148,6 @@ class EulerKineticSolverMultiD
           const auto& cell_to_face = cell_to_face_matrix[cell_id];
 
           for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
-            deltaLFn[cell_id][i_wave] = 0;
-
             for (size_t i_face_cell = 0; i_face_cell < cell_to_face.size(); ++i_face_cell) {
               const FaceId face_id     = cell_to_face[i_face_cell];
               const auto& face_to_node = face_to_node_matrix[face_id];
@@ -896,7 +1171,7 @@ class EulerKineticSolverMultiD
 
                 const double li_Nlr = sign * dot(m_lambda_vector[i_wave], Nlr(face_id, i_node_face));
 
-                deltaLFn[cell_id][i_wave] += Fr[node_id][i_face_node][i_wave] * li_Nlr;
+                deltaLFn[cell_id][i_wave] += li_Nlr * Flr[node_id][i_face_node][i_wave];
               }
             }
           }
@@ -1010,6 +1285,22 @@ class EulerKineticSolverMultiD
         bc_v);
     }
 
+    NodeValue<bool> is_symmetry_boundary_node{p_mesh->connectivity()};
+    is_symmetry_boundary_node.fill(false);
+    for (auto&& bc_v : bc_list) {
+      std::visit(
+        [=](auto&& bc) {
+          using BCType = std::decay_t<decltype(bc)>;
+          if constexpr (std::is_same_v<BCType, SymmetryBoundaryCondition>) {
+            auto node_list = bc.nodeList();
+            for (size_t i_node = 0; i_node < node_list.size(); ++i_node) {
+              is_symmetry_boundary_node[node_list[i_node]] = 1;
+            }
+          }
+        },
+        bc_v);
+    }
+
     const CellValue<const TinyVector<Dimension>> A_rho_ex   = getA_rho(rho_u_ex);
     const CellValue<const TinyMatrix<Dimension>> A_rho_u_ex = getA_rho_u(rho_ex, rho_u_ex, rho_E_ex);
     const CellValue<const TinyVector<Dimension>> A_rho_E_ex = getA_rho_E(rho_ex, rho_u_ex, rho_E_ex);
@@ -1032,59 +1323,40 @@ class EulerKineticSolverMultiD
     const CellValue<const TinyVector<Dimension>> rho_u = compute_PFn<TinyVector<Dimension>>(Fn_rho_u);
     const CellValue<const double> rho_E                = compute_PFn<double>(Fn_rho_E);
 
-    std::vector<std::shared_ptr<const IBoundaryDescriptor>> symmetry_boundary_descriptor_list;
-    // Reconstruction uniquement à l'intérieur donc pas utile
-    // for (auto&& bc_descriptor : bc_descriptor_list) {
-    //   if (bc_descriptor->type() == IBoundaryConditionDescriptor::Type::symmetry) {
-    //     symmetry_boundary_descriptor_list.push_back(bc_descriptor->boundaryDescriptor_shared());
-    //   }
-    // }
-
-    // PolynomialReconstructionDescriptor reconstruction_descriptor(IntegrationMethodType::cell_center, 1,
-    //                                                              symmetry_boundary_descriptor_list);
-
-    // auto reconstruction =
-    //   PolynomialReconstruction{reconstruction_descriptor}.build(DiscreteFunctionP0Vector(p_mesh, Fn_rho),
-    //                                                             DiscreteFunctionP0Vector(p_mesh, Fn_rho_E));
-    // auto DPk_Fn_rho = reconstruction[0]->template get<DiscreteFunctionDPkVector<Dimension, const double>>();
-    // // auto DPk_Fn_rho_u   = reconstruction[1]->get<DiscreteFunctionDPkVector<Dimension, const TinyVector < Dimension
-    // // >>> ();
-    // auto DPk_Fn_rho_E = reconstruction[2]->template get<DiscreteFunctionDPkVector<Dimension, const double>>();
-
-    // NodeArray<double> Fr_rho    = compute_Flux1(Fn_rho);
-    // NodeArray<double> Fr_rho_u1 = compute_Flux1(Fn_rho_u1);
-    // NodeArray<double> Fr_rho_u2 = compute_Flux1(Fn_rho_u2);
-    // NodeArray<double> Fr_rho_E  = compute_Flux1(Fn_rho_E);
-
-    // FaceArrayPerNode<double> Flr_rho    = compute_Flux1_eucchlyd(Fn_rho);
-    // FaceArrayPerNode<double> Flr_rho_u1 = compute_Flux1_eucchlyd(Fn_rho_u1);
-    // FaceArrayPerNode<double> Flr_rho_u2 = compute_Flux1_eucchlyd(Fn_rho_u2);
-    // FaceArrayPerNode<double> Flr_rho_E  = compute_Flux1_eucchlyd(Fn_rho_E);
-
-    FaceArray<double> Fl_rho                  = compute_Flux1_face<double>(Fn_rho);
-    FaceArray<TinyVector<Dimension>> Fl_rho_u = compute_Flux1_face<TinyVector<Dimension>>(Fn_rho_u);
-    FaceArray<double> Fl_rho_E                = compute_Flux1_face<double>(Fn_rho_E);
-
-    apply_bc(Fl_rho, Fl_rho_u, Fl_rho_E, rho, rho_u, rho_E, Fn_rho, Fn_rho_u, Fn_rho_E, bc_list);
-
-    synchronize(Fl_rho);
-    synchronize(Fl_rho_u);
-    synchronize(Fl_rho_E);
-
-    // DiscreteFunctionP0Vector<double> deltaLFn_rho    = compute_deltaLFn(Fr_rho);
-    // DiscreteFunctionP0Vector<double> deltaLFn_rho_u1 = compute_deltaLFn(Fr_rho_u1);
-    // DiscreteFunctionP0Vector<double> deltaLFn_rho_u2 = compute_deltaLFn(Fr_rho_u2);
-    // DiscreteFunctionP0Vector<double> deltaLFn_rho_E  = compute_deltaLFn(Fr_rho_E);
-
-    // DiscreteFunctionP0Vector<double> deltaLFn_rho    = compute_deltaLFn_eucclhyd(Flr_rho);
-    // DiscreteFunctionP0Vector<double> deltaLFn_rho_u1 = compute_deltaLFn_eucclhyd(Flr_rho_u1);
-    // DiscreteFunctionP0Vector<double> deltaLFn_rho_u2 = compute_deltaLFn_eucclhyd(Flr_rho_u2);
-    // DiscreteFunctionP0Vector<double> deltaLFn_rho_E  = compute_deltaLFn_eucclhyd(Flr_rho_E);
-
-    const CellArray<const double> deltaLFn_rho = compute_deltaLFn_face<double>(Fl_rho);
-    const CellArray<const TinyVector<Dimension>> deltaLFn_rho_u =
-      compute_deltaLFn_face<TinyVector<Dimension>>(Fl_rho_u);
-    const CellArray<const double> deltaLFn_rho_E = compute_deltaLFn_face<double>(Fl_rho_E);
+    // NodeArray<double> Fr_rho = compute_Flux1_glace<double>(Fn_rho, is_symmetry_boundary_node);
+    // NodeArray<TinyVector<Dimension>> Fr_rho_u =
+    //   compute_Flux1_glace<TinyVector<Dimension>>(Fn_rho_u, is_symmetry_boundary_node);
+    // NodeArray<double> Fr_rho_E = compute_Flux1_glace<double>(Fn_rho_E, is_symmetry_boundary_node);
+
+    FaceArrayPerNode<double> Flr_rho = compute_Flux1_eucclhyd<double>(Fn_rho, is_symmetry_boundary_node);
+    FaceArrayPerNode<TinyVector<Dimension>> Flr_rho_u =
+      compute_Flux1_eucclhyd<TinyVector<Dimension>>(Fn_rho_u, is_symmetry_boundary_node);
+    FaceArrayPerNode<double> Flr_rho_E = compute_Flux1_eucclhyd<double>(Fn_rho_E, is_symmetry_boundary_node);
+
+    // FaceArray<double> Fl_rho                  = compute_Flux1_face<double>(Fn_rho);
+    // FaceArray<TinyVector<Dimension>> Fl_rho_u = compute_Flux1_face<TinyVector<Dimension>>(Fn_rho_u);
+    // FaceArray<double> Fl_rho_E                = compute_Flux1_face<double>(Fn_rho_E);
+
+    //    apply_face_bc(Fl_rho, Fl_rho_u, Fl_rho_E, rho, rho_u, rho_E, Fn_rho, Fn_rho_u, Fn_rho_E, bc_list);
+    // apply_glace_bc(Fr_rho, Fr_rho_u, Fr_rho_E, rho, rho_u, rho_E, Fn_rho, Fn_rho_u, Fn_rho_E, bc_list);
+    apply_eucclhyd_bc(Flr_rho, Flr_rho_u, Flr_rho_E, rho, rho_u, rho_E, bc_list);
+
+    // synchronize(Flr_rho);
+    // synchronize(Flr_rho_u);
+    // synchronize(Flr_rho_E);
+
+    // const CellArray<const double> deltaLFn_rho                  = compute_deltaLFn_glace(Fr_rho);
+    // const CellArray<const TinyVector<Dimension>> deltaLFn_rho_u = compute_deltaLFn_glace(Fr_rho_u);
+    // const CellArray<const double> deltaLFn_rho_E                = compute_deltaLFn_glace(Fr_rho_E);
+
+    const CellArray<const double> deltaLFn_rho                  = compute_deltaLFn_eucclhyd(Flr_rho);
+    const CellArray<const TinyVector<Dimension>> deltaLFn_rho_u = compute_deltaLFn_eucclhyd(Flr_rho_u);
+    const CellArray<const double> deltaLFn_rho_E                = compute_deltaLFn_eucclhyd(Flr_rho_E);
+
+    // const CellArray<const double> deltaLFn_rho = compute_deltaLFn_face<double>(Fl_rho);
+    // const CellArray<const TinyVector<Dimension>> deltaLFn_rho_u =
+    //   compute_deltaLFn_face<TinyVector<Dimension>>(Fl_rho_u);
+    // const CellArray<const double> deltaLFn_rho_E = compute_deltaLFn_face<double>(Fl_rho_E);
 
     const CellValue<const TinyVector<Dimension>> A_rho   = getA_rho(rho_u);
     const CellValue<const TinyMatrix<Dimension>> A_rho_u = getA_rho_u(rho, rho_u, rho_E);
diff --git a/src/scheme/EulerKineticSolverMultiDOrder2.cpp b/src/scheme/EulerKineticSolverMultiDOrder2.cpp
index 8fade4f0387b8b4d4ff77a7f10abb56973b89463..82776378ca7350104635c83f47621f00d48cebf4 100644
--- a/src/scheme/EulerKineticSolverMultiDOrder2.cpp
+++ b/src/scheme/EulerKineticSolverMultiDOrder2.cpp
@@ -9,6 +9,7 @@
 #include <mesh/MeshFlatNodeBoundary.hpp>
 #include <mesh/MeshNodeBoundary.hpp>
 #include <mesh/MeshVariant.hpp>
+#include <mesh/StencilManager.hpp>
 #include <scheme/DiscreteFunctionDPkVariant.hpp>
 #include <scheme/DiscreteFunctionDPkVector.hpp>
 #include <scheme/DiscreteFunctionDescriptorP0Vector.hpp>
@@ -280,8 +281,8 @@ class EulerKineticSolverMultiDOrder2
   }
 
   template <typename T>
-  const CellValue<const T>
-  compute_PFnp1(const CellArray<const T>& Fn, const CellArray<const T>& deltaLFn)
+  CellValue<const T>
+  compute_PFnp1(const CellArray<const T>& Fn, const CellArray<const T>& deltaLFn, const CellArray<const T>& deltaLFnp1)
 
   {
     CellValue<T> PFnp1{p_mesh->connectivity()};
@@ -292,15 +293,30 @@ class EulerKineticSolverMultiDOrder2
       PFnp1.fill(0.);
     }
 
-    parallel_for(
-      m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
-        const double inv_Vj     = m_inv_Vj[cell_id];
-        const double dt_over_Vj = m_dt * inv_Vj;
+    if (m_TimeOrder == 1) {
+      parallel_for(
+        m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+          const double inv_Vj     = m_inv_Vj[cell_id];
+          const double dt_over_Vj = m_dt * inv_Vj;
 
-        for (size_t i_wave = 0; i_wave < m_lambda_vector.size(); ++i_wave) {
-          PFnp1[cell_id] += Fn[cell_id][i_wave] - dt_over_Vj * deltaLFn[cell_id][i_wave];
-        }
-      });
+          for (size_t i_wave = 0; i_wave < m_lambda_vector.size(); ++i_wave) {
+            PFnp1[cell_id] += Fn[cell_id][i_wave] - dt_over_Vj * deltaLFn[cell_id][i_wave];
+          }
+        });
+    } else if (m_TimeOrder == 2) {
+      parallel_for(
+        m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+          const double inv_Vj     = m_inv_Vj[cell_id];
+          const double dt_over_Vj = m_dt * inv_Vj;
+
+          for (size_t i_wave = 0; i_wave < m_lambda_vector.size(); ++i_wave) {
+            PFnp1[cell_id] +=
+              Fn[cell_id][i_wave] - 0.5 * dt_over_Vj * (deltaLFn[cell_id][i_wave] + deltaLFnp1[cell_id][i_wave]);
+          }
+        });
+    } else {
+      throw NotImplementedError("Eulerian scheme in multi D not implemented for order higher than 2");
+    }
 
     return PFnp1;
   }
@@ -374,7 +390,7 @@ class EulerKineticSolverMultiDOrder2
 
   template <typename T>
   FaceArrayPerNode<T>
-  compute_Flux1_eucchlyd(CellArray<T> Fn)
+  compute_Flux1_eucclhyd(CellArray<T> Fn)
   {
     if constexpr (Dimension > 1) {
       const NodeValuePerFace<const TinyVector<Dimension>> nlr = MeshDataManager::instance().getMeshData(m_mesh).nlr();
@@ -794,6 +810,137 @@ class EulerKineticSolverMultiDOrder2
     return is_boundary_cell;
   }
 
+  void
+  scalar_limiter(const CellArray<const double>& f, DiscreteFunctionDPkVector<Dimension, double>& DPk_fh) const
+  {
+    StencilManager::BoundaryDescriptorList symmetry_boundary_descriptor_list;
+    StencilDescriptor stencil_descriptor{1, StencilDescriptor::ConnectionType::by_nodes};
+    auto stencil = StencilManager::instance().getCellToCellStencilArray(m_mesh.connectivity(), stencil_descriptor,
+                                                                        symmetry_boundary_descriptor_list);
+    const size_t nb_waves = m_lambda_vector.size();
+
+    parallel_for(
+      m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+          const double fj = f[cell_id][i_wave];
+
+          double f_min = fj;
+          double f_max = fj;
+
+          const auto cell_stencil = stencil[cell_id];
+          for (size_t i_cell = 0; i_cell < cell_stencil.size(); ++i_cell) {
+            f_min = std::min(f_min, f[cell_stencil[i_cell]][i_wave]);
+            f_max = std::max(f_max, f[cell_stencil[i_cell]][i_wave]);
+          }
+
+          double f_bar_min = fj;
+          double f_bar_max = fj;
+
+          for (size_t i_cell = 0; i_cell < cell_stencil.size(); ++i_cell) {
+            const CellId cell_k_id = cell_stencil[i_cell];
+            const double f_xk      = DPk_fh(cell_id, i_wave)(m_xj[cell_k_id]);
+
+            f_bar_min = std::min(f_bar_min, f_xk);
+            f_bar_max = std::max(f_bar_max, f_xk);
+          }
+
+          const double eps = 1E-14;
+          double coef1     = 1;
+          if (std::abs(f_bar_max - fj) > eps) {
+            coef1 = (f_max - fj) / ((f_bar_max - fj));
+          }
+
+          double coef2 = 1.;
+          if (std::abs(f_bar_min - fj) > eps) {
+            coef2 = (f_min - fj) / ((f_bar_min - fj));
+          }
+
+          const double lambda = std::max(0., std::min(1., std::min(coef1, coef2)));
+
+          auto coefficients = DPk_fh.componentCoefficients(cell_id, i_wave);
+          coefficients[0]   = (1 - lambda) * f[cell_id][i_wave] + lambda * coefficients[0];
+          for (size_t i = 1; i < coefficients.size(); ++i) {
+            coefficients[i] *= lambda;
+          }
+        }
+      });
+  }
+
+  void
+  vector_limiter(const CellArray<const TinyVector<Dimension>>& f,
+                 DiscreteFunctionDPkVector<Dimension, TinyVector<Dimension>>& DPk_fh) const
+  {
+    StencilManager::BoundaryDescriptorList symmetry_boundary_descriptor_list;
+    StencilDescriptor stencil_descriptor{1, StencilDescriptor::ConnectionType::by_nodes};
+    auto stencil = StencilManager::instance().getCellToCellStencilArray(m_mesh.connectivity(), stencil_descriptor,
+                                                                        symmetry_boundary_descriptor_list);
+    const size_t nb_waves = m_lambda_vector.size();
+
+    parallel_for(
+      m_mesh.numberOfCells(), PUGS_LAMBDA(const CellId cell_id) {
+        for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+          const TinyVector<Dimension> fj = f[cell_id][i_wave];
+
+          TinyVector<Dimension> f_min = fj;
+          TinyVector<Dimension> f_max = fj;
+
+          const auto cell_stencil = stencil[cell_id];
+          for (size_t i_cell = 0; i_cell < cell_stencil.size(); ++i_cell) {
+            for (size_t dim = 0; dim < Dimension; ++dim) {
+              f_min[dim] = std::min(f_min[dim], f[cell_stencil[i_cell]][i_wave][dim]);
+              f_max[dim] = std::max(f_max[dim], f[cell_stencil[i_cell]][i_wave][dim]);
+            }
+          }
+
+          TinyVector<Dimension> f_bar_min = fj;
+          TinyVector<Dimension> f_bar_max = fj;
+
+          for (size_t i_cell = 0; i_cell < cell_stencil.size(); ++i_cell) {
+            const CellId cell_k_id           = cell_stencil[i_cell];
+            const TinyVector<Dimension> f_xk = DPk_fh(cell_id, i_wave)(m_xj[cell_k_id]);
+
+            for (size_t dim = 0; dim < Dimension; ++dim) {
+              f_bar_min[dim] = std::min(f_bar_min[dim], f_xk[dim]);
+              f_bar_max[dim] = std::max(f_bar_max[dim], f_xk[dim]);
+            }
+          }
+
+          const double eps = 1E-14;
+          TinyVector<Dimension> coef1;
+          for (size_t dim = 0; dim < Dimension; ++dim) {
+            coef1[dim] = 1;
+            if (std::abs(f_bar_max[dim] - fj[dim]) > eps) {
+              coef1[dim] = (f_max[dim] - fj[dim]) / ((f_bar_max[dim] - fj[dim]));
+            }
+          }
+
+          TinyVector<Dimension> coef2;
+          for (size_t dim = 0; dim < Dimension; ++dim) {
+            coef2[dim] = 1;
+            if (std::abs(f_bar_min[dim] - fj[dim]) > eps) {
+              coef2[dim] = (f_min[dim] - fj[dim]) / ((f_bar_min[dim] - fj[dim]));
+            }
+          }
+
+          double min_coef1 = coef1[0];
+          double min_coef2 = coef2[0];
+          for (size_t dim = 1; dim < Dimension; ++dim) {
+            min_coef1 = std::min(min_coef1, coef1[dim]);
+            min_coef2 = std::min(min_coef2, coef2[dim]);
+          }
+
+          const double lambda = std::max(0., std::min(1., std::min(min_coef1, min_coef2)));
+
+          auto coefficients = DPk_fh.componentCoefficients(cell_id, i_wave);
+
+          coefficients[0] = (1 - lambda) * f[cell_id][i_wave] + lambda * coefficients[0];
+          for (size_t i = 1; i < coefficients.size(); ++i) {
+            coefficients[i] *= lambda;
+          }
+        }
+      });
+  }
+
   std::tuple<std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>,
              std::shared_ptr<const DiscreteFunctionVariant>>
@@ -844,9 +991,9 @@ class EulerKineticSolverMultiDOrder2
     const CellArray<const TinyVector<Dimension>> Fn_rho_u = copy(m_Fn_rho_u);
     const CellArray<const double> Fn_rho_E                = copy(m_Fn_rho_E);
 
-    DiscreteFunctionP0Vector<double> Fnp1_rho(p_mesh, nb_waves);
-    DiscreteFunctionP0Vector<TinyVector<Dimension>> Fnp1_rho_u(p_mesh, nb_waves);
-    DiscreteFunctionP0Vector<double> Fnp1_rho_E(p_mesh, nb_waves);
+    CellArray<double> Fnp1_rho                  = copy(Fn_rho);
+    CellArray<TinyVector<Dimension>> Fnp1_rho_u = copy(Fn_rho_u);
+    CellArray<double> Fnp1_rho_E                = copy(Fn_rho_E);
 
     // Compute first order F
 
@@ -854,6 +1001,10 @@ class EulerKineticSolverMultiDOrder2
     const CellValue<const TinyVector<Dimension>> rho_u = compute_PFn<TinyVector<Dimension>>(Fn_rho_u);
     const CellValue<const double> rho_E                = compute_PFn<double>(Fn_rho_E);
 
+    CellValue<const double> rho_np1                  = copy(rho);
+    CellValue<const TinyVector<Dimension>> rho_u_np1 = copy(rho_u);
+    CellValue<const double> rho_E_np1                = copy(rho_E);
+
     std::vector<std::shared_ptr<const IBoundaryDescriptor>> symmetry_boundary_descriptor_list;
     // Reconstruction uniquement à l'intérieur donc pas utile
     // for (auto&& bc_descriptor : bc_descriptor_list) {
@@ -874,9 +1025,19 @@ class EulerKineticSolverMultiDOrder2
       reconstruction[1]->template get<DiscreteFunctionDPkVector<Dimension, const TinyVector<Dimension>>>();
     auto DPk_Fn_rho_E = reconstruction[2]->template get<DiscreteFunctionDPkVector<Dimension, const double>>();
 
-    FaceArray<double> Fl_rho                  = compute_Flux1_face<double>(DPk_Fn_rho);
-    FaceArray<TinyVector<Dimension>> Fl_rho_u = compute_Flux1_face<TinyVector<Dimension>>(DPk_Fn_rho_u);
-    FaceArray<double> Fl_rho_E                = compute_Flux1_face<double>(DPk_Fn_rho_E);
+    DiscreteFunctionDPkVector<Dimension, double> Fn_rho_lim   = copy(DPk_Fn_rho);
+    DiscreteFunctionDPkVector<Dimension, double> Fn_rho_E_lim = copy(DPk_Fn_rho_E);
+
+    scalar_limiter(Fn_rho, Fn_rho_lim);
+    scalar_limiter(Fn_rho_E, Fn_rho_E_lim);
+
+    DiscreteFunctionDPkVector<Dimension, TinyVector<Dimension>> Fn_rho_u_lim = copy(DPk_Fn_rho_u);
+
+    vector_limiter(Fn_rho_u, Fn_rho_u_lim);
+
+    FaceArray<double> Fl_rho                  = compute_Flux1_face<double>(Fn_rho_lim);
+    FaceArray<TinyVector<Dimension>> Fl_rho_u = compute_Flux1_face<TinyVector<Dimension>>(Fn_rho_u_lim);
+    FaceArray<double> Fl_rho_E                = compute_Flux1_face<double>(Fn_rho_E_lim);
 
     apply_bc(Fl_rho, Fl_rho_u, Fl_rho_E, rho, rho_u, rho_E, Fn_rho, Fn_rho_u, Fn_rho_E, bc_list);
 
@@ -897,46 +1058,121 @@ class EulerKineticSolverMultiDOrder2
     const CellArray<const TinyVector<Dimension>> M_rho_u = compute_vector_M(rho_u, A_rho_u);
     const CellArray<const double> M_rho_E                = compute_scalar_M(rho_E, A_rho_E);
 
-    const CellValue<const double> rho_np1 = compute_PFnp1<double>(Fn_rho, deltaLFn_rho);
-    const CellValue<const TinyVector<Dimension>> rho_u_np1 =
-      compute_PFnp1<TinyVector<Dimension>>(Fn_rho_u, deltaLFn_rho_u);
-    const CellValue<const double> rho_E_np1 = compute_PFnp1<double>(Fn_rho_E, deltaLFn_rho_E);
+    for (size_t i_subtimestep = 0; i_subtimestep < m_TimeOrder; i_subtimestep++) {
+      auto reconstruction_np1 =
+        PolynomialReconstruction{reconstruction_descriptor}.build(DiscreteFunctionP0Vector(p_mesh, Fnp1_rho),
+                                                                  DiscreteFunctionP0Vector(p_mesh, Fnp1_rho_u),
+                                                                  DiscreteFunctionP0Vector(p_mesh, Fnp1_rho_E));
+      auto DPk_Fnp1_rho = reconstruction[0]->template get<DiscreteFunctionDPkVector<Dimension, const double>>();
+      auto DPk_Fnp1_rho_u =
+        reconstruction[1]->template get<DiscreteFunctionDPkVector<Dimension, const TinyVector<Dimension>>>();
+      auto DPk_Fnp1_rho_E = reconstruction[2]->template get<DiscreteFunctionDPkVector<Dimension, const double>>();
 
-    const CellValue<const TinyVector<Dimension>> A_rho_np1   = getA_rho(rho_u_np1);
-    const CellValue<const TinyMatrix<Dimension>> A_rho_u_np1 = getA_rho_u(rho_np1, rho_u_np1, rho_E_np1);
-    const CellValue<const TinyVector<Dimension>> A_rho_E_np1 = getA_rho_E(rho_np1, rho_u_np1, rho_E_np1);
+      DiscreteFunctionDPkVector<Dimension, double> Fnp1_rho_lim   = copy(DPk_Fnp1_rho);
+      DiscreteFunctionDPkVector<Dimension, double> Fnp1_rho_E_lim = copy(DPk_Fnp1_rho_E);
 
-    const CellArray<const double> M_rho_np1                  = compute_scalar_M(rho_np1, A_rho_np1);
-    const CellArray<const TinyVector<Dimension>> M_rho_u_np1 = compute_vector_M(rho_u_np1, A_rho_u_np1);
-    const CellArray<const double> M_rho_E_np1                = compute_scalar_M(rho_E_np1, A_rho_E_np1);
+      scalar_limiter(Fnp1_rho, Fnp1_rho_lim);
+      scalar_limiter(Fnp1_rho_E, Fnp1_rho_E_lim);
 
-    parallel_for(
-      p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
-        if (not is_inflow_boundary_cell[cell_id]) {
-          const double c1 = 1. / (m_eps + m_dt);
-          const double c2 = m_eps * m_dt * m_inv_Vj[cell_id];
-          for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
-            Fnp1_rho[cell_id][i_wave] = c1 * (m_eps * Fn_rho[cell_id][i_wave] - c2 * deltaLFn_rho[cell_id][i_wave] +
-                                              m_dt * M_rho_np1[cell_id][i_wave]);
-            Fnp1_rho_u[cell_id][i_wave] =
-              c1 * (m_eps * Fn_rho_u[cell_id][i_wave] - c2 * deltaLFn_rho_u[cell_id][i_wave] +
-                    m_dt * M_rho_u_np1[cell_id][i_wave]);
-            Fnp1_rho_E[cell_id][i_wave] =
-              c1 * (m_eps * Fn_rho_E[cell_id][i_wave] - c2 * deltaLFn_rho_E[cell_id][i_wave] +
-                    m_dt * M_rho_E_np1[cell_id][i_wave]);
-          }
-        } else {
-          for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
-            Fnp1_rho[cell_id][i_wave]   = Fn_rho_ex[cell_id][i_wave];
-            Fnp1_rho_u[cell_id][i_wave] = Fn_rho_u_ex[cell_id][i_wave];
-            Fnp1_rho_E[cell_id][i_wave] = Fn_rho_E_ex[cell_id][i_wave];
-          }
-        }
-      });
+      DiscreteFunctionDPkVector<Dimension, TinyVector<Dimension>> Fnp1_rho_u_lim = copy(DPk_Fnp1_rho_u);
+
+      vector_limiter(Fnp1_rho_u, Fnp1_rho_u_lim);
+
+      FaceArray<double> Fl_rho_np1                  = compute_Flux1_face<double>(Fnp1_rho_lim);
+      FaceArray<TinyVector<Dimension>> Fl_rho_u_np1 = compute_Flux1_face<TinyVector<Dimension>>(Fnp1_rho_u_lim);
+      FaceArray<double> Fl_rho_E_np1                = compute_Flux1_face<double>(Fnp1_rho_E_lim);
+
+      apply_bc(Fl_rho_np1, Fl_rho_u_np1, Fl_rho_E_np1, rho_np1, rho_u_np1, rho_E_np1, Fnp1_rho, Fnp1_rho_u, Fnp1_rho_E,
+               bc_list);
+
+      synchronize(Fl_rho_np1);
+      synchronize(Fl_rho_u_np1);
+      synchronize(Fl_rho_E_np1);
+
+      const CellArray<const double> deltaLFnp1_rho = compute_deltaLFn_face<double>(Fl_rho_np1);
+      const CellArray<const TinyVector<Dimension>> deltaLFnp1_rho_u =
+        compute_deltaLFn_face<TinyVector<Dimension>>(Fl_rho_u_np1);
+      const CellArray<const double> deltaLFnp1_rho_E = compute_deltaLFn_face<double>(Fl_rho_E_np1);
+
+      rho_np1   = compute_PFnp1<double>(Fn_rho, deltaLFn_rho, deltaLFnp1_rho);
+      rho_u_np1 = compute_PFnp1<TinyVector<Dimension>>(Fn_rho_u, deltaLFn_rho_u, deltaLFnp1_rho_u);
+      rho_E_np1 = compute_PFnp1<double>(Fn_rho_E, deltaLFn_rho_E, deltaLFnp1_rho_E);
+
+      const CellValue<const TinyVector<Dimension>> A_rho_np1   = getA_rho(rho_u_np1);
+      const CellValue<const TinyMatrix<Dimension>> A_rho_u_np1 = getA_rho_u(rho_np1, rho_u_np1, rho_E_np1);
+      const CellValue<const TinyVector<Dimension>> A_rho_E_np1 = getA_rho_E(rho_np1, rho_u_np1, rho_E_np1);
+
+      const CellArray<const double> M_rho_np1                  = compute_scalar_M(rho_np1, A_rho_np1);
+      const CellArray<const TinyVector<Dimension>> M_rho_u_np1 = compute_vector_M(rho_u_np1, A_rho_u_np1);
+      const CellArray<const double> M_rho_E_np1                = compute_scalar_M(rho_E_np1, A_rho_E_np1);
+
+      if (m_TimeOrder == 1) {
+        parallel_for(
+          p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
+            if (not is_inflow_boundary_cell[cell_id]) {
+              const double c1 = 1. / (m_eps + m_dt);
+              const double c2 = m_eps * m_dt * m_inv_Vj[cell_id];
+              for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+                Fnp1_rho[cell_id][i_wave] = c1 * (m_eps * Fn_rho[cell_id][i_wave] - c2 * deltaLFn_rho[cell_id][i_wave] +
+                                                  m_dt * M_rho_np1[cell_id][i_wave]);
+                Fnp1_rho_u[cell_id][i_wave] =
+                  c1 * (m_eps * Fn_rho_u[cell_id][i_wave] - c2 * deltaLFn_rho_u[cell_id][i_wave] +
+                        m_dt * M_rho_u_np1[cell_id][i_wave]);
+                Fnp1_rho_E[cell_id][i_wave] =
+                  c1 * (m_eps * Fn_rho_E[cell_id][i_wave] - c2 * deltaLFn_rho_E[cell_id][i_wave] +
+                        m_dt * M_rho_E_np1[cell_id][i_wave]);
+              }
+            } else {
+              for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+                Fnp1_rho[cell_id][i_wave]   = Fn_rho_ex[cell_id][i_wave];
+                Fnp1_rho_u[cell_id][i_wave] = Fn_rho_u_ex[cell_id][i_wave];
+                Fnp1_rho_E[cell_id][i_wave] = Fn_rho_E_ex[cell_id][i_wave];
+              }
+            }
+          });
+      } else if (m_TimeOrder == 2) {
+        parallel_for(
+          p_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) {
+            if (not is_inflow_boundary_cell[cell_id]) {
+              const double c1 = 1. / (2 * m_eps + m_dt);
+              const double c2 = 2 * m_eps * m_dt * m_inv_Vj[cell_id];
+              for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+                Fnp1_rho[cell_id][i_wave] =
+                  c1 *
+                  (2 * m_eps * m_Fn_rho[cell_id][i_wave] -
+                   c2 * (deltaLFn_rho[cell_id][i_wave] + deltaLFnp1_rho[cell_id][i_wave]) +
+                   m_dt * M_rho_np1[cell_id][i_wave] + m_dt * (M_rho[cell_id][i_wave] - m_Fn_rho[cell_id][i_wave]));
+                Fnp1_rho_u[cell_id][i_wave] =
+                  c1 * (2 * m_eps * m_Fn_rho_u[cell_id][i_wave] -
+                        c2 * (deltaLFn_rho_u[cell_id][i_wave] + deltaLFnp1_rho_u[cell_id][i_wave]) +
+                        m_dt * M_rho_u_np1[cell_id][i_wave] +
+                        m_dt * (M_rho_u[cell_id][i_wave] - m_Fn_rho_u[cell_id][i_wave]));
+                Fnp1_rho_E[cell_id][i_wave] =
+                  c1 * (2 * m_eps * m_Fn_rho_E[cell_id][i_wave] -
+                        c2 * (deltaLFn_rho_E[cell_id][i_wave] + deltaLFnp1_rho_E[cell_id][i_wave]) +
+                        m_dt * M_rho_E_np1[cell_id][i_wave] +
+                        m_dt * (M_rho_E[cell_id][i_wave] - m_Fn_rho_E[cell_id][i_wave]));
+              }
+            } else {
+              for (size_t i_wave = 0; i_wave < nb_waves; ++i_wave) {
+                Fnp1_rho[cell_id][i_wave]   = Fn_rho_ex[cell_id][i_wave];
+                Fnp1_rho_u[cell_id][i_wave] = Fn_rho_u_ex[cell_id][i_wave];
+                Fnp1_rho_E[cell_id][i_wave] = Fn_rho_E_ex[cell_id][i_wave];
+              }
+            }
+          });
+      } else {
+        throw NotImplementedError("Lagrangian multi D scheme not implemented for time order higher than 2");
+      }
+    }
+
+    DiscreteFunctionP0Vector<const double> DFV_Fnp1_rho                  = DiscreteFunctionP0Vector(p_mesh, Fnp1_rho);
+    DiscreteFunctionP0Vector<const TinyVector<Dimension>> DFV_Fnp1_rho_u = DiscreteFunctionP0Vector(p_mesh, Fnp1_rho_u);
+    DiscreteFunctionP0Vector<const double> DFV_Fnp1_rho_E                = DiscreteFunctionP0Vector(p_mesh, Fnp1_rho_E);
 
-    return std::make_tuple(std::make_shared<DiscreteFunctionVariant>(Fnp1_rho),
-                           std::make_shared<DiscreteFunctionVariant>(Fnp1_rho_u),
-                           std::make_shared<DiscreteFunctionVariant>(Fnp1_rho_E));
+    return std::make_tuple(std::make_shared<DiscreteFunctionVariant>(DFV_Fnp1_rho),
+                           std::make_shared<DiscreteFunctionVariant>(DFV_Fnp1_rho_u),
+                           std::make_shared<DiscreteFunctionVariant>(DFV_Fnp1_rho_E));
   }
 
   EulerKineticSolverMultiDOrder2(std::shared_ptr<const MeshType> mesh,
@@ -1183,8 +1419,8 @@ eulerKineticSolverMultiDOrder2(
   if (mesh_v.use_count() == 0) {
     throw NormalError("F_rho, F_rho_u1, F_rho_u2 and F_rho_E have to be defined on the same mesh");
   }
-  if (SpaceOrder > 1 or TimeOrder > 1) {
-    throw NotImplementedError("Euler kinetic solver in Multi D not implemented at order > 1");
+  if (SpaceOrder > 2 or TimeOrder > 2) {
+    throw NotImplementedError("Euler kinetic solver in Multi D not implemented at order > 2");
   }
 
   return std::visit(