diff --git a/src/language/modules/SchemeModule.cpp b/src/language/modules/SchemeModule.cpp
index b9b789cfa8e3d7bc5328062c6085217dbe142120..e629783ba307ec56302a5719a6eabf13f68ea006 100644
--- a/src/language/modules/SchemeModule.cpp
+++ b/src/language/modules/SchemeModule.cpp
@@ -25,6 +25,7 @@
 #include <mesh/MeshSmoother.hpp>
 #include <mesh/MeshTraits.hpp>
 #include <scheme/AcousticSolver.hpp>
+#include <scheme/DDFVSolver.hpp>
 #include <scheme/AxisBoundaryConditionDescriptor.hpp>
 #include <scheme/DirichletBoundaryConditionDescriptor.hpp>
 #include <scheme/DiscreteFunctionDescriptorP0.hpp>
@@ -461,6 +462,7 @@ SchemeModule::SchemeModule()
 
                                               ));
 
+
   this->_addBuiltinFunction("glace_solver",
                             std::function(
 
@@ -524,6 +526,64 @@ SchemeModule::SchemeModule()
 
                               ));
 
+  this->_addBuiltinFunction("DDFV_solver",
+                            std::function(
+
+                              [](const double& dt,
+                                 const double& dt_moyen,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& m_j,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& p_j,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& u_j,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& E_j,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& q_j,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& m_r,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& p_r,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& u_r,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& e_r,
+                                 const std::shared_ptr<const DiscreteFunctionVariant>& q_r,
+                                 const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>&
+                                   bc_descriptor_list) -> std::tuple<std::shared_ptr<const MeshVariant>,
+                                                                 std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                 std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                 std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                 std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                 std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                 std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                 std::shared_ptr<const DiscreteFunctionVariant>,
+                                                                 std::shared_ptr<const DiscreteFunctionVariant>> {
+                                return DDFVSolverHandler{getCommonMesh({u_j, E_j, p_j})}
+                                  .solver()
+                                  .solve(dt, dt_moyen, m_j, p_j, u_j, E_j, q_j, m_r, p_r, u_r, e_r, q_r,
+                                         bc_descriptor_list);
+                              }
+
+                              ));
+  this->_addBuiltinFunction("init_dual_sca",
+                            std::function(
+
+                              [](const std::shared_ptr<const DiscreteFunctionVariant>& f_j_v,
+                                 const std::shared_ptr<const MeshVariant> primal_mesh_v,
+                                 const std::shared_ptr<const MeshVariant> dual_mesh_v) -> std::shared_ptr<const DiscreteFunctionVariant> {
+                                return DDFVSolverHandler{primal_mesh_v}
+                                  .solver()
+                                  .init_dual_sca(f_j_v, primal_mesh_v, dual_mesh_v);
+                              }
+
+                              ));            
+                              
+  this->_addBuiltinFunction("init_dual_vec",
+                            std::function(
+
+                              [](const std::shared_ptr<const DiscreteFunctionVariant>& f_j_v,
+                                 const std::shared_ptr<const MeshVariant> primal_mesh_v,
+                                 const std::shared_ptr<const MeshVariant> dual_mesh_v) -> std::shared_ptr<const DiscreteFunctionVariant> {
+                                return DDFVSolverHandler{primal_mesh_v}
+                                  .solver()
+                                  .init_dual_vec(f_j_v, primal_mesh_v, dual_mesh_v);
+                              }
+
+                              ));           
+
   this->_addBuiltinFunction("apply_acoustic_fluxes",
                             std::function(
 
diff --git a/src/scheme/CMakeLists.txt b/src/scheme/CMakeLists.txt
index a4642f38ffbc8a07e6e341ada1ce63e54a2137cf..5e7012de488985a9798b985f75e9e7c132ef0574 100644
--- a/src/scheme/CMakeLists.txt
+++ b/src/scheme/CMakeLists.txt
@@ -3,6 +3,7 @@
 add_library(
   PugsScheme
   AcousticSolver.cpp
+  DDFVSolver.cpp
   DiscreteFunctionIntegrator.cpp
   DiscreteFunctionInterpoler.cpp
   DiscreteFunctionUtils.cpp
diff --git a/src/scheme/DDFVSolver.cpp b/src/scheme/DDFVSolver.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..53aafc4ffaa045d753cc19588cbfa960980146b1
--- /dev/null
+++ b/src/scheme/DDFVSolver.cpp
@@ -0,0 +1,880 @@
+#include <scheme/DDFVSolver.hpp>
+
+#include <language/utils/InterpolateItemValue.hpp>
+#include <mesh/ItemValueUtils.hpp>
+#include <mesh/ItemValueVariant.hpp>
+#include <mesh/MeshFaceBoundary.hpp>
+#include <mesh/MeshFlatNodeBoundary.hpp>
+#include <mesh/MeshNodeBoundary.hpp>
+#include <mesh/MeshTraits.hpp>
+#include <mesh/MeshVariant.hpp>
+#include <mesh/SubItemValuePerItemVariant.hpp>
+#include <scheme/DirichletBoundaryConditionDescriptor.hpp>
+#include <scheme/DiscreteFunctionP0.hpp>
+#include <scheme/DiscreteFunctionUtils.hpp>
+#include <scheme/ExternalBoundaryConditionDescriptor.hpp>
+#include <scheme/FixedBoundaryConditionDescriptor.hpp>
+#include <scheme/IBoundaryConditionDescriptor.hpp>
+#include <scheme/IDiscreteFunctionDescriptor.hpp>
+#include <scheme/SymmetryBoundaryConditionDescriptor.hpp>
+#include <utils/Socket.hpp>
+
+#include <variant>
+#include <vector>
+
+
+#include <algebra/CRSMatrix.hpp>
+#include <algebra/CRSMatrixDescriptor.hpp>
+#include <algebra/LinearSolver.hpp>
+#include <algebra/TinyMatrix.hpp>
+#include <algebra/TinyVector.hpp>
+#include <algebra/Vector.hpp>
+#include <language/utils/EvaluateAtPoints.hpp>
+#include <language/utils/InterpolateItemValue.hpp>
+#include <mesh/DualConnectivityManager.hpp>
+#include <mesh/DualMeshManager.hpp>
+#include <mesh/IBoundaryDescriptor.hpp>
+#include <mesh/ItemValueUtils.hpp>
+#include <mesh/Mesh.hpp>
+#include <mesh/MeshData.hpp>
+#include <mesh/MeshDataManager.hpp>
+#include <mesh/MeshFaceBoundary.hpp>
+#include <mesh/MeshNodeBoundary.hpp>
+#include <mesh/PrimalToMedianDualConnectivityDataMapper.hpp>
+#include <mesh/SubItemValuePerItem.hpp>
+#include <scheme/DirichletBoundaryConditionDescriptor.hpp>
+#include <scheme/DiscreteFunctionP0.hpp>
+#include <scheme/DiscreteFunctionUtils.hpp>
+#include <scheme/FourierBoundaryConditionDescriptor.hpp>
+#include <scheme/NeumannBoundaryConditionDescriptor.hpp>
+#include <utils/Array.hpp>
+#include <utils/Exceptions.hpp>
+#include <utils/PugsAssert.hpp>
+#include <mesh/PrimalToDual1DConnectivityDataMapper.hpp>
+
+#include <iostream>
+#include <rang.hpp>
+
+
+double
+ddfv_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c_v)
+{
+  const auto& c = c_v->get<DiscreteFunctionP0<const double>>();
+
+  return std::visit(
+    [&](auto&& p_mesh) -> double {
+      const auto& mesh = *p_mesh;
+
+      using MeshType = decltype(mesh);
+      if constexpr (is_polygonal_mesh_v<MeshType>) {
+        const auto Vj = MeshDataManager::instance().getMeshData(mesh).Vj();
+        const auto Sj = MeshDataManager::instance().getMeshData(mesh).sumOverRLjr();
+
+        CellValue<double> local_dt{mesh.connectivity()};
+        parallel_for(
+          mesh.numberOfCells(), PUGS_LAMBDA(CellId j) { local_dt[j] = 2 * Vj[j] / (Sj[j] * c[j]); });
+
+        return min(local_dt);
+      } else {
+        throw NormalError("unexpected mesh type");
+      }
+    },
+    c.meshVariant()->variant());
+}
+
+template <MeshConcept MeshType>
+class DDFVSolverHandler::DDFVSolver final : public DDFVSolverHandler::IDDFVSolver
+{
+ private:
+  static constexpr size_t Dimension = MeshType::Dimension;
+
+  using Rdxd = TinyMatrix<Dimension>;
+  using Rd   = TinyVector<Dimension>;
+
+  using MeshDataType = MeshData<MeshType>;
+
+  using DiscreteScalarFunction = DiscreteFunctionP0<const double>;
+  using DiscreteVectorFunction = DiscreteFunctionP0<const Rd>;
+
+  class FixedBoundaryCondition;
+  class PressureBoundaryCondition;
+  class SymmetryBoundaryCondition;
+  class VelocityBoundaryCondition;
+  class ExternalFSIVelocityBoundaryCondition;
+  class DDFVBoundaryCondition;
+
+  using BoundaryCondition = std::variant<FixedBoundaryCondition,
+                                         PressureBoundaryCondition,
+                                         SymmetryBoundaryCondition,
+                                         VelocityBoundaryCondition,
+                                         ExternalFSIVelocityBoundaryCondition,
+                                         DDFVBoundaryCondition>;
+
+  using BoundaryConditionList = std::vector<BoundaryCondition>;
+
+  
+
+  
+
+  BoundaryConditionList
+  _getBCList(const MeshType& mesh,
+             const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const
+  {
+    BoundaryConditionList bc_list;
+
+    for (const auto& bc_descriptor : bc_descriptor_list) {
+      bool is_valid_boundary_condition = true;
+
+      switch (bc_descriptor->type()) {
+      case IBoundaryConditionDescriptor::Type::dirichlet: {
+        const DirichletBoundaryConditionDescriptor& dirichlet_bc_descriptor =
+          dynamic_cast<const DirichletBoundaryConditionDescriptor&>(*bc_descriptor);
+        if (dirichlet_bc_descriptor.name() == "velocity") {
+          MeshNodeBoundary mesh_node_boundary = getMeshNodeBoundary(mesh, dirichlet_bc_descriptor.boundaryDescriptor());
+
+          Array<const Rd> value_list =
+            InterpolateItemValue<Rd(Rd)>::template interpolate<ItemType::node>(dirichlet_bc_descriptor.rhsSymbolId(),
+                                                                               mesh.xr(),
+                                                                               mesh_node_boundary.nodeList());
+
+          bc_list.emplace_back(DDFVBoundaryCondition{mesh_node_boundary, value_list});
+        } else {
+          is_valid_boundary_condition = false;
+        }
+        break;
+      }
+      default: {
+        is_valid_boundary_condition = false;
+      }
+      }
+      if (not is_valid_boundary_condition) {
+        std::ostringstream error_msg;
+        error_msg << *bc_descriptor << " is an invalid boundary condition for ddfv solver";
+        throw NormalError(error_msg.str());
+      }
+    }
+
+    return bc_list;
+  }
+
+  void _applyDDFVBC(const BoundaryConditionList& bc_list,NodeValue<CellId>& computed_node_dual_cell_id, CellValue<Rd>& br) const;
+
+ public:
+  
+
+
+
+
+  std::tuple<std::shared_ptr<const MeshVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>>
+  solve(const double& dt,///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+                const double& dt_moyen,
+                const MeshType& mesh_p,
+                const MeshType& mesh_d,           
+                const DiscreteScalarFunction& m_j,
+                const DiscreteScalarFunction& p_j,
+                const DiscreteVectorFunction& u_j,
+                const DiscreteScalarFunction& E_j,
+                const DiscreteScalarFunction& q_j,
+                const DiscreteScalarFunction& m_r,
+                const DiscreteScalarFunction& p_r,
+                const DiscreteVectorFunction& u_r,
+                const DiscreteScalarFunction& e_r,
+                const DiscreteScalarFunction& q_r,
+                const BoundaryConditionList& bc_list) const
+  {
+    TinyMatrix<Dimension> I =identity;
+    double gamma = 1.4;
+
+
+    const auto& cell_to_node_matrix_p = mesh_p.connectivity().cellToNodeMatrix();
+    const auto& node_to_cell_matrix_p = mesh_p.connectivity().nodeToCellMatrix();
+    const auto node_local_numbers_in_their_cells = mesh_p.connectivity().nodeLocalNumbersInTheirCells();
+    //const auto& cell_to_node_matrix_d = mesh_d.connectivity().cellToNodeMatrix();
+
+    MeshDataType& mesh_data_p = MeshDataManager::instance().getMeshData(mesh_p);
+    //MeshDataType& mesh_data_d = MeshDataManager::instance().getMeshData(mesh_d);
+    CellValue<const double> Vj = MeshDataManager::instance().getMeshData(mesh_p).Vj();
+    CellValue<const double> Vr = MeshDataManager::instance().getMeshData(mesh_d).Vj();
+
+    const NodeValuePerCell<const Rd> Cjr = mesh_data_p.Cjr();
+
+    auto data_mapper_d =
+        DualConnectivityManager::instance().getPrimalToMedianDualConnectivityDataMapper(mesh_d.connectivity());
+    auto data_mapper_p =
+        DualConnectivityManager::instance().getPrimalToMedianDualConnectivityDataMapper(mesh_p.connectivity());
+
+    CellValue<double> new_p_j {mesh_p.connectivity()};
+    new_p_j=copy(p_j.cellValues());
+    CellValue<Rd> new_u_r{mesh_d.connectivity()};
+    new_u_r = copy(u_r.cellValues());
+
+//on passe du sommet en duale au cellule en primale
+    NodeValue<CellId> computed_node_primal_cell_id{mesh_d.connectivity()};
+    CellValue<CellId> primal_cell_id{mesh_p.connectivity()};
+    parallel_for(
+        mesh_p.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { primal_cell_id[cell_id] = cell_id; });
+      data_mapper_d->fromDualCell(primal_cell_id, computed_node_primal_cell_id);
+//////////////////////////////////////////////////////////////////////////////////////////
+//on passe du sommet en primale au cellule en duale
+    NodeValue<CellId> computed_node_dual_cell_id{mesh_p.connectivity()};
+    CellValue<CellId> dual_cell_id{mesh_d.connectivity()};
+      parallel_for(
+        mesh_d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { dual_cell_id[cell_id] = cell_id; });
+      data_mapper_p->fromDualCell(dual_cell_id, computed_node_dual_cell_id);
+/////////////////////////////////////////////////////////////////////////////////////////
+/*
+std::cout<<"pppppppppppppp"<<std::endl;
+    parallel_for(
+      mesh_p.numberOfNodes(), PUGS_LAMBDA(NodeId r) {
+        
+        const auto& node_cells = node_to_cell_matrix_p[r];
+        CellId dual_cell_id_r    = computed_node_dual_cell_id[r];
+        std::cout<<"nodeId="<<r<<"cell_id="<<dual_cell_id_r<<std::endl;
+        for (size_t j = 0; j < node_cells.size(); ++j)
+        {
+
+          size_t i_node_in_face = node_local_number_in_their_cells[r][node_cells[j]];
+
+            new_u_r[dual_cell_id_r] += dt_moyen * new_p_j[node_cells[j]] * (1.0/m_r[dual_cell_id_r]) * Cjr(node_cells[j],i_node_in_face) ;
+        }
+    });*/
+
+      for(NodeId r = 0; r<mesh_p.numberOfNodes(); r++){
+        
+        const auto& node_cells = node_to_cell_matrix_p[r];
+        CellId dual_cell_id_r    = computed_node_dual_cell_id[r];
+        const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r);
+
+        for (size_t j = 0; j < node_cells.size(); ++j)
+        {
+          const unsigned int R = node_local_number_in_its_cells[j]; //numérotation local je comprends rien
+
+            new_u_r[dual_cell_id_r] -= dt_moyen * (-new_p_j[node_cells[j]] - q_j[node_cells[j]]) * (1.0/m_r[dual_cell_id_r]) * Cjr(node_cells[j],R) ;
+
+        }
+    };
+
+
+    _applyDDFVBC(bc_list, computed_node_dual_cell_id, new_u_r);
+
+
+    NodeValue<Rd> new_xr = copy(mesh_p.xr());
+
+
+    parallel_for(
+      mesh_p.numberOfNodes(), PUGS_LAMBDA(NodeId r) { 
+        CellId dual_cell_id_r    = computed_node_dual_cell_id[r];
+        new_xr[r] += dt * new_u_r[dual_cell_id_r]; 
+      });
+
+    
+    std::shared_ptr<const MeshType> new_mesh_p = std::make_shared<MeshType>(mesh_p.shared_connectivity(), new_xr);
+    std::shared_ptr<const MeshVariant> new_mesh_d_v = DualMeshManager::instance().getMedianDualMesh(std::make_shared<MeshVariant>(new_mesh_p));
+    std::shared_ptr<const MeshType> new_mesh_d =new_mesh_d_v->get<MeshType>();
+
+    MeshDataType& new_mesh_data_p = MeshDataManager::instance().getMeshData(*new_mesh_p);
+    MeshDataType& new_mesh_data_d = MeshDataManager::instance().getMeshData(*new_mesh_d);
+    const NodeValuePerCell<const Rd> new_Cjr = new_mesh_data_p.Cjr();
+    const NodeValuePerCell<const Rd> new_Crj = new_mesh_data_d.Cjr();
+
+    CellValue<const double> new_Vj = MeshDataManager::instance().getMeshData(*new_mesh_p).Vj();
+    CellValue<const double> new_Vr = MeshDataManager::instance().getMeshData(*new_mesh_d).Vj();
+    //CellValue<double> new_Vr {mesh_d.connectivity()};
+
+    CellValue<double> new_rho_j{mesh_p.connectivity()};
+    
+    parallel_for(
+      mesh_p.numberOfCells(), PUGS_LAMBDA(CellId j) { 
+
+        new_rho_j[j] = m_j[j] / new_Vj[j];
+
+    });
+    
+    CellValue<double> new_rho_r{mesh_d.connectivity()};
+    /*
+    for(NodeId r = 0; r<mesh_p.numberOfNodes(); r++){
+        
+        const auto& node_cells = node_to_cell_matrix_p[r];
+        CellId dual_cell_id_r    = computed_node_dual_cell_id[r];
+        const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r);
+
+        new_Vr[dual_cell_id_r] = Vr[dual_cell_id_r];
+
+        for (size_t j = 0; j < node_cells.size(); ++j)
+        {
+          const unsigned int R = node_local_number_in_its_cells[j]; //numérotation local je comprends rien
+
+            new_Vr[dual_cell_id_r] -= dt_moyen * dot(u_j[node_cells[j]] , Cjr(node_cells[j],R)) ;
+
+        }
+    };
+     */
+    parallel_for(
+      mesh_d.numberOfCells(), PUGS_LAMBDA(CellId r) {
+        new_rho_r[r] = m_r[r] *2.0 / (Vr[r] + new_Vr[r]);
+    });
+    
+    
+    CellValue<double> new_p_r{mesh_d.connectivity()};
+    CellValue<double> new_epsilon_r = copy(e_r.cellValues());
+
+      for(NodeId r = 0; r<mesh_p.numberOfNodes(); r++){
+
+        const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r);
+        const auto& node_cells = node_to_cell_matrix_p[r];
+        CellId cell_r = computed_node_dual_cell_id[r];
+        new_epsilon_r[cell_r] = new_epsilon_r[cell_r] * m_r[cell_r];
+
+        double mem=m_r[cell_r];
+
+        for (size_t j = 0; j < node_cells.size(); ++j)
+        {
+          
+          CellId cell_j  = node_cells[j];
+          const unsigned int R = node_local_number_in_its_cells[j]; //numérotation local je comprends rien
+          new_epsilon_r[cell_r] -= dt_moyen * (-q_r[cell_r] - 0.5 * p_r[cell_r]) * doubleDot(I,tensorProduct(u_j[cell_j],Cjr(cell_j,R)));
+
+          mem -= dt_moyen * 0.5 * (gamma-1.0) * new_rho_r[cell_r] * doubleDot(I,tensorProduct(u_j[cell_j],Cjr(cell_j,R)));
+        }
+
+        new_epsilon_r[cell_r] = new_epsilon_r[cell_r] / mem;
+
+        new_p_r[cell_r]=(gamma - 1.0) * new_epsilon_r[cell_r] * new_rho_r[cell_r];
+    };
+
+    
+
+
+    CellValue<Rd> new_u_j = copy(u_j.cellValues());
+    
+    parallel_for(
+      mesh_p.numberOfCells(), PUGS_LAMBDA(CellId j) {
+        
+        const auto& cell_nodes = cell_to_node_matrix_p[j];
+
+        for (size_t r = 0; r < cell_nodes.size(); ++r)
+        {
+          CellId dual_cell_id_r    = computed_node_dual_cell_id[cell_nodes[r]];
+
+          new_u_j[j] += dt * 0.5 * (1.0/m_j[j]) * (-new_p_r[dual_cell_id_r] - q_r[dual_cell_id_r]) * (Cjr(j,r) + new_Cjr(j,r));
+
+        }
+
+    });
+    
+    CellValue<double> new_E_j = copy(E_j.cellValues());
+    CellValue<double> new_e_j{mesh_p.connectivity()} ;
+
+    parallel_for(
+      mesh_p.numberOfCells(), PUGS_LAMBDA(CellId j) {
+        
+        const auto& cell_nodes = cell_to_node_matrix_p[j];
+
+        for (size_t r = 0; r < cell_nodes.size(); ++r)
+        {
+          CellId dual_cell_id_r    = computed_node_dual_cell_id[cell_nodes[r]];
+
+          new_E_j[j] += dt * 0.5 * (1.0/m_j[j]) * (-new_p_r[dual_cell_id_r] - q_r[dual_cell_id_r]) * dot(new_u_r[dual_cell_id_r],(Cjr(j,r) + new_Cjr(j,r)));
+
+        }
+
+          new_e_j[j] = new_E_j[j] - 0.5 * dot(new_u_j[j],new_u_j[j]);
+          new_p_j[j] = (gamma - 1.0) * new_e_j[j] * new_rho_j[j];
+    });
+    CellValue<double> grad_u_r{mesh_d.connectivity()};
+    CellValue<double> new_q_r{mesh_d.connectivity()};
+    
+    for(NodeId r = 0; r<mesh_p.numberOfNodes(); r++){
+        
+        const auto& node_cells = node_to_cell_matrix_p[r];
+        CellId dual_cell_id_r    = computed_node_dual_cell_id[r];
+        const auto& node_local_number_in_its_cells = node_local_numbers_in_their_cells.itemArray(r);
+
+        grad_u_r[dual_cell_id_r] = 0;
+
+        for (size_t j = 0; j < node_cells.size(); ++j)
+        {
+          const unsigned int R = node_local_number_in_its_cells[j]; //numérotation local je comprends rien
+
+            grad_u_r[dual_cell_id_r] -= 0.25 * (1.0/new_Vr[dual_cell_id_r]) * dot(new_u_j[node_cells[j]] + u_j[node_cells[j]], Cjr(node_cells[j],R) + new_Cjr(node_cells[j],R));
+
+        }
+        //double c=sqrt(gamma * new_p_r[dual_cell_id_r] / new_rho_r[dual_cell_id_r]);
+        //double lambda=new_mesh_data_d.sumOverRLjr()[dual_cell_id_r];
+        //double lambda = new_Vr[dual_cell_id_r];
+
+        new_q_r[dual_cell_id_r] = - 1.0 * new_Vr[dual_cell_id_r] * new_rho_r[dual_cell_id_r] * grad_u_r[dual_cell_id_r] * sqrt(gamma * new_p_r[dual_cell_id_r] / new_rho_r[dual_cell_id_r]);
+        //new_q_r[dual_cell_id_r] =  -lambda * new_rho_r[dual_cell_id_r] * (-0.0 * c + lambda * grad_u_r[dual_cell_id_r]) * grad_u_r[dual_cell_id_r];
+    };
+
+    CellValue<double> grad_u_j{mesh_p.connectivity()};
+    CellValue<double> new_q_j{mesh_p.connectivity()};
+    for(CellId j = 0; j<mesh_p.numberOfCells(); j++){
+        
+        const auto& cell_nodes = cell_to_node_matrix_p[j];
+
+        grad_u_j[j] = 0.0;
+
+        for (size_t r = 0.0; r < cell_nodes.size(); ++r)
+        {
+
+          CellId dual_cell_id_r    = computed_node_dual_cell_id[cell_nodes[r]];
+          grad_u_j[j] += 0.5 * (1.0/new_Vj[j]) * dot(new_u_r[dual_cell_id_r], Cjr(j,r) + new_Cjr(j,r)) ;
+
+        }
+        //double c = sqrt(gamma * new_p_j[j] / new_rho_j[j]);
+        //double lambda = new_mesh_data_p.sumOverRLjr()[j];
+        //double lambda = new_Vj[j];
+
+        new_q_j[j] = - 1.0 * new_Vj[j] * new_rho_j[j] * grad_u_j[j] * sqrt(gamma * new_p_j[j] / new_rho_j[j]);
+        //new_q_j[j] = -lambda * new_rho_j[j] * (-0.0 * c + lambda * grad_u_j[j]) * grad_u_j[j];
+
+    };
+
+ 
+    return {std::make_shared<MeshVariant>(new_mesh_p),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh_p, new_rho_j)),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh_p, new_u_j)),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh_p, new_E_j)),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh_p, new_q_j)),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh_d, new_rho_r)),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(new_mesh_d, new_u_r)),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh_d, new_epsilon_r)),
+            std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(new_mesh_d, new_q_r))};
+  }
+
+  
+
+  std::tuple<std::shared_ptr<const MeshVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>,
+             std::shared_ptr<const DiscreteFunctionVariant>>
+  solve(const double& dt,
+               const double& dt_moyen,
+               const std::shared_ptr<const DiscreteFunctionVariant>& m_j,
+               const std::shared_ptr<const DiscreteFunctionVariant>& p_j,
+               const std::shared_ptr<const DiscreteFunctionVariant>& u_j,
+               const std::shared_ptr<const DiscreteFunctionVariant>& E_j,
+               const std::shared_ptr<const DiscreteFunctionVariant>& q_j,
+               const std::shared_ptr<const DiscreteFunctionVariant>& m_r,
+               const std::shared_ptr<const DiscreteFunctionVariant>& p_r,
+               const std::shared_ptr<const DiscreteFunctionVariant>& u_r,
+               const std::shared_ptr<const DiscreteFunctionVariant>& e_r,
+               const std::shared_ptr<const DiscreteFunctionVariant>& q_r,
+               const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const
+  {
+    std::shared_ptr mesh_p = getCommonMesh({u_j, p_j, E_j});
+    if (not mesh_p) {
+      throw NormalError("discrete functions are not defined on the same mesh");
+    }
+
+    std::shared_ptr mesh_d = getCommonMesh({u_r, p_r, e_r});
+    if (not mesh_d) {
+      throw NormalError("discrete functions are not defined on the same mesh");
+    }
+
+    const BoundaryConditionList bc_list = this->_getBCList(*mesh_p->get<MeshType>(), bc_descriptor_list);
+
+    return this->solve(dt,                                 
+                              dt_moyen,
+                              *mesh_p->get<MeshType>(),
+                              *mesh_d->get<MeshType>(),               
+                              m_j->get<DiscreteScalarFunction>(),
+                              p_j->get<DiscreteScalarFunction>(),
+                              u_j->get<DiscreteVectorFunction>(),   
+                              E_j->get<DiscreteScalarFunction>(),
+                              q_j->get<DiscreteScalarFunction>(),
+                              m_r->get<DiscreteScalarFunction>(),
+                              p_r->get<DiscreteScalarFunction>(),
+                              u_r->get<DiscreteVectorFunction>(),
+                              e_r->get<DiscreteScalarFunction>(),
+                              q_r->get<DiscreteScalarFunction>(),
+                              bc_list);
+  }
+
+  std::shared_ptr<const DiscreteFunctionVariant>
+  init_dual_sca(const DiscreteScalarFunction& f_j,
+        const std::shared_ptr<const MeshVariant>& primal_mesh_v,
+        const std::shared_ptr<const MeshVariant>& dual_mesh_v) const {
+//std::cout<<"début test initialisation"<<std::endl;
+    const MeshType& mesh_p= *primal_mesh_v->get<MeshType>() ;
+    const MeshType& mesh_d= *dual_mesh_v->get<MeshType>() ;
+    CellValue<double> f_r{mesh_d.connectivity()} ;
+
+    auto data_mapper_p = DualConnectivityManager::instance().getPrimalToMedianDualConnectivityDataMapper(mesh_p.connectivity());
+    const auto& node_to_cell_matrix_p = mesh_p.connectivity().nodeToCellMatrix();
+    
+    NodeValue<CellId> computed_node_dual_cell_id{mesh_p.connectivity()};
+    CellValue<CellId> dual_cell_id{mesh_d.connectivity()};
+      parallel_for(
+        mesh_d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { dual_cell_id[cell_id] = cell_id; });
+      data_mapper_p->fromDualCell(dual_cell_id, computed_node_dual_cell_id);
+
+      /*parallel_for(
+        mesh_p.numberOfNodes(), PUGS_LAMBDA(NodeId r) {*/
+        for(NodeId r=0 ; r<mesh_p.numberOfNodes() ; r++){
+          const auto& node_cells = node_to_cell_matrix_p[r];
+          CellId dual_cell_id_r = computed_node_dual_cell_id[r];
+
+          for (size_t j = 0; j < node_cells.size(); ++j)
+          {
+            
+            CellId primal_cell_id_j = node_cells[j];
+            
+            f_r[dual_cell_id_r] += f_j[primal_cell_id_j] ;
+          }
+          f_r[dual_cell_id_r] = (1.0 / node_cells.size()) * f_r[dual_cell_id_r]; //pas sûre de la division (1/int)
+          //std::cout<<"u("<<dual_cell_id_r<<")= "<<f_r[dual_cell_id_r]<<std::endl;
+        }
+      
+        /*});*/   
+
+ //std::cout<<"fin de test";
+    return std::make_shared<DiscreteFunctionVariant>(DiscreteScalarFunction(dual_mesh_v, f_r));
+  }
+  
+  std::shared_ptr<const DiscreteFunctionVariant>
+  init_dual_sca(const std::shared_ptr<const DiscreteFunctionVariant>& f_j_v,
+            const std::shared_ptr<const MeshVariant>& primal_mesh_v,
+            const std::shared_ptr<const MeshVariant>& dual_mesh_v) const {
+
+    const DiscreteScalarFunction f_j = f_j_v->get<DiscreteScalarFunction>();
+
+    return this->init_dual_sca(f_j, primal_mesh_v, dual_mesh_v);
+  }
+
+  std::shared_ptr<const DiscreteFunctionVariant>
+  init_dual_vec(const DiscreteVectorFunction& f_j,
+            const std::shared_ptr<const MeshVariant>& primal_mesh_v,
+            const std::shared_ptr<const MeshVariant>& dual_mesh_v) const{
+              
+    //std::cout<<"début test initialisation"<<std::endl;
+    const MeshType& mesh_p= *primal_mesh_v->get<MeshType>() ;
+    const MeshType& mesh_d= *dual_mesh_v->get<MeshType>() ;
+
+    CellValue<Rd> f_r{mesh_d.connectivity()};
+
+    auto data_mapper_p = DualConnectivityManager::instance().getPrimalToMedianDualConnectivityDataMapper(mesh_p.connectivity());
+    const auto& node_to_cell_matrix_p = mesh_p.connectivity().nodeToCellMatrix();
+    
+    NodeValue<CellId> computed_node_dual_cell_id{mesh_p.connectivity()};
+    CellValue<CellId> dual_cell_id{mesh_d.connectivity()};
+      parallel_for(
+        mesh_d.numberOfCells(), PUGS_LAMBDA(CellId cell_id) { dual_cell_id[cell_id] = cell_id; });
+      data_mapper_p->fromDualCell(dual_cell_id, computed_node_dual_cell_id);
+/*
+      parallel_for(
+        mesh_p.numberOfNodes(), PUGS_LAMBDA(NodeId r) {*/
+        for(NodeId r=0 ; r<mesh_p.numberOfNodes() ; r++){
+          const auto& node_cells = node_to_cell_matrix_p[r];
+          CellId dual_cell_id_r = computed_node_dual_cell_id[r];
+
+          for (size_t j = 0; j < node_cells.size(); ++j)
+          {
+            
+            CellId primal_cell_id_j = node_cells[j];
+            
+            f_r[dual_cell_id_r] += f_j[primal_cell_id_j] ;
+          }
+          f_r[dual_cell_id_r] = (1.0 / node_cells.size()) * f_r[dual_cell_id_r]; //pas sûre de la division (1/int)
+          //std::cout<<"u("<<dual_cell_id_r<<")= "<<f_r[dual_cell_id_r]<<std::endl;
+        }
+      /*  });*/
+
+    //std::cout<<"fin de test";
+      
+
+    return std::make_shared<DiscreteFunctionVariant>(DiscreteVectorFunction(dual_mesh_v, f_r));
+  }
+
+  std::shared_ptr<const DiscreteFunctionVariant>
+  init_dual_vec(const std::shared_ptr<const DiscreteFunctionVariant>& f_j_v,
+            const std::shared_ptr<const MeshVariant>& primal_mesh_v,
+            const std::shared_ptr<const MeshVariant>& dual_mesh_v) const {
+              
+
+    const DiscreteVectorFunction f_j = f_j_v->get<DiscreteVectorFunction>();
+
+    return this->init_dual_vec(f_j, primal_mesh_v, dual_mesh_v);
+  }
+
+  DDFVSolver()                 = default;
+  DDFVSolver(DDFVSolver&&) = default;
+  ~DDFVSolver()                = default;
+};
+
+template <MeshConcept MeshType>
+void
+DDFVSolverHandler::DDFVSolver<MeshType>::_applyDDFVBC(const BoundaryConditionList& bc_list,
+                                                                          NodeValue<CellId>& computed_node_dual_cell_id,
+                                                                          CellValue<Rd>& u_r) const
+{
+  for (const auto& boundary_condition : bc_list) {
+    std::visit(
+      [&](auto&& bc) {
+        using T = std::decay_t<decltype(bc)>;
+        if constexpr (std::is_same_v<DDFVBoundaryCondition, T>) {
+          const auto& node_list  = bc.nodeList();
+          const auto& value_list = bc.valueList();
+
+          parallel_for(
+            node_list.size(), PUGS_LAMBDA(size_t i_node) {
+              NodeId node_id    = node_list[i_node];
+              const auto& value = value_list[i_node];
+              CellId node_dual_cell_id    = computed_node_dual_cell_id[node_id];
+
+              u_r[node_dual_cell_id] = value;
+
+            });
+        }
+      },
+      boundary_condition);
+  }
+}
+
+template <MeshConcept MeshType>
+class DDFVSolverHandler::DDFVSolver<MeshType>::FixedBoundaryCondition
+{
+ private:
+  const MeshNodeBoundary m_mesh_node_boundary;
+
+ public:
+  const Array<const NodeId>&
+  nodeList() const
+  {
+    return m_mesh_node_boundary.nodeList();
+  }
+
+  FixedBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary) : m_mesh_node_boundary{mesh_node_boundary} {}
+
+  ~FixedBoundaryCondition() = default;
+};
+
+template <MeshConcept MeshType>
+class DDFVSolverHandler::DDFVSolver<MeshType>::PressureBoundaryCondition
+{
+ private:
+  const MeshFaceBoundary m_mesh_face_boundary;
+  const Array<const double> m_value_list;
+
+ public:
+  const Array<const FaceId>&
+  faceList() const
+  {
+    return m_mesh_face_boundary.faceList();
+  }
+
+  const Array<const double>&
+  valueList() const
+  {
+    return m_value_list;
+  }
+
+  PressureBoundaryCondition(const MeshFaceBoundary& mesh_face_boundary, const Array<const double>& value_list)
+    : m_mesh_face_boundary{mesh_face_boundary}, m_value_list{value_list}
+  {}
+
+  ~PressureBoundaryCondition() = default;
+};
+
+template <>
+class DDFVSolverHandler::DDFVSolver<Mesh<1>>::PressureBoundaryCondition
+{
+ private:
+  const MeshNodeBoundary m_mesh_node_boundary;
+  const Array<const double> m_value_list;
+
+ public:
+  const Array<const NodeId>&
+  nodeList() const
+  {
+    return m_mesh_node_boundary.nodeList();
+  }
+
+  const Array<const double>&
+  valueList() const
+  {
+    return m_value_list;
+  }
+
+  PressureBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary, const Array<const double>& value_list)
+    : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list}
+  {}
+
+  ~PressureBoundaryCondition() = default;
+};
+
+template <MeshConcept MeshType>
+class DDFVSolverHandler::DDFVSolver<MeshType>::ExternalFSIVelocityBoundaryCondition
+{
+ private:
+  const ItemToItemMatrix<ItemType::node, ItemType::cell> m_node_to_cell_matrix;
+  const MeshNodeBoundary m_mesh_node_boundary;
+  const Array<TinyVector<Dimension>> m_value_list;
+  const std::shared_ptr<const Socket> m_socket;
+
+ public:
+  const Array<const NodeId>&
+  nodeList() const
+  {
+    return m_mesh_node_boundary.nodeList();
+  }
+
+  Array<const TinyVector<Dimension>>
+  valueList(const DiscreteScalarFunction& p) const
+  {
+    if (parallel::size() > 1) {
+      throw NotImplementedError("Parallelism is not supported");
+    }
+    if (m_value_list.size() != 1) {
+      throw NotImplementedError("Non connected boundaries are not supported");
+    }
+
+    const CellId cell_id = m_node_to_cell_matrix[m_mesh_node_boundary.nodeList()[0]][0];
+
+    write(*m_socket, p[cell_id]);
+    read(*m_socket, m_value_list[0]);
+    return m_value_list;
+  }
+
+  ExternalFSIVelocityBoundaryCondition(const Mesh<Dimension>& mesh,
+                                       const MeshNodeBoundary& mesh_node_boundary,
+                                       const std::shared_ptr<const Socket>& socket)
+    : m_node_to_cell_matrix{mesh.connectivity().nodeToCellMatrix()},
+      m_mesh_node_boundary{mesh_node_boundary},
+      m_value_list(mesh_node_boundary.nodeList().size()),
+      m_socket{socket}
+  {
+    if constexpr (Dimension > 1) {
+      throw NotImplementedError("external FSI velocity bc in dimension > 1");
+    }
+  }
+
+  ~ExternalFSIVelocityBoundaryCondition() = default;
+};
+
+template <MeshConcept MeshType>
+class DDFVSolverHandler::DDFVSolver<MeshType>::VelocityBoundaryCondition
+{
+ private:
+  const MeshNodeBoundary m_mesh_node_boundary;
+
+  const Array<const TinyVector<Dimension>> m_value_list;
+
+ public:
+  const Array<const NodeId>&
+  nodeList() const
+  {
+    return m_mesh_node_boundary.nodeList();
+  }
+
+  const Array<const TinyVector<Dimension>>&
+  valueList() const
+  {
+    return m_value_list;
+  }
+
+  VelocityBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary,
+                            const Array<const TinyVector<Dimension>>& value_list)
+    : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list}
+  {}
+
+  ~VelocityBoundaryCondition() = default;
+};
+
+template <MeshConcept MeshType>
+class DDFVSolverHandler::DDFVSolver<MeshType>::SymmetryBoundaryCondition
+{
+ public:
+  using Rd = TinyVector<Dimension, double>;
+
+ private:
+  const MeshFlatNodeBoundary<MeshType> m_mesh_flat_node_boundary;
+
+ public:
+  const Rd&
+  outgoingNormal() const
+  {
+    return m_mesh_flat_node_boundary.outgoingNormal();
+  }
+
+  size_t
+  numberOfNodes() const
+  {
+    return m_mesh_flat_node_boundary.nodeList().size();
+  }
+
+  const Array<const NodeId>&
+  nodeList() const
+  {
+    return m_mesh_flat_node_boundary.nodeList();
+  }
+
+  SymmetryBoundaryCondition(const MeshFlatNodeBoundary<MeshType>& mesh_flat_node_boundary)
+    : m_mesh_flat_node_boundary(mesh_flat_node_boundary)
+  {
+    ;
+  }
+
+  ~SymmetryBoundaryCondition() = default;
+};
+
+template <MeshConcept MeshType>
+class DDFVSolverHandler::DDFVSolver<MeshType>::DDFVBoundaryCondition
+{
+ private:
+  const MeshNodeBoundary m_mesh_node_boundary;
+
+  const Array<const TinyVector<Dimension>> m_value_list;
+
+ public:
+  const Array<const NodeId>&
+  nodeList() const
+  {
+    return m_mesh_node_boundary.nodeList();
+  }
+
+  const Array<const TinyVector<Dimension>>&
+  valueList() const
+  {
+    return m_value_list;
+  }
+
+  DDFVBoundaryCondition(const MeshNodeBoundary& mesh_node_boundary,
+                            const Array<const TinyVector<Dimension>>& value_list)
+    : m_mesh_node_boundary{mesh_node_boundary}, m_value_list{value_list}
+  {}
+
+  ~DDFVBoundaryCondition() = default;
+};
+
+DDFVSolverHandler::DDFVSolverHandler(const std::shared_ptr<const MeshVariant>& mesh_v)
+{
+  if (not mesh_v) {
+    throw NormalError("discrete functions are not defined on the same mesh");
+  }
+
+  std::visit(
+    [&](auto&& mesh) {
+      using MeshType = mesh_type_t<decltype(mesh)>;
+      if constexpr (is_polygonal_mesh_v<MeshType>) {
+        m_ddfv_solver = std::make_unique<DDFVSolver<MeshType>>();
+      } else {
+        throw NormalError("unexpected mesh type");
+      }
+    },
+    mesh_v->variant());
+}
diff --git a/src/scheme/DDFVSolver.hpp b/src/scheme/DDFVSolver.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..8ff34bf02a1598b7e81bdfdbbef61cf25ef5e58d
--- /dev/null
+++ b/src/scheme/DDFVSolver.hpp
@@ -0,0 +1,85 @@
+#ifndef DDFV_SOLVER_HPP
+#define DDFV_SOLVER_HPP
+
+#include <mesh/MeshTraits.hpp>
+
+#include <memory>
+#include <tuple>
+#include <vector>
+
+class DiscreteFunctionVariant;
+class IBoundaryConditionDescriptor;
+class MeshVariant;
+class ItemValueVariant;
+class SubItemValuePerItemVariant;
+
+double ddfv_dt(const std::shared_ptr<const DiscreteFunctionVariant>& c);
+
+class DDFVSolverHandler
+{
+ public:
+  enum class SolverType
+  {
+    Glace,
+    Eucclhyd
+  };
+
+ private:
+  struct IDDFVSolver
+  {
+    virtual std::tuple<std::shared_ptr<const MeshVariant>,
+                 std::shared_ptr<const DiscreteFunctionVariant>,
+                 std::shared_ptr<const DiscreteFunctionVariant>,
+                 std::shared_ptr<const DiscreteFunctionVariant>,
+                 std::shared_ptr<const DiscreteFunctionVariant>,
+                 std::shared_ptr<const DiscreteFunctionVariant>,
+                 std::shared_ptr<const DiscreteFunctionVariant>,
+                 std::shared_ptr<const DiscreteFunctionVariant>,
+                 std::shared_ptr<const DiscreteFunctionVariant>>
+    solve(const double& dt, 
+                   const double& dt_moyen,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& m_j,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& p_j,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& u_j,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& E_j,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& q_j,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& m_r,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& p_r,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& u_r,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& e_r,
+                   const std::shared_ptr<const DiscreteFunctionVariant>& q_r,
+                   const std::vector<std::shared_ptr<const IBoundaryConditionDescriptor>>& bc_descriptor_list) const =0;
+
+    virtual std::shared_ptr<const DiscreteFunctionVariant>
+    init_dual_sca(const std::shared_ptr<const DiscreteFunctionVariant>& f_j_v,
+                  const std::shared_ptr<const MeshVariant>& primal_mesh_v,
+                  const std::shared_ptr<const MeshVariant>& dual_mesh_v) const =0;
+    
+    virtual std::shared_ptr<const DiscreteFunctionVariant>
+    init_dual_vec(const std::shared_ptr<const DiscreteFunctionVariant>& f_j_v,
+                  const std::shared_ptr<const MeshVariant>& primal_mesh_v,
+                  const std::shared_ptr<const MeshVariant>& dual_mesh_v) const =0;
+
+    IDDFVSolver()                  = default;
+    IDDFVSolver(IDDFVSolver&&) = default;
+    IDDFVSolver& operator=(IDDFVSolver&&) = default;
+
+    virtual ~IDDFVSolver() = default;
+  };
+
+  template <MeshConcept MeshType>
+  class DDFVSolver;
+
+  std::unique_ptr<IDDFVSolver> m_ddfv_solver;
+
+ public:
+  const IDDFVSolver&
+  solver() const
+  {
+    return *m_ddfv_solver;
+  }
+
+  DDFVSolverHandler(const std::shared_ptr<const MeshVariant>& mesh_v);
+};
+
+#endif   // DDFV_SOLVER_HPP