From 00f7593c39d4cad03fcf61b90aa626e3474446b0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?C=C3=A9lestin=20Marot?= <celestin.marot@uclouvain.be>
Date: Fri, 12 Jun 2020 09:19:04 +0200
Subject: [PATCH] clmin, clmax and clscale options integrated in hxt

---
 Mesh/meshGRegionHxt.cpp                       |  7 +-
 contrib/hxt/CMakeLists.txt                    |  2 +-
 contrib/hxt/tetMesh/CMakeLists.txt            |  2 +-
 contrib/hxt/tetMesh/exe/tetMesh_CLI.c         | 19 ++--
 contrib/hxt/tetMesh/include/hxt_tetDelaunay.h |  6 +-
 contrib/hxt/tetMesh/include/hxt_tetMesh.h     | 15 ++--
 .../hxt/tetMesh/include/hxt_tetNodalSize.h    | 60 +++++++++++++
 contrib/hxt/tetMesh/src/hxt_tetDelaunay.c     | 42 ++++-----
 contrib/hxt/tetMesh/src/hxt_tetMesh.c         | 34 ++++---
 contrib/hxt/tetMesh/src/hxt_tetNodalSize.c    | 45 +++++-----
 contrib/hxt/tetMesh/src/hxt_tetNodalSize.h    | 29 ------
 contrib/hxt/tetMesh/src/hxt_tetRefine.c       | 90 +++++++------------
 contrib/hxt/tetMesh/src/hxt_tetRefine.h       |  6 +-
 13 files changed, 183 insertions(+), 174 deletions(-)
 create mode 100644 contrib/hxt/tetMesh/include/hxt_tetNodalSize.h
 delete mode 100644 contrib/hxt/tetMesh/src/hxt_tetNodalSize.h

diff --git a/Mesh/meshGRegionHxt.cpp b/Mesh/meshGRegionHxt.cpp
index c2a5aa4a7c..db429e6333 100644
--- a/Mesh/meshGRegionHxt.cpp
+++ b/Mesh/meshGRegionHxt.cpp
@@ -27,7 +27,6 @@
 
 extern "C" {
 #include "hxt_tools.h"
-#include "hxt_boundary_recovery.h"
 #include "hxt_tetMesh.h"
 }
 
@@ -37,7 +36,7 @@ static HXTStatus messageCallback(HXTMessage *msg)
   return HXT_STATUS_OK;
 }
 
-static HXTStatus meshSizeCallBack(double* pts, size_t numPts, void *userData)
+static HXTStatus nodalSizesCallBack(double* pts, size_t numPts, void *userData)
 {
   GRegion *gr = (GRegion *)userData;
 
@@ -404,8 +403,8 @@ static HXTStatus _meshGRegionHxt(std::vector<GRegion *> &regions)
       0, // void* userData;
       CTX::instance()->mesh.optimizeThreshold // double qualityMin;
     },
-    { // meshSize
-      meshSizeCallBack, // HXTStatus (*callback)(double*, size_t, void* userData)
+    { // nodalSize
+      nodalSizesCallBack, // HXTStatus (*callback)(double*, size_t, void* userData)
       regions[0], // void* meshSizeData; // FIXME: should be dynamic!
       CTX::instance()->mesh.lcMin,
       CTX::instance()->mesh.lcMax,
diff --git a/contrib/hxt/CMakeLists.txt b/contrib/hxt/CMakeLists.txt
index d69f0a0cce..bb9de91499 100644
--- a/contrib/hxt/CMakeLists.txt
+++ b/contrib/hxt/CMakeLists.txt
@@ -131,7 +131,6 @@ set(SRC
     hxt_tetFlag.c
     hxt_tetMesh.c
     hxt_tetNodalSize.c
-    hxt_tetNodalSize.h
     hxt_tetOpti.c
     hxt_tetOptiUtils.h
     hxt_tetPartition.h
@@ -151,6 +150,7 @@ set(INC
     hxt_tetDelaunay.h
     hxt_tetFlag.h
     hxt_tetMesh.h
+    hxt_tetNodalSize.h
     hxt_tetOpti.h
     hxt_tetRepair.h
     hxt_vertices.h
diff --git a/contrib/hxt/tetMesh/CMakeLists.txt b/contrib/hxt/tetMesh/CMakeLists.txt
index 8071103883..2544ffe24a 100644
--- a/contrib/hxt/tetMesh/CMakeLists.txt
+++ b/contrib/hxt/tetMesh/CMakeLists.txt
@@ -43,12 +43,12 @@ set(HXT_TETMESH_SRC
     "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetRefine.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetQuality.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_edgeRemoval.h"
-    "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetNodalSize.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetOptiUtils.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/src/hxt_tetPartition.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tetDelaunay.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tetFlag.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tetMesh.h"
+    "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tetNodalSize.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tetOpti.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_tetRepair.h"
     "${CMAKE_CURRENT_SOURCE_DIR}/include/hxt_vertices.h"
diff --git a/contrib/hxt/tetMesh/exe/tetMesh_CLI.c b/contrib/hxt/tetMesh/exe/tetMesh_CLI.c
index b638f631e4..29422c9415 100644
--- a/contrib/hxt/tetMesh/exe/tetMesh_CLI.c
+++ b/contrib/hxt/tetMesh/exe/tetMesh_CLI.c
@@ -10,7 +10,6 @@
 #include "hxt_opt.h"
 #include "hxt_tools.h"
 #include "hxt_omp.h"
-#include <float.h>
 
 
 int main(int argc, char** argv) {
@@ -19,7 +18,7 @@ int main(int argc, char** argv) {
   const char* output = NULL;
   const char* geoFile = NULL;
 
-  HXTTetMeshOptions options = {.refine=1, .optimize=1, .verbosity=1, .quality.min=0.35, .meshSize.min=0.0, .meshSize.max=DBL_MAX, .meshSize.scaling=1.0};
+  HXTTetMeshOptions options = {.refine=1, .optimize=1, .verbosity=1, .quality.min=0.35, .nodalSizes.factor=1.0};
 
   HXT_CHECK( hxtAddOption('t', "omp_num_threads",
                           "Number of threads used for parallel work.\n"
@@ -50,17 +49,17 @@ int main(int argc, char** argv) {
   HXT_CHECK( hxtAddOption('N', "no-improvement", "Do not optimize the mesh quality", HXT_NO_FLAG, NULL, &options.optimize) );
 
 
-  HXT_CHECK( hxtAddOption('l', "clmin", "minimum mesh size", HXT_DOUBLE, &HXT_POSITIVE_RANGE, &options.meshSize.min));
-  HXT_CHECK( hxtAddOption('h', "clmax", "maximum mesh size", HXT_DOUBLE, &HXT_POSITIVE_RANGE, &options.meshSize.max));
-  HXT_CHECK( hxtAddOption('s', "clscale", "scale mesh size by a factor of VAL", HXT_DOUBLE, &HXT_POSITIVE_RANGE, &options.meshSize.scaling));
-  HXT_CHECK( hxtAddOption('a', "aspect-ratio-min", "The threshold on the aspect-ratio used during the optimization", HXT_DOUBLE, &HXT_0_1_RANGE, &options.quality.min));
+  HXT_CHECK( hxtAddOption('L', "clmin", "minimum mesh size", HXT_DOUBLE, &HXT_POSITIVE_RANGE, &options.nodalSizes.min));
+  HXT_CHECK( hxtAddOption('H', "clmax", "maximum mesh size", HXT_DOUBLE, &HXT_POSITIVE_RANGE, &options.nodalSizes.max));
+  HXT_CHECK( hxtAddOption('S', "clscale", "scale mesh size by a factor of VAL", HXT_DOUBLE, &HXT_POSITIVE_RANGE, &options.nodalSizes.factor));
+  HXT_CHECK( hxtAddOption('A', "aspect-ratio-min", "The threshold on the aspect-ratio used during the optimization", HXT_DOUBLE, &HXT_0_1_RANGE, &options.quality.min));
 
   HXT_CHECK( hxtAddOption('v', "verbosity",
                           "Verbosity level of output messages\n"
                           " * NUM=0: print no information\n"
                           " * NUM=1: print some information\n"
                           " * NUM=2: print all information", HXT_INT, &HXT_0_2_RANGE, &options.verbosity));
-  HXT_CHECK( hxtAddOption('p', "stat", "Print timing for each portion of the program", HXT_FLAG, NULL, &options.stat));
+  HXT_CHECK( hxtAddOption('s', "stat", "Print timing for each portion of the program", HXT_FLAG, NULL, &options.stat));
 
   HXT_CHECK( hxtAddTrailingOption("INPUT_FILE", HXT_EXISTING_FILENAME, NULL, &input));
   HXT_CHECK( hxtAddTrailingOption("OUTPUT_FILE", HXT_STRING, NULL, &output));
@@ -77,10 +76,12 @@ int main(int argc, char** argv) {
     printf("\ninput:             %s\noutput:            %s\n"
              "Number of threads: %d\nDelaunay threads:  %d\nOptim. threads:    %d\n"
              "reproducible:      %s\nverbosity level:   %d\nshow statistics:   %s\n"
-             "refine:            %s\noptimize :         %s\nmin aspect ratio:  %.3f\n\n",
+             "refine:            %s\noptimize :         %s\nmin aspect ratio:  %.3f\n"
+             "min. nodalSize:    %g\nmax. nodalSize:    %g\nnodalSize scaling: %g\n\n",
            input?input:"-", output?output:"-", options.defaultThreads<=0?omp_get_max_threads():options.defaultThreads,
            options.delaunayThreads, options.improveThreads,
-           options.reproducible?T:F, (int) options.verbosity, options.stat?T:F, options.refine?T:F, options.optimize?T:F, options.quality.min);
+           options.reproducible?T:F, (int) options.verbosity, options.stat?T:F, options.refine?T:F, options.optimize?T:F, options.quality.min,
+           options.nodalSizes.min, options.nodalSizes.max, options.nodalSizes.factor);
   }
 
 
diff --git a/contrib/hxt/tetMesh/include/hxt_tetDelaunay.h b/contrib/hxt/tetMesh/include/hxt_tetDelaunay.h
index 67fc922806..dfd0d57dfb 100644
--- a/contrib/hxt/tetMesh/include/hxt_tetDelaunay.h
+++ b/contrib/hxt/tetMesh/include/hxt_tetDelaunay.h
@@ -13,7 +13,7 @@
 extern "C" {
 #endif
 
-#include "hxt_mesh.h"
+#include "hxt_tetNodalSize.h"
 #include "hxt_vertices.h"
 #include "hxt_bbox.h"
 
@@ -34,8 +34,8 @@ typedef struct {
                                *  - if bbox==NULL, the bbox is recomputed internally;
                                *  - if bbox!=NULL, bbox must contain all vertices */
 
-  double* nodalSizes;         /**<
-                               *  - if nodalSize==NULL, doesn't restrict nodalSize;
+  HXTNodalSizes* nodalSizes;  /**<
+                               *  - if nodalSizes==NULL, doesn't restrict nodalSize;
                                *  - if nodalSize!=NULL, nodalSize contains the minimum
                                *  mesh size at each vertex.\n
                                *  If the insertion of a vertex create an edge smaller than
diff --git a/contrib/hxt/tetMesh/include/hxt_tetMesh.h b/contrib/hxt/tetMesh/include/hxt_tetMesh.h
index 06b5e90de4..afdd0cd76e 100644
--- a/contrib/hxt/tetMesh/include/hxt_tetMesh.h
+++ b/contrib/hxt/tetMesh/include/hxt_tetMesh.h
@@ -63,14 +63,17 @@ typedef struct {
 
     void* userData; /* user pointer given to callback */
 
-    /* mesh size s0 at a new point is first clamped between min and max,
-       then scaled by scaling. If another point of the mesh with mesh size
-       s1 (also clamped and scaled) is closer than 0.5*(s0+s1), then the new point
-       is filtered out */
+    /* if we want to insert a point p0 with size s0, and there is a point p1
+       with size s1 at a distance d, we check if
+
+       d > fmax(nodalSize.min, fmin(nodalSize.min, 0.5*(s0+s1))) * scaling
+
+      if it is not the case, the point is filtered out
+       */
     double min;     /* default value: 0.0                                     */
     double max;     /* default value: DBL_MAX (converted to DBL_MAX if <=0.0) */
-    double scaling; /* default value: 1.0     (converted to 1.0 if <=0.0)     */
-  } meshSize;
+    double factor;  /* default value: 1.0     (converted to 1.0 if <=0.0)     */
+  } nodalSizes;
 } HXTTetMeshOptions;
 
 
diff --git a/contrib/hxt/tetMesh/include/hxt_tetNodalSize.h b/contrib/hxt/tetMesh/include/hxt_tetNodalSize.h
new file mode 100644
index 0000000000..f0a060ea42
--- /dev/null
+++ b/contrib/hxt/tetMesh/include/hxt_tetNodalSize.h
@@ -0,0 +1,60 @@
+// Hxt - Copyright (C)
+// 2016 - 2020 UCLouvain
+//
+// See the LICENSE.txt file for license information.
+//
+// Contributor(s):
+//   Célestin Marot
+
+#ifndef HXT_TETNODALSIZE_H
+#define HXT_TETNODALSIZE_H
+
+#include "hxt_mesh.h"
+#include <math.h>
+#include <float.h>
+
+typedef struct {
+  double* array;
+  HXTStatus (*callback)(double *coord, size_t n, void* userData);
+  void* userData;
+  double min;
+  double max;
+  double factor;
+} HXTNodalSizes;
+
+HXTStatus hxtNodalSizesInit(HXTMesh* mesh, HXTNodalSizes* nodalSize);
+HXTStatus hxtNodalSizesDestroy(HXTNodalSizes* nodalSize);
+
+/// Compute sizes at vertices of the mesh from meshSizeFun
+HXTStatus hxtComputeNodalSizesFromFunction(HXTMesh* mesh, HXTNodalSizes* nodalSize);
+
+/// Compute sizes at vertices of the mesh from existing edges
+HXTStatus hxtComputeNodalSizesFromTrianglesAndLines(HXTMesh* mesh, HXTNodalSizes* nodalSize);
+HXTStatus hxtComputeNodalSizesFromMesh(HXTMesh* mesh, HXTNodalSizes* nodalSize);
+
+
+
+static inline double squareDist(double v0[3], double v1[3])
+{
+  double d0 = v1[0] - v0[0];
+  double d1 = v1[1] - v0[1];
+  double d2 = v1[2] - v0[2];
+  return d0*d0 + d1*d1 + d2*d2;
+}
+
+
+static inline int isTooClose(double s0, double s1, double squareDist, const HXTNodalSizes* ns)
+{
+  if(s0!=DBL_MAX && s1!=DBL_MAX) {
+    double meanSize = fmin(ns->max, fmax(ns->min, 0.5*(s0+s1))) * ns->factor;
+    if(squareDist < meanSize * meanSize) { // we won't enter this on overflow of meansize when max is too big...
+      return 1;
+    }
+  }
+
+  return 0;
+}
+
+
+
+#endif
diff --git a/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c
index d4727a01ca..8a4584013e 100644
--- a/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c
+++ b/contrib/hxt/tetMesh/src/hxt_tetDelaunay.c
@@ -13,6 +13,7 @@
 #include "hxt_tetFlag.h"
 #include "hxt_tetRepair.h"
 #include "hxt_sort.h"
+#include "hxt_tetNodalSize.h"
 
 
 /**
@@ -273,22 +274,11 @@ static inline HXTStatus checkTetrahedron(HXTVertex* vertices, HXTPartition* part
 }
 
 
-static inline HXTStatus pointIsTooClose(const double* __restrict__ p1, const double* __restrict__ p2, double nodalSize){
-  double d2 = (p1[0]-p2[0])*(p1[0]-p2[0])
-            + (p1[1]-p2[1])*(p1[1]-p2[1])
-            + (p1[2]-p2[2])*(p1[2]-p2[2]); 
-  if (d2 < /*(0.94*0.94) * */nodalSize*nodalSize){
-    return  HXT_STATUS_INTERNAL;
-  }
-
-  return HXT_STATUS_OK;
-}
-
 /* if one edge of the cavity is shorter than the nodalSize, return HXT_STATUS_INTERNAL */
-static inline HXTStatus filterCavity (TetLocal* local, HXTMesh *mesh, const double *nodalSizes, const uint32_t vta)
+static inline HXTStatus filterCavity (TetLocal* local, HXTMesh *mesh, const HXTNodalSizes* nodalSizes, const uint32_t vta)
 {
   double *vtaCoord = mesh->vertices.coord + 4*vta;
-  double vtaNodalSize = nodalSizes[vta];
+  double vtaNodalSize = nodalSizes->array[vta];
 
   for (uint64_t i = 0 ; i< local->ball.num ; i++) {
     for (unsigned j=0;j<3;j++) {
@@ -296,33 +286,35 @@ static inline HXTStatus filterCavity (TetLocal* local, HXTMesh *mesh, const doub
 
       if (j!=3 || nodej != HXT_GHOST_VERTEX){
         double *Xj = mesh->vertices.coord + 4*nodej;
-        double otherNodalSize = nodalSizes[nodej];
+        double otherNodalSize = nodalSizes->array[nodej];
         if(otherNodalSize==DBL_MAX){
           otherNodalSize = vtaNodalSize;
         }
-        HXT_CHECK( pointIsTooClose(vtaCoord, Xj, 0.5*( vtaNodalSize + otherNodalSize)) );
+        if( isTooClose(vtaNodalSize, otherNodalSize, squareDist(vtaCoord, Xj), nodalSizes) )
+          return HXT_STATUS_INTERNAL;
       }
     }
   }
   return  HXT_STATUS_OK;
 }
 
-static inline HXTStatus filterTet(HXTMesh* mesh, const double *nodalSizes, const uint64_t curTet, const uint32_t vta){
+static inline HXTStatus filterTet(HXTMesh* mesh, const HXTNodalSizes* nodalSizes, const uint64_t curTet, const uint32_t vta){
   HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord;
 
   double *vtaCoord = vertices[vta].coord;
-  double vtaNodalSize = nodalSizes[vta];
+  double vtaNodalSize = nodalSizes->array[vta];
 
   for (unsigned j=0; j<4; j++) {
     uint32_t nodej = mesh->tetrahedra.node[4*curTet+j];
 
     if (j!=3 || nodej != HXT_GHOST_VERTEX){
       double* Xj = vertices[nodej].coord;
-      double otherNodalSize = nodalSizes[nodej];
+      double otherNodalSize = nodalSizes->array[nodej];
       if(otherNodalSize==DBL_MAX){
         otherNodalSize = vtaNodalSize;
       }
-      HXT_CHECK( pointIsTooClose(vtaCoord, Xj, 0.5*( vtaNodalSize + otherNodalSize)) );
+      if( isTooClose(vtaNodalSize, otherNodalSize, squareDist(vtaCoord, Xj), nodalSizes) )
+          return HXT_STATUS_INTERNAL;
     }
   }
   return HXT_STATUS_OK;
@@ -1228,7 +1220,7 @@ static inline HXTStatus fillingACavity(HXTMesh* mesh, TetLocal* local, unsigned
 static HXTStatus insertion(HXT2Sync* shared2sync,
                            TetLocal* local,
                            unsigned char* verticesID,
-                           const double* nodalSizes,
+                           const HXTNodalSizes* nodalSizes,
                            uint64_t* curTet,
                            const uint32_t vta,
                            int perfectlyDelaunay){
@@ -1297,7 +1289,7 @@ static HXTStatus insertion(HXT2Sync* shared2sync,
 static inline uint32_t filterOnMooreCurve(HXTVertex* vertices,
                                           HXTNodeInfo* nodeInfo,
                                           uint32_t n,
-                                          double* nodalSizes)
+                                          HXTNodalSizes* nodalSizes)
 {
   uint32_t mooreSkipped = 0;
   #pragma omp parallel reduction(+:mooreSkipped)
@@ -1311,8 +1303,8 @@ static inline uint32_t filterOnMooreCurve(HXTVertex* vertices,
       uint32_t lastNode = nodeInfo[i].node;
       if(nodeInfo[i].status==HXT_STATUS_TRYAGAIN){
         double* p2 = vertices[lastNode].coord;
-        double p2Size = nodalSizes[lastNode];
-        if(p1!=NULL && pointIsTooClose(p1, p2, 0.5*(p1Size+p2Size))!=HXT_STATUS_OK){
+        double p2Size = nodalSizes->array[lastNode];
+        if(p1!=NULL && isTooClose(p1Size, p2Size, squareDist(p1, p2), nodalSizes)){
           mooreSkipped++;
           nodeInfo[i].status=HXT_STATUS_FALSE;
         }
@@ -1395,7 +1387,7 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh,
     }
 
     if(!noReordering) {
-      double* sizesToInsert = options->nodalSizes + options->insertionFirst;
+      double* sizesToInsert = options->nodalSizes->array + options->insertionFirst;
 
       size_t vertSize = nToInsert*sizeof(HXTVertex);
       size_t sizeSize = nToInsert*sizeof(double);
@@ -1921,7 +1913,7 @@ static HXTStatus parallelDelaunay3D(HXTMesh* mesh,
     // 5th: put vertices at the right indices
     for (uint32_t i=firstShifted; i<mesh->vertices.num; i++) {
       if(options->nodalSizes!=NULL){
-        options->nodalSizes[vertices[i].padding.index] = options->nodalSizes[i];
+        options->nodalSizes->array[vertices[i].padding.index] = options->nodalSizes->array[i];
       }
       vertices[vertices[i].padding.index] = vertices[i];
     }
diff --git a/contrib/hxt/tetMesh/src/hxt_tetMesh.c b/contrib/hxt/tetMesh/src/hxt_tetMesh.c
index d7f741157a..bcda2f5771 100644
--- a/contrib/hxt/tetMesh/src/hxt_tetMesh.c
+++ b/contrib/hxt/tetMesh/src/hxt_tetMesh.c
@@ -55,11 +55,11 @@ HXTStatus hxtTetMesh(HXTMesh* mesh,
   if(options->defaultThreads>0) {
     omp_set_num_threads(options->defaultThreads);
   }
-  if(options->meshSize.max<=0.0) {
-    options->meshSize.max = DBL_MAX;
+  if(options->nodalSizes.max<=0.0) {
+    options->nodalSizes.max = DBL_MAX;
   }
-  if(options->meshSize.scaling<=0.0) {
-    options->meshSize.scaling = 1.0;
+  if(options->nodalSizes.factor<=0.0) {
+    options->nodalSizes.factor = 1.0;
   }
 
   double t[8]={0};
@@ -155,22 +155,32 @@ HXTStatus hxtTetMesh(HXTMesh* mesh,
   t[4] = omp_get_wtime();
 
   if(options->refine){
-    HXT_CHECK(hxtCreateNodalSize(mesh, &delOptions.nodalSizes));
-
-    if(options->meshSize.callback!=NULL) {
-      if(hxtComputeNodalSizeFromFunction(mesh, delOptions.nodalSizes, options->meshSize.callback, options->meshSize.userData)!=HXT_STATUS_OK) {
+    HXTNodalSizes nodalSizes = {
+      .array = NULL,
+      .callback = options->nodalSizes.callback,
+      .userData = options->nodalSizes.userData,
+      .min = options->nodalSizes.min,
+      .max = options->nodalSizes.max,
+      .factor = options->nodalSizes.factor
+    };
+    HXT_CHECK(hxtNodalSizesInit(mesh, &nodalSizes));
+
+    if(nodalSizes.callback!=NULL) {
+      if(hxtComputeNodalSizesFromFunction(mesh, &nodalSizes)!=HXT_STATUS_OK) {
         HXT_WARNING("Initial sizes are interpolated instead of being fetched from the size map");
-        HXT_CHECK(hxtComputeNodalSizeFromTrianglesAndLines(mesh, delOptions.nodalSizes));
+        HXT_CHECK(hxtComputeNodalSizesFromTrianglesAndLines(mesh, &nodalSizes));
       }
     }
     else
-      HXT_CHECK(hxtComputeNodalSizeFromTrianglesAndLines(mesh, delOptions.nodalSizes));
+      HXT_CHECK(hxtComputeNodalSizesFromTrianglesAndLines(mesh, &nodalSizes));
+
+    delOptions.nodalSizes = &nodalSizes;
 
     HXT_CHECK( setFlagsToProcessOnlyVolumesInBrep(mesh) );
 
-    HXT_CHECK(hxtRefineTetrahedra(mesh, &delOptions, options->meshSize.callback, options->meshSize.userData));
+    HXT_CHECK( hxtRefineTetrahedra(mesh, &delOptions) );
 
-    HXT_CHECK( hxtDestroyNodalSize(&delOptions.nodalSizes) );
+    HXT_CHECK( hxtNodalSizesDestroy(&nodalSizes) );
 
     HXT_INFO_COND(options->verbosity>1, "Mesh refinement finished\n");
   }
diff --git a/contrib/hxt/tetMesh/src/hxt_tetNodalSize.c b/contrib/hxt/tetMesh/src/hxt_tetNodalSize.c
index a2826d2764..337871915d 100644
--- a/contrib/hxt/tetMesh/src/hxt_tetNodalSize.c
+++ b/contrib/hxt/tetMesh/src/hxt_tetNodalSize.c
@@ -7,43 +7,42 @@
 //   Célestin Marot
 
 #include "hxt_vertices.h"
+#include "hxt_tetNodalSize.h"
 
-HXTStatus hxtCreateNodalSize(HXTMesh* mesh, double** nodalSizes_ptr)
+
+HXTStatus hxtNodalSizesInit(HXTMesh* mesh, HXTNodalSizes* nodalSizes)
 {
-  HXT_CHECK(hxtAlignedMalloc(nodalSizes_ptr,mesh->vertices.num*sizeof(double)));
+  HXT_CHECK(hxtAlignedMalloc(&nodalSizes->array,mesh->vertices.num*sizeof(double)));
   return HXT_STATUS_OK;
 }
 
-HXTStatus hxtComputeNodalSizeFromFunction(HXTMesh* mesh, double* nodalSizes,
-                                          HXTStatus (*meshSizeFun)(double* coord, size_t n,
-                                                                   void* meshSizeData),
-                                          void* meshSizeData)
+HXTStatus hxtComputeNodalSizesFromFunction(HXTMesh* mesh, HXTNodalSizes* nodalSizes)
 {
   #pragma omp parallel for
   for (uint32_t i = 0; i<mesh->vertices.num; i++){
     mesh->vertices.coord[4 * i + 3] = -DBL_MAX;
   }
 
-  HXT_CHECK( meshSizeFun(mesh->vertices.coord, mesh->vertices.num, meshSizeData) );
+  HXT_CHECK( nodalSizes->callback(mesh->vertices.coord, mesh->vertices.num, nodalSizes->userData) );
 
   int failed = 0;
   #pragma omp parallel for reduction(||:failed)
   for (uint32_t i=0; i<mesh->vertices.num; i++) {
     if(mesh->vertices.coord[4 * i + 3] <= 0.)
       failed = 1;
-    nodalSizes[i] = mesh->vertices.coord[4 * i + 3];
+    nodalSizes->array[i] = mesh->vertices.coord[4 * i + 3];
   }
 
   return failed==0 ? HXT_STATUS_OK : HXT_STATUS_FAILED;
 }
 
-HXTStatus hxtComputeNodalSizeFromTrianglesAndLines(HXTMesh* mesh, double* nodalSizes)
+HXTStatus hxtComputeNodalSizesFromTrianglesAndLines(HXTMesh* mesh, HXTNodalSizes* nodalSizes)
 {
   HXTVertex* vertices = (HXTVertex*) mesh->vertices.coord;
 
   #pragma omp parallel for
   for (uint32_t i = 0; i<mesh->vertices.num; i++){
-    nodalSizes[i] = 0;
+    nodalSizes->array[i] = 0;
     vertices[i].padding.hilbertDist = 0; // we use that as a counter to do the average...
   }
 
@@ -62,8 +61,8 @@ HXTStatus hxtComputeNodalSizeFromTrianglesAndLines(HXTMesh* mesh, double* nodalS
         double l = sqrt ((X1[0]-X2[0])*(X1[0]-X2[0])+
                          (X1[1]-X2[1])*(X1[1]-X2[1])+
                          (X1[2]-X2[2])*(X1[2]-X2[2]));
-        nodalSizes[n1] += l;
-        nodalSizes[n2] += l;
+        nodalSizes->array[n1] += l;
+        nodalSizes->array[n2] += l;
       }
     }
   }
@@ -78,32 +77,32 @@ HXTStatus hxtComputeNodalSizeFromTrianglesAndLines(HXTMesh* mesh, double* nodalS
       double l = sqrt ((X1[0]-X2[0])*(X1[0]-X2[0])+
                        (X1[1]-X2[1])*(X1[1]-X2[1])+
                        (X1[2]-X2[2])*(X1[2]-X2[2]));
-      nodalSizes[n1] += l;
-      nodalSizes[n2] += l;
+      nodalSizes->array[n1] += l;
+      nodalSizes->array[n2] += l;
   }
 
   #pragma omp parallel for
   for (uint32_t i=0; i<mesh->vertices.num; i++)
   {
     if(vertices[i].padding.hilbertDist == 0) {
-      nodalSizes[i] = DBL_MAX;
+      nodalSizes->array[i] = DBL_MAX;
     }
     else {
-      nodalSizes[i] /= (double) vertices[i].padding.hilbertDist;
+      nodalSizes->array[i] /= (double) vertices[i].padding.hilbertDist;
     }
   }
   return HXT_STATUS_OK;
 }
 
-HXTStatus hxtComputeNodalSizeFromMesh(HXTMesh* mesh, double* nodalSizes)
+HXTStatus hxtComputeNodalSizesFromMesh(HXTMesh* mesh, HXTNodalSizes* nodalSizes)
 {
 
   #pragma omp parallel for
   for (uint32_t i = 0; i<mesh->vertices.num; i++){
-    nodalSizes[i] = DBL_MAX;
+    nodalSizes->array[i] = DBL_MAX;
   }
 
-  // we do not take into account hereafter nodalSizes = to DBL_MAX
+  // we do not take into account hereafter nodalSizes->array = to DBL_MAX
   for (uint32_t i = 0; i<mesh->tetrahedra.num; i++){
     for (uint32_t j = 0; j<3; j++){
       for (uint32_t k = j+1; k<4; k++){
@@ -115,8 +114,8 @@ HXTStatus hxtComputeNodalSizeFromMesh(HXTMesh* mesh, double* nodalSizes)
           double l = sqrt ((X1[0]-X2[0])*(X1[0]-X2[0])+
                            (X1[1]-X2[1])*(X1[1]-X2[1])+
                            (X1[2]-X2[2])*(X1[2]-X2[2]));
-          if(l<nodalSizes[n1]) nodalSizes[n1] = l;
-          if(l<nodalSizes[n2]) nodalSizes[n2] = l;
+          if(l<nodalSizes->array[n1]) nodalSizes->array[n1] = l;
+          if(l<nodalSizes->array[n2]) nodalSizes->array[n2] = l;
         }
       }
     }
@@ -124,8 +123,8 @@ HXTStatus hxtComputeNodalSizeFromMesh(HXTMesh* mesh, double* nodalSizes)
   return HXT_STATUS_OK;
 }
 
-HXTStatus hxtDestroyNodalSize(double** nodalSizes_ptr)
+HXTStatus hxtNodalSizesDestroy(HXTNodalSizes* nodalSizes)
 {
-  HXT_CHECK( hxtAlignedFree(nodalSizes_ptr) );
+  HXT_CHECK( hxtAlignedFree(&nodalSizes->array) );
   return HXT_STATUS_OK;
 }
diff --git a/contrib/hxt/tetMesh/src/hxt_tetNodalSize.h b/contrib/hxt/tetMesh/src/hxt_tetNodalSize.h
deleted file mode 100644
index e4330092ab..0000000000
--- a/contrib/hxt/tetMesh/src/hxt_tetNodalSize.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Hxt - Copyright (C)
-// 2016 - 2020 UCLouvain
-//
-// See the LICENSE.txt file for license information.
-//
-// Contributor(s):
-//   Célestin Marot
-
-#ifndef HXT_TETNODALSIZE_H
-#define HXT_TETNODALSIZE_H
-
-#include "hxt_mesh.h"
-
-HXTStatus hxtCreateNodalSize(HXTMesh* mesh, double** nodalSizes_ptr);
-HXTStatus hxtDestroyNodalSize(double** nodalSize);
-
-/// Compute sizes at vertices of the mesh from meshSizeFun
-HXTStatus hxtComputeNodalSizeFromFunction(HXTMesh* mesh, double* nodalSize,
-                                          HXTStatus (*meshSizeFun)(double *coord, size_t n,
-                                                                   void* meshSizeData),
-                                          void* meshSizeData);
-
-/// Compute sizes at vertices of the mesh from existing edges
-HXTStatus hxtComputeNodalSizeFromTrianglesAndLines(HXTMesh* mesh, double* nodalSize);
-HXTStatus hxtComputeNodalSizeFromMesh(HXTMesh* mesh, double* nodalSize);
-
-
-
-#endif
diff --git a/contrib/hxt/tetMesh/src/hxt_tetRefine.c b/contrib/hxt/tetMesh/src/hxt_tetRefine.c
index 76b9ae7999..52e7bcc539 100644
--- a/contrib/hxt/tetMesh/src/hxt_tetRefine.c
+++ b/contrib/hxt/tetMesh/src/hxt_tetRefine.c
@@ -10,6 +10,7 @@
 #include "predicates.h"
 #include "hxt_tetFlag.h"
 #include "hxt_sort.h"
+#include "hxt_tetNodalSize.h"
 
 // mark all the points which are in mesh->(points | lines | triangles)
 static void markMeshPoints(HXTMesh* mesh)
@@ -78,33 +79,11 @@ HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions)
 }
 
 
-static inline double square_dist(double v0[3], double v1[3])
-{
-  return (v1[0] - v0[0])*(v1[0] - v0[0]) +
-         (v1[1] - v0[1])*(v1[1] - v0[1]) +
-         (v1[2] - v0[2])*(v1[2] - v0[2]);
-}
-
-
-static int is_too_close(double ptSize, double vtaSize, double squareDist)
-{
-  if(ptSize!=DBL_MAX) {
-    double meanSize = 0.5*(ptSize+vtaSize);
-    if(squareDist < /*(0.94*0.94) * */meanSize * meanSize) {
-      return 1;
-    }
-  }
-
-  return 0;
-}
-
-
-
 /* compute a point (center) inside the tetrahedron which is very likely to respect the nodalsize.
  * return 0 if the computed point does respect the interpolated nodalsize
  * return 1 if the computed point does not respect the interpolated nodalsize
  * the interpolated nodalsize is placed into center[3]  */
-static int getBestCenter(double p[4][4], double nodalSize[4], double center[4])
+static int getBestCenter(double p[4][4], double nodalSize[4], double center[4], HXTNodalSizes* ns)
 {
   double avg = 0.0;
   double num = 0;
@@ -130,12 +109,12 @@ static int getBestCenter(double p[4][4], double nodalSize[4], double center[4])
   double s3 = nodalSize[3]!=DBL_MAX && nodalSize[3]>0.0 ? nodalSize[3] : avg;
 
   // (e/s)^2  (e is the norm of the edge, s is the mean nodalSize over that edge)
-  double e0l2 = square_dist(p[0], p[1])/(0.25*(s0 + s1)*(s0 + s1));
-  double e1l2 = square_dist(p[0], p[2])/(0.25*(s0 + s2)*(s0 + s2));
-  double e2l2 = square_dist(p[0], p[3])/(0.25*(s0 + s3)*(s0 + s3));
-  double e3l2 = square_dist(p[1], p[2])/(0.25*(s1 + s2)*(s1 + s2));
-  double e4l2 = square_dist(p[1], p[3])/(0.25*(s1 + s3)*(s1 + s3));
-  double e5l2 = square_dist(p[2], p[3])/(0.25*(s2 + s3)*(s2 + s3));
+  double e0l2 = squareDist(p[0], p[1])/(0.25*(s0 + s1)*(s0 + s1));
+  double e1l2 = squareDist(p[0], p[2])/(0.25*(s0 + s2)*(s0 + s2));
+  double e2l2 = squareDist(p[0], p[3])/(0.25*(s0 + s3)*(s0 + s3));
+  double e3l2 = squareDist(p[1], p[2])/(0.25*(s1 + s2)*(s1 + s2));
+  double e4l2 = squareDist(p[1], p[3])/(0.25*(s1 + s3)*(s1 + s3));
+  double e5l2 = squareDist(p[2], p[3])/(0.25*(s2 + s3)*(s2 + s3));
 
   // normally, this thing should be near 1 if the tet are well refined
   // it can be below 1 only on the surface, because we averaged the line lengths to get the nodalsize
@@ -199,10 +178,10 @@ static int getBestCenter(double p[4][4], double nodalSize[4], double center[4])
     center[3] = bary0*s0 + bary1*s1 + bary2*s2 + bary3*s3; // the interpolated nodalSize
 
     circumcenterTooClose = (
-      is_too_close(s0, center[3], square_dist(p[0], center)) ||
-      is_too_close(s1, center[3], square_dist(p[1], center)) ||
-      is_too_close(s2, center[3], square_dist(p[2], center)) ||
-      is_too_close(s3, center[3], square_dist(p[3], center))
+      isTooClose(s0, center[3], squareDist(p[0], center), ns) ||
+      isTooClose(s1, center[3], squareDist(p[1], center), ns) ||
+      isTooClose(s2, center[3], squareDist(p[2], center), ns) ||
+      isTooClose(s3, center[3], squareDist(p[3], center), ns)
     );
   }
   else { // we should also enter this if a bary is not finite
@@ -244,10 +223,10 @@ static int getBestCenter(double p[4][4], double nodalSize[4], double center[4])
     otherCenter[3] = bary0*s0 + bary1*s1 + bary2*s2 + bary3*s3; // the interpolated nodalSize
 
     otherCenterTooClose = (
-      is_too_close(s0, otherCenter[3], square_dist(p[0], otherCenter)) ||
-      is_too_close(s1, otherCenter[3], square_dist(p[1], otherCenter)) ||
-      is_too_close(s2, otherCenter[3], square_dist(p[2], otherCenter)) ||
-      is_too_close(s3, otherCenter[3], square_dist(p[3], otherCenter))
+      isTooClose(s0, otherCenter[3], squareDist(p[0], otherCenter), ns) ||
+      isTooClose(s1, otherCenter[3], squareDist(p[1], otherCenter), ns) ||
+      isTooClose(s2, otherCenter[3], squareDist(p[2], otherCenter), ns) ||
+      isTooClose(s3, otherCenter[3], squareDist(p[3], otherCenter), ns)
     );
 
     if(circumcenterOutside || !otherCenterTooClose) {
@@ -264,7 +243,7 @@ static int getBestCenter(double p[4][4], double nodalSize[4], double center[4])
 
 /* just fill tetCoord and tetNodalSize with the coordinates and nodal size of each node of
  * tetrahedron tet */
-static inline void getTetCoordAndNodalSize(HXTMesh* mesh, double* nodalSizes, uint64_t tet,
+static inline void getTetCoordAndNodalSize(HXTMesh* mesh, double* nsarray, uint64_t tet,
                                            double tetCoord[4][4], double tetNodalSize[4])
 {
   uint32_t* nodes = &mesh->tetrahedra.node[4*tet];
@@ -273,7 +252,7 @@ static inline void getTetCoordAndNodalSize(HXTMesh* mesh, double* nodalSizes, ui
     tetCoord[i][1] = mesh->vertices.coord[4 * nodes[i] + 1];
     tetCoord[i][2] = mesh->vertices.coord[4 * nodes[i] + 2];
 
-    tetNodalSize[i] = nodalSizes[nodes[i]];
+    tetNodalSize[i] = nsarray[nodes[i]];
   }
 }
 
@@ -379,10 +358,8 @@ static HXTStatus balanceRefineWork(HXTMesh* mesh, uint32_t* startPt, size_t* sta
 }
 
 
-HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions,
-                              HXTStatus (*meshSizeFun)(double* coord, size_t n,
-                                                       void* meshSizeData),
-                              void* meshSizeData)
+HXTStatus hxtRefineTetrahedra(HXTMesh* mesh,
+                              HXTDelaunayOptions* delOptions)
 {
   int maxThreads = omp_get_max_threads();
 
@@ -419,10 +396,11 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions,
 
         double p[4][4];
         double s[4];
-        getTetCoordAndNodalSize(mesh, delOptions->nodalSizes, tet, p, s);
+        getTetCoordAndNodalSize(mesh, delOptions->nodalSizes->array, tet, p, s);
 
         // TODO: do a SIMD getBestCenter function if it gets slow
-        if(getBestCenter(p, s, &newVertices[4*ptIndex]) && meshSizeFun==NULL)
+        if(getBestCenter(p, s, &newVertices[4*ptIndex], delOptions->nodalSizes) &&
+                         delOptions->nodalSizes->callback==NULL)
           newVertices[4*ptIndex+3] = -DBL_MAX;
 
 #ifndef NDEBUG
@@ -435,9 +413,9 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions,
       }
     }
 
-    // second step (meshSizeFun): compute the effective mesh size at all these newly create points
-    if(meshSizeFun!=NULL)
-      HXT_CHECK( meshSizeFun(newVertices, totNewPts, meshSizeData) );
+    // second step (meshSizeCB): compute the effective mesh size at all these newly create points
+    if(delOptions->nodalSizes->callback!=NULL)
+      HXT_CHECK( delOptions->nodalSizes->callback(newVertices, totNewPts, delOptions->nodalSizes->userData) );
 
 
     HXTStatus status;
@@ -459,15 +437,15 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions,
         uint64_t tetID = ptToTet[i];
         double p[4][4];
         double s[4];
-        getTetCoordAndNodalSize(mesh, delOptions->nodalSizes, tetID, p, s);
+        getTetCoordAndNodalSize(mesh, delOptions->nodalSizes->array, tetID, p, s);
 
         double* vtaCoord = &newVertices[4*i];
         double vtaSize = newVertices[4*i + 3];
-
-        if(is_too_close(s[0], vtaSize, square_dist(p[0], vtaCoord)) ||
-           is_too_close(s[1], vtaSize, square_dist(p[1], vtaCoord)) ||
-           is_too_close(s[2], vtaSize, square_dist(p[2], vtaCoord)) ||
-           is_too_close(s[3], vtaSize, square_dist(p[3], vtaCoord))){
+        
+        if(isTooClose(s[0], vtaSize, squareDist(p[0], vtaCoord), delOptions->nodalSizes) ||
+           isTooClose(s[1], vtaSize, squareDist(p[1], vtaCoord), delOptions->nodalSizes) ||
+           isTooClose(s[2], vtaSize, squareDist(p[2], vtaCoord), delOptions->nodalSizes) ||
+           isTooClose(s[3], vtaSize, squareDist(p[3], vtaCoord), delOptions->nodalSizes)){
           newVertices[4*i + 3] = -DBL_MAX;
         }
         else {
@@ -496,7 +474,7 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions,
         if(mesh->vertices.num > mesh->vertices.size){
           status=hxtAlignedRealloc(&mesh->vertices.coord, sizeof(double)*4*mesh->vertices.num);
           if(status==HXT_STATUS_OK){
-            status=hxtAlignedRealloc(&delOptions->nodalSizes, sizeof(double)*mesh->vertices.num);
+            status=hxtAlignedRealloc(&delOptions->nodalSizes->array, sizeof(double)*mesh->vertices.num);
             mesh->vertices.size = mesh->vertices.num;
           }
         }
@@ -512,7 +490,7 @@ HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions,
           mesh->vertices.coord[v*4  ] = newVertices[4*i + 0];
           mesh->vertices.coord[v*4+1] = newVertices[4*i + 1];
           mesh->vertices.coord[v*4+2] = newVertices[4*i + 2];
-          delOptions->nodalSizes[v] = newVertices[4*i + 3];
+          delOptions->nodalSizes->array[v] = newVertices[4*i + 3];
           v++;
         }
       }
diff --git a/contrib/hxt/tetMesh/src/hxt_tetRefine.h b/contrib/hxt/tetMesh/src/hxt_tetRefine.h
index 3d2e8447c4..c70fb03650 100644
--- a/contrib/hxt/tetMesh/src/hxt_tetRefine.h
+++ b/contrib/hxt/tetMesh/src/hxt_tetRefine.h
@@ -15,10 +15,6 @@
 HXTStatus hxtEmptyMesh(HXTMesh* mesh, HXTDelaunayOptions* delOptions);
 
 /// Add points at tets circumcenter in order to fullfill a mesh size constraint 
-HXTStatus hxtRefineTetrahedra(HXTMesh* mesh,
-                              HXTDelaunayOptions* delOptions,
-                              HXTStatus (*meshSizeFun)(double* coord, size_t n,
-                                                       void* meshSizeData),
-                              void* meshSizeData);
+HXTStatus hxtRefineTetrahedra(HXTMesh* mesh, HXTDelaunayOptions* delOptions);
 
 #endif
-- 
GitLab