diff --git a/CMakeLists.txt b/CMakeLists.txt
index 28b217b49009abadc141fde32d0485885dda498f..5048463a1be0718a24bad95190951760cc301de5 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -78,6 +78,7 @@ opt(OPENMP "Enable OpenMP" OFF)
 opt(OPTHOM "Enable high-order mesh optimization tools" ${DEFAULT})
 opt(OS_SPECIFIC_INSTALL "Enable OS-specific (e.g. app bundle) installation" OFF)
 opt(OSMESA "Enable OSMesa for offscreen rendering (experimental)" OFF)
+opt(P4EST "Enable p4est for enabling automatic mesh size firld (experimental)" OFF)
 opt(PARSER "Enable GEO file parser (required for .geo/.pos files)" ${DEFAULT})
 opt(PETSC "Enable PETSc linear solvers (required for SLEPc)" OFF)
 opt(PLUGINS "Enable post-processing plugins" ${DEFAULT})
@@ -850,6 +851,17 @@ if(ENABLE_POPPLER)
   endif()
 endif()
 
+if(ENABLE_P4EST)
+  find_library(P4EST_LIB p4est)
+  find_path(P4EST_INC "p4est.h" PATH_SUFFIXES src)
+  if(P4EST_LIB AND P4EST_INC)
+    set_config_option(HAVE_P4EST "p4est")
+    list(APPEND EXTERNAL_LIBRARIES ${P4EST_LIB})
+    list(APPEND EXTERNAL_LIBRARIES ${POPPLER_CPP_LIB})
+    list(APPEND EXTERNAL_INCLUDES ${P4EST_INC})
+  endif()
+endif()
+
 if(HAVE_MESH OR HAVE_SOLVER)
   if(ENABLE_METIS)
     find_library(METIS_LIB metis PATH_SUFFIXES lib)
diff --git a/Common/GmshConfig.h.in b/Common/GmshConfig.h.in
index f545795ad5fcd0677ca5e032ff113f5aaa9cbcfd..996c0c93999f6cd65bff22a71f5d57617016febb 100644
--- a/Common/GmshConfig.h.in
+++ b/Common/GmshConfig.h.in
@@ -53,6 +53,7 @@
 #cmakedefine HAVE_OPENGL
 #cmakedefine HAVE_OPTHOM
 #cmakedefine HAVE_OSMESA
+#cmakedefine HAVE_P4EST
 #cmakedefine HAVE_PARSER
 #cmakedefine HAVE_PETSC
 #cmakedefine HAVE_PETSC4PY
diff --git a/Fltk/fieldWindow.cpp b/Fltk/fieldWindow.cpp
index c1473b34807faa088d553f32669ede4a30d63da6..0ce7fa93752dc382be68ce5718d699516716e7b7 100644
--- a/Fltk/fieldWindow.cpp
+++ b/Fltk/fieldWindow.cpp
@@ -71,6 +71,7 @@ static void field_put_on_view_cb(Fl_Widget *w, void *data)
 {
   Fl_Menu_Button *mb = ((Fl_Menu_Button *)w);
   Field *field = (Field *)FlGui::instance()->fields->editor_group->user_data();
+  field->update();
   if(mb->value() == 0)
     field->putOnNewView();
   else if(mb->value() - 1 < (int)PView::list.size())
diff --git a/Mesh/automaticMeshSizeField.cpp b/Mesh/automaticMeshSizeField.cpp
index ba9b6159b76a77c273df5fc2b66d935d9b95c17f..72ff90ebd1ad9e691533fee0bffbabe96aad1b20 100644
--- a/Mesh/automaticMeshSizeField.cpp
+++ b/Mesh/automaticMeshSizeField.cpp
@@ -1,10 +1,167 @@
 #include "automaticMeshSizeField.h"
+#include "GModel.h"
+#include "GRegion.h"
+#include "MVertex.h"
 
-
+#ifdef HAVE_HXT
+extern "C" {
+#include "hxt_edge.h"
+#include "hxt_curvature.h"
+#include "hxt_bbox.h"
+}
+#endif  
 
 double automaticMeshSizeField:: operator()(double X, double Y, double Z, GEntity *ge) {  
-  return _hbulk;
+#ifdef HAVE_HXT
+  //  return .2;
+  double val = 1.e22;
+  HXTStatus s = hxtOctreeSearchOne(forest, X, Y, Z, &val);
+  if (s == HXT_STATUS_OK){
+    return val;
+  }
+  else Msg::Error ("Cannot find point %g %g %g in the octree",X,Y,Z);
+  return val;
+#else
+  Msg::Error ("Gmsh has to be compiled with HXT for using automaticMeshSizeField");
+#endif  
 }
 
-void automaticMeshSizeField:: update(){
+automaticMeshSizeField::~automaticMeshSizeField(){
+#ifdef HAVE_P4EST
+  if (forest)hxtForestDelete(&forest);  
+  if (forestOptions)hxtForestOptionsDelete(&forestOptions);
+#endif
+}  
+
+
+#ifdef HAVE_HXT
+
+HXTStatus Gmsh2Hxt(std::vector<GRegion *> &regions, HXTMesh *m,
+		   std::map<MVertex *, int> &v2c,
+		   std::vector<MVertex *> &c2v);
+
+
+HXTStatus automaticMeshSizeField:: updateHXT(){
+#ifdef HAVE_P4EST
+
+  
+  //  printf("%d points per circle\n",_nPointsPerCircle);
+  
+  if (!update_needed)return HXT_STATUS_OK;
+  
+  if (forest)hxtForestDelete(&forest);  
+  if (forestOptions)hxtForestOptionsDelete(&forestOptions);
+
+  update_needed = false;
+  // --------------------------------------------------------
+  // Soit on charge un fichier avec l'octree (ma préférence)
+  // Soit on calcule "en live" l'octree ici
+
+  
+  // verify that only one region exists in the model
+  if (GModel::current()->getNumRegions() != 1){
+    Msg::Error ("automaticMeshSizeField can only work for now on models with one region");
+    return HXT_STATUS_ERROR;
+  }
+  std::vector<GRegion*> regions;
+  regions.push_back(*(GModel::current()->firstRegion()));
+  
+  // create HXT mesh structure
+  HXTMesh *mesh;
+  HXTContext *context;
+  HXT_CHECK(hxtContextCreate(&context));
+  HXT_CHECK(hxtMeshCreate(context, &mesh));
+  std::map<MVertex *, int> v2c;
+  std::vector<MVertex *> c2v;  
+  Gmsh2Hxt(regions, mesh, v2c, c2v);
+
+  // Compute curvature
+  double           *curvatureCrossfield;
+  double           *nodalCurvature;
+  HXTEdges         *edges;
+  HXT_CHECK(hxtEdgesCreate(mesh,&edges));
+  HXT_CHECK(hxtCurvatureRusinkiewicz(mesh,&nodalCurvature,&curvatureCrossfield,edges,1));
+  
+  // compute rtree
+  RTree<int , double,3> triRTree;
+  HXTBbox          bbox_triangle;
+
+  for(uint64_t i = 0; i < mesh->triangles.num; ++i){
+    hxtBboxInit(&bbox_triangle);
+    // Noeuds
+    for(int j = 0; j < 3; ++j){
+      double coord[3];
+      int node = mesh->triangles.node[(size_t) 3*i+j];
+      // Coordonnees
+      for(int k = 0; k < 3; ++k){ coord[k] = mesh->vertices.coord[(size_t) 4*node+k]; }
+      hxtBboxAddOne(&bbox_triangle, coord);
+    }
+    int K = (int)i;
+    triRTree.Insert(bbox_triangle.min,bbox_triangle.max,K);
+  }
+  
+  // compute bbox of the mesh
+  double            bbox_vertices[6];
+  HXTBbox           bbox_mesh;
+  hxtBboxInit(&bbox_mesh);
+  // Ajout de tous les points du maillages à la bounding box
+  HXT_CHECK(hxtBboxAdd(&bbox_mesh, mesh->vertices.coord, mesh->vertices.num));
+  for(int i = 0; i < 3; ++i){
+    bbox_vertices[i  ] = 1.3*bbox_mesh.min[i];
+    bbox_vertices[i+3] = 1.3*bbox_mesh.max[i];
+  }
+  
+  // 1 --> OPTIONS ------------------------------------------
+  HXT_CHECK(hxtForestOptionsCreate(&forestOptions));
+  forestOptions->nodePerTwoPi = _nPointsPerCircle;  
+  forestOptions->bbox = bbox_vertices;
+  forestOptions->nodalCurvature = nodalCurvature;
+  forestOptions->triRTree = &triRTree;
+  forestOptions->mesh = mesh;
+  forestOptions->sizeFunction = NULL;
+  
+  // --------------------------------------------------------
+  HXT_CHECK(hxtForestCreate(0, NULL, &forest, NULL, forestOptions));
+  //  return HXT_STATUS_OK;
+  // ---------------------------------------------------------
+  // aller --> niveau 3 par exemple, serait une option ...
+  HXT_CHECK(hxtOctreeRefineToLevel(forest, 3/*_nRefine*/));
+  // idéalement --> convergence
+  int ITER = 0;
+  if (forestOptions->nodePerTwoPi > 0){
+    HXT_CHECK(hxtOctreeCurvatureRefine(forest, 3/*_nRefine*/));
+    // ensuite lissage du gradient 
+    while (ITER++ < 4*_nRefine) {
+      HXT_CHECK(hxtOctreeComputeLaplacian(forest));    
+      HXT_CHECK(hxtOctreeSetMaxGradient(forest));
+    }
+  }
+  forestOptions->nodePerGap = _nPointsPerGap;
+  printf("coucou\n");
+  HXT_CHECK(hxtOctreeSurfacesProches(forest));   
+  ITER = 0;
+  //  while (ITER++ < 4*_nRefine) {
+  //    HXT_CHECK(hxtOctreeComputeLaplacian(forest));    
+  //    HXT_CHECK(hxtOctreeSetMaxGradient(forest));
+  //  }
+
+  HXT_CHECK(hxtEdgesDelete(&edges)       );
+  HXT_CHECK(hxtFree(&curvatureCrossfield));
+  HXT_CHECK(hxtFree(&nodalCurvature)              );
+  HXT_CHECK(hxtMeshDelete(&mesh)                  );
+  HXT_CHECK(hxtContextDelete(&context)            );
+
+
+#endif //ifdef HAVE_P4EST
 }
+#endif
+
+void automaticMeshSizeField:: update(){
+#ifdef HAVE_HXT
+  HXTStatus s = updateHXT();
+  if (s != HXT_STATUS_OK)Msg::Error ("Something went wrong when computing the octree");
+#else
+  Msg::Error ("Gmsh has to be compiled with HXT for using automaticMeshSizeField");
+#endif    
+    
+};
diff --git a/Mesh/automaticMeshSizeField.h b/Mesh/automaticMeshSizeField.h
index 7178e9ac1d3832019e81b0026285c39ddfe23875..0b4579c92b2405749fc9015069355488113d31a6 100644
--- a/Mesh/automaticMeshSizeField.h
+++ b/Mesh/automaticMeshSizeField.h
@@ -1,41 +1,55 @@
 #ifndef _AUTOMATIC_MESH_SIZE_FIELD_H_
 #define _AUTOMATIC_MESH_SIZE_FIELD_H_
 
+#include "GmshConfig.h"
+
+#ifdef HAVE_HXT
+#include "hxt_octree.h"
+#endif
+
 #include "Field.h"
 
 class automaticMeshSizeField : public Field {
-
+  
+#ifdef HAVE_HXT
+  struct HXTForest *forest;
+  struct HXTForestOptions *forestOptions;
+  HXTStatus updateHXT();
+#endif
+  
   int _nPointsPerCircle;
   int _nPointsPerGap;
   double _hmin, _hmax;
   double _hbulk;
   double _gradientMax;
+  int _nRefine;
   char fileName[256];
-
-public:
-  automaticMeshSizeField()
-  {
-    _nPointsPerCircle = 15;
+  
+ public:
+  ~automaticMeshSizeField();
+  automaticMeshSizeField() : forest(NULL), forestOptions(NULL){
+    _nPointsPerCircle = 55 ;
     _nPointsPerGap = 5;
     _hmin = 1.e-8;// update needed
     _hmax = 1.e+8;// update needed    
     _hbulk = 0.1; // update needed
-    _gradientMax =1.4; 
-
-    
+    _gradientMax =1.4;
+    _nRefine = 5;
     
     options["nPointsPerCircle"] = new FieldOptionInt(_nPointsPerCircle,
-						     "Number of points per circle (adapt to curvature of surfaces)");
+						     "Number of points per circle (adapt to curvature of surfaces)",&update_needed);
     
     options["nPointsPerGap"] = new FieldOptionInt(_nPointsPerGap,
-						  "Number of points in thin layers");
+						  "Number of points in thin layers",&update_needed);
     
     options["hBulk"] = new FieldOptionDouble(_hbulk,
 					     "Size everywhere no size is prescribed", &update_needed);
     
     options["gradientMax"] = new FieldOptionDouble(_gradientMax,
-						   "Maximun gradient of the size field");
+						   "Maximun gradient of the size field",&update_needed);
     
+    options["NRefine"] = new FieldOptionInt(_nRefine,
+					    "Initial refinement level for the octree",&update_needed);
   }
   const char *getName() { return "AutomaticMeshSizeField"; }
   
diff --git a/Mesh/meshGRegionHxt.cpp b/Mesh/meshGRegionHxt.cpp
index fdaa1535b0f0b766be8c4bbf004bc35e29b35290..8eb318de7b18665f8e9e21f154bced2e80d44416 100644
--- a/Mesh/meshGRegionHxt.cpp
+++ b/Mesh/meshGRegionHxt.cpp
@@ -234,9 +234,9 @@ static HXTStatus Hxt2Gmsh(std::vector<GRegion *> &regions, HXTMesh *m,
   return HXT_STATUS_OK;
 }
 
-static HXTStatus Gmsh2Hxt(std::vector<GRegion *> &regions, HXTMesh *m,
-                          std::map<MVertex *, int> &v2c,
-                          std::vector<MVertex *> &c2v)
+HXTStatus Gmsh2Hxt(std::vector<GRegion *> &regions, HXTMesh *m,
+		   std::map<MVertex *, int> &v2c,
+		   std::vector<MVertex *> &c2v)
 {
   std::set<MVertex *> all;
   std::vector<GFace *> faces;
diff --git a/Mesh/meshGRegionHxt.h b/Mesh/meshGRegionHxt.h
index c711111f27d4ab9e0fca39d68ee760fc07e993ec..082032a049087664fdde40c08339b6a052a0a2e9 100644
--- a/Mesh/meshGRegionHxt.h
+++ b/Mesh/meshGRegionHxt.h
@@ -12,4 +12,5 @@ class GRegion;
 
 int meshGRegionHxt(std::vector<GRegion *> &regions);
 
+
 #endif
diff --git a/contrib/hxt/CMakeLists.txt b/contrib/hxt/CMakeLists.txt
index a63c4218dd6de3c5db881115501bfd969c3ac765..3908e210cd95735e820f733e863c04772356c2f8 100644
--- a/contrib/hxt/CMakeLists.txt
+++ b/contrib/hxt/CMakeLists.txt
@@ -39,6 +39,7 @@ set(SRC ${SRC}
   hxt_tetUtils.c
   hxt_tet_aspect_ratio.c
   hxt_vertices.c
+  hxt_octree.cpp
   predicates.c
 )
 endif()
diff --git a/contrib/hxt/hxt_octree.cpp b/contrib/hxt/hxt_octree.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..0d63d2435ba8038dbf52d79dd79f0d6c49caf2bf
--- /dev/null
+++ b/contrib/hxt/hxt_octree.cpp
@@ -0,0 +1,2291 @@
+#include <hxt_octree.h>
+
+#include <math.h>
+#include <iostream>
+
+#define MAX_DIFF 0.05 // La difference de taille max absolue sur un quadrant pour raffiner
+#define D2S_TOL 0.05
+#define ALPHA 1.40123
+#define BULK_SIZE 7.77;
+
+#ifdef HAVE_P4EST
+
+p4est_connectivity_t *p8est_connectivity_new_cube (double c);
+  
+static double hxtOctreeBulkSize(double x, double y, double z){
+  return BULK_SIZE;
+}
+
+static HXTStatus hxtOctreeGetCenter(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *q, double xyz[3])
+{
+  p4est_qcoord_t      half_length = P4EST_QUADRANT_LEN (q->level) / 2;
+  p4est_qcoord_to_vertex (p4est->connectivity, which_tree,
+                          q->x + half_length, q->y + half_length,
+  #ifdef P4_TO_P8
+                          q->z + half_length,
+  #endif
+                          xyz);
+
+  return HXT_STATUS_OK;
+}
+
+static HXTStatus hxtOctreeGetBboxOctant(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *q, double min[3], double max[3])
+{
+  p4est_qcoord_t      length = P4EST_QUADRANT_LEN (q->level);
+  p4est_qcoord_to_vertex (p4est->connectivity, which_tree,
+                          q->x, q->y,
+  #ifdef P4_TO_P8
+                          q->z,
+  #endif
+                          min);
+
+  p4est_qcoord_to_vertex (p4est->connectivity, which_tree,
+                          q->x + length, q->y + length,
+  #ifdef P4_TO_P8
+                          q->z + length,
+  #endif
+                          max);
+
+  return HXT_STATUS_OK;
+}
+
+static HXTStatus hxtOctreeGetOctantSize(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *q, double *h)
+{
+  double min[3], max[3];
+  p4est_qcoord_t      length = P4EST_QUADRANT_LEN (q->level);
+  p4est_qcoord_to_vertex (p4est->connectivity, which_tree,
+                          q->x, q->y,
+  #ifdef P4_TO_P8
+                          q->z,
+  #endif
+                          min);
+
+  p4est_qcoord_to_vertex (p4est->connectivity, which_tree,
+                          q->x + length, q->y + length,
+  #ifdef P4_TO_P8
+                          q->z + length,
+  #endif
+                          max);
+  
+  *h = fmax(max[0] - min[0],fmax(max[1] - min[1],max[2] - min[2]));
+
+  return HXT_STATUS_OK;
+}
+
+static void hxtOctreeSetInitialSize(p4est_t* p4est, p4est_topidx_t which_tree, p4est_quadrant_t *q){
+
+    // size_fun_t  *fun  = (size_fun_t *) p4est->user_pointer;
+    size_data_t *data = (size_data_t *) q->p.user_data;
+
+    double center[3];
+
+    hxtOctreeGetCenter(p4est, which_tree, q, center);
+
+    // HXTForestOptions *forestOptions = (HXTForestOptions *) p4est->user_pointer;
+    // double (*size_fun)(double, double, double) = (double (*)(double, double, double)) forestOptions->sizeFunction;
+    // std::cout<<"Dans initialsize 1 : "<<p4est->user_pointer<<std::endl;
+    double (*size_fun)(double, double, double) = (double (*)(double, double, double)) p4est->user_pointer;
+    // std::cout<<"Dans initialsize 2 : "<<&size_fun<<std::endl;
+    // std::cout<<size_fun(0,0,0)<<std::endl;
+
+    data->size = size_fun(center[0], center[1], center[2]);
+
+    for(int i = 0; i < P4EST_DIM; ++i){
+        data->ds[i] = 0.0;
+    }
+
+    data->d2s = 0;
+
+    // Initialisation des tailles à partir des donnees du demi-quadrant;
+    // double h = (double) P4EST_QUADRANT_LEN (q->level) / (double) P4EST_ROOT_LEN /2;
+    hxtOctreeGetOctantSize(p4est, which_tree, q, &(data->h));
+    // data->h /= 2.0;
+
+    data->h_xL = data->h/2;
+    data->h_xR = data->h/2;
+    data->h_yD = data->h/2;
+    data->h_yU = data->h/2;
+
+    data->h_xavg = 0;
+    data->h_yavg = 0;
+
+#ifdef P4_TO_P8
+    data->h_zB = data->h/2;
+    data->h_zT = data->h/2;
+    data->h_zavg = 0;
+#endif
+
+    data->refineFlag = 0;
+}
+
+HXTStatus hxtForestOptionsCreate(HXTForestOptions **forestOptions){
+
+  HXT_CHECK( hxtMalloc (forestOptions, sizeof(HXTForestOptions)) );
+    if(*forestOptions == NULL) return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY);
+
+  return HXT_STATUS_OK;
+}
+
+HXTStatus hxtForestOptionsDelete(HXTForestOptions **forestOptions){
+
+  HXT_CHECK(hxtFree(forestOptions));
+
+  return HXT_STATUS_OK;
+}
+
+// HXTStatus hxtForestCreate(int argc, char **argv, HXTForest **forest, const char* filename, void *user_pointer){
+// HXTStatus hxtForestCreate(int argc, char **argv, HXTForest **forest, const char* filename, double *bbox, RTree<int,double,3> *triRTree, double *nodalCurvature, void *user_pointer){
+HXTStatus hxtForestCreate(int argc, char **argv, HXTForest **forest, const char* filename, HXTForestOptions *forestOptions){
+
+    HXT_CHECK( hxtMalloc (forest, sizeof(HXTForest)) );
+    if(*forest == NULL) return HXT_ERROR(HXT_STATUS_OUT_OF_MEMORY);
+
+    int mpiret;
+    int balance;
+    sc_MPI_Comm mpicomm;
+    p4est_connectivity_t *connect;
+
+    /* Initialize MPI; see sc_mpi.h.
+     * If configure --enable-mpi is given these are true MPI calls.
+     * Else these are dummy functions that simulate a single-processor run. */
+    mpiret = sc_MPI_Init (&argc, &argv);
+    SC_CHECK_MPI(mpiret);
+    mpicomm = sc_MPI_COMM_WORLD;
+
+    /* These functions are optional.  If called they store the MPI rank as a
+     * static variable so subsequent global p4est log messages are only issued
+     * from processor zero.  Here we turn off most of the logging; see sc.h. */
+    sc_init(mpicomm, 1, 1, NULL, SC_LP_ESSENTIAL);
+    p4est_init(NULL, SC_LP_PRODUCTION);
+
+    /* Create a forest from the inp file with name filename  */
+    // connect = p4est_connectivity_read_inp(filename);
+    // connect = p4est_connectivity_load(filename, NULL);
+    #ifdef P4_TO_P8
+    //    std::cout<<"3D connectivity"<<std::endl;
+    // connect = p8est_connectivity_new_cube(forestOptions->bbox[0],forestOptions->bbox[1],forestOptions->bbox[2],
+                                          // forestOptions->bbox[3],forestOptions->bbox[4],forestOptions->bbox[5]);
+    double coordMin = fmin(fmin(forestOptions->bbox[0],forestOptions->bbox[1]),forestOptions->bbox[2]);
+    double coordMax = fmax(fmax(forestOptions->bbox[3],forestOptions->bbox[4]),forestOptions->bbox[5]);
+
+    connect = p8est_connectivity_new_cube(coordMax);
+    #else
+    //    std::cout<<"2D connectivity"<<std::endl;
+    // Sera éliminé plus tard pour ne plus devoir écrire un fichier inp.
+    connect = p4est_connectivity_read_inp(filename);
+    #endif
+
+    if(connect == NULL)return HXT_ERROR(HXT_STATUS_FILE_CANNOT_BE_OPENED);
+
+    #ifdef P4EST_WITH_METIS
+    //  Use metis (if p4est is compiled with the flag '--with-metis') to
+    //  * reorder the connectivity for better parititioning of the forest
+    //  * across processors. 
+    p4est_connectivity_reorder(mpicomm, 0, conn, P4EST_CONNECT_FACE);
+    #endif /* P4EST_WITH_METIS */
+
+    /* Create a forest that is not refined; it consists of the root octant. */
+    // std::cout<<"Dans forestCreate 1 : "<<reinterpret_cast<double (*)(double, double, double)>(*(forestOptions->sizeFunction))<<std::endl;
+    // std::cout<<"Dans forestCreate 1 : "<<(void *) forestOptions->sizeFunction<<std::endl;
+    // std::cout<<forestOptions->sizeFunction(0,0,0)<<std::endl;
+
+    if(forestOptions->sizeFunction == NULL) forestOptions->sizeFunction = &hxtOctreeBulkSize;
+
+    // std::cout<<"Dans forestCreate 2 : "<<&(forestOptions->sizeFunction)<<std::endl;
+    // std::cout<<forestOptions->sizeFunction(0,0,0)<<std::endl;
+
+    (*forest)->p4est = p4est_new(mpicomm, connect, sizeof(size_data_t), hxtOctreeSetInitialSize, (void *)forestOptions->sizeFunction);
+    (*forest)->forestOptions = forestOptions;
+
+    // std::cout<<"Après la creation : "<<&(forestOptions->sizeFunction)<<std::endl;
+    // std::cout<<forestOptions->sizeFunction(0,0,0)<<std::endl;
+
+    return HXT_STATUS_OK;
+}
+
+HXTStatus hxtForestDelete(HXTForest **forest){
+    /* Destroy the p4est structure. */
+    p4est_connectivity_destroy((*forest)->p4est->connectivity);
+    p4est_destroy((*forest)->p4est);
+    /* Verify that allocations internal to p4est and sc do not leak memory.
+     * This should be called if sc_init () has been called earlier. */
+    sc_finalize();
+    /* This is standard MPI programs.  Without --enable-mpi, this is a dummy. */
+    int mpiret = sc_MPI_Finalize();
+    SC_CHECK_MPI(mpiret);
+
+    HXT_CHECK(hxtFree(forest));
+
+    return HXT_STATUS_OK;
+}
+
+static int hxtOctreeRefineToLevelCallback(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *q){
+  return true;
+}
+
+HXTStatus hxtOctreeRefineToLevel(HXTForest *forest, int lvl){
+  for(int i = 0; i < lvl; ++i)
+    p4est_refine(forest->p4est, 0, hxtOctreeRefineToLevelCallback, hxtOctreeSetInitialSize);
+  
+  return HXT_STATUS_OK;
+}
+
+HXTStatus hxtOctreeBalance(HXTForest *forest){
+    p4est_balance(forest->p4est, P4EST_CONNECT_FACE, hxtOctreeSetInitialSize);
+    return HXT_STATUS_OK;
+}
+
+static int hxtOctreeRefineSizeCallback(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *q){
+
+    double center[3];
+    hxtOctreeGetCenter(p4est, which_tree, q, center);
+
+    
+    
+
+    double (*size_fun)(double, double, double) = (double (*)(double, double, double)) p4est->user_pointer;
+
+    size_data_t *data = (size_data_t *) q->p.user_data;
+
+    // double h = (double) P4EST_QUADRANT_LEN (q->level) / (double) P4EST_ROOT_LEN / 2;
+    double h = data->h;
+
+    double diff_max = 0, size_center = data->size, size_loc;
+
+    #define NSAMPLE 4
+
+    #ifdef P4_TO_P8
+        for(int i = 0; i < NSAMPLE; ++i){
+            for(int j = 0; j < NSAMPLE; ++j){
+                for(int k = 0; k < NSAMPLE; ++k){
+                    size_loc = size_fun(center[0] + (NSAMPLE*(i-1)+1) * h/2/NSAMPLE, center[1] + (NSAMPLE*(j-1)+1) * h/2/NSAMPLE, center[2] + (NSAMPLE*(k-1)+1) * h/2/NSAMPLE);
+                    diff_max = fmax(diff_max, fabs(size_center - size_loc));
+                }
+            }
+        }
+    #else
+        for(int i = 0; i < NSAMPLE; ++i){
+            for(int j = 0; j < NSAMPLE; ++j){
+                size_loc = size_fun(center[0] + (NSAMPLE*(i-1)+1) * h/2/NSAMPLE, center[1] + (NSAMPLE*(j-1)+1) * h/2/NSAMPLE, 0.0);
+                diff_max = fmax(diff_max, fabs(size_center - size_loc));
+            }
+        }
+    #endif
+
+    return diff_max > MAX_DIFF;
+}
+
+static int hxtOctreeCoarsenSizeCallback(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *children[]){
+    
+    double diff_max = 0;
+
+    for(int n = 0; n < P4EST_CHILDREN; ++n){
+
+        double center[3];
+        hxtOctreeGetCenter(p4est, which_tree, children[n], center);
+
+        double (*size_fun)(double, double, double) = (double (*)(double, double, double)) p4est->user_pointer;
+
+        size_data_t *data = (size_data_t *) children[n]->p.user_data;
+
+        // double h = (double) P4EST_QUADRANT_LEN (children[n]->level) / (double) P4EST_ROOT_LEN / 2;
+        double h = data->h;
+
+        double size_center = data->size, size_loc;
+
+        #ifdef P4_TO_P8
+            for(int i = 0; i < NSAMPLE; ++i){
+                for(int j = 0; j < NSAMPLE; ++j){
+                    for(int k = 0; k < NSAMPLE; ++k){
+                        size_loc = size_fun(center[0] + (NSAMPLE*(i-1)+1) * h/2/NSAMPLE, center[1] + (NSAMPLE*(j-1)+1) * h/2/NSAMPLE, center[2] + (NSAMPLE*(k-1)+1) * h/2/NSAMPLE);
+                        diff_max = fmax(diff_max, fabs(size_center - size_loc));
+                    }
+                }
+            }
+        #else
+            for(int i = 0; i < NSAMPLE; ++i){
+                for(int j = 0; j < NSAMPLE; ++j){
+                    size_loc = size_fun(center[0] + (NSAMPLE*(i-1)+1) * h/2/NSAMPLE, center[1] + (NSAMPLE*(j-1)+1) * h/2/NSAMPLE, 0.0);
+                    diff_max = fmax(diff_max, fabs(size_center - size_loc));
+                }
+            }
+        #endif
+
+    }
+
+    return diff_max < MAX_DIFF;
+}
+
+HXTStatus hxtOctreeRefineSizeVariation(HXTForest *forest, int recursive){
+    p4est_refine(forest->p4est, recursive, hxtOctreeRefineSizeCallback, hxtOctreeSetInitialSize);
+    return HXT_STATUS_OK;
+}
+
+HXTStatus hxtOctreeCoarsenSizeVariation(HXTForest *forest, int recursive){
+    p4est_coarsen(forest->p4est, recursive, hxtOctreeCoarsenSizeCallback, hxtOctreeSetInitialSize);
+    return HXT_STATUS_OK;
+}
+
+HXTStatus hxtOctreeInitialRefine(HXTForest *forest, int nRefine){
+    for(int i = 0; i < nRefine; ++i){
+        HXT_CHECK(hxtOctreeRefineSizeVariation(forest, 0));
+        HXT_CHECK(hxtOctreeCoarsenSizeVariation(forest, 0));
+        HXT_CHECK(hxtOctreeBalance(forest));
+    }
+    return HXT_STATUS_OK;
+}
+
+static int hxtRefineLaplacianCallback(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *q){
+    size_data_t *data = (size_data_t *) q->p.user_data;
+    return (data->d2s * data->h * data->h > D2S_TOL);
+}
+
+// HXTStatus hxtOctreeRefineLaplacian(HXTForest *forest){
+    // Ne peut pas être raffiné récursivement : il faut calculer le laplacien après chaque raffinement
+    // p4est_refine(forest->p4est, 0, hxtRefineLaplacianCallback, hxtOctreeSetInitialSize);
+    // return HXT_STATUS_OK;
+// }
+
+static int hxtCoarsenLaplacianCallback(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *children[]){
+
+    double err_max = 0.0;
+
+    for(int n = 0; n < P4EST_CHILDREN; ++n){
+        size_data_t *data = (size_data_t *) children[n]->p.user_data;
+        err_max = fmax(err_max, fabs(data->d2s * data->h * data->h));
+    }
+    return err_max < D2S_TOL;
+}
+
+HXTStatus hxtOctreeCoarsenLaplacian(p4est_t *p4est, int recursive){
+    p4est_coarsen(p4est, recursive, hxtCoarsenLaplacianCallback, hxtOctreeSetInitialSize);
+    return HXT_STATUS_OK;
+}
+
+// static void hxtOctreeComputeGradientFaces(p4est_iter_face_info_t * info, void *user_data){
+    
+//     p4est_iter_face_side_t *side[2];
+//     sc_array_t             *sides = &(info->sides);
+//     size_data_t            *ghost_data = (size_data_t *) user_data;
+//     size_data_t            *size_data;
+//     p4est_quadrant_t       *quad;
+//     double                  s_avg[2];
+//     double                  h[2];
+//     double                  ds_est, ds_old;
+//     int                     which_dir;
+
+//     P4EST_ASSERT(sides->elem_count == 2);
+
+//     side[0] = p4est_iter_fside_array_index_int (sides, 0);
+//     side[1] = p4est_iter_fside_array_index_int (sides, 1);
+
+//     which_dir = side[0]->face / 2;        /* 0 == x, 1 == y, 2 == z */
+
+//     if(sides->elem_count == 2){
+//         // std::cout<<"Intérieur"<<std::endl;
+//         for(int i = 0; i < 2; i++) {
+//             s_avg[i] = 0;
+//             if (side[i]->is_hanging) {
+//                 /* there are 2^(d-1) (P4EST_HALF) subfaces */
+//                 for(int j = 0; j < P4EST_HALF; j++) {
+//                     quad = side[i]->is.hanging.quad[j];
+//                     h[i] = (double) P4EST_QUADRANT_LEN (quad->level) / (double) P4EST_ROOT_LEN /2;
+//                     if (side[i]->is.hanging.is_ghost[j]) {
+//                         size_data = &ghost_data[side[i]->is.hanging.quadid[j]];
+//                     }
+//                     else {
+//                         size_data = (size_data_t *) side[i]->is.hanging.quad[j]->p.user_data;
+//                     }
+//                     s_avg[i] += size_data->size;
+//                 }
+
+//                 s_avg[i] /= P4EST_HALF;
+//             }
+//             else {
+//                 quad = side[i]->is.full.quad;
+//                 h[i] = (double) P4EST_QUADRANT_LEN (quad->level) / (double) P4EST_ROOT_LEN /2;
+//                 if(side[i]->is.full.is_ghost) {
+//                     size_data = &ghost_data[side[i]->is.full.quadid];
+//                 }
+//                 else{
+//                     size_data = (size_data_t *) side[i]->is.full.quad->p.user_data;
+//                 }
+            
+//                 s_avg[i] = size_data->size;
+//             }
+//         }
+
+//         ds_est = (s_avg[1] - s_avg[0]) / ((h[0] + h[1]) / 2.);
+  
+//         for (int i = 0; i < 2; i++) {
+//             if (side[i]->is_hanging) {
+//                  there are 2^(d-1) (P4EST_HALF) subfaces 
+//                 for (int j = 0; j < P4EST_HALF; j++) {
+//                     quad = side[i]->is.hanging.quad[j];
+//                     if (!side[i]->is.hanging.is_ghost[j]) {
+//                         size_data = (size_data_t *) quad->p.user_data;
+//                         // ds_old = size_data->ds[which_dir];
+//                         // if (ds_old == ds_old) {
+//                         // /* there has already been an update */
+//                         //     if (ds_est * ds_old >= 0.) {
+//                         //         if (fabs (ds_est) < fabs (ds_old)) {
+//                         //             size_data->ds[which_dir] = ds_est;
+//                         //         }
+//                         //     }
+//                         //     else {
+//                         //         size_data->ds[which_dir] = 0.;
+//                         //     }
+//                         // }
+//                         // else {
+//                             size_data->ds[which_dir] = ds_est;
+//                         // }
+//                     }
+//                 }
+//             }
+//             else {
+//                 quad = side[i]->is.full.quad;
+//                 if (!side[i]->is.full.is_ghost) {
+//                     size_data = (size_data_t *) quad->p.user_data;
+//                     // ds_old = size_data->ds[which_dir];
+//                     // if (ds_old == ds_old) {
+//                     //     /* there has already been an update */
+//                     //     if (ds_est * ds_old >= 0.) {
+//                     //         if (fabs (ds_est) < fabs (ds_old)) {
+//                     //             size_data->ds[which_dir] = ds_est;
+//                     //         }
+//                     //     }
+//                     //     else {
+//                     //         size_data->ds[which_dir] = 0.;
+//                     //     }
+//                     // }
+//                     // else {
+//                         size_data->ds[which_dir] = ds_est;
+//                     // }
+//                 }
+//             }
+//         }
+
+//         // }
+//     }
+//     else{
+//         // std::cout<<"Frontière ?"<<std::endl;
+//         // std::cout<<side[1]->is.full.is_ghost<<std::endl;
+//         // std::cout<<side[1]->is.full.quadid<<std::endl;
+//         // std::cout<<(int) side[0]->face<<std::endl;
+//         // std::cout<<(int) side[1]->face<<std::endl;
+//     }
+// }
+
+static void hxtOctreeComputeGradientCenter(p4est_iter_face_info_t * info, void *user_data){
+
+    p4est_iter_face_side_t *side[2];
+    sc_array_t             *sides = &(info->sides);
+    // size_data_t            *ghost_data = (size_data_t *) user_data;
+    size_data_t            *size_data;
+    size_data_t            *size_data_opp;
+    double                  s_avg;
+    double                  h;
+    int                     which_face;
+    int                     which_face_opp;
+
+    // Indice de l'autre côté de la face (0 si 1 et 1 si 0)
+    int                     iOpp; 
+
+    side[0] = p4est_iter_fside_array_index_int (sides, 0);
+    side[1] = p4est_iter_fside_array_index_int (sides, 1);
+
+    if(sides->elem_count == 2){
+
+        for(int i = 0; i < 2; i++) {
+            // Indice dans side[] de la face opposée
+            iOpp = 1 - i;
+
+            which_face_opp = side[iOpp]->face;     /* 0,1 == -+x, 2,3 == -+y, 4,5 == -+z */
+
+            s_avg = 0;
+            if (side[i]->is_hanging) {
+                /* there are 2^(d-1) (P4EST_HALF) subfaces */
+                for(int j = 0; j < P4EST_HALF; j++) {
+
+                    size_data     = (size_data_t *) side[i]->is.hanging.quad[j]->p.user_data;
+                    size_data_opp = (size_data_t *) side[iOpp]->is.full.quad->p.user_data;
+                
+                    s_avg += size_data->size;
+                }
+
+                // Calcul de la valeur moyenne sur les P4EST_HALF quadrants courants
+                s_avg /= P4EST_HALF;
+
+                switch(which_face_opp){
+                    case 0 :    size_data_opp->ds[0] -= s_avg; break;
+                    case 1 :    size_data_opp->ds[0] += s_avg; break;
+                    case 2 :    size_data_opp->ds[1] -= s_avg; break;
+                    case 3 :    size_data_opp->ds[1] += s_avg; break;
+                #ifdef P4_TO_P8
+                    case 4 :    size_data_opp->ds[2] -= s_avg; break;
+                    case 5 :    size_data_opp->ds[2] += s_avg; break;
+                #endif
+                    default :
+                        std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                }
+            }
+            else {
+
+                size_data = (size_data_t *) side[i]->is.full.quad->p.user_data;
+                s_avg = size_data->size;
+
+                if(side[iOpp]->is_hanging){
+                    // Full - Oppose hanging
+                    for(int j = 0; j < P4EST_HALF; ++j){
+                        size_data_opp = (size_data_t *) side[iOpp]->is.hanging.quad[j]->p.user_data;
+
+                        switch(which_face_opp){
+                            case 0 :    size_data_opp->ds[0] -= s_avg; break;
+                            case 1 :    size_data_opp->ds[0] += s_avg; break;
+                            case 2 :    size_data_opp->ds[1] -= s_avg; break;
+                            case 3 :    size_data_opp->ds[1] += s_avg; break;
+                        #ifdef P4_TO_P8
+                            case 4 :    size_data_opp->ds[2] -= s_avg; break;
+                            case 5 :    size_data_opp->ds[2] += s_avg; break;
+                        #endif
+                            default :
+                                std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                        }
+                    }
+                    
+                }
+                else{
+                    // Full - Oppose full
+                    size_data_opp = (size_data_t *) side[iOpp]->is.full.quad->p.user_data;
+
+                    switch(which_face_opp){
+                        case 0 :    size_data_opp->ds[0] -= s_avg;  break;
+                        case 1 :    size_data_opp->ds[0] += s_avg;  break;
+                        case 2 :    size_data_opp->ds[1] -= s_avg;  break;
+                        case 3 :    size_data_opp->ds[1] += s_avg;  break;
+                    #ifdef P4_TO_P8
+                        case 4 :    size_data_opp->ds[2] -= s_avg; break;
+                        case 5 :    size_data_opp->ds[2] += s_avg; break;
+                    #endif
+                        default :
+                            std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                    }
+                }
+                  
+            }
+        }
+    }
+    else{
+        size_data = (size_data_t *) side[0]->is.full.quad->p.user_data;
+
+        which_face = side[0]->face;
+
+        // double center[3];
+
+        // get_center(info->p4est, side[0]->treeid, side[0]->is.full.quad, center);
+
+        // h = (double) P4EST_QUADRANT_LEN (side[0]->is.full.quad->level) / (double) P4EST_ROOT_LEN /2;
+
+        // double s_out;
+
+        // switch(which_face){
+        //     case 0 :
+        //         s_out = myFunction(center[0] - h, center[1], center[2]);
+        //         size_data->ds[0] -= s_out;
+        //         break;
+        //     case 1 :
+        //         s_out = myFunction(center[0] + h, center[1], center[2]);
+        //         size_data->ds[0] += s_out;
+        //         break;
+        //     case 2 : 
+        //         s_out = myFunction(center[0], center[1] - h, center[2]);
+        //         size_data->ds[1] -= s_out;
+        //         break;
+        //     case 3 : 
+        //         s_out = myFunction(center[0], center[1] + h, center[2]);
+        //         size_data->ds[1] += s_out;
+        //         break;
+        //     default :
+        //         std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+        //         exit(-1);
+        // }
+
+        // Differences finies aux faces (decentrees) si le quadrant est a la frontiere
+        switch(which_face){
+            case 0 :    size_data->ds[0] -= size_data->size; break;
+            case 1 :    size_data->ds[0] += size_data->size; break;
+            case 2 :    size_data->ds[1] -= size_data->size; break;
+            case 3 :    size_data->ds[1] += size_data->size; break;
+        #ifdef P4_TO_P8
+            case 4 :    size_data->ds[2] -= size_data->size; break;
+            case 5 :    size_data->ds[2] += size_data->size; break;
+        #endif
+            default :
+                std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+        }
+    }
+}
+
+
+static void hxtOctreeComputeGradientCenterBoundary(p4est_iter_face_info_t * info, void *user_data){
+
+    p4est_iter_face_side_t *side[2];
+    sc_array_t             *sides = &(info->sides);
+    size_data_t            *size_data;
+    int                     which_dir;
+
+    side[0] = p4est_iter_fside_array_index_int (sides, 0);
+    side[1] = p4est_iter_fside_array_index_int (sides, 1);
+
+    if(sides->elem_count == 1){
+        size_data = (size_data_t *) side[0]->is.full.quad->p.user_data;
+        which_dir = side[0]->face / 2;
+        size_data->ds[which_dir] *= 2.0; // Sera divise par hMin dans laplacian_volume !
+    }
+}
+
+static void hxtOctreeComputeSizeMin(p4est_iter_face_info_t * info, void *user_data){
+
+    p4est_iter_face_side_t *side[2];
+    sc_array_t             *sides = &(info->sides);
+    size_data_t            *ghost_data = (size_data_t *) user_data;
+    size_data_t            *size_data;
+    size_data_t            *size_data_opp;
+    p4est_quadrant_t       *quad;
+    p4est_quadrant_t       *quadOpp;
+    double                  h;
+    int                     which_face;
+    int                     which_face_opp;
+
+    // Indice de l'autre côté de la face (0 si 1 et 1 si 0)
+    int                     iOpp; 
+
+    side[0] = p4est_iter_fside_array_index_int (sides, 0);
+    side[1] = p4est_iter_fside_array_index_int (sides, 1);
+
+    if(sides->elem_count == 2){
+
+        for(int i = 0; i < 2; i++) {
+
+            // Indice dans side[] de la face opposée
+            iOpp = 1 - i;
+
+            which_face_opp = side[iOpp]->face;     /* 0,1 == x, 2,3 == y, 4,5 == z */
+
+            if (side[i]->is_hanging) {
+
+                // Taille identique pour les deux quadrants hanging
+                quad = side[i]->is.hanging.quad[0];
+                // h = (double) P4EST_QUADRANT_LEN (quad->level) / (double) P4EST_ROOT_LEN /2;
+                // hxtOctreeGetOctantSize(info->p4est, quad->p.which_tree, quad, &h);
+                // h /= 2.0;
+                size_data = (size_data_t *) quad->p.user_data;
+                h = size_data->h;
+                // Le quadrant oppose ne peut pas etre hanging, sinon j'imagine que 
+                // la face est divisee en deux. Comme on est hanging, l'oppose est
+                // presumement full.
+                size_data_opp = (size_data_t *) side[iOpp]->is.full.quad->p.user_data;
+
+                // Contribution pour la taille dans le quadrant oppose
+                switch(which_face_opp){
+                    case 0 :    size_data_opp->h_xL += h/2 ; break;
+                    case 1 :    size_data_opp->h_xR += h/2 ; break;
+                    case 2 :    size_data_opp->h_yD += h/2 ; break;
+                    case 3 :    size_data_opp->h_yU += h/2 ; break;
+                #ifdef P4_TO_P8
+                    case 4 :    size_data_opp->h_zB += h/2 ; break;
+                    case 5 :    size_data_opp->h_zT += h/2 ; break;
+                #endif
+                    default :
+                        std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                        exit(-1); // Brutal
+                }
+            }
+            else {
+                // Taille du quadrant courant
+                quad = side[i]->is.full.quad;
+                // h = (double) P4EST_QUADRANT_LEN (quad->level) / (double) P4EST_ROOT_LEN /2;
+                // hxtOctreeGetOctantSize(info->p4est, quad->p.which_tree, quad, &h);
+                // h /= 2.0;
+                size_data = (size_data_t *) quad->p.user_data;
+                h = size_data->h;
+
+                // Contribution pour la taille dans le quadrant oppose
+                if(side[iOpp]->is_hanging){
+                    // Full - Oppose Hanging
+                    for(int j = 0; j < P4EST_HALF; ++j){
+                        size_data_opp = (size_data_t *) side[iOpp]->is.hanging.quad[j]->p.user_data;
+
+                        switch(which_face_opp){
+                            case 0 :    size_data_opp->h_xL += h/2 ; break;
+                            case 1 :    size_data_opp->h_xR += h/2 ; break;
+                            case 2 :    size_data_opp->h_yD += h/2 ; break;
+                            case 3 :    size_data_opp->h_yU += h/2 ; break;
+                        #ifdef P4_TO_P8
+                            case 4 :    size_data_opp->h_zB += h/2 ; break;
+                            case 5 :    size_data_opp->h_zT += h/2 ; break;
+                        #endif
+                            default :
+                                std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                                exit(-1); // Brutal
+                        }
+                    }
+                }
+                else{
+                    // Full - Oppose Full
+                    size_data_opp = (size_data_t *) side[iOpp]->is.full.quad->p.user_data;
+
+                    switch(which_face_opp){
+                        case 0 :    size_data_opp->h_xL += h/2 ; break;
+                        case 1 :    size_data_opp->h_xR += h/2 ; break;
+                        case 2 :    size_data_opp->h_yD += h/2 ; break;
+                        case 3 :    size_data_opp->h_yU += h/2 ; break;
+                    #ifdef P4_TO_P8
+                        case 4 :    size_data_opp->h_zB += h/2 ; break;
+                        case 5 :    size_data_opp->h_zT += h/2 ; break;
+                    #endif
+                        default :
+                            std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                            exit(-1); // Brutal
+                    }  
+                }  
+
+            }
+        }
+    }
+    else{
+        // Frontière
+        size_data = (size_data_t *) side[0]->is.full.quad->p.user_data;
+
+        which_face = side[0]->face;
+
+        // h = (double) P4EST_QUADRANT_LEN (side[0]->is.full.quad->level) / (double) P4EST_ROOT_LEN /2;
+        // hxtOctreeGetOctantSize(info->p4est, quad->p.which_tree, quad, &h);
+        // h /= 2.0;
+        h = size_data->h;
+
+        switch(which_face){
+            case 0 :    size_data->h_xL += h/2; break;
+            case 1 :    size_data->h_xR += h/2; break;
+            case 2 :    size_data->h_yD += h/2; break;
+            case 3 :    size_data->h_yU += h/2; break;
+        #ifdef P4_TO_P8
+            case 4 :    size_data->h_zB += h/2 ; break;
+            case 5 :    size_data->h_zT += h/2 ; break;
+        #endif
+            default :
+                std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                exit(-1); // Brutal
+        }
+    }
+}
+
+static void hxtOctreeLaplacianFacesContribution(p4est_iter_face_info_t * info, void *user_data){
+
+    p4est_iter_face_side_t *side[2];
+    sc_array_t             *sides = &(info->sides);
+    size_data_t            *ghost_data = (size_data_t *) user_data;
+    size_data_t            *size_data;
+    size_data_t            *size_data_opp1;
+    size_data_t            *size_data_opp2;
+    p4est_quadrant_t       *quad;
+    double                  s_avg;
+    int                     which_dir;
+    int                     which_face;
+    int                     which_face_opp;
+
+    double (*size_fun)(double, double, double) = (double (*)(double, double, double)) info->p4est->user_pointer;
+
+    // Indice de l'autre côté de la face (0 si 1 et 1 si 0)
+    int                     iOpp; 
+
+    side[0] = p4est_iter_fside_array_index_int (sides, 0);
+    side[1] = p4est_iter_fside_array_index_int (sides, 1);
+
+    if(sides->elem_count == 2){
+
+        for(int i = 0; i < 2; i++) {
+
+            // Indice dans side[] de la face opposée
+            iOpp = 1 - i;
+
+            which_face_opp = side[iOpp]->face;     /* 0,1 == -+x, 2,3 == -+y, 4,5 == -+z */
+            // which_dir = which_face_opp /2;         /* 0 == x, 1 == y, 2 == z */
+
+            s_avg = 0;
+            if (side[i]->is_hanging) {
+
+                /* there are 2^(d-1) (P4EST_HALF) subfaces */
+                for(int j = 0; j < P4EST_HALF; j++) {
+
+                    size_data = (size_data_t *) side[i]->is.hanging.quad[j]->p.user_data;
+                    s_avg += size_data->size;
+                }
+
+                // Calcul de la valeur moyenne sur les P4EST_HALF quadrants courants
+                s_avg /= P4EST_HALF;
+
+                size_data_opp1 = (size_data_t *) side[iOpp]->is.full.quad->p.user_data;
+                // Switch sur which_dir : les faces selon x ont le meme denominateur,
+                // idem pour les faces selon y
+                switch(which_face_opp){
+                    case 0 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_xavg; break;
+                    case 1 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_xavg; break;
+                    case 2 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_yavg; break;
+                    case 3 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_yavg; break;
+                #ifdef P4_TO_P8
+                    case 4 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_zavg; break;
+                    case 5 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_zavg; break;
+                #endif
+                    default :
+                        std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                        exit(-1); // Brutal
+                }
+            }
+            else {
+
+                size_data = (size_data_t *) side[i]->is.full.quad->p.user_data;
+                s_avg = size_data->size;
+
+                // Switch sur which_dir : les faces selon x ont les memes signe et denominateur,
+                // idem pour les faces selon y
+                if(side[iOpp]->is_hanging){
+                    // Full - Oppose hanging
+                    for(int j = 0; j < P4EST_HALF; ++j){
+                        size_data_opp1 = (size_data_t *) side[iOpp]->is.hanging.quad[j]->p.user_data;
+
+                        switch(which_face_opp){
+                            case 0 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_xavg; break;
+                            case 1 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_xavg; break;
+                            case 2 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_yavg; break;
+                            case 3 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_yavg; break;
+                        #ifdef P4_TO_P8
+                            case 4 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_zavg; break;
+                            case 5 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_zavg; break;
+                        #endif
+                            default :
+                                std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                                exit(-1); // Brutal
+                        }
+                    }
+                }
+                else{
+                    // Full - Oppose full
+                    size_data_opp1 = (size_data_t *) side[iOpp]->is.full.quad->p.user_data;
+
+                    switch(which_face_opp){
+                        case 0 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_xavg; break;
+                        case 1 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_xavg; break;
+                        case 2 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_yavg; break;
+                        case 3 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_yavg; break;
+                    #ifdef P4_TO_P8
+                        case 4 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_zavg; break;
+                        case 5 :    size_data_opp1->d2s += s_avg / size_data_opp1->h_zavg; break;
+                    #endif
+                        default :
+                            std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                            exit(-1); // Brutal
+                    }
+                }   
+            }
+        }
+    }
+    else{
+        // Frontière
+        size_data = (size_data_t *) side[0]->is.full.quad->p.user_data;
+
+        which_face = side[0]->face;
+
+        // double h = (double) P4EST_QUADRANT_LEN (side[0]->is.full.quad->level) / (double) P4EST_ROOT_LEN /2;
+        double h = size_data->h;
+
+        double center[3];
+
+        hxtOctreeGetCenter(info->p4est, side[0]->treeid, side[0]->is.full.quad, center);
+
+        double s_out;
+
+        switch(which_face){
+            case 0 :
+                s_out = size_fun(center[0] - h, center[1], center[2]);
+                size_data->d2s += s_out / size_data->h_xavg;
+                // size_data->d2s += size_data->size / size_data->h_xavg;
+                break;
+            case 1 :
+                s_out = size_fun(center[0] + h, center[1], center[2]);
+                // size_data->d2s += SIZE_FOND / size_data->h_xavg;
+                size_data->d2s += s_out / size_data->h_xavg;
+                // size_data->d2s += size_data->size / size_data->h_xavg;
+                break;
+            case 2 : 
+                s_out = size_fun(center[0], center[1] - h, center[2]);
+                size_data->d2s += s_out / size_data->h_yavg;
+                // size_data->d2s += size_data->size / size_data->h_yavg;
+                break;
+            case 3 : 
+                s_out = size_fun(center[0], center[1] + h, center[2]);
+                // size_data->d2s += SIZE_FOND / size_data->h_yavg;
+                size_data->d2s += s_out / size_data->h_yavg;
+                // size_data->d2s += size_data->size / size_data->h_yavg;
+                break;
+        #ifdef P4_TO_P8
+            case 4 : 
+                s_out = size_fun(center[0], center[1], center[2] - h);
+                size_data->d2s += s_out / size_data->h_zavg;
+                // size_data->d2s += size_data->size / size_data->h_yavg;
+                break;
+            case 5 : 
+                s_out = size_fun(center[0], center[1], center[2] + h);
+                // size_data->d2s += SIZE_FOND / size_data->h_yavg;
+                size_data->d2s += s_out / size_data->h_zavg;
+                // size_data->d2s += size_data->size / size_data->h_yavg;
+                break;
+        #endif 
+        }
+    }
+}
+
+static void hxtOctreeSizeAvg(p4est_iter_volume_info_t * info, void *user_data){
+
+    size_data_t *data = (size_data_t *) info->quad->p.user_data;
+ 
+    // data->h_xavg = ( pow(data->h_xL, 2) + pow(data->h_xR, 2) ) /2.0;
+    // data->h_yavg = ( pow(data->h_yU, 2) + pow(data->h_yD, 2) ) /2.0;
+
+    data->hMin = fmin(fmin(fmin(data->h_xL, data->h_xR),data->h_yU),data->h_yD);
+
+#ifdef P4_TO_P8
+    data->hMin = fmin(data->hMin, fmin(data->h_zB, data->h_zT));
+#endif
+
+    data->h_xavg = pow(data->hMin,2);
+    data->h_yavg = pow(data->hMin,2);
+#ifdef P4_TO_P8
+    data->h_zavg = pow(data->hMin,2);
+#endif
+
+    // data->h_xavg = ( data->h_xL * data->h_xL + data->h_xR * data->h_xR ) /2.0;
+    // data->h_yavg = ( data->h_yU * data->h_yU + data->h_yD * data->h_yD ) /2.0;
+}
+
+static void hxtOctreeComputeLaplacianQuadrant(p4est_iter_volume_info_t * info, void *user_data){
+
+    size_data_t *data = (size_data_t *) info->quad->p.user_data;
+
+    if(data->h_xavg == 0 || data->h_yavg == 0){ std::cout<<"ERREUR"<<std::endl; exit(-1); }
+
+    // double h = (double) P4EST_QUADRANT_LEN (info->quad->level) / (double) P4EST_ROOT_LEN /2;
+
+    // data->ds[0] /= (data->h_xL + data->h_xR);
+    // data->ds[1] /= (data->h_yU + data->h_yD);
+
+    data->hMin = fmin(fmin(fmin(data->h_xL, data->h_xR),data->h_yU),data->h_yD);
+
+#ifdef P4_TO_P8
+    data->hMin = fmin(data->hMin, fmin(data->h_zB, data->h_zT));
+#endif
+
+    // data->ds[0] /= 2.0 * fmin(data->h_xL,data->h_xR);
+    // data->ds[1] /= 2.0 * fmin(data->h_yU,data->h_yD);
+
+    for(int i = 0; i < P4EST_DIM; ++i){
+        data->ds[i] /= 2.0 * data->hMin;
+    }
+    
+    // data->d2s -= 2.0 * data->size / data->h_xavg;
+    // data->d2s -= 2.0 * data->size / data->h_yavg;
+#ifdef P4_TO_P8
+    data->d2s -= 6.0 * data->size / pow(data->hMin,2);
+#else
+    data->d2s -= 4.0 * data->size / pow(data->hMin,2);
+#endif
+
+    // data->d2s -= data->ds[0] * (data->h_xR - data->h_xL) / data->h_xavg;
+    // data->d2s -= data->ds[1] * (data->h_yU - data->h_yD) / data->h_yavg;
+
+}
+
+static void hxtOctreeResetLaplacian(p4est_iter_volume_info_t * info, void *user_data){
+
+    size_data_t *size_data = (size_data_t *) info->quad->p.user_data;
+    // double h = (double) P4EST_QUADRANT_LEN (info->quad->level) / (double) P4EST_ROOT_LEN / 2;
+
+    size_data->d2s = 0.0;
+
+    for(int i = 0; i < P4EST_DIM; ++i){
+        size_data->ds[i] = 0.0;
+    }
+    
+    size_data->h_xL = size_data->h/2;
+    size_data->h_xR = size_data->h/2;
+    size_data->h_yU = size_data->h/2;
+    size_data->h_yD = size_data->h/2;
+#ifdef P4_TO_P8
+    size_data->h_zB = size_data->h/2;
+    size_data->h_zT = size_data->h/2;
+#endif
+    
+    size_data->h_xavg = 0.0;
+    size_data->h_yavg = 0.0;
+
+    size_data->hMin = 0.0;
+}
+
+HXTStatus hxtOctreeComputeLaplacian(HXTForest *forest){
+
+    // Remet à 0 les derivees, h et laplacien sur chaque quadrant
+    p4est_iterate(forest->p4est, NULL, NULL, hxtOctreeResetLaplacian, NULL,
+            #ifdef P4_TO_P8
+                        NULL,
+            #endif
+                        NULL);
+
+    // Calcule les tailles
+    p4est_iterate(forest->p4est, NULL, NULL, NULL, hxtOctreeComputeSizeMin,
+        #ifdef P4_TO_P8
+                    NULL,
+        #endif
+                    NULL);
+
+    p4est_iterate(forest->p4est, NULL, NULL, hxtOctreeSizeAvg, NULL,
+        #ifdef P4_TO_P8
+                    NULL,
+        #endif
+                    NULL);
+
+    // Calcule le gradient au centre de chaque quadrant
+    p4est_iterate(forest->p4est, NULL, NULL, NULL, hxtOctreeComputeGradientCenter,
+        #ifdef P4_TO_P8
+                    NULL,
+        #endif
+                    NULL);
+
+    // Finalise le calcul gradient sur les quadrants aux bords
+    p4est_iterate(forest->p4est, NULL, NULL, NULL, hxtOctreeComputeGradientCenterBoundary,
+        #ifdef P4_TO_P8
+                    NULL,
+        #endif
+                    NULL);
+
+    // Ajoute les contributions des cellules voisines
+    p4est_iterate(forest->p4est, NULL, NULL, NULL, hxtOctreeLaplacianFacesContribution, 
+        #ifdef P4_TO_P8
+                    NULL,
+        #endif
+                    NULL);
+
+    // Ajoute les contributions sur chaque quadrant
+    p4est_iterate(forest->p4est, NULL, NULL, hxtOctreeComputeLaplacianQuadrant, NULL,
+        #ifdef P4_TO_P8
+                    NULL,
+        #endif
+                    NULL);
+
+    return HXT_STATUS_OK;
+}
+
+void min_size (p4est_iter_volume_info_t * info, void *user_data)
+{
+  p4est_quadrant_t   *q = info->quad;
+  size_data_t        *data = (size_data_t *) q->p.user_data;
+  double              size_min = *((double *) user_data);
+
+  size_min = SC_MIN (data->size, size_min);
+
+  *((double *) user_data) = size_min;
+}
+
+void max_dsdx (p4est_iter_volume_info_t * info, void *user_data)
+{
+  p4est_quadrant_t   *q = info->quad;
+  size_data_t        *data = (size_data_t *) q->p.user_data;
+  double              umax = *((double *) user_data);
+
+  umax = SC_MAX (data->ds[0], umax);
+
+  *((double *) user_data) = umax;
+}
+
+void max_dsdy (p4est_iter_volume_info_t * info, void *user_data)
+{
+  p4est_quadrant_t   *q = info->quad;
+  size_data_t        *data = (size_data_t *) q->p.user_data;
+  double              umax = *((double *) user_data);
+
+  umax = SC_MAX (data->ds[1], umax);
+
+  *((double *) user_data) = umax;
+}
+
+// #ifdef P4_TO_P8
+void max_dsdz (p4est_iter_volume_info_t * info, void *user_data)
+{
+  p4est_quadrant_t   *q = info->quad;
+  size_data_t        *data = (size_data_t *) q->p.user_data;
+  double              umax = *((double *) user_data);
+
+  umax = SC_MAX (data->ds[2], umax);
+
+  *((double *) user_data) = umax;
+}
+// #endif
+
+HXTStatus hxtOctreeComputeMinimumSize(HXTForest *forest, double *size_min){
+  p4est_iterate (forest->p4est, NULL, (void *) size_min, min_size, NULL,
+            #ifdef P4_TO_P8
+                       NULL,
+            #endif
+                       NULL);
+  return HXT_STATUS_OK;
+}
+
+HXTStatus hxtOctreeComputeMaxGradientX(HXTForest *forest, double *dsdx_max){
+	p4est_iterate (forest->p4est, NULL, (void *) dsdx_max, max_dsdx, NULL,
+            #ifdef P4_TO_P8
+                       NULL,
+            #endif
+                       NULL);
+	return HXT_STATUS_OK;
+}
+
+HXTStatus hxtOctreeComputeMaxGradientY(HXTForest *forest, double *dsdy_max){
+	p4est_iterate (forest->p4est, NULL, (void *) dsdy_max, max_dsdy, NULL,
+            #ifdef P4_TO_P8
+                       NULL,
+            #endif
+                       NULL);
+	return HXT_STATUS_OK;
+}
+
+HXTStatus hxtOctreeComputeMaxGradientZ(HXTForest *forest, double *dsdz_max){
+	p4est_iterate (forest->p4est, NULL, (void *) dsdz_max, max_dsdz, NULL,
+            #ifdef P4_TO_P8
+                       NULL,
+            #endif
+                       NULL);
+	return HXT_STATUS_OK;
+}
+
+void set_max_gradient_faces(p4est_iter_face_info_t * info, void *user_data){
+    p4est_iter_face_side_t *side[2];
+    sc_array_t             *sides = &(info->sides);
+    size_data_t            *ghost_data = (size_data_t *) user_data;
+    size_data_t            *size_data;
+    size_data_t            *size_data_opp1;
+    size_data_t            *size_data_opp2;
+    p4est_quadrant_t       *quad;
+    double                  s_avg;
+    int                     which_dir;
+    int                     which_face;
+    int                     which_face_opp;
+    int                     iOpp;
+
+    side[0] = p4est_iter_fside_array_index_int (sides, 0);
+    side[1] = p4est_iter_fside_array_index_int (sides, 1);
+
+    if(sides->elem_count==2){
+
+        for(int i = 0; i < 2; ++i){
+
+            iOpp = 1 - i;
+            which_dir = side[i]->face / 2; // Direction x (0), y (1) ou z(2)
+            which_face_opp = side[iOpp]->face;
+
+            if(side[i]->is_hanging){
+
+                size_data_opp1 = (size_data_t *) side[iOpp]->is.full.quad->p.user_data;
+
+                for(int j = 0; j < P4EST_HALF; ++j){
+
+                    size_data = (size_data_t *) side[i]->is.hanging.quad[j]->p.user_data;
+
+                    if(fabs(size_data->ds[which_dir]) > ALPHA-1){
+                        // std::cout<<"Coucou  "<<size_data->ds[which_dir]<<std::endl;
+                        // if(size_data->ds[which_dir] > 0){
+
+                            if(size_data->size > size_data_opp1->size){
+                                size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin);
+                            }else{
+                                size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                            }
+
+                            // switch(which_face_opp){
+                            //     case 0 : 
+                            //         if(size_data->size > size_data_opp1->size){
+                            //             size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin);
+                            //         }else{
+                            //             size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                            //         } break;
+
+                            //     case 1 :
+                            //         if(size_data->size > size_data_opp1->size){
+                            //             size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin);
+                            //         }else{
+                            //             size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                            //         } break;
+
+                            //     case 2 : 
+                            //         if(size_data->size > size_data_opp1->size){
+                            //             size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin);
+                            //         }else{
+                            //             size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                            //         } break;
+
+                            //     case 3 : 
+                            //         if(size_data->size > size_data_opp1->size){
+                            //             size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin);
+                            //         }else{
+                            //             size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                            //         } break;
+
+                            //     default : 
+                            //         std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                            //         exit(-1);
+                            // }
+                        // }
+                        // else{
+                        //     switch(which_face_opp){
+                        //         case 0 : size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin);
+                        //             if(size_data->size > size_data_opp1->size){
+                        //                 size_data->size = fmin(size_data->size, size_data_opp1->size - (ALPHA-1) * size_data_opp1->hMin);
+                        //             }else{
+                        //                 size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                        //             } break;
+                        //         case 1 : size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin); break;
+                        //         case 2 : size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin); break;
+                        //         case 3 : size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin); break;
+                        //         default : 
+                        //             std::cout<<"Valeur inattendue : "<<which_face_opp<<std::endl;
+                        //             exit(-1);
+                        //     }
+                        // }
+                    } // if
+
+                } // for j
+            }
+            else{
+
+                size_data = (size_data_t *) side[i]->is.full.quad->p.user_data;
+
+                if(fabs(size_data->ds[which_dir]) > ALPHA-1){
+                    if(side[iOpp]->is_hanging){
+                        // Full - Oppose hanging
+                        for(int j = 0; j < P4EST_HALF; ++j){
+                            size_data_opp1 = (size_data_t *) side[iOpp]->is.hanging.quad[j]->p.user_data;
+                            // size_data_opp2 = (size_data_t *) side[iOpp]->is.hanging.quad[1]->p.user_data;
+
+                            // if(size_data->size > fmin(size_data_opp1->size, size_data_opp2->size) ){
+                            if(size_data->size > size_data_opp1->size){
+                                size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin);
+                                // size_data->size = fmin(size_data->size, size_data_opp2->size + (ALPHA-1) * size_data_opp2->hMin);
+                            }
+                            else{
+                                size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                                // size_data_opp2->size = fmin(size_data_opp2->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                            }
+                        }
+                    }
+                    else{
+                        // Full - Oppose full
+                        size_data_opp1 = (size_data_t *) side[iOpp]->is.full.quad->p.user_data;
+
+                        if(size_data->size > size_data_opp1->size){
+                            size_data->size = fmin(size_data->size, size_data_opp1->size + (ALPHA-1) * size_data_opp1->hMin);
+                        }
+                        else{
+                            size_data_opp1->size = fmin(size_data_opp1->size, size_data->size + (ALPHA-1) * size_data->hMin);
+                        }
+
+                    }
+                    
+                } // if gradient trop grand
+
+            } // else
+
+        }
+    }
+    else{
+        // size_data = (size_data_t *) side[0]->is.full.quad->p.user_data;
+
+        // which_dir = side[0]->face / 2;
+
+        // if(fabs(size_data->ds[which_dir]) > ALPHA-1){
+        //     size_data->ds[which_dir] = fmin(size_data->ds[which_dir], ALPHA-1);
+        //     size_data->ds[which_dir] = nan("");
+
+        // }
+    }
+}
+
+HXTStatus hxtOctreeSetMaxGradient(HXTForest *forest){
+	p4est_iterate (forest->p4est, NULL, NULL, NULL, set_max_gradient_faces,
+            #ifdef P4_TO_P8
+                       NULL,
+            #endif
+                       NULL);
+	return HXT_STATUS_OK;
+}
+
+static void fill_size_vec(p4est_iter_volume_info_t * info, void *user_data){
+    sc_array_t         *size_vec = (sc_array_t *) user_data;      /* we passed the array of values to fill as the user_data in the call to p4est_iterate */
+    p4est_t            *p4est = info->p4est;
+    p4est_quadrant_t   *q = info->quad;
+    p4est_topidx_t      which_tree = info->treeid;
+    p4est_locidx_t      local_id = info->quadid;  /* this is the index of q *within its tree's numbering*.  We want to convert it its index for all the quadrants on this process, which we do below */
+    p4est_tree_t       *tree;
+    size_data_t        *data = (size_data_t *) q->p.user_data;
+    p4est_locidx_t      arrayoffset;
+    double              this_size;
+    double             *this_size_ptr;
+
+    tree = p4est_tree_array_index(p4est->trees, which_tree);
+    local_id += tree->quadrants_offset;   /* now the id is relative to the MPI process */
+    arrayoffset = local_id;      /* Chaque quadrant a une donne pour l'offset*/
+
+    // On copie la valeur de la taille sur la cellule dans size_vec, en tenant compte de l'offset
+    this_size = data->size;
+    this_size_ptr = (double *) sc_array_index(size_vec, arrayoffset);
+    this_size_ptr[0] = this_size;
+}
+
+static void fill_dsdx_vec(p4est_iter_volume_info_t * info, void *user_data){
+    sc_array_t         *dsdx_vec = (sc_array_t *) user_data;      /* we passed the array of values to fill as the user_data in the call to p4est_iterate */
+    p4est_t            *p4est = info->p4est;
+    p4est_quadrant_t   *q = info->quad;
+    p4est_topidx_t      which_tree = info->treeid;
+    p4est_locidx_t      local_id = info->quadid;  /* this is the index of q *within its tree's numbering*.  We want to convert it its index for all the quadrants on this process, which we do below */
+    p4est_tree_t       *tree;
+    size_data_t        *data = (size_data_t *) q->p.user_data;
+    p4est_locidx_t      arrayoffset;
+    double             *this_dsdx_ptr;
+
+    tree = p4est_tree_array_index(p4est->trees, which_tree);
+    local_id += tree->quadrants_offset;   /* now the id is relative to the MPI process */
+    arrayoffset = local_id;      /* Chaque quadrant deux valeurs pour la derivee (offset dans le vecteur)*/
+
+    this_dsdx_ptr = (double *) sc_array_index(dsdx_vec, arrayoffset);
+    this_dsdx_ptr[0] = data->ds[0];
+    // std::cout<<data->ds[0]<<"  -  "<<data->ds[1]<<std::endl;
+}
+
+static void fill_dsdy_vec(p4est_iter_volume_info_t * info, void *user_data){
+    sc_array_t         *dsdy_vec = (sc_array_t *) user_data;      /* we passed the array of values to fill as the user_data in the call to p4est_iterate */
+    p4est_t            *p4est = info->p4est;
+    p4est_quadrant_t   *q = info->quad;
+    p4est_topidx_t      which_tree = info->treeid;
+    p4est_locidx_t      local_id = info->quadid;  /* this is the index of q *within its tree's numbering*.  We want to convert it its index for all the quadrants on this process, which we do below */
+    p4est_tree_t       *tree;
+    size_data_t        *data = (size_data_t *) q->p.user_data;
+    p4est_locidx_t      arrayoffset;
+    double             *this_dsdy_ptr;
+
+    tree = p4est_tree_array_index(p4est->trees, which_tree);
+    local_id += tree->quadrants_offset;   /* now the id is relative to the MPI process */
+    arrayoffset = local_id;      /* Chaque quadrant deux valeurs pour la derivee (offset dans le vecteur)*/
+
+    this_dsdy_ptr = (double *) sc_array_index(dsdy_vec, arrayoffset);
+    this_dsdy_ptr[0] = data->ds[1];
+}
+
+#ifdef P4_TO_P8
+static void fill_dsdz_vec(p4est_iter_volume_info_t * info, void *user_data){
+    sc_array_t         *dsdz_vec = (sc_array_t *) user_data;      /* we passed the array of values to fill as the user_data in the call to p4est_iterate */
+    p4est_t            *p4est = info->p4est;
+    p4est_quadrant_t   *q = info->quad;
+    p4est_topidx_t      which_tree = info->treeid;
+    p4est_locidx_t      local_id = info->quadid;  /* this is the index of q *within its tree's numbering*.  We want to convert it its index for all the quadrants on this process, which we do below */
+    p4est_tree_t       *tree;
+    size_data_t        *data = (size_data_t *) q->p.user_data;
+    p4est_locidx_t      arrayoffset;
+    double             *this_dsdz_ptr;
+
+    tree = p4est_tree_array_index(p4est->trees, which_tree);
+    local_id += tree->quadrants_offset;   /* now the id is relative to the MPI process */
+    arrayoffset = local_id;      /* Chaque quadrant deux valeurs pour la derivee (offset dans le vecteur)*/
+
+    this_dsdz_ptr = (double *) sc_array_index(dsdz_vec, arrayoffset);
+    this_dsdz_ptr[0] = data->ds[2];
+}
+#endif
+
+static void fill_d2s_vec(p4est_iter_volume_info_t * info, void *user_data){
+    sc_array_t         *d2s_vec = (sc_array_t *) user_data;      /* we passed the array of values to fill as the user_data in the call to p4est_iterate */
+    p4est_t            *p4est = info->p4est;
+    p4est_quadrant_t   *q = info->quad;
+    p4est_topidx_t      which_tree = info->treeid;
+    p4est_locidx_t      local_id = info->quadid;  /* this is the index of q *within its tree's numbering*.  We want to convert it its index for all the quadrants on this process, which we do below */
+    p4est_tree_t       *tree;
+    size_data_t        *data = (size_data_t *) q->p.user_data;
+    p4est_locidx_t      arrayoffset;
+    double             *this_d2s_ptr;
+
+    tree = p4est_tree_array_index(p4est->trees, which_tree);
+    local_id += tree->quadrants_offset;   /* now the id is relative to the MPI process */
+    arrayoffset = local_id;      /* Chaque quadrant deux valeurs pour la derivee (offset dans le vecteur)*/
+
+    this_d2s_ptr = (double *) sc_array_index(d2s_vec, arrayoffset);
+    this_d2s_ptr[0] = data->d2s;
+    // std::cout<<data->d2s<<std::endl;
+}
+
+static void fill_h_vec(p4est_iter_volume_info_t * info, void *user_data){
+    sc_array_t         *h_vec = (sc_array_t *) user_data;      /* we passed the array of values to fill as the user_data in the call to p4est_iterate */
+    p4est_t            *p4est = info->p4est;
+    p4est_quadrant_t   *q = info->quad;
+    p4est_topidx_t      which_tree = info->treeid;
+    p4est_locidx_t      local_id = info->quadid;  /* this is the index of q *within its tree's numbering*.  We want to convert it its index for all the quadrants on this process, which we do below */
+    p4est_tree_t       *tree;
+    size_data_t        *data = (size_data_t *) q->p.user_data;
+    p4est_locidx_t      arrayoffset;
+    double             *this_h_ptr;
+
+    tree = p4est_tree_array_index(p4est->trees, which_tree);
+    local_id += tree->quadrants_offset;   /* now the id is relative to the MPI process */
+    arrayoffset = local_id;      /* Chaque quadrant deux valeurs pour la derivee (offset dans le vecteur)*/
+
+    this_h_ptr = (double *) sc_array_index(h_vec, arrayoffset);
+    this_h_ptr[0] = data->hMin;
+    // std::cout<<data->d2s<<std::endl;
+}
+
+static void write_4est_to_vtk(p4est_t *p4est, const char *filename){
+    p4est_vtk_write_file(p4est, NULL, filename);
+}
+
+static void write_size_to_vtk(p4est_t *p4est, const char *filename){
+
+    p4est_locidx_t numquads = p4est->local_num_quadrants;
+
+    /* Chaque quadrant a une place a allouer dans size_vec (info par cellule) */
+    sc_array_t *size_vec = sc_array_new_size (sizeof (double), numquads);
+
+    p4est_iterate (p4est, NULL,   /* we don't need any ghost quadrants for this loop */
+                 (void *) size_vec,     /* user_data : pass in size_vec so that we can fill it */
+                 fill_size_vec,    /* callback function that interpolates from the cell center to the cell corners, defined above */
+                 NULL,          /* there is no callback for the faces between quadrants */
+        #ifdef P4_TO_P8
+                 NULL,          /* there is no callback for the edges between quadrants */
+        #endif
+                 NULL);         /* there is no callback for the corners between quadrants */
+
+    /* create VTK output context and set its parameters */
+    p4est_vtk_context_t *context = p4est_vtk_context_new(p4est, filename);
+    p4est_vtk_context_set_scale (context, 1.0);  /* quadrant at almost full scale */
+
+    /* begin writing the output files */
+    context = p4est_vtk_write_header (context);
+    SC_CHECK_ABORT (context != NULL, P4EST_STRING "_vtk: Error writing vtk header");
+
+    /* do not write the tree id's of each quadrant
+     * (there is only one tree in this example) */
+    context = p4est_vtk_write_cell_dataf(context, 0, 1,  /* do write the refinement level of each quadrant */
+                                        1,      /* do write the mpi process id of each quadrant */
+                                        0,      /* do not wrap the mpi rank (if this were > 0, the modulus of the rank relative to this number would be written instead of the rank) */
+                                        1,      /* there is no custom cell scalar data. */
+                                        0,      /* there is no custom cell vector data. */
+                                        "Size",
+                                        size_vec,
+                                        context);       /* mark the end of the variable cell data. */
+    SC_CHECK_ABORT (context != NULL, P4EST_STRING "_vtk: Error writing cell data");
+
+    const int retval = p4est_vtk_write_footer (context);
+    SC_CHECK_ABORT (!retval, P4EST_STRING "_vtk: Error writing footer");
+
+    sc_array_destroy (size_vec);
+}
+
+void write_ds_to_vtk(p4est_t *p4est, const char *filename){
+
+    p4est_locidx_t numquads = p4est->local_num_quadrants;
+
+    /* Chaque quadrant a une place a allouer dans size_vec (info par cellule) */
+    sc_array_t *s_vec = sc_array_new_size (sizeof (double), numquads);
+    sc_array_t *dsdx_vec = sc_array_new_size (sizeof (double), numquads);
+    sc_array_t *dsdy_vec = sc_array_new_size (sizeof (double), numquads);
+#ifdef P4_TO_P8
+    sc_array_t *dsdz_vec = sc_array_new_size (sizeof (double), numquads);
+#endif
+    sc_array_t *d2s_vec = sc_array_new_size (sizeof (double), numquads);
+    sc_array_t *h_vec = sc_array_new_size (sizeof (double), numquads);
+
+    p4est_iterate (p4est, NULL,   /* we don't need any ghost quadrants for this loop */
+                 (void *) s_vec,     /* user_data : pass in size_vec so that we can fill it */
+                 fill_size_vec,    /* callback function that interpolates from the cell center to the cell corners, defined above */
+                 NULL,          /* there is no callback for the faces between quadrants */
+        #ifdef P4_TO_P8
+                 NULL,          /* there is no callback for the edges between quadrants */
+        #endif
+                 NULL);         /* there is no callback for the corners between quadrants */
+
+    p4est_iterate (p4est, NULL,   /* we don't need any ghost quadrants for this loop */
+                 (void *) dsdx_vec,     /* user_data : pass in size_vec so that we can fill it */
+                 fill_dsdx_vec,    /* callback function that interpolates from the cell center to the cell corners, defined above */
+                 NULL,          /* there is no callback for the faces between quadrants */
+        #ifdef P4_TO_P8
+                 NULL,          /* there is no callback for the edges between quadrants */
+        #endif
+                 NULL);         /* there is no callback for the corners between quadrants */
+
+    p4est_iterate (p4est, NULL,   /* we don't need any ghost quadrants for this loop */
+                 (void *) dsdy_vec,     /* user_data : pass in size_vec so that we can fill it */
+                 fill_dsdy_vec,    /* callback function that interpolates from the cell center to the cell corners, defined above */
+                 NULL,          /* there is no callback for the faces between quadrants */
+        #ifdef P4_TO_P8
+                 NULL,          /* there is no callback for the edges between quadrants */
+        #endif
+                 NULL);         /* there is no callback for the corners between quadrants */
+
+#ifdef P4_TO_P8
+    p4est_iterate (p4est, NULL,   /* we don't need any ghost quadrants for this loop */
+                 (void *) dsdz_vec,     /* user_data : pass in size_vec so that we can fill it */
+                 fill_dsdz_vec,    /* callback function that interpolates from the cell center to the cell corners, defined above */
+                 NULL,          /* there is no callback for the faces between quadrants */
+                 NULL,          /* there is no callback for the edges between quadrants */
+                 NULL);         /* there is no callback for the corners between quadrants */
+#endif
+
+    p4est_iterate (p4est, NULL,   /* we don't need any ghost quadrants for this loop */
+                 (void *) d2s_vec,     /* user_data : pass in size_vec so that we can fill it */
+                 fill_d2s_vec,    /* callback function that interpolates from the cell center to the cell corners, defined above */
+                 NULL,          /* there is no callback for the faces between quadrants */
+        #ifdef P4_TO_P8
+                 NULL,          /* there is no callback for the edges between quadrants */
+        #endif
+                 NULL);         /* there is no callback for the corners between quadrants */
+
+    p4est_iterate (p4est, NULL,   /* we don't need any ghost quadrants for this loop */
+                 (void *) h_vec,     /* user_data : pass in size_vec so that we can fill it */
+                 fill_h_vec,    /* callback function that interpolates from the cell center to the cell corners, defined above */
+                 NULL,          /* there is no callback for the faces between quadrants */
+        #ifdef P4_TO_P8
+                 NULL,          /* there is no callback for the edges between quadrants */
+        #endif
+                 NULL);         /* there is no callback for the corners between quadrants */
+
+    /* create VTK output context and set its parameters */
+    p4est_vtk_context_t *context = p4est_vtk_context_new(p4est, filename);
+    p4est_vtk_context_set_scale (context, 1.0);  /* quadrant at almost full scale */
+
+    /* begin writing the output files */
+    context = p4est_vtk_write_header (context);
+    SC_CHECK_ABORT (context != NULL, P4EST_STRING "_vtk: Error writing vtk header");
+
+#ifdef P4_TO_P8
+    int nScalarFields = 6;
+#else
+    int nScalarFields = 5;
+#endif
+
+    /* do not write the tree id's of each quadrant
+     * (there is only one tree in this example) */
+    context = p4est_vtk_write_cell_dataf(context, 0, 1,  /* do write the refinement level of each quadrant */
+                                        1,      /* do write the mpi process id of each quadrant */
+                                        0,      /* do not wrap the mpi rank (if this were > 0, the modulus of the rank relative to this number would be written instead of the rank) */
+                                        nScalarFields,      /* there is no custom cell scalar data. */
+                                        0,
+                                        "Size",
+                                        s_vec,
+                                        "dsdx",
+                                        dsdx_vec,
+                                        "dsdy",
+                                        dsdy_vec,
+                                    #ifdef P4_TO_P8
+                                        "dsdz",
+                                        dsdz_vec,
+                                    #endif
+                                        "d2s",
+                                        d2s_vec,
+                                        "hMin",
+                                        h_vec,
+                                        context);       /* mark the end of the variable cell data. */
+    SC_CHECK_ABORT (context != NULL, P4EST_STRING "_vtk: Error writing cell data");
+
+    const int retval = p4est_vtk_write_footer (context);
+    SC_CHECK_ABORT (!retval, P4EST_STRING "_vtk: Error writing footer");
+
+    sc_array_destroy(s_vec);
+    sc_array_destroy(dsdx_vec);
+    sc_array_destroy(dsdy_vec);
+#ifdef P4_TO_P8
+    sc_array_destroy(dsdz_vec);
+#endif
+    sc_array_destroy(d2s_vec);
+    sc_array_destroy(h_vec);
+}
+
+int finalizeP4est(p4est_t *p4est, p4est_connectivity_t *connect)
+{
+    int mpiret;
+    /* Destroy the p4est and the connectivity structure. */
+    p4est_destroy(p4est);
+    p4est_connectivity_destroy(connect);
+
+    /* Verify that allocations internal to p4est and sc do not leak memory.
+     * This should be called if sc_init () has been called earlier. */
+    sc_finalize();
+
+    /* This is standard MPI programs.  Without --enable-mpi, this is a dummy. */
+    mpiret = sc_MPI_Finalize();
+    SC_CHECK_MPI(mpiret);
+    return mpiret;
+}
+
+
+double myFun(double x, double y, double z, void *user_data){
+    return  *(double*) user_data;
+}
+
+int search_quadrant_fn(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t * q, p4est_locidx_t local_num, void *point){
+
+    // double *point_to_find = (double *) point;
+    std::cout<<"search_quadrant_fn"<<std::endl;
+
+    return 1;
+
+}
+
+static int hxtOctreeSearchCallback(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t * q, p4est_locidx_t local_num, void *point){
+
+    bool in_box;
+    int is_match;
+    int is_leaf = local_num >= 0;
+    
+    size_data_t  *data = (size_data_t *) q->p.user_data;
+    size_point_t *p    = (size_point_t *) point;
+
+    // We have to recompute the cell dimension h for the root (non leaves) octants 
+    // because it seems to be undefined. Otherwise it's contained in q->p.user_data.
+    double h;
+    if(!is_leaf) hxtOctreeGetOctantSize(p4est, which_tree, q, &h);
+    else h = data->h;
+    
+
+    double center[3];
+    hxtOctreeGetCenter(p4est, which_tree, q, center);
+
+    double epsilon = 1e-12;
+    in_box  = (p->x < center[0] + h/2 + epsilon) && (p->x > center[0] - h/2 - epsilon);
+    in_box &= (p->y < center[1] + h/2 + epsilon) && (p->y > center[1] - h/2 - epsilon);
+#ifdef P4_TO_P8
+    in_box &= (p->z < center[2] + h/2 + epsilon) && (p->z > center[2] - h/2 - epsilon);
+#endif
+
+    if(in_box && is_leaf){
+        p->size = data->size;
+    }
+
+    return in_box;
+}
+
+/* Search for a single point in the tree structure and returns its size.
+   See hxtOctreeSearch for the detailed comments. */
+HXTStatus hxtOctreeSearchOne(HXTForest *forest, double x, double y, double z, double *size){
+  
+  sc_array_t *points = sc_array_new_size(sizeof(size_point_t), 1);
+
+  size_point_t *p = (size_point_t *) sc_array_index(points, 0);
+  p->x = x;
+  p->y = y;
+  p->z = z;
+  p->size = -1.0;
+
+  p4est_search(forest->p4est, NULL, hxtOctreeSearchCallback, points);
+
+  *size = p->size;
+
+  sc_array_destroy(points);
+
+  return HXT_STATUS_OK;
+}
+
+static int hxtOctreeReplaceCallback(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t * q, p4est_locidx_t local_num, void *point){
+
+    bool in_box;
+    int is_match;
+    int is_leaf = local_num >= 0;
+    
+    size_data_t  *data = (size_data_t *) q->p.user_data;
+    size_point_t *p    = (size_point_t *) point;
+
+    // We have to recompute the cell dimension h for the root (non leaves) octants 
+    // because it seems to be undefined. Otherwise it's contained in q->p.user_data.
+    double h;
+    if(!is_leaf) hxtOctreeGetOctantSize(p4est, which_tree, q, &h);
+    else h = data->h;
+    
+
+    double center[3];
+    hxtOctreeGetCenter(p4est, which_tree, q, center);
+
+    double epsilon = 1e-12;
+    in_box  = (p->x < center[0] + h/2 + epsilon) && (p->x > center[0] - h/2 - epsilon);
+    in_box &= (p->y < center[1] + h/2 + epsilon) && (p->y > center[1] - h/2 - epsilon);
+#ifdef P4_TO_P8
+    in_box &= (p->z < center[2] + h/2 + epsilon) && (p->z > center[2] - h/2 - epsilon);
+#endif
+
+    if(in_box && is_leaf){
+        data->size = p->size;
+    }
+
+    return in_box;
+}
+
+HXTStatus hxtOctreeSearch(HXTForest *forest, std::vector<double> *x, std::vector<double> *y, std::vector<double> *z, std::vector<double> *size){
+  
+  // Array of size_point_t to search in the tree
+  sc_array_t *points = sc_array_new_size(sizeof(size_point_t), (*x).size());
+  size_point_t *p;
+
+  for(int i = 0; i < (*x).size(); ++i){
+    p = (size_point_t *) sc_array_index(points, i);
+    p->x = (*x)[i];
+    p->y = (*y)[i];
+    p->z = (*z)[i];
+    p->size = -1.0;
+  }
+  
+  // Search on all cells
+  p4est_search(forest->p4est, NULL, hxtOctreeSearchCallback, points);
+
+  // Get the sizes
+  for(int i = 0; i < (*x).size(); ++i){ 
+    p = (size_point_t *) sc_array_index(points, i);
+    (*size)[i] = p->size;
+  }
+
+  // Clean up
+  sc_array_destroy(points);
+
+  return HXT_STATUS_OK;
+}
+
+static bool rtreeCallback(int id, void *ctx) {
+  std::vector<int>* vec = reinterpret_cast< std::vector<int>* >(ctx);
+  vec->push_back(id);
+  return true;
+}
+
+static void hxtOctreeRTreeCallback(p4est_iter_volume_info_t * info, void *user_data){
+
+  p4est_t            *p4est = info->p4est;
+  p4est_quadrant_t   *q = info->quad;
+  p4est_topidx_t      which_tree = info->treeid;
+  size_data_t        *data = (size_data_t *) q->p.user_data;
+  HXTForestOptions   *forestOptions = (HXTForestOptions *) user_data;
+
+  // double h;
+  // hxtOctreeGetOctantSize(p4est, which_tree, q, &h);
+
+  double min[3], max[3];
+  hxtOctreeGetBboxOctant(p4est, which_tree, q, min, max);
+
+  std::vector<int> candidates;  
+  forestOptions->triRTree->Search(min, max, rtreeCallback, &candidates);
+
+  if(!candidates.empty()){
+    double kappa = 0.0;
+    for(auto &val : candidates){
+      // std::cout<<val<<std::endl;
+      for(int i = 0; i < 3; ++i){
+          int node = forestOptions->mesh->triangles.node[(size_t) 3*val+i];
+
+          double *v1 = forestOptions->nodalCurvature + 6*node;
+          double *v2 = forestOptions->nodalCurvature + 6*node + 3;
+
+          double k1, k2;
+          hxtNorm2V3(v1, &k1);
+          hxtNorm2V3(v2, &k2);
+
+          kappa = fmax(kappa,fmax(k1,k2));
+        }
+    }
+
+    // std::cout<<kappa<<std::endl;
+    double size = 2*M_PI/(forestOptions->nodePerTwoPi * kappa);
+    // std::cout<<size<<std::endl;
+    // std::cout<<data->size<<std::endl;
+    // std::cout<<size<<std::endl;
+    if(data->size > size){
+      data->size = size;
+      data->refineFlag = 1;
+    }
+  }
+}
+
+HXTStatus hxtOctreeLaplacianRefine(HXTForest *forest, int nRefine){
+
+  p4est_gloidx_t numQuadrants = forest->p4est->global_num_quadrants;
+
+  uint32_t i = 0;
+  do{
+    // Compute d2s on each cell
+    HXT_CHECK(hxtOctreeComputeLaplacian(forest));
+    // Refine the octree once with respect to the value of d2s on each quadrant/octant
+    p4est_refine(forest->p4est, 0, hxtRefineLaplacianCallback, hxtOctreeSetInitialSize);
+    // HXT_CHECK(hxtOctreeRefineLaplacian(forest));
+    // Balance the octree to get 2:1 ratio between adjacent cells
+    HXT_CHECK(hxtOctreeBalance(forest));
+
+    ++i;
+    std::cout<<"Number of quadrants : "<<forest->p4est->global_num_quadrants<<std::endl;
+
+    // If the number of quadrants is the same after refinement, we stop
+    if(forest->p4est->global_num_quadrants == numQuadrants){
+        numQuadrants = forest->p4est->global_num_quadrants;
+        std::cout<<"Laplace refinement converged"<<std::endl;
+        break;
+    }
+    else{
+        numQuadrants = forest->p4est->global_num_quadrants;
+    }        
+  }while(i < nRefine);
+
+  if(i == nRefine){ std::cout<<"Laplace refinement stopped after "<<i<<" iterations"<<std::endl; }
+  
+  p4est_iterate(forest->p4est, NULL, forest->forestOptions, hxtOctreeRTreeCallback, NULL,
+      #ifdef P4_TO_P8
+                  NULL,
+      #endif
+                  NULL);
+
+  return HXT_STATUS_OK;
+}
+
+static int hxtCurvatureRefineCallback(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *q){
+  // std::cout<<((size_data_t *) q->p.user_data)->refineFlag<<std::endl;
+  return ((size_data_t *) q->p.user_data)->refineFlag;
+}
+
+
+// static void hxtOctreeResetRefineFlag(p4est_iter_volume_info_t * info, void *user_data){
+//   size_data_t *data = (size_data_t *) info->quad->p.user_data;
+//   data->refineFlag = 0;
+// }
+
+HXTStatus hxtOctreeCurvatureRefine(HXTForest *forest, int nMax){
+
+  p4est_gloidx_t numQuadrants;
+
+  int i = 0;
+  do{
+    numQuadrants = forest->p4est->global_num_quadrants;
+
+    // Check if size is smaller than the size prescribed by curvature
+    p4est_iterate(forest->p4est, NULL, forest->forestOptions, hxtOctreeRTreeCallback, NULL,
+      #ifdef P4_TO_P8
+                  NULL,
+      #endif
+                  NULL);
+
+    // Refine with respect to the curvature
+    p4est_refine(forest->p4est, 0, hxtCurvatureRefineCallback, hxtOctreeSetInitialSize);
+
+    // Balance the octree to get 2:1 ratio between adjacent cells
+    p4est_balance(forest->p4est, P4EST_CONNECT_FACE, hxtOctreeSetInitialSize);
+
+    // Recompute size on newly created cells ?
+    p4est_iterate(forest->p4est, NULL, forest->forestOptions, hxtOctreeRTreeCallback, NULL,
+      #ifdef P4_TO_P8
+                  NULL,
+      #endif
+                  NULL);
+
+    // Print octree in VTK
+    //    std::string fileVTK = "/Users/arthur/Documents/Code/Mesh_octree/results_octree/dummy_3D_rtree_curvature_refine" + std::to_string(i);
+    //    write_ds_to_vtk(forest->p4est, fileVTK.c_str()); 
+
+    ++i;
+
+    std::cout<<"Number of quadrants : "<<forest->p4est->global_num_quadrants<<std::endl;
+    
+  }while(i < nMax && numQuadrants < forest->p4est->global_num_quadrants);
+
+  std::cout<<"Number of quadrants : "<<forest->p4est->global_num_quadrants<<std::endl;
+  if(i == nMax){ std::cout<<"Curvature refinement stopped after "<<i<<" iterations"<<std::endl; }
+
+  return HXT_STATUS_OK;
+}
+
+static double det3x3(const double mat[3][3])
+{
+  return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) -
+      mat[0][1] * (mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) +
+      mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]));
+}
+
+static HXTStatus inv3x3(const double mat[3][3], double inv[3][3], double *det)
+{
+  *det = det3x3(mat);
+  if(det) {
+    double ud = 1. / *det;
+    inv[0][0] = (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) * ud;
+    inv[1][0] = -(mat[1][0] * mat[2][2] - mat[1][2] * mat[2][0]) * ud;
+    inv[2][0] = (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0]) * ud;
+    inv[0][1] = -(mat[0][1] * mat[2][2] - mat[0][2] * mat[2][1]) * ud;
+    inv[1][1] = (mat[0][0] * mat[2][2] - mat[0][2] * mat[2][0]) * ud;
+    inv[2][1] = -(mat[0][0] * mat[2][1] - mat[0][1] * mat[2][0]) * ud;
+    inv[0][2] = (mat[0][1] * mat[1][2] - mat[0][2] * mat[1][1]) * ud;
+    inv[1][2] = -(mat[0][0] * mat[1][2] - mat[0][2] * mat[1][0]) * ud;
+    inv[2][2] = (mat[0][0] * mat[1][1] - mat[0][1] * mat[1][0]) * ud;
+  } else {
+    return HXT_STATUS_ERROR;
+  }
+  return HXT_STATUS_OK;
+}
+
+/*
+ distance to triangle
+
+ P(p) = p1 + t1 xi + t2 eta
+
+ t1 = (p2-p1) ; t2 = (p3-p1) ;
+
+ (P(p) - p) = d n
+
+ (p1 + t1 xi + t2 eta - p) = d n
+ t1 xi + t2 eta - d n = p - p1
+
+ | t1x t2x -nx | |xi  |   |px-p1x|
+ | t1y t2y -ny | |eta | = |py-p1y|
+ | t1z t2z -nz | |d   |   |pz-p1z|
+
+ distance to segment
+
+ P(p) = p1 + t (p2-p1)
+
+ (p - P(p)) * (p2-p1) = 0
+ (p - p1 - t (p2-p1) ) * (p2-p1) = 0
+ - t ||p2-p1||^2 + (p-p1)(p2-p1) = 0
+
+ t = (p-p1)*(p2-p1)/||p2-p1||^2
+*/
+void signedDistancePointTriangle2(const SPoint3 &p1, const SPoint3 &p2,
+                                const SPoint3 &p3, const SPoint3 &p, double &d,
+                                SPoint3 &closePt)
+{
+ SVector3 t1 = p2 - p1;
+ SVector3 t2 = p3 - p1;
+ SVector3 t3 = p3 - p2;
+ SVector3 n = crossprod(t1, t2);
+ n.normalize();
+ const double n2t1 = dot(t1, t1);
+ const double n2t2 = dot(t2, t2);
+ const double n2t3 = dot(t3, t3);
+ double mat[3][3] = {{t1.x(), t2.x(), -n.x()},
+                     {t1.y(), t2.y(), -n.y()},
+                     {t1.z(), t2.z(), -n.z()}};
+ double inv[3][3];
+ double det;
+ inv3x3(mat, inv, &det);
+ if(det == 0.0) return;
+
+ double u, v;
+ SVector3 pp1 = p - p1;
+ u = (inv[0][0] * pp1.x() + inv[0][1] * pp1.y() + inv[0][2] * pp1.z());
+ v = (inv[1][0] * pp1.x() + inv[1][1] * pp1.y() + inv[1][2] * pp1.z());
+ d = (inv[2][0] * pp1.x() + inv[2][1] * pp1.y() + inv[2][2] * pp1.z());
+ double sign = (d > 0) ? 1. : -1.;
+ if(d == 0.) sign = 1.;
+ if(u >= 0. && v >= 0. && 1. - u - v >= 0.0) { // P(p) inside triangle
+   closePt = p1 + (p2 - p1) * u + (p3 - p1) * v;
+ }
+ else {
+   const double t12 = dot(pp1, t1) / n2t1;
+   const double t13 = dot(pp1, t2) / n2t2;
+   SVector3 pp2 = p - p2;
+   const double t23 = dot(pp2, t3) / n2t3;
+   d = 1.e10;
+   if(t12 >= 0 && t12 <= 1.) {
+     d = sign * std::min(fabs(d), p.distance(p1 + (p2 - p1) * t12));
+     closePt = p1 + (p2 - p1) * t12;
+   }
+   if(t13 >= 0 && t13 <= 1.) {
+     if(p.distance(p1 + (p3 - p1) * t13) < fabs(d))
+       closePt = p1 + (p3 - p1) * t13;
+     d = sign * std::min(fabs(d), p.distance(p1 + (p3 - p1) * t13));
+   }
+   if(t23 >= 0 && t23 <= 1.) {
+     if(p.distance(p2 + (p3 - p2) * t23) < fabs(d))
+       closePt = p2 + (p3 - p2) * t23;
+     d = sign * std::min(fabs(d), p.distance(p2 + (p3 - p2) * t23));
+   }
+   if(p.distance(p1) < fabs(d)) {
+     closePt = p1;
+     d = sign * std::min(fabs(d), p.distance(p1));
+   }
+   if(p.distance(p2) < fabs(d)) {
+     closePt = p2;
+     d = sign * std::min(fabs(d), p.distance(p2));
+   }
+   if(p.distance(p3) < fabs(d)) {
+     closePt = p3;
+     d = sign * std::min(fabs(d), p.distance(p3));
+   }
+ }
+}
+
+HXTStatus hxtDistanceToTriangles(HXTForest *forest, std::vector<int> *candidates, const SPoint3 &p, double &d){
+
+  SPoint3 p1 = SPoint3();
+  SPoint3 p2 = SPoint3();
+  SPoint3 p3 = SPoint3();
+  SPoint3 closePt = SPoint3();
+
+  d = DBL_MAX;
+
+  double x,y,z;
+
+  for(std::vector<int>::iterator tri = candidates->begin(); tri != candidates->end(); ++tri){
+    // Coordonnees des points du triangle
+    int node1 = forest->forestOptions->mesh->triangles.node[(size_t) 3*(*tri)  ];
+    int node2 = forest->forestOptions->mesh->triangles.node[(size_t) 3*(*tri)+1];
+    int node3 = forest->forestOptions->mesh->triangles.node[(size_t) 3*(*tri)+2];
+      
+    x = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node1  ];
+    y = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node1+1];
+    z = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node1+2];
+    p1.setPosition(x,y,z);
+    x = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node2  ];
+    y = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node2+1];
+    z = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node2+2];
+    p2.setPosition(x,y,z);
+    x = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node3  ];
+    y = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node3+1];
+    z = forest->forestOptions->mesh->vertices.coord[(size_t) 4*node3+2];
+    p3.setPosition(x,y,z);
+
+    // double x1,y1,z1;
+    // p1.getPosition(&x1, &y1, &z1);
+    // printf("%f - %f - %f \n", x1, y1, z1);
+    // p2.getPosition(&x1, &y1, &z1);
+    // printf("%f - %f - %f \n", x1, y1, z1);
+    // p3.getPosition(&x1, &y1, &z1);
+    // printf("%f - %f - %f \n", x1, y1, z1);
+    // p.getPosition(&x1, &y1, &z1);
+    // printf("%f - %f - %f \n", x1, y1, z1);
+ 
+    double d_tmp;
+    signedDistancePointTriangle2(p1, p2, p3, p, d_tmp, closePt);
+    d = fmin(d, fabs(d_tmp));
+    printf("d = %f \n", d);
+
+  }
+
+  return HXT_STATUS_OK;
+
+}
+
+// Algorithme breadth first search pour eliminer les triangles de candidates 
+// qui sont proches de node par rapport a la topologie de la triangulation (!= distance euclidienne)
+// In : - candidates, le vecteur des triangles qui intersectent la boite de cote h autour de node
+//      - node, le noeud courant dans SurfacesProches
+void hxtBFSTriangles(HXTForest *forest, std::vector<int> *candidates, int node){
+
+  // Contient des noeuds (il faut partir de node)
+  std::queue<int> q; 
+  // Partir de node (ajouter dans la file)
+  q.push(node);
+  while(!q.empty()){
+    // std::cout<<q.front()<<std::endl;
+    // Prendre tous les triangles de candidates qui contiennent node, puis les retirer de candidates. 
+    // Prendre tous les noeuds de ces triangles et les ajouter dans la file
+    for(std::vector<int>::iterator tri = candidates->begin(); tri != candidates->end(); ){
+      bool flag = false;
+      for(int i = 0; i < 3; ++i){
+        int local_node = forest->forestOptions->mesh->triangles.node[(size_t) 3*(*tri)+i];
+        if(local_node == q.front()) flag = true;
+      }
+      // Si q.front() est dans le triangle courant, on ajoute les deux autres sommets et on le retire de la liste
+      if(flag){
+        for(int i = 0; i < 3; ++i){
+          int local_node = forest->forestOptions->mesh->triangles.node[(size_t) 3*(*tri)+i];
+          if(local_node != q.front()) q.push(local_node);
+        }
+        tri = candidates->erase(tri);
+      }
+      else{
+        ++tri;
+      }
+    }
+    q.pop();
+  }
+
+  //  std::cout<<"Elements restants"<<std::endl;
+  //  for(auto &val : *candidates)
+  //    std::cout<<val<<std::endl;
+}
+
+HXTStatus hxtOctreeSurfacesProches(HXTForest *forest){
+
+  // Pour chaque noeud : recuperer sa taille dans l'octree et prendre les triangles dans la boule de rayon h
+  // for(int i = 0; i < forest->forestOptions->mesh->vertices.num; ++i){
+  SPoint3 p = SPoint3();
+  sc_array_t *points = sc_array_new_size(sizeof(size_point_t), forest->forestOptions->mesh->vertices.num);
+  size_point_t *p_tmp;
+
+  for(int i = 0; i < forest->forestOptions->mesh->vertices.num; ++i){
+    p_tmp = (size_point_t *) sc_array_index(points, i);
+
+    // La taille du noeud courant
+    double size; 
+    // Coordonnees
+    double x = forest->forestOptions->mesh->vertices.coord[(size_t) 4*i  ];
+    double y = forest->forestOptions->mesh->vertices.coord[(size_t) 4*i+1];
+    double z = forest->forestOptions->mesh->vertices.coord[(size_t) 4*i+2];
+    HXT_CHECK(hxtOctreeSearchOne(forest, x, y, z, &size));
+    // printf("%f - %f - %f \n", x , y, z);
+
+    p_tmp->x = x;
+    p_tmp->y = y;
+    p_tmp->z = z;
+
+    //    printf("Point %d - taille initiale = %f \n", i+1, size);
+
+    // Boite autour du point de taille h  -> PAS UNE BOULE ?
+    double min[3], max[3];
+    min[0] = x - size; max[0] = x + size;
+    min[1] = y - size; max[1] = y + size;
+    min[2] = z - size; max[2] = z + size;
+    std::vector<int> candidates;  
+    forest->forestOptions->triRTree->Search(min, max, rtreeCallback, &candidates);
+
+    // printf("=========  Test\n");
+    // for(std::vector<int>::iterator tri = candidates.begin(); tri != candidates.end(); ++tri)
+    //   std::cout<<*tri<<std::endl;
+    
+    // std::sort(candidates.begin(),candidates.end());
+    // std::unique(candidates.begin(),candidates.end());
+    // printf("=========  Unique\n");
+    // for(std::vector<int>::iterator tri = candidates.begin(); tri != candidates.end(); ++tri)
+    //   std::cout<<(*tri)+1<<std::endl;
+    // printf("=========  BFS\n");
+
+    hxtBFSTriangles(forest, &candidates, i);
+
+    if(candidates.size()){
+      p.setPosition(x,y,z);
+      hxtDistanceToTriangles(forest, &candidates, p, size);
+      size /= forest->forestOptions->nodePerGap;
+      printf("Taille corrigée au noeud %d = %f \n", i+1, size);
+    }
+
+    p_tmp->size = size;
+  }
+
+  // On cherche dans l'octree et on remplace dans les quadrants associes aux noeuds
+  p4est_search(forest->p4est, NULL, hxtOctreeReplaceCallback, points);
+
+  // Clean up
+  sc_array_destroy(points);
+
+  return HXT_STATUS_OK;
+
+}
+
+void elementEstimateCallback(p4est_iter_volume_info_t * info, void *user_data)
+{
+  p4est_quadrant_t   *q = info->quad;
+  size_data_t        *data = (size_data_t *) q->p.user_data;
+
+// #ifndef P4_TO_P8
+  // *((double *) user_data) += (data->h * data->h)           / pow(data->size, 2);
+// #else
+  *((double *) user_data) += (data->h * data->h * data->h) / pow(data->size, 3);
+  // printf("size = %f et total = %f\n",data->size, *((double *) user_data));
+// #endif
+
+}
+
+HXTStatus hxtOctreeElementEstimation(HXTForest *forest, double *elemEstimate){
+
+  p4est_iterate (forest->p4est, NULL, (void *) elemEstimate, elementEstimateCallback, NULL,
+            #ifdef P4_TO_P8
+                       NULL,
+            #endif
+                       NULL);
+
+  return HXT_STATUS_OK;
+}
+
+// Deprecated
+HXTStatus hxtForestWriteBBoxMesh(HXTBbox *bbox, const char* filename){
+  FILE* file = fopen(filename,"w");
+  if(file==NULL)
+    return HXT_ERROR_MSG(HXT_STATUS_FILE_CANNOT_BE_OPENED,
+      "Cannot open mesh file \"%s\"",(filename==NULL)?"(null)":filename);
+
+  /* Writing a simple ABAQUS (.inp) file with a single element*/
+  fprintf(file,"*Heading\n %s\n",filename);
+
+  for(int i = 0; i < 3; ++i){
+    bbox->min[i] *= 1.3;
+    bbox->max[i] *= 1.3;
+  }
+  
+  /* print the nodes */
+  fprintf(file,"*NODE\n");
+  fprintf(file,"%u, %f, %f, %f\n",1, bbox->min[0], bbox->min[1], bbox->min[2]);
+  fprintf(file,"%u, %f, %f, %f\n",2, bbox->max[0], bbox->min[1], bbox->min[2]);
+  fprintf(file,"%u, %f, %f, %f\n",3, bbox->max[0], bbox->max[1], bbox->min[2]);
+  fprintf(file,"%u, %f, %f, %f\n",4, bbox->min[0], bbox->max[1], bbox->min[2]);
+  fprintf(file,"%u, %f, %f, %f\n",5, bbox->min[0], bbox->min[1], bbox->max[2]);
+  fprintf(file,"%u, %f, %f, %f\n",6, bbox->max[0], bbox->min[1], bbox->max[2]);
+  fprintf(file,"%u, %f, %f, %f\n",7, bbox->max[0], bbox->max[1], bbox->max[2]);
+  fprintf(file,"%u, %f, %f, %f\n",8, bbox->min[0], bbox->max[1], bbox->max[2]);
+
+  fprintf(file,"******* E L E M E N T S *************\n");
+  fprintf(file,"*ELEMENT, type=C3D8, ELSET=Volume8\n");
+  fprintf(file,"1, 1, 2, 3, 4, 5, 6, 7, 8\n");
+
+  fclose(file);
+  return HXT_STATUS_OK;
+}
+
+p4est_connectivity_t *
+p8est_connectivity_new_cube (double c)
+{
+  const p4est_topidx_t num_vertices = 8;
+  const p4est_topidx_t num_trees = 1;
+  const p4est_topidx_t num_ett = 0;
+  const p4est_topidx_t num_ctt = 0;
+  const double        vertices[8 * 3] = {
+    -c, -c, -c,
+    c, -c, -c,
+    -c, c, -c,
+    c, c, -c,
+    -c, -c, c,
+    c, -c, c,
+    -c, c, c,
+    c, c, c,
+  };
+  const p4est_topidx_t tree_to_vertex[1 * 8] = {
+    0, 1, 2, 3, 4, 5, 6, 7,
+  };
+  const p4est_topidx_t tree_to_tree[1 * 6] = {
+    0, 0, 0, 0, 0, 0,
+  };
+  const int8_t        tree_to_face[1 * 6] = {
+    0, 1, 2, 3, 4, 5,
+  };
+  return p4est_connectivity_new_copy (num_vertices, num_trees, 0, 0,
+				      vertices, tree_to_vertex,
+				      tree_to_tree, tree_to_face,
+				      NULL, &num_ett, NULL, NULL,
+				      NULL, &num_ctt, NULL, NULL);
+}
+
+#else // HAVE_P4EST
+
+HXTStatus hxtOctreeSearchOne(HXTForest *forest, double x, double y, double z, double *size) {
+
+  *size = 1.e22;}
+  static int count = 0;
+  if (count ++ < 20)
+    return HXT_ERROR_MSG(HXT_STATUS_ERROR,"HXT needs P4EST to compute automatic size fields");
+  return HXT_STATUS_ERROR;
+}
+
+
+  
+#endif // HAVE_P4EST
diff --git a/contrib/hxt/hxt_octree.h b/contrib/hxt/hxt_octree.h
new file mode 100644
index 0000000000000000000000000000000000000000..67ba99e4cf598cc3c6cec78ac3edb0618cdb86f5
--- /dev/null
+++ b/contrib/hxt/hxt_octree.h
@@ -0,0 +1,109 @@
+#ifndef HXT_OCTREE_H
+#define HXT_OCTREE_H
+
+// STD INCLUDES
+#include <queue>
+#include <vector>
+
+// GMSH INCLUDES ...
+
+#include "GmshConfig.h"
+#include "SPoint3.h"
+#include "SVector3.h"
+#include "rtree.h"
+
+// P4EST INCLUDES
+
+#ifdef HAVE_P4EST
+#include <p4est_to_p8est.h>
+#include <p8est_bits.h>
+#include <p8est_ghost.h>
+#include <p8est_nodes.h>
+#include <p8est_vtk.h>
+#include <p8est_iterate.h>
+#include <p8est_extended.h>
+#include <p8est_search.h>
+#endif 
+
+// HXT INCLUDES
+
+extern "C" {
+#include "hxt_api.h"
+#include "hxt_mesh.h"
+#include "hxt_bbox.h"
+}
+
+typedef struct HXTForestOptions{
+  int                   nodePerTwoPi;
+  int                   nodePerGap;
+  double               *bbox;
+  double               *nodalCurvature;
+  double              (*sizeFunction)(double, double, double) ;
+  RTree<int,double,3>  *triRTree;
+  HXTMesh              *mesh;
+} HXTForestOptions;
+
+typedef struct HXTForest{
+#ifdef HAVE_P4EST
+  p4est_t          *p4est;
+#endif 
+  HXTForestOptions  *forestOptions;
+} HXTForest;
+
+// Donnees disponibles sur chaque quadrant
+typedef struct size_data{
+  double size;
+#ifdef HAVE_P4EST
+  double ds[P4EST_DIM];
+#endif 
+  double d2s; // Laplacien
+
+  double h;
+  // Les tailles pour les differences finies
+  double h_xL, h_xR;
+  double h_yD, h_yU;
+  
+  double h_xavg;
+  double h_yavg;
+  
+  double h_zB, h_zT;
+  double h_zavg;
+
+  double hMin;
+  
+  // Pour raffiner sur la courbure : pas possible de donner un user_pointer
+  //  à p4est_refine ?
+  int refineFlag; 
+  
+} size_data_t;
+
+// Un point pour la recherche dans l'arbre
+typedef struct size_point{
+  double x;
+  double y;
+  double z;
+  double size;
+} size_point_t;
+
+typedef struct size_fun{
+  double (*myFun)(double, double, double);
+} size_fun_t;
+
+// API ---------------------------------------------------------------------------------------------
+
+HXTStatus hxtOctreeRefineToLevel(HXTForest *forest, int lvl);
+HXTStatus hxtOctreeComputeLaplacian(HXTForest *forest);
+HXTStatus hxtOctreeLaplacianRefine(HXTForest *forest, int nRefine);
+HXTStatus hxtOctreeSetMaxGradient(HXTForest *forest);
+HXTStatus hxtOctreeSmoothGradient(HXTForest *forest, int nMax);
+HXTStatus hxtForestOptionsCreate(HXTForestOptions **forestOptions);
+HXTStatus hxtForestOptionsDelete(HXTForestOptions **forestOptions);
+HXTStatus hxtForestCreate(int argc, char **argv, HXTForest **forest, const char* filename, HXTForestOptions *forestOptions);
+HXTStatus hxtForestDelete(HXTForest **forest);
+HXTStatus hxtOctreeRTreeIntersection(HXTForest *forest);
+HXTStatus hxtOctreeCurvatureRefine(HXTForest *forest, int nMax);
+HXTStatus hxtOctreeSearchOne(HXTForest *forest, double x, double y, double z, double *size);
+HXTStatus hxtOctreeSurfacesProches(HXTForest *forest);
+HXTStatus hxtOctreeElementEstimation(HXTForest *forest, double *elemEstimate);
+
+#endif