From ec1f8f27c994f718c96b51afe9df8d8e053292d8 Mon Sep 17 00:00:00 2001
From: Jean-Francois Remacle <jean-francois.remacle@uclouvain.be>
Date: Wed, 28 Nov 2007 14:18:10 +0000
Subject: [PATCH] 3D Optimization is now implemented !

---
 Common/Context.h                      |   2 +-
 Common/DefaultOptions.h               |   2 +
 Common/Options.cpp                    |  13 ++-
 Common/Options.h                      |   1 +
 Fltk/Callbacks.cpp                    |  17 ++-
 Fltk/Callbacks.h                      |   1 +
 Fltk/GUI.cpp                          |  17 +--
 Mesh/Generator.cpp                    |  19 +++-
 Mesh/Generator.h                      |   1 +
 Mesh/meshGRegion.cpp                  |  19 +++-
 Mesh/meshGRegion.h                    |  10 +-
 Mesh/meshGRegionDelaunayInsertion.cpp | 144 +++++++++++---------------
 Mesh/meshGRegionDelaunayInsertion.h   |  18 +++-
 Mesh/meshGRegionLocalMeshMod.cpp      |  50 +++++----
 Mesh/meshGRegionLocalMeshMod.h        |   3 +-
 15 files changed, 189 insertions(+), 128 deletions(-)

diff --git a/Common/Context.h b/Common/Context.h
index 66ca89f9d2..da82dddd23 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -178,7 +178,7 @@ public :
     double label_frequency;
     int point_type; // flat or 3D
     double point_size, line_width;
-    int optimize, refine_steps;
+    int optimize, optimizeNetgen, refine_steps;
     int quality_type, label_type;
     double quality_inf, quality_sup, radius_inf, radius_sup;
     double scaling_factor, lc_factor, rand_factor, lc_integration_precision;
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 8b10e3d11f..dccec3c36f 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -981,6 +981,8 @@ StringXNumber MeshOptions_Number[] = {
     "Display size of normal vectors (in pixels)" }, 
 
   { F|O, "Optimize" , opt_mesh_optimize , 0. , 
+    "Optimize the mesh to improve the quality of tetrahedral elements" },
+  { F|O, "OptimizeNetgen" , opt_mesh_optimize_netgen , 0. , 
     "Optimize the mesh using Netgen to improve the quality of tetrahedral elements" },
 
   { F|O, "Points" , opt_mesh_points , 0. , 
diff --git a/Common/Options.cpp b/Common/Options.cpp
index 7af769f1e0..f90161a6a1 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -1,4 +1,4 @@
-// $Id: Options.cpp,v 1.368 2007-11-26 14:34:09 remacle Exp $
+// $Id: Options.cpp,v 1.369 2007-11-28 14:18:09 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -4209,6 +4209,17 @@ double opt_mesh_optimize(OPT_ARGS_NUM)
   return CTX.mesh.optimize;
 }
 
+double opt_mesh_optimize_netgen(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX.mesh.optimize =(int) val;
+#if defined(HAVE_FLTK)
+  if(WID && (action & GMSH_GUI))
+    WID->mesh_butt[2]->value(CTX.mesh.optimizeNetgen);
+#endif
+  return CTX.mesh.optimize;
+}
+
 double opt_mesh_refine_steps(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
diff --git a/Common/Options.h b/Common/Options.h
index 864b3aa168..aac39194c4 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -426,6 +426,7 @@ double opt_geometry_snap1(OPT_ARGS_NUM);
 double opt_geometry_snap2(OPT_ARGS_NUM);
 double opt_mesh_label_frequency(OPT_ARGS_NUM);
 double opt_mesh_optimize(OPT_ARGS_NUM);
+double opt_mesh_optimize_netgen(OPT_ARGS_NUM);
 double opt_mesh_refine_steps(OPT_ARGS_NUM);
 double opt_mesh_normals(OPT_ARGS_NUM);
 double opt_mesh_tangents(OPT_ARGS_NUM);
diff --git a/Fltk/Callbacks.cpp b/Fltk/Callbacks.cpp
index 2bc63a6bf1..3e64e74a13 100644
--- a/Fltk/Callbacks.cpp
+++ b/Fltk/Callbacks.cpp
@@ -1,4 +1,4 @@
-// $Id: Callbacks.cpp,v 1.552 2007-10-03 19:40:40 geuzaine Exp $
+// $Id: Callbacks.cpp,v 1.553 2007-11-28 14:18:09 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -1071,6 +1071,7 @@ void mesh_options_ok_cb(CALLBACK_ARGS)
   opt_mesh_reverse_all_normals(0, GMSH_SET, WID->mesh_butt[0]->value());
   opt_mesh_lc_from_curvature(0, GMSH_SET, WID->mesh_butt[1]->value());
   opt_mesh_optimize(0, GMSH_SET, WID->mesh_butt[2]->value());
+  opt_mesh_optimize_netgen(0, GMSH_SET, WID->mesh_butt[24]->value());
   opt_mesh_order(0, GMSH_SET, WID->mesh_value[3]->value());
   opt_mesh_smooth_internal_edges(0, GMSH_SET, WID->mesh_butt[3]->value());
   opt_mesh_second_order_incomplete(0, GMSH_SET, WID->mesh_butt[4]->value());
@@ -3860,6 +3861,20 @@ void mesh_optimize_cb(CALLBACK_ARGS)
   Msg(STATUS2N, " ");
 }
 
+void mesh_optimize_netgen_cb(CALLBACK_ARGS)
+{
+  if(CTX.threads_lock) {
+    Msg(INFO, "I'm busy! Ask me that later...");
+    return;
+  }
+  CTX.threads_lock = 1;
+  OptimizeMeshNetgen(GModel::current());
+  CTX.threads_lock = 0;
+  CTX.mesh.changed = ENT_LINE | ENT_SURFACE | ENT_VOLUME;
+  Draw();
+  Msg(STATUS2N, " ");
+}
+
 
 void mesh_define_length_cb(CALLBACK_ARGS)
 {
diff --git a/Fltk/Callbacks.h b/Fltk/Callbacks.h
index 49b4b14fd7..72ff2afc10 100644
--- a/Fltk/Callbacks.h
+++ b/Fltk/Callbacks.h
@@ -282,6 +282,7 @@ void mesh_update_edges_cb(CALLBACK_ARGS);
 void mesh_parameterize_cb(CALLBACK_ARGS);
 void mesh_degree_cb(CALLBACK_ARGS); 
 void mesh_optimize_cb(CALLBACK_ARGS); 
+void mesh_optimize_netgen_cb(CALLBACK_ARGS); 
 void mesh_classify_cb(CALLBACK_ARGS); 
 void mesh_define_length_cb (CALLBACK_ARGS);
 void mesh_define_recombine_cb (CALLBACK_ARGS);
diff --git a/Fltk/GUI.cpp b/Fltk/GUI.cpp
index e2c30e0844..c4282222c5 100644
--- a/Fltk/GUI.cpp
+++ b/Fltk/GUI.cpp
@@ -1,4 +1,4 @@
-// $Id: GUI.cpp,v 1.644 2007-11-08 19:30:30 geuzaine Exp $
+// $Id: GUI.cpp,v 1.645 2007-11-28 14:18:10 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -288,8 +288,9 @@ Context_Item menu_mesh[] = {
   {"3D",           (Fl_Callback *)mesh_3d_cb} , 
   {"First order",  (Fl_Callback *)mesh_degree_cb, (void*)1 } , 
   {"Second order", (Fl_Callback *)mesh_degree_cb, (void*)2 } , 
+  {"Optimize", (Fl_Callback *)mesh_optimize_cb} , 
 #if defined(HAVE_NETGEN)
-  {"Optimize quality", (Fl_Callback *)mesh_optimize_cb} , 
+  {"Optimize (netgen)", (Fl_Callback *)mesh_optimize_netgen_cb} , 
 #endif
 #if defined(HAVE_FOURIER_MODEL)
   {"Reparameterize",   (Fl_Callback *)mesh_parameterize_cb} , 
@@ -2457,16 +2458,20 @@ void GUI::create_option_window()
 
       mesh_butt[2] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 3 * BH, BW, BH, "Optimize quality of tetrahedra");
       mesh_butt[2]->type(FL_TOGGLE_BUTTON);
+      mesh_butt[2]->callback(mesh_options_ok_cb);
+
+      mesh_butt[24] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 4 * BH, BW, BH, "Optimize quality of tetrahedra with Netgen");
+      mesh_butt[24]->type(FL_TOGGLE_BUTTON);
 #if !defined(HAVE_NETGEN)
-      mesh_butt[2]->deactivate();
+      mesh_butt[24]->deactivate();
 #endif
-      mesh_butt[2]->callback(mesh_options_ok_cb);
+      mesh_butt[24]->callback(mesh_options_ok_cb);
 
-      mesh_butt[3] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 4 * BH, BW, BH, "Optimize high order mesh (only for 2D-plane)");
+      mesh_butt[3] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 5 * BH, BW, BH, "Optimize high order mesh (only for 2D-plane)");
       mesh_butt[3]->type(FL_TOGGLE_BUTTON);
       mesh_butt[3]->callback(mesh_options_ok_cb);
 
-      mesh_butt[21] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 5 * BH, BW, BH, "Impose C1 continuity (only for 2D-plane, order 2 and 3)");
+      mesh_butt[21] = new Fl_Check_Button(L + 2 * WB, 2 * WB + 6 * BH, BW, BH, "Impose C1 continuity (only for 2D-plane, order 2 and 3)");
       mesh_butt[21]->type(FL_TOGGLE_BUTTON);
       mesh_butt[21]->callback(mesh_options_ok_cb);
 
diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp
index f8e6968612..a64bac22a7 100644
--- a/Mesh/Generator.cpp
+++ b/Mesh/Generator.cpp
@@ -1,4 +1,4 @@
-// $Id: Generator.cpp,v 1.126 2007-11-27 16:45:27 geuzaine Exp $
+// $Id: Generator.cpp,v 1.127 2007-11-28 14:18:10 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -307,12 +307,24 @@ void Mesh3D(GModel *m)
   Msg(STATUS1, "Mesh");
 }
 
+void OptimizeMeshNetgen(GModel *m)
+{
+  Msg(STATUS1, "Optimizing 3D with Netgen...");
+  double t1 = Cpu();
+
+  std::for_each(m->firstRegion(), m->lastRegion(), optimizeMeshGRegionNetgen());
+
+  double t2 = Cpu();
+  Msg(INFO, "Mesh 3D optimization with Netgen complete (%g s)", t2 - t1);
+  Msg(STATUS1, "Mesh");
+}
+
 void OptimizeMesh(GModel *m)
 {
   Msg(STATUS1, "Optimizing 3D...");
   double t1 = Cpu();
 
-  std::for_each(m->firstRegion(), m->lastRegion(), optimizeMeshGRegion());
+  std::for_each(m->firstRegion(), m->lastRegion(), optimizeMeshGRegionGmsh());
 
   double t2 = Cpu();
   Msg(INFO, "Mesh 3D optimization complete (%g s)", t2 - t1);
@@ -359,6 +371,9 @@ void GenerateMesh(int ask)
   // Optimize quality
   if(m->getMeshStatus() == 3 && CTX.mesh.optimize)
     OptimizeMesh(m);
+  // Optimize quality with netgen
+  if(m->getMeshStatus() == 3 && CTX.mesh.optimizeNetgen)
+    OptimizeMeshNetgen(m);
   
   // Create high order elements
   if(m->getMeshStatus() && CTX.mesh.order > 1) 
diff --git a/Mesh/Generator.h b/Mesh/Generator.h
index ad54f320e1..a39d30ff9e 100644
--- a/Mesh/Generator.h
+++ b/Mesh/Generator.h
@@ -25,5 +25,6 @@ class GModel;
 void GetStatistics(double stat[50], double quality[3][100]=0);
 void GenerateMesh(int dimension);
 void OptimizeMesh(GModel *m);
+void OptimizeMeshNetgen(GModel *m);
 
 #endif
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index 552f8545e4..0635f2abdd 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -1,4 +1,4 @@
-// $Id: meshGRegion.cpp,v 1.36 2007-11-12 10:41:52 colignon Exp $
+// $Id: meshGRegion.cpp,v 1.37 2007-11-28 14:18:10 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -565,7 +565,7 @@ void meshGRegion::operator() (GRegion *gr)
   }
 }
 
-void optimizeMeshGRegion::operator() (GRegion *gr) 
+void optimizeMeshGRegionNetgen::operator() (GRegion *gr) 
 {  
   if(gr->geomType() == GEntity::DiscreteVolume) return;
   
@@ -594,3 +594,18 @@ void optimizeMeshGRegion::operator() (GRegion *gr)
   Ng_Exit();
 #endif
 }
+
+void optimizeMeshGRegionGmsh::operator() (GRegion *gr) 
+{  
+  if(gr->geomType() == GEntity::DiscreteVolume) return;
+  
+  // don't optimize extruded meshes
+  ExtrudeParams *ep = gr->meshAttributes.extrude;
+  if(ep && ep->mesh.ExtrudeMesh && ep->geo.Mode == EXTRUDED_ENTITY) return;
+  
+  Msg(STATUS2, "Optimizing volume %d", gr->tag());
+  // import mesh into netgen, including volume tets
+  
+  gmshOptimizeMesh (gr, QMTET_2);  
+  
+}
diff --git a/Mesh/meshGRegion.h b/Mesh/meshGRegion.h
index cc9081fb47..6744f4bf6f 100644
--- a/Mesh/meshGRegion.h
+++ b/Mesh/meshGRegion.h
@@ -38,8 +38,14 @@ class meshGRegionExtruded {
   void operator () (GRegion *);
 };
 
-// Optimize the mesh of the region
-class optimizeMeshGRegion {
+// Optimize the mesh of the region using gmsh's algo
+class optimizeMeshGRegionGmsh {
+ public :
+  void operator () (GRegion *);
+};
+
+// Optimize the mesh of the region using netgen's algo
+class optimizeMeshGRegionNetgen {
  public :
   void operator () (GRegion *);
 };
diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp
index 3a13696d0e..16c8064b82 100644
--- a/Mesh/meshGRegionDelaunayInsertion.cpp
+++ b/Mesh/meshGRegionDelaunayInsertion.cpp
@@ -1,4 +1,4 @@
-// $Id: meshGRegionDelaunayInsertion.cpp,v 1.23 2007-11-28 11:47:36 remacle Exp $
+// $Id: meshGRegionDelaunayInsertion.cpp,v 1.24 2007-11-28 14:18:10 remacle Exp $
 //
 // Copyright (C) 1997-2007 C. Geuzaine, J.-F. Remacle
 //
@@ -432,32 +432,53 @@ void recur_classify ( MTet4 *t ,
     }
 }
 
-template <class CONTAINER, class DATA> 
-void gmshOptimizeMesh (CONTAINER &allTets, DATA &vSizes)
+//template <class CONTAINER, class DATA> 
+void gmshOptimizeMesh (GRegion *gr, const gmshQualityMeasure4Tet &qm)
 {
+  typedef std::list<MTet4 *> CONTAINER ;
+  CONTAINER allTets;
+  for (int i=0;i<gr->tetrahedra.size();i++){
+    allTets.push_back(new MTet4(gr->tetrahedra[i],qm));
+  }
+  gr->tetrahedra.clear();
+  
+  connectTets(allTets.begin(),allTets.end());
+
+
+
+
   double t1 = Cpu();
   std::vector<MTet4*> illegals;
   const int nbRanges=10;
   int quality_ranges [nbRanges];
-
-
   {
     double totalVolumeb = 0.0;
     double worst = 1.0;
     double avg = 0;
     int count=0;
-    for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
+    for (int i=0;i<nbRanges;i++)quality_ranges[i] = 0;
+    for (CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
       {
 	if (!(*it)->isDeleted()){
-	  double vol;
-	  double qual = qmTet((*it)->tet(),QMTET_2,&vol);
+	  double vol = fabs((*it)->tet()->getVolume());
+	  double qual = (*it)->getQuality();
 	  worst = std::min(qual,worst);
 	  avg+=qual;
 	  count++;
 	  totalVolumeb+=vol;
+	  for (int i=0;i<nbRanges;i++){
+	    double low  = (double)i/(nbRanges);
+	    double high = (double)(i+1)/(nbRanges);
+	    if (qual >= low && qual < high)quality_ranges[i]++;
+	  }	      	      
 	}
       }
     Msg(INFO,"Opti : START with %12.5E QBAD %12.5E QAVG %12.5E",totalVolumeb,worst,avg/count);
+    for (int i=0;i<nbRanges;i++){
+      double low  = (double)i/(nbRanges);
+      double high = (double)(i+1)/(nbRanges);
+      Msg(INFO,"Opti : %3.2f < QUAL < %3.2f : %9d elements ",low,high,quality_ranges[i]);
+    }	      	      
   }    
     
   double qMin = 0.5;
@@ -466,35 +487,29 @@ void gmshOptimizeMesh (CONTAINER &allTets, DATA &vSizes)
   int nbESwap=0, nbFSwap=0, nbReloc=0;
     
   while (1){
-    std::vector<MTet4*> newTets;
-    
-    // get a bad tet and try to swap each of its edges and faces
-
-    for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it){
+    std::vector<MTet4*> newTets;    
+    for (CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it){
       if (!(*it)->isDeleted()){
 	double vol;
-	double qq = qmTet((*it)->tet(),QMTET_2,&vol);
+	double qq = (*it)->getQuality();
 	if (qq < qMin){
 	  for (int i=0;i<4;i++){
-	    if (gmshFaceSwap(newTets,*it,i,QMTET_2)){nbFSwap++;break;}
+	    if (gmshFaceSwap(newTets,*it,i,qm)){nbFSwap++;break;}
 	  }
 	}
       }
     }
  
-    connectTets(allTets.begin(),allTets.end());
-
     illegals.clear();
     for (int i=0;i<nbRanges;i++)quality_ranges[i] = 0;
 
-    for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
+    for (CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
       {
 	if (!(*it)->isDeleted()){
-	  double vol;
-	  double qq = qmTet((*it)->tet(),QMTET_2,&vol);
+	  double qq = (*it)->getQuality();
 	  if (qq < qMin)
 	    for (int i=0;i<6;i++){
-	      if (gmshEdgeSwap(newTets,*it,i,QMTET_2)) {nbESwap++;break;}
+	      if (gmshEdgeSwap(newTets,*it,i,qm)) {nbESwap++;break;}
 	    }
 	  if (!(*it)->isDeleted()){
 	    if (qq < sliverLimit)illegals.push_back(*it);
@@ -504,29 +519,15 @@ void gmshOptimizeMesh (CONTAINER &allTets, DATA &vSizes)
 	      if (qq >= low && qq < high)quality_ranges[i]++;
 	    }	      	      
 	  }
-	  //	  if (newTets.size())break;
 	}
       }
 
-    // if no new tet is created, leave
-
     if (!newTets.size())break;
     
     // add all the new tets in the container
     for (int i=0;i<newTets.size();i++){
       if (!newTets[i]->isDeleted()){
-	// it was bugged here because the setup fct removes 
-	// the neighbors. Now it seems to work fine
-	MTet4 *t0 = newTets[i]->getNeigh(0);
-	MTet4 *t1 = newTets[i]->getNeigh(1);
-	MTet4 *t2 = newTets[i]->getNeigh(2);
-	MTet4 *t3 = newTets[i]->getNeigh(3);
-	newTets[i]->setup(newTets[i]->tet(),vSizes);
-	newTets[i]->setNeigh(0,t0);
-	newTets[i]->setNeigh(1,t1);
-	newTets[i]->setNeigh(2,t2);
-	newTets[i]->setNeigh(3,t3);
-	allTets.insert(newTets[i]);
+	allTets.push_back(newTets[i]);
       }
       else{
 	delete newTets[i]->tet();
@@ -534,56 +535,14 @@ void gmshOptimizeMesh (CONTAINER &allTets, DATA &vSizes)
       }
     }  
 
-//     int nbNeigh  = 0;
-//     int k =0;
-//     MTet4 *test [10000][4];
-//     for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
-//       {
-// 	if (!(*it)->isDeleted()){
-// 	  for (int i=0;i<4;i++){
-// 	    MTet4 *neigh = (*it)->getNeigh(i);
-// 	    test[k][i] = neigh;
-// 	    if (neigh){
-// 	      nbNeigh++;
-// 	    }
-// 	  }
-// 	  k++;
-// 	}
-//       }
-    
-//     printf("nbNeigh = %d --> ",nbNeigh);
-
-    //    connectTets(allTets.begin(),allTets.end());
-
-//     nbNeigh  = 0;
-//     k = 0;
-//     for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
-//       {
-// 	if (!(*it)->isDeleted()){
-// 	  for (int i=0;i<4;i++){
-// 	    MTet4 *neigh = (*it)->getNeigh(i);
-// 	    if (test[k][i] != neigh)
-// 	      {
-// 		printf("connexion tet %d %p , item %d differs %p %p\n",k,(*it),i,neigh,test[k][i]);
-// 	      }
-// 	    if (neigh){
-// 	      nbNeigh++;
-// 	    }
-// 	  }
-// 	  k++;
-// 	}
-//       }
-    
-//     printf("nbNeigh = %d\n",nbNeigh);
     // relocate vertices
-    for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
+    for (CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
       {
 	if (!(*it)->isDeleted()){
-	  double vol;
-	  double qq = qmTet((*it)->tet(),QMTET_2,&vol);
-	  if (qq < .5)
+	  double qq = (*it)->getQuality();
+	  if (qq < qMin)
 	    for (int i=0;i<4;i++){
-	      if (gmshSmoothVertex(*it,i))nbReloc++;
+	      if (gmshSmoothVertex(*it,i,qm))nbReloc++;
 	    }
 	}
       }
@@ -592,11 +551,11 @@ void gmshOptimizeMesh (CONTAINER &allTets, DATA &vSizes)
     double worst = 1.0;
     double avg = 0;
     int count=0;
-    for (typename CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
+    for (CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
       {
 	if (!(*it)->isDeleted()){
-	  double vol;
-	  double qual = qmTet((*it)->tet(),QMTET_2,&vol);
+	  double vol = fabs((*it)->tet()->getVolume());
+	  double qual = (*it)->getQuality();
 	  worst = std::min(qual,worst);
 	  avg+=qual;
 	  count++;
@@ -623,6 +582,19 @@ void gmshOptimizeMesh (CONTAINER &allTets, DATA &vSizes)
     double high = (double)(i+1)/(nbRanges);
     Msg(INFO,"Opti : %3.2f < QUAL < %3.2f : %9d elements ",low,high,quality_ranges[i]);
   }	      	      
+
+  for (CONTAINER::iterator it = allTets.begin();it!=allTets.end();++it)
+    {
+      if (!(*it)->isDeleted()){
+	gr->tetrahedra.push_back((*it)->tet());
+	delete *it;
+      }
+      else{
+	delete (*it)->tet();
+	delete *it;	
+      }
+    }
+
 }
 
 
@@ -760,7 +732,7 @@ void insertVerticesInRegion (GRegion *gr)
 	  Msg(INFO,"cleaning up the memory %d -> %d ",n1,allTets.size());	  	  
 	}
     }
-  gmshOptimizeMesh (allTets,vSizes);
+
   
   while (1)
     {
diff --git a/Mesh/meshGRegionDelaunayInsertion.h b/Mesh/meshGRegionDelaunayInsertion.h
index 846385298a..d10f0c91de 100644
--- a/Mesh/meshGRegionDelaunayInsertion.h
+++ b/Mesh/meshGRegionDelaunayInsertion.h
@@ -21,6 +21,7 @@
 // Please report all bugs and problems to <gmsh@geuz.org>.
 
 #include "MElement.h"
+#include "qualityMeasures.h"
 #include <list>
 #include <set>
 #include <stack>
@@ -62,10 +63,16 @@ class MTet4
     {
       neigh[0] = neigh[1] = neigh[2] = neigh[3] = 0;
     }
-  MTet4 (MTetrahedron * t) : deleted(false),  gr(0),circum_radius(0.0),base(t)
+  MTet4 (MTetrahedron * t, double qual) : deleted(false),  gr(0),circum_radius(qual),base(t)
   {
     neigh[0] = neigh[1] = neigh[2] = neigh[3] = 0;
   }
+  MTet4 (MTetrahedron * t, const gmshQualityMeasure4Tet &qm) : deleted(false), gr(0),base(t)
+  {
+    neigh[0] = neigh[1] = neigh[2] = neigh[3] = 0;
+    double vol;
+    circum_radius = qmTet(t,qm,&vol);
+  }
 
   void setup ( MTetrahedron * t, std::vector<double> & sizes)
   {
@@ -91,10 +98,9 @@ class MTet4
   
   bool isDeleted () const {return deleted;}
   void   forceRadius (double r){circum_radius=r;}
-  inline double getRadius ()const {return circum_radius;}
-  
-
-
+  inline double getRadius  ()const {return circum_radius;}
+  inline double getQuality ()const {return circum_radius;} 
+  inline double setQuality (const double &q){circum_radius=q;} 
   inline MTetrahedron * tet() const {return base;}
   inline MTetrahedron * &tet() {return base;}
   inline void  setNeigh (int iN , MTet4 *n) {neigh[iN]=n;}
@@ -225,4 +231,6 @@ private:
 
 };
 
+void gmshOptimizeMesh (GRegion *gr, const gmshQualityMeasure4Tet &qm);
+
 #endif
diff --git a/Mesh/meshGRegionLocalMeshMod.cpp b/Mesh/meshGRegionLocalMeshMod.cpp
index 448be11299..e0017a26b5 100644
--- a/Mesh/meshGRegionLocalMeshMod.cpp
+++ b/Mesh/meshGRegionLocalMeshMod.cpp
@@ -203,15 +203,14 @@ bool gmshEdgeSwap (std::vector<MTet4 *> &newTets,
 
   bool closed = gmshBuildEdgeCavity ( tet,iLocalEdge,&v1,&v2,cavity,outside,ring);
 
-
   if (!closed)return false;
   
   double volumeRef = 0.0;
   double tetQualityRef = 1;
   for (int i=0;i<cavity.size();i++){
-    double vol;
-    tetQualityRef = std::min(qmTet (cavity[i]->tet() ,  cr , &vol) , tetQualityRef);
-    volumeRef += fabs(vol);
+    double vol = fabs(cavity[i]->tet()->getVolume());
+    tetQualityRef = std::min(tetQualityRef,cavity[i]->getQuality());
+    volumeRef += vol;
   }
 
   // build swap patterns
@@ -288,8 +287,8 @@ bool gmshEdgeSwap (std::vector<MTet4 *> &newTets,
 					   pv2,
 					   pv1,
 					   v2);
-    MTet4 *t41 = new MTet4 ( tr1 ); 
-    MTet4 *t42 = new MTet4 ( tr2 );
+    MTet4 *t41 = new MTet4 ( tr1 , tetQuality1[iT]); 
+    MTet4 *t42 = new MTet4 ( tr2 , tetQuality2[iT]);
     t41->setOnWhat(cavity[0]->onWhat());
     t42->setOnWhat(cavity[0]->onWhat());
     outside.push_back(t41);
@@ -346,10 +345,10 @@ bool gmshFaceSwap (std::vector<MTet4 *> &newTets,
 
   //  printf("%p %p -- %p %p %p\n",v1,v2,f1,f2,f3);
 
-  double vol1;
-  double q1 = qmTet(t1->tet(),cr,&vol1);
-  double vol2;
-  double q2 = qmTet(t2->tet(),cr,&vol2);
+  double vol1 = fabs(t1->tet()->getVolume());
+  double q1 = t1->getQuality();
+  double vol2 = fabs(t2->tet()->getVolume());
+  double q2 = t2->getQuality();
   
   double vol3;
   double q3 = qmTet(f1,f2,v1,v2,cr,&vol3);
@@ -392,9 +391,9 @@ bool gmshFaceSwap (std::vector<MTet4 *> &newTets,
   MTetrahedron *tr1 = new MTetrahedron ( f1,f2,v1,v2);
   MTetrahedron *tr2 = new MTetrahedron ( f2,f3,v1,v2);
   MTetrahedron *tr3 = new MTetrahedron ( f3,f1,v1,v2);
-  MTet4 *t41 = new MTet4 ( tr1 ); 
-  MTet4 *t42 = new MTet4 ( tr2 );
-  MTet4 *t43 = new MTet4 ( tr3 ); 
+  MTet4 *t41 = new MTet4 ( tr1 , q3); 
+  MTet4 *t42 = new MTet4 ( tr2 , q4);
+  MTet4 *t43 = new MTet4 ( tr3 , q5); 
   t41->setOnWhat(t1->onWhat());
   t42->setOnWhat(t1->onWhat());
   t43->setOnWhat(t1->onWhat());
@@ -446,7 +445,8 @@ void gmshBuildVertexCavity_recur ( MTet4 *t,
 
 
 bool gmshSmoothVertex ( MTet4 *t, 
-			int iVertex){
+			int iVertex,
+			const gmshQualityMeasure4Tet &cr){
   
   if(t->isDeleted())throw;
   if(t->tet()->getVertex(iVertex)->onWhat()->dim() < 3)return false;
@@ -455,14 +455,13 @@ bool gmshSmoothVertex ( MTet4 *t,
   cavity.push_back(t);
   gmshBuildVertexCavity_recur (t,t->tet()->getVertex(iVertex),cavity);
   
-  //  printf("cavity o size %d\n",cavity.size());
-
   double xcg=0,ycg=0,zcg=0;  
   double vTot=0;
   double worst = 1.0;
+
   for (int i=0 ; i< cavity.size() ; i++){
-    double volume;
-    double q = qmTet(cavity[i]->tet(),QMTET_2,&volume);
+    double volume = fabs(cavity[i]->tet()->getVolume());
+    double q = cavity[i]->getQuality();
     worst = std::min(worst,q);
     xcg += 0.25*(cavity[i]->tet()->getVertex(0)->x()+
 		 cavity[i]->tet()->getVertex(1)->x()+
@@ -492,11 +491,13 @@ bool gmshSmoothVertex ( MTet4 *t,
   t->tet()->getVertex(iVertex)->y() = ycg;
   t->tet()->getVertex(iVertex)->z() = zcg;
   double worstAfter = 1.0;
+  double newQuals[2000];
+  if (cavity.size() > 2000) throw;
   for (int i=0 ; i< cavity.size() ; i++){
     double volume;
-    double q = qmTet(cavity[i]->tet(),QMTET_2,&volume);
+    newQuals[i] = qmTet(cavity[i]->tet(),cr,&volume);
     volumeAfter += volume;
-    worstAfter =std::min(worstAfter,q);
+    worstAfter =std::min(worstAfter,newQuals[i]);
   }
 
   if (fabs(volumeAfter-vTot) > 1.e-10 * vTot || worstAfter < worst){
@@ -505,7 +506,14 @@ bool gmshSmoothVertex ( MTet4 *t,
     t->tet()->getVertex(iVertex)->z() = z;
     return false;
   }
-  return true;
+  else{
+    // restore new quality
+    for (int i=0 ; i< cavity.size() ; i++){
+      cavity[i]->setQuality(newQuals[i]);
+    }
+    
+    return true;
+  }
 }
 
 
diff --git a/Mesh/meshGRegionLocalMeshMod.h b/Mesh/meshGRegionLocalMeshMod.h
index cad25536b3..7a4ef0dfc1 100644
--- a/Mesh/meshGRegionLocalMeshMod.h
+++ b/Mesh/meshGRegionLocalMeshMod.h
@@ -32,7 +32,8 @@ bool gmshFaceSwap (std::vector<MTet4 *> &newTets,
 		   int iLocalFace,
 		   const gmshQualityMeasure4Tet &cr);
 bool gmshSmoothVertex ( MTet4 *t, 
-			int iLocalVertex);
+			int iLocalVertex,
+			const gmshQualityMeasure4Tet &cr);
   
 #endif
 
-- 
GitLab