diff --git a/src/scheme/ScalarNodalScheme.cpp b/src/scheme/ScalarNodalScheme.cpp
index fd4e2d5bd210e0aa3e61759c982770ce47685124..791e1c8ff7b94c39663bea036faff5ecc5a08b51 100644
--- a/src/scheme/ScalarNodalScheme.cpp
+++ b/src/scheme/ScalarNodalScheme.cpp
@@ -128,8 +128,8 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand
 
   ScalarNodalScheme(const std::shared_ptr<const MeshType>& mesh,
                       const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& alpha,
-                      const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyMatrix<Dimension>>>& nod_k_bound,
-                      const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyMatrix<Dimension>>>& nod_k,
+                      const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyMatrix<Dimension>>>& cell_k_bound,
+                      const std::shared_ptr<const DiscreteFunctionP0<Dimension, TinyMatrix<Dimension>>>& cell_k,
                       const std::shared_ptr<const DiscreteFunctionP0<Dimension, double>>& f,
                       const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list)
   {
@@ -246,7 +246,7 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand
         return compute_face_dof_number;
       }();
 
-      const FaceValue<const bool> primal_face_is_neumann = [&] {
+      const FaceValue<const bool> face_is_neumann = [&] {
         FaceValue<bool> face_is_neumann{mesh->connectivity()};
         face_is_neumann.fill(false);
         for (const auto& boundary_condition : boundary_condition_list) {
@@ -269,64 +269,27 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand
         return face_is_neumann;
       }();
 
-      const auto& primal_face_to_node_matrix = mesh->connectivity().faceToNodeMatrix();
-      const auto& face_to_cell_matrix        = mesh->connectivity().faceToCellMatrix();
-      NodeValue<bool> primal_node_is_on_boundary(mesh->connectivity());
-      if (parallel::size() > 1) {
-        throw NotImplementedError("Calculation of node_is_on_boundary is incorrect");
-      }
-
-      primal_node_is_on_boundary.fill(false);
-      for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
-        if (face_to_cell_matrix[face_id].size() == 1) {
-          for (size_t i_node = 0; i_node < primal_face_to_node_matrix[face_id].size(); ++i_node) {
-            NodeId node_id                      = primal_face_to_node_matrix[face_id][i_node];
-            primal_node_is_on_boundary[node_id] = true;
-          }
-        }
-      }
-
-      FaceValue<bool> primal_face_is_on_boundary(mesh->connectivity());
-      if (parallel::size() > 1) {
-        throw NotImplementedError("Calculation of face_is_on_boundary is incorrect");
-      }
-
-      primal_face_is_on_boundary.fill(false);
-      for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
-        if (face_to_cell_matrix[face_id].size() == 1) {
-          primal_face_is_on_boundary[face_id] = true;
-        }
-      }
-
-      FaceValue<bool> primal_face_is_dirichlet(mesh->connectivity());
-      if (parallel::size() > 1) {
-        throw NotImplementedError("Calculation of face_is_neumann is incorrect");
-      }
-
-      primal_face_is_dirichlet.fill(false);
-      for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
-        primal_face_is_dirichlet[face_id] = (primal_face_is_on_boundary[face_id] && (!primal_face_is_neumann[face_id]));
-      }
-
 
       MeshDataType& mesh_data = MeshDataManager::instance().getMeshData(*mesh);
 
       const FaceValue<const TinyVector<Dimension>>& xl = mesh_data.xl();
       const CellValue<const TinyVector<Dimension>>& xj = mesh_data.xj();
-      const auto& node_to_face_matrix                  = mesh->connectivity().nodeToFaceMatrix();
+      const NodeValue<const TinyVector<Dimension>>& xr = mesh_data.xr();
 
-      {
-        std::shared_ptr diamond_mesh = DualMeshManager::instance().getDiamondDualMesh(*mesh);
+      const auto& node_to_face_matrix = mesh->connectivity().nodeToFaceMatrix();
+      const auto& cell_to_node_matrix = mesh.connectivity().cellToNodeMatrix();
+      const auto& node_local_numbers_in_their_cells = mesh.connectivity().nodeLocalNumbersInTheirCells();
 
-        MeshDataType& diamond_mesh_data = MeshDataManager::instance().getMeshData(*diamond_mesh);
+      const NodeValuePerCell<const TinyVector<Dimension>>& Cjr = mesh_data.Cjr();
 
-        std::shared_ptr mapper =
-          DualConnectivityManager::instance().getPrimalToDiamondDualConnectivityDataMapper(mesh->connectivity());
+      {
 
-        CellValue<const TinyMatrix<Dimension>> nod_kappar  = nod_k->cellValues();
-        CellValue<const TinyMatrix<Dimension>> nod_kapparb = nod_k_bound->cellValues();
 
-        const CellValue<const double> dual_Vj = diamond_mesh_data.Vj();
+        CellValue<const TinyMatrix<Dimension>> cell_kappaj  = cell_k->cellValues();
+        CellValue<const TinyMatrix<Dimension>> cell_kappajb = cell_k_bound->cellValues();
+
+        const CellValue<const double> Vj = mesh_data.Vj();
+        const auto& node_to_cell_matrix = mesh->connectivity().nodeToCellMatrix();
 
         const FaceValue<const double> mes_l = [&] {
           if constexpr (Dimension == 1) {
@@ -338,92 +301,59 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand
           }
         }();
 
-        const CellValue<const double> dual_mes_l_j = [=] {
-          CellValue<double> compute_mes_j{diamond_mesh->connectivity()};
-          mapper->toDualCell(mes_l, compute_mes_j);
-
-          return compute_mes_j;
-        }();
-
-        FaceValue<const CellId> face_dual_cell_id = [=]() {
-          FaceValue<CellId> computed_face_dual_cell_id{mesh->connectivity()};
-          CellValue<CellId> dual_cell_id{diamond_mesh->connectivity()};
+        const NodeValue<const TinyMatrix<Dimension>> node_kappar = [&] {
+          NodeValue<const TinyMatrix<Dimension>> kappa;
           parallel_for(
-            diamond_mesh->numberOfCells(), PUGS_LAMBDA(CellId cell_id) { dual_cell_id[cell_id] = cell_id; });
-
-          mapper->fromDualCell(dual_cell_id, computed_face_dual_cell_id);
-
-          return computed_face_dual_cell_id;
+              mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) {
+                kappa[node_id] = zero;
+                const auto& node_to_cell = node_to_cell_matrix[node_id];
+                double weight = 0;
+                for (size_t j = 0; j < node_to_cell.size(); ++j) {
+                  const CellId J       = node_to_cell[j];
+                  double local_weight = 1 / l2Norm(xr[node_id]-xj[J]);
+                  kappa[node_id] += cell_kappaj[J] * local_weight;
+                  weight += local_weight;
+                }
+                kappa[node_id] /= weight;
+            }
+          );
+          return kappa;
         }();
 
-        NodeValue<const NodeId> dual_node_primal_node_id = [=]() {
-          CellValue<NodeId> cell_ignored_id{mesh->connectivity()};
-          cell_ignored_id.fill(NodeId{std::numeric_limits<unsigned int>::max()});
-
-          NodeValue<NodeId> node_primal_id{mesh->connectivity()};
-
+        const NodeValue<const TinyMatrix<Dimension>> node_kapparb = [&] {
+          NodeValue<const TinyMatrix<Dimension>> kappa;
           parallel_for(
-            mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { node_primal_id[node_id] = node_id; });
-
-          NodeValue<NodeId> computed_dual_node_primal_node_id{diamond_mesh->connectivity()};
-
-          mapper->toDualNode(node_primal_id, cell_ignored_id, computed_dual_node_primal_node_id);
-
-          return computed_dual_node_primal_node_id;
+              mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) {
+                kappa[node_id] = zero;
+                const auto& node_to_cell = node_to_cell_matrix[node_id];
+                double weight = 0;
+                for (size_t j = 0; j < node_to_cell.size(); ++j) {
+                  const CellId J       = node_to_cell[j];
+                  double local_weight = 1 / l2Norm(xr[node_id]-xj[J]);
+                  kappa[node_id] += cell_kappajb[J] * local_weight;
+                  weight += local_weight;
+                }
+                kappa[node_id] /= weight;
+            });
+          return kappa;
         }();
 
-        CellValue<NodeId> primal_cell_dual_node_id = [=]() {
-          CellValue<NodeId> cell_id{mesh->connectivity()};
-          NodeValue<NodeId> node_ignored_id{mesh->connectivity()};
-          node_ignored_id.fill(NodeId{std::numeric_limits<unsigned int>::max()});
-
-          NodeValue<NodeId> dual_node_id{diamond_mesh->connectivity()};
-
-          parallel_for(
-            diamond_mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) { dual_node_id[node_id] = node_id; });
-
-          CellValue<NodeId> computed_primal_cell_dual_node_id{mesh->connectivity()};
-
-          mapper->fromDualNode(dual_node_id, node_ignored_id, cell_id);
-
-          return cell_id;
-        }();
-        const auto& dual_Cjr                     = diamond_mesh_data.Cjr();
-        FaceValue<TinyVector<Dimension>> dualClj = [&] {
-          FaceValue<TinyVector<Dimension>> computedClj{mesh->connectivity()};
-          const auto& dual_node_to_cell_matrix = diamond_mesh->connectivity().nodeToCellMatrix();
-          const auto& dual_cell_to_node_matrix = diamond_mesh->connectivity().cellToNodeMatrix();
+        const NodeValue<const TinyMatrix<Dimension>> node_betar = [&] {
+          NodeValue<const TinyMatrix<Dimension>> beta;
           parallel_for(
-            mesh->numberOfFaces(), PUGS_LAMBDA(FaceId face_id) {
-              const auto& primal_face_to_cell = face_to_cell_matrix[face_id];
-              for (size_t i = 0; i < primal_face_to_cell.size(); i++) {
-                CellId cell_id            = primal_face_to_cell[i];
-                const NodeId dual_node_id = primal_cell_dual_node_id[cell_id];
-                for (size_t i_dual_cell = 0; i_dual_cell < dual_node_to_cell_matrix[dual_node_id].size();
-                     i_dual_cell++) {
-                  const CellId dual_cell_id = dual_node_to_cell_matrix[dual_node_id][i_dual_cell];
-                  if (face_dual_cell_id[face_id] == dual_cell_id) {
-                    for (size_t i_dual_node = 0; i_dual_node < dual_cell_to_node_matrix[dual_cell_id].size();
-                         i_dual_node++) {
-                      const NodeId final_dual_node_id = dual_cell_to_node_matrix[dual_cell_id][i_dual_node];
-                      if (final_dual_node_id == dual_node_id) {
-                        computedClj[face_id] = dual_Cjr(dual_cell_id, i_dual_node);
-                      }
-                    }
-                  }
+            mesh->numberOfNodes(), PUGS_LAMBDA(NodeId node_id) {
+              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];
+              beta[node_id] = zero;
+                for (size_t j = 0; j < node_to_cell.size(); ++j) {
+                  const CellId J = node_to_cell[j];
+                  const unsigned int R = node_local_number_in_its_cell[j];
+                  beta[node_id] += tensorProduct(Cjr(J,R),xr[node_id]-xj[J]);
                 }
-              }
             });
-          return computedClj;
+            return beta;
         }();
 
-        FaceValue<TinyVector<Dimension>> nlj = [&] {
-          FaceValue<TinyVector<Dimension>> computedNlj{mesh->connectivity()};
-          parallel_for(
-            mesh->numberOfFaces(),
-            PUGS_LAMBDA(FaceId face_id) { computedNlj[face_id] = 1. / l2Norm(dualClj[face_id]) * dualClj[face_id]; });
-          return computedNlj;
-        }();
 
         FaceValue<const double> alpha_l = [&] {
           FaceValue<double> alpha_j{mesh->connectivity()};
@@ -447,23 +377,22 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand
           return alpha_lb;
         }();
 
-        const CellValue<const double> primal_Vj = mesh_data.Vj();
 
         const Array<int> non_zeros{number_of_dof};
-        non_zeros.fill(Dimension);
+        non_zeros.fill(Dimension); //Modif pour optimiser
         CRSMatrixDescriptor<double> S(number_of_dof, number_of_dof, non_zeros);
 
         for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
-          const auto& primal_face_to_cell = face_to_cell_matrix[face_id];
+          const auto& face_to_cell = face_to_cell_matrix[face_id];
           const double beta_l             = l2Norm(dualClj[face_id]) * alpha_l[face_id] * mes_l[face_id];
           const double betab_l            = l2Norm(dualClj[face_id]) * alphab_l[face_id] * mes_l[face_id];
-          for (size_t i_cell = 0; i_cell < primal_face_to_cell.size(); ++i_cell) {
-            const CellId cell_id1 = primal_face_to_cell[i_cell];
-            for (size_t j_cell = 0; j_cell < primal_face_to_cell.size(); ++j_cell) {
-              const CellId cell_id2 = primal_face_to_cell[j_cell];
+          for (size_t i_cell = 0; i_cell < face_to_cell.size(); ++i_cell) {
+            const CellId cell_id1 = face_to_cell[i_cell];
+            for (size_t j_cell = 0; j_cell < face_to_cell.size(); ++j_cell) {
+              const CellId cell_id2 = face_to_cell[j_cell];
               if (i_cell == j_cell) {
                 S(cell_dof_number[cell_id1], cell_dof_number[cell_id2]) += beta_l;
-                if (primal_face_is_neumann[face_id]) {
+                if (face_is_neumann[face_id]) {
                   S(face_dof_number[face_id], cell_dof_number[cell_id2]) -= betab_l;
                 }
               } else {
@@ -475,12 +404,12 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand
 
         for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) {
           const size_t j = cell_dof_number[cell_id];
-          S(j, j) += (*alpha)[cell_id] * primal_Vj[cell_id];
+          S(j, j) += (*alpha)[cell_id] * Vj[cell_id];
         }
 
 
         for (FaceId face_id = 0; face_id < mesh->numberOfFaces(); ++face_id) {
-          if (primal_face_is_dirichlet[face_id]) {
+          if (face_is_dirichlet[face_id]) {
             S(face_dof_number[face_id], face_dof_number[face_id]) += 1;
           }
         }
@@ -491,7 +420,7 @@ class ScalarNodalSchemeHandler::ScalarNodalScheme : public ScalarNodalSchemeHand
         Vector<double> b{number_of_dof};
         b = zero;
         for (CellId cell_id = 0; cell_id < mesh->numberOfCells(); ++cell_id) {
-          b[cell_dof_number[cell_id]] = fj[cell_id] * primal_Vj[cell_id];
+          b[cell_dof_number[cell_id]] = fj[cell_id] * Vj[cell_id];
         }
         // Dirichlet on b^L_D
         {
@@ -552,8 +481,8 @@ ScalarNodalSchemeHandler::solution() const
 
 ScalarNodalSchemeHandler::ScalarNodalSchemeHandler(
   const std::shared_ptr<const IDiscreteFunction>& alpha,
-  const std::shared_ptr<const IDiscreteFunction>& nod_k_bound,
-  const std::shared_ptr<const IDiscreteFunction>& nod_k,
+  const std::shared_ptr<const IDiscreteFunction>& k_bound,
+  const std::shared_ptr<const IDiscreteFunction>& cell_k,
   const std::shared_ptr<const IDiscreteFunction>& f,
   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list)
 {
@@ -561,11 +490,11 @@ ScalarNodalSchemeHandler::ScalarNodalSchemeHandler(
   if (not i_mesh) {
     throw NormalError("primal discrete functions are not defined on the same mesh");
   }
-  const std::shared_ptr i_dual_mesh = getCommonMesh({nod_k_bound, nod_k});
+  const std::shared_ptr i_dual_mesh = getCommonMesh({cell_k_bound, cell_k});
   if (not i_dual_mesh) {
     throw NormalError("dual discrete functions are not defined on the same mesh");
   }
-  checkDiscretizationType({alpha, nod_k_bound, nod_k, f}, DiscreteFunctionType::P0);
+  checkDiscretizationType({alpha, cell_k_bound, cell_k, f}, DiscreteFunctionType::P0);
 
   switch (i_mesh->dimension()) {
   case 1: {
@@ -581,8 +510,8 @@ ScalarNodalSchemeHandler::ScalarNodalSchemeHandler(
 
     m_scheme =
       std::make_unique<ScalarNodalScheme<1>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha),
-                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(nod_k_bound),
-                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(nod_k),
+                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(cell_k_bound),
+                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(cell_k),
                                                std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(f),
                                                bc_descriptor_list);
     break;
@@ -600,8 +529,8 @@ ScalarNodalSchemeHandler::ScalarNodalSchemeHandler(
 
     m_scheme =
       std::make_unique<ScalarNodalScheme<2>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha),
-                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(nod_k_bound),
-                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(nod_k),
+                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(cell_k_bound),
+                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(cell_k),
                                                std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(f),
                                                bc_descriptor_list);
     break;
@@ -619,8 +548,8 @@ ScalarNodalSchemeHandler::ScalarNodalSchemeHandler(
 
     m_scheme =
       std::make_unique<ScalarNodalScheme<3>>(mesh, std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(alpha),
-                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(nod_k_bound),
-                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(nod_k),
+                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(cell_k_bound),
+                                               std::dynamic_pointer_cast<const DiscreteTensorFunctionType>(cell_k),
                                                std::dynamic_pointer_cast<const DiscreteScalarFunctionType>(f),
                                                bc_descriptor_list);
     break;