diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp
index 2491767f4dfaa9e988a4960d625f32077d32311d..477e3cc80cf439ae369cb1bd5074e53116eda91b 100644
--- a/src/language/modules/SchemeModule.cpp
+++ b/src/language/modules/SchemeModule.cpp
@@ -93,8 +93,8 @@ class InterpolateItemValue<OutputType(InputType)> : public PugsFunctionAdapter<O
   }
 };
 
-template <size_t Dimension>
-struct GlaceScheme
+template <size_t Dimension, AcousticSolverType solver_type>
+struct AcousticSolverScheme
 {
   using ConnectivityType = Connectivity<Dimension>;
   using MeshType         = Mesh<ConnectivityType>;
@@ -103,11 +103,11 @@ struct GlaceScheme
 
   std::shared_ptr<const MeshType> m_mesh;
 
-  GlaceScheme(std::shared_ptr<const IMesh> i_mesh,
-              const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
-              const FunctionSymbolId& rho_id,
-              const FunctionSymbolId& u_id,
-              const FunctionSymbolId& p_id)
+  AcousticSolverScheme(std::shared_ptr<const IMesh> i_mesh,
+                       const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
+                       const FunctionSymbolId& rho_id,
+                       const FunctionSymbolId& u_id,
+                       const FunctionSymbolId& p_id)
     : m_mesh{std::dynamic_pointer_cast<const MeshType>(i_mesh)}
   {
     std::cout << "number of bc descr = " << bc_descriptor_list.size() << '\n';
@@ -160,34 +160,6 @@ struct GlaceScheme
                 TinyVector<Dimension>)>::template interpolate<ItemType::node>(velocity_id, m_mesh->xr(), node_list);
 
               bc_list.push_back(VelocityBoundaryCondition{node_list, value_list});
-
-              // if constexpr (Dimension == 1) {
-              //   const auto& node_list = ref_face_list.list();
-
-              //   Array<const TinyVector<Dimension>> value_list = InterpolateItemValue<TinyVector<Dimension>(
-              //     TinyVector<Dimension>)>::template interpolate<FaceType>(velocity_id, m_mesh->xr(), node_list);
-
-              //   bc_list.push_back(VelocityBoundaryCondition{node_list, value_list});
-              // } else {
-              //   const auto& face_list           = ref_face_list.list();
-              //   const auto& face_to_node_matrix = m_mesh->connectivity().faceToNodeMatrix();
-              //   std::set<NodeId> node_set;
-              //   for (size_t i_face = 0; i_face < face_list.size(); ++i_face) {
-              //     FaceId face_id         = face_list[i_face];
-              //     const auto& face_nodes = face_to_node_matrix[face_id];
-              //     for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) {
-              //       node_set.insert(face_nodes[i_node]);
-              //     }
-              //   }
-
-              //   Array<NodeId> node_list = convert_to_array(node_set);
-
-              //   Array<const TinyVector<Dimension>> value_list = InterpolateItemValue<TinyVector<Dimension>(
-              //     TinyVector<Dimension>)>::template interpolate<ItemType::node>(velocity_id, m_mesh->xr(),
-              //     node_list);
-
-              //   bc_list.push_back(VelocityBoundaryCondition{node_list, value_list});
-              // }
             }
           }
           break;
@@ -249,7 +221,7 @@ struct GlaceScheme
     }
     unknowns.gammaj().fill(1.4);
 
-    AcousticSolver acoustic_solver(m_mesh, bc_list);
+    AcousticSolver acoustic_solver(m_mesh, bc_list, solver_type);
 
     const double tmax = 0.2;
     double t          = 0;
@@ -290,12 +262,13 @@ struct GlaceScheme
     while ((t < tmax) and (iteration < itermax)) {
       MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh);
 
-      // vtk_writer.write(m_mesh,
-      //                  {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()},
-      //                   NamedItemValue{"coords", m_mesh->xr()}, NamedItemValue{"xj", mesh_data.xj()},
-      //                   NamedItemValue{"cell_owner", m_mesh->connectivity().cellOwner()},
-      //                   NamedItemValue{"node_owner", m_mesh->connectivity().nodeOwner()}},
-      //                  t);
+      vtk_writer.write(m_mesh,
+                       {NamedItemValue{"density", rhoj}, NamedItemValue{"velocity", unknowns.uj()},
+                        NamedItemValue{"coords", m_mesh->xr()}, NamedItemValue{"xj", mesh_data.xj()},
+                        NamedItemValue{"cell_owner", m_mesh->connectivity().cellOwner()},
+                        NamedItemValue{"node_owner", m_mesh->connectivity().nodeOwner()}},
+                       t);
+
       double dt = 0.4 * acoustic_solver.acoustic_dt(mesh_data.Vj(), cj);
       if (t + dt > tmax) {
         dt = tmax - t;
@@ -392,35 +365,63 @@ SchemeModule::SchemeModule()
 
                               ));
 
-  this->_addBuiltinFunction("glace",
-                            std::make_shared<BuiltinFunctionEmbedder<
-                              void(std::shared_ptr<const IMesh>,
-                                   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&,
-                                   const FunctionSymbolId&, const FunctionSymbolId&, const FunctionSymbolId&)>>(
-
-                              [](std::shared_ptr<const IMesh> p_mesh,
-                                 const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
-                                   bc_descriptor_list,
-                                 const FunctionSymbolId& rho_id, const FunctionSymbolId& u_id,
-                                 const FunctionSymbolId& p_id) -> void {
-                                switch (p_mesh->dimension()) {
-                                case 1: {
-                                  GlaceScheme<1>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
-                                  break;
-                                }
-                                case 2: {
-                                  GlaceScheme<2>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
-                                  break;
-                                }
-                                case 3: {
-                                  GlaceScheme<3>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
-                                  break;
-                                }
-                                default: {
-                                  throw UnexpectedError("invalid mesh dimension");
-                                }
-                                }
-                              }
+  this->_addBuiltinFunction(
+    "glace",
+    std::make_shared<BuiltinFunctionEmbedder<
+      void(std::shared_ptr<const IMesh>, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&,
+           const FunctionSymbolId&, const FunctionSymbolId&, const FunctionSymbolId&)>>(
+
+      [](std::shared_ptr<const IMesh> p_mesh,
+         const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
+         const FunctionSymbolId& rho_id, const FunctionSymbolId& u_id, const FunctionSymbolId& p_id) -> void {
+        switch (p_mesh->dimension()) {
+        case 1: {
+          AcousticSolverScheme<1, AcousticSolverType::Glace>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
+          break;
+        }
+        case 2: {
+          AcousticSolverScheme<2, AcousticSolverType::Glace>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
+          break;
+        }
+        case 3: {
+          AcousticSolverScheme<3, AcousticSolverType::Glace>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
+          break;
+        }
+        default: {
+          throw UnexpectedError("invalid mesh dimension");
+        }
+        }
+      }
 
-                              ));
+      ));
+
+  this->_addBuiltinFunction(
+    "eucclhyd",
+    std::make_shared<BuiltinFunctionEmbedder<
+      void(std::shared_ptr<const IMesh>, const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&,
+           const FunctionSymbolId&, const FunctionSymbolId&, const FunctionSymbolId&)>>(
+
+      [](std::shared_ptr<const IMesh> p_mesh,
+         const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list,
+         const FunctionSymbolId& rho_id, const FunctionSymbolId& u_id, const FunctionSymbolId& p_id) -> void {
+        switch (p_mesh->dimension()) {
+        case 1: {
+          AcousticSolverScheme<1, AcousticSolverType::Eucclhyd>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
+          break;
+        }
+        case 2: {
+          AcousticSolverScheme<2, AcousticSolverType::Eucclhyd>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
+          break;
+        }
+        case 3: {
+          AcousticSolverScheme<3, AcousticSolverType::Eucclhyd>{p_mesh, bc_descriptor_list, rho_id, u_id, p_id};
+          break;
+        }
+        default: {
+          throw UnexpectedError("invalid mesh dimension");
+        }
+        }
+      }
+
+      ));
 }
diff --git a/src/mesh/MeshData.hpp b/src/mesh/MeshData.hpp
index fa5f2bf63c5e27ca79f0684dee98b2f9c32d249d..aeddc582f09332543df40fbcb11e368f1d7e929e 100644
--- a/src/mesh/MeshData.hpp
+++ b/src/mesh/MeshData.hpp
@@ -32,6 +32,8 @@ class MeshData : public IMeshData
 
  private:
   const MeshType& m_mesh;
+  NodeValuePerFace<const Rd> m_Nlr;
+  NodeValuePerFace<const Rd> m_nlr;
   NodeValuePerCell<const Rd> m_Cjr;
   NodeValuePerCell<const double> m_ljr;
   NodeValuePerCell<const Rd> m_njr;
@@ -39,7 +41,6 @@ class MeshData : public IMeshData
   CellValue<const Rd> m_xj;
   CellValue<const double> m_Vj;
   FaceValue<const double> m_ll;
-  NodeValuePerFace<const Rd> m_Nlr;
 
   PUGS_INLINE
   void
@@ -48,7 +49,7 @@ class MeshData : public IMeshData
     if constexpr (Dimension == 1) {
       static_assert(Dimension != 1, "ll does not make sense in 1d");
     } else {
-      const auto& nlr = this->Nlr();
+      const auto& Nlr = this->Nlr();
 
       FaceValue<double> ll{m_mesh.connectivity()};
 
@@ -59,7 +60,7 @@ class MeshData : public IMeshData
 
           double lenght = 0;
           for (size_t i_node = 0; i_node < face_nodes.size(); ++i_node) {
-            lenght += l2Norm(nlr(face_id, i_node));
+            lenght += l2Norm(Nlr(face_id, i_node));
           }
 
           ll[face_id] = lenght;
@@ -69,6 +70,27 @@ class MeshData : public IMeshData
     }
   }
 
+  PUGS_INLINE
+  void
+  _compute_nlr()
+  {
+    if constexpr (Dimension == 1) {
+      static_assert(Dimension != 1, "nlr does not make sense in 1d");
+    } else {
+      const auto& Nlr = this->Nlr();
+
+      NodeValuePerFace<Rd> nlr{m_mesh.connectivity()};
+
+      parallel_for(
+        Nlr.numberOfValues(), PUGS_LAMBDA(size_t lr) {
+          double length = l2Norm(Nlr[lr]);
+          nlr[lr]       = 1. / length * Nlr[lr];
+        });
+
+      m_nlr = nlr;
+    }
+  }
+
   PUGS_INLINE void
   _computeFaceIsobarycenter()
   {   // Computes vertices isobarycenter
@@ -368,6 +390,16 @@ class MeshData : public IMeshData
     return m_Nlr;
   }
 
+  PUGS_INLINE
+  NodeValuePerFace<const Rd>
+  nlr()
+  {
+    if (not m_nlr.isBuilt()) {
+      this->_compute_nlr();
+    }
+    return m_nlr;
+  }
+
   PUGS_INLINE
   NodeValuePerCell<const Rd>
   Cjr()
diff --git a/src/scheme/AcousticSolver.hpp b/src/scheme/AcousticSolver.hpp
index 88007ac4709f2163bbd0a1737bebbf5633ea074a..1e246f2dbf054715d67e80819078ed84b9441785 100644
--- a/src/scheme/AcousticSolver.hpp
+++ b/src/scheme/AcousticSolver.hpp
@@ -20,6 +20,12 @@
 
 #include <iostream>
 
+enum class AcousticSolverType
+{
+  Eucclhyd,
+  Glace
+};
+
 template <typename MeshType>
 class AcousticSolver
 {
@@ -47,6 +53,8 @@ class AcousticSolver
 
   const BoundaryConditionList m_boundary_condition_list;
 
+  const AcousticSolverType m_solver_type;
+
   void
   _applyPressureBC()
   {
@@ -173,11 +181,13 @@ class AcousticSolver
 
   PUGS_INLINE
   void
-  computeAjr(const CellValue<const double>& rhocj,
-             const NodeValuePerCell<const Rd>& Cjr,
-             const NodeValuePerCell<const double>& /* ljr */,
-             const NodeValuePerCell<const Rd>& njr)
+  _computeGlaceAjr(const CellValue<const double>& rhocj)
   {
+    MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh);
+
+    const NodeValuePerCell<const Rd> Cjr = mesh_data.Cjr();
+    const NodeValuePerCell<const Rd> njr = mesh_data.njr();
+
     parallel_for(
       m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) {
         const size_t& nb_nodes = m_Ajr.numberOfSubValues(j);
@@ -188,6 +198,71 @@ class AcousticSolver
       });
   }
 
+  PUGS_INLINE
+  void
+  _computeEucclhydAjr(const CellValue<const double>& rhocj)
+  {
+    MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh);
+
+    const NodeValuePerFace<const Rd> Nlr = mesh_data.Nlr();
+    const NodeValuePerFace<const Rd> nlr = mesh_data.nlr();
+
+    const auto& face_to_node_matrix = m_connectivity.faceToNodeMatrix();
+    const auto& cell_to_node_matrix = m_connectivity.cellToNodeMatrix();
+    const auto& cell_to_face_matrix = m_connectivity.cellToFaceMatrix();
+
+    parallel_for(
+      m_Ajr.numberOfValues(), PUGS_LAMBDA(size_t jr) { m_Ajr[jr] = zero; });
+
+    parallel_for(
+      m_mesh->numberOfCells(), PUGS_LAMBDA(CellId j) {
+        const auto& cell_nodes = cell_to_node_matrix[j];
+
+        const auto& cell_faces = cell_to_face_matrix[j];
+
+        const double& rho_c = rhocj[j];
+
+        for (size_t L = 0; L < cell_faces.size(); ++L) {
+          const FaceId& l        = cell_faces[L];
+          const auto& face_nodes = face_to_node_matrix[l];
+
+          auto local_node_number_in_cell = [&](NodeId node_number) {
+            for (size_t i_node = 0; i_node < cell_nodes.size(); ++i_node) {
+              if (node_number == cell_nodes[i_node]) {
+                return i_node;
+              }
+            }
+            return std::numeric_limits<size_t>::max();
+          };
+
+          for (size_t rl = 0; rl < face_nodes.size(); ++rl) {
+            const size_t R = local_node_number_in_cell(face_nodes[rl]);
+            m_Ajr(j, R) += tensorProduct(rho_c * Nlr(l, rl), nlr(l, rl));
+          }
+        }
+      });
+  }
+
+  PUGS_INLINE
+  void
+  computeAjr(const CellValue<const double>& rhocj)
+  {
+    switch (m_solver_type) {
+    case AcousticSolverType::Glace: {
+      this->_computeGlaceAjr(rhocj);
+      break;
+    }
+    case AcousticSolverType::Eucclhyd: {
+      if constexpr (Dimension > 1) {
+        this->_computeEucclhydAjr(rhocj);
+      } else {
+        this->_computeGlaceAjr(rhocj);
+      }
+      break;
+    }
+    }
+  }
+
   PUGS_INLINE
   const NodeValue<const Rdd>
   computeAr(const NodeValuePerCell<const Rdd>& Ajr)
@@ -214,11 +289,13 @@ class AcousticSolver
 
   PUGS_INLINE
   const NodeValue<const Rd>
-  computeBr(const NodeValuePerCell<Rdd>& Ajr,
-            const NodeValuePerCell<const Rd>& Cjr,
-            const CellValue<const Rd>& uj,
-            const CellValue<const double>& pj)
+  computeBr(const CellValue<const Rd>& uj, const CellValue<const double>& pj)
   {
+    MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh);
+
+    const NodeValuePerCell<const Rd>& Cjr  = mesh_data.Cjr();
+    const NodeValuePerCell<const Rdd>& Ajr = m_Ajr;
+
     const auto& node_to_cell_matrix               = m_connectivity.nodeToCellMatrix();
     const auto& node_local_numbers_in_their_cells = m_connectivity.nodeLocalNumbersInTheirCells();
 
@@ -246,24 +323,28 @@ class AcousticSolver
     this->_applyVelocityBC();
   }
 
-  NodeValue<Rd>
-  computeUr(const NodeValue<const Rdd>& Ar, const NodeValue<const Rd>& br)
+  void
+  computeUr()
   {
+    const NodeValue<const Rdd> Ar = m_Ar;
+    const NodeValue<const Rd> br  = m_br;
+
     inverse(Ar, m_inv_Ar);
     const NodeValue<const Rdd> invAr = m_inv_Ar;
     parallel_for(
       m_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId r) { m_ur[r] = invAr[r] * br[r]; });
-
-    return m_ur;
   }
 
   void
-  computeFjr(const NodeValuePerCell<Rdd>& Ajr,
-             const NodeValue<const Rd>& ur,
-             const NodeValuePerCell<const Rd>& Cjr,
-             const CellValue<const Rd>& uj,
-             const CellValue<const double>& pj)
+  computeFjr(const CellValue<const Rd>& uj, const CellValue<const double>& pj)
   {
+    MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh);
+
+    const NodeValuePerCell<const Rd> Cjr  = mesh_data.Cjr();
+    const NodeValuePerCell<const Rdd> Ajr = m_Ajr;
+
+    const NodeValue<const Rd> ur = m_ur;
+
     const auto& cell_to_node_matrix = m_mesh->connectivity().cellToNodeMatrix();
 
     parallel_for(
@@ -288,26 +369,22 @@ class AcousticSolver
   computeExplicitFluxes(const CellValue<const double>& rhoj,
                         const CellValue<const Rd>& uj,
                         const CellValue<const double>& pj,
-                        const CellValue<const double>& cj,
-                        const NodeValuePerCell<const Rd>& Cjr,
-                        const NodeValuePerCell<const double>& ljr,
-                        const NodeValuePerCell<const Rd>& njr)
+                        const CellValue<const double>& cj)
   {
     const CellValue<const double> rhocj = computeRhoCj(rhoj, cj);
-    computeAjr(rhocj, Cjr, ljr, njr);
+    computeAjr(rhocj);
 
     NodeValuePerCell<const Rdd> Ajr = m_Ajr;
     this->computeAr(Ajr);
-    this->computeBr(m_Ajr, Cjr, uj, pj);
+    this->computeBr(uj, pj);
 
     this->applyBoundaryConditions();
 
     synchronize(m_Ar);
     synchronize(m_br);
 
-    NodeValue<Rd>& ur = m_ur;
-    ur                = computeUr(m_Ar, m_br);
-    computeFjr(m_Ajr, ur, Cjr, uj, pj);
+    computeUr();
+    computeFjr(uj, pj);
   }
 
   NodeValue<Rd> m_br;
@@ -320,10 +397,13 @@ class AcousticSolver
   CellValue<double> m_Vj_over_cj;
 
  public:
-  AcousticSolver(std::shared_ptr<const MeshType> p_mesh, const BoundaryConditionList& bc_list)
+  AcousticSolver(std::shared_ptr<const MeshType> p_mesh,
+                 const BoundaryConditionList& bc_list,
+                 const AcousticSolverType solver_type)
     : m_mesh(p_mesh),
       m_connectivity(m_mesh->connectivity()),
       m_boundary_condition_list(bc_list),
+      m_solver_type(solver_type),
       m_br(m_connectivity),
       m_Ajr(m_connectivity),
       m_Ar(m_connectivity),
@@ -372,12 +452,9 @@ class AcousticSolver
 
     MeshData<Dimension>& mesh_data = MeshDataManager::instance().getMeshData(*m_mesh);
 
-    const CellValue<const double> Vj         = mesh_data.Vj();
-    const NodeValuePerCell<const Rd> Cjr     = mesh_data.Cjr();
-    const NodeValuePerCell<const double> ljr = mesh_data.ljr();
-    const NodeValuePerCell<const Rd> njr     = mesh_data.njr();
+    const CellValue<const double> Vj = mesh_data.Vj();
 
-    computeExplicitFluxes(rhoj, uj, pj, cj, Cjr, ljr, njr);
+    computeExplicitFluxes(rhoj, uj, pj, cj);
 
     const NodeValuePerCell<Rd>& Fjr = m_Fjr;
     const NodeValue<const Rd> ur    = m_ur;