diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index e05057fb1c4567173f900f403f16c21ad944b885..729ac6f88e853f91f1cd6687dc53799481049b71 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -1,3 +1,5 @@
+3.0.3 (June 27, 2017): new element quality measures; Block->Box; minor fixes.
+
 3.0.2 (May 13, 2017): improved handling of meshing constraints and entity
 numbering after boolean operations; improved handling of fast coarseness
 transitions in MeshAdapt; new TIKZ export; small bug fixes.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9ebe2d1c9d9d5edcc66202f41e43071e32002d70..cfa3b2c2d87acc4bb6e6755c25adc13f09c86d73 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -93,7 +93,7 @@ opt(ZIPPER "Enable Zip file compression/decompression" OFF)
 
 set(GMSH_MAJOR_VERSION 3)
 set(GMSH_MINOR_VERSION 0)
-set(GMSH_PATCH_VERSION 2)
+set(GMSH_PATCH_VERSION 3)
 set(GMSH_EXTRA_VERSION "" CACHE STRING "Gmsh extra version string")
 
 set(GMSH_VERSION "${GMSH_MAJOR_VERSION}.${GMSH_MINOR_VERSION}")
diff --git a/Common/Context.h b/Common/Context.h
index 10675fc468bed2b046b7514f55906a0ab747206f..762b7380e327b7b00e29f6d67dea6047411c0dd0 100644
--- a/Common/Context.h
+++ b/Common/Context.h
@@ -279,7 +279,7 @@ class CTX {
     int jpegQuality, jpegSmoothing, geoLabels, geoOnlyPhysicals;
     int text, texAsEquation;
     int gifDither, gifSort, gifInterlace, gifTransparent;
-    int posElementary, posElement, posGamma, posEta, posRho, posDisto;
+    int posElementary, posElement, posGamma, posEta, posSICN, posSIGE, posDisto;
     int compositeWindows, deleteTmpFiles, background;
     int width, height;
     double parameter, parameterFirst, parameterLast, parameterSteps;
diff --git a/Common/CreateFile.cpp b/Common/CreateFile.cpp
index f744e81f1ec5484322bf62cc01199dc48c4b51c5..7ec744426dacf7c2091fc665bf8c63b64f8c7d16 100644
--- a/Common/CreateFile.cpp
+++ b/Common/CreateFile.cpp
@@ -377,10 +377,10 @@ void CreateOutputFile(const std::string &fileName, int format,
   case FORMAT_POS:
     GModel::current()->writePOS
       (name, CTX::instance()->print.posElementary,
-       CTX::instance()->print.posElement, CTX::instance()->print.posGamma,
-       CTX::instance()->print.posEta, CTX::instance()->print.posRho,
-       CTX::instance()->print.posDisto, CTX::instance()->mesh.saveAll,
-       CTX::instance()->mesh.scalingFactor);
+       CTX::instance()->print.posElement,
+       CTX::instance()->print.posSICN, CTX::instance()->print.posSIGE,
+       CTX::instance()->print.posGamma, CTX::instance()->print.posDisto,
+       CTX::instance()->mesh.saveAll, CTX::instance()->mesh.scalingFactor);
     break;
 
   case FORMAT_GEO:
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index 430bee5ec9142a331bce6d6a6233cd27d71df1ca..7dbcb5cf43f9cd03ff9808538adc88debf199417 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1193,8 +1193,9 @@ StringXNumber MeshOptions_Number[] = {
   { F|O, "QualitySup" , opt_mesh_quality_sup , 0.0 ,
     "Only display elements whose quality measure is smaller than QualitySup" },
   { F|O, "QualityType" , opt_mesh_quality_type , 2. ,
-    "Type of quality measure (0=gamma~vol/sum_face/max_edge, "
-    "1=eta~vol^(2/3)/sum_edge^2, 2=rho~min_edge/max_edge)" },
+    "Type of quality measure (0=SICN~signed inverse condition number, "
+    "1=SIGE~signed inverse gradient error, 2=gamma~vol/sum_face/max_edge, "
+    "3=Disto~minJ/maxJ"},
 
   { F|O, "RadiusInf" , opt_mesh_radius_inf , 0.0 ,
     "Only display elements whose longest edge is greater than RadiusInf" },
@@ -1760,9 +1761,12 @@ StringXNumber PrintOptions_Number[] = {
   { F|O, "PostEta" , opt_print_pos_eta , 0. ,
     "Save Eta quality measure in mesh statistics exported as "
     "post-processing views" },
-  { F|O, "PostRho" , opt_print_pos_rho , 0. ,
-    "Save Rho quality measure in mesh statistics exported as "
-    "post-processing views" },
+  { F|O, "PostSICN" , opt_print_pos_SICN , 0. ,
+    "Save SICN (signed inverse condition number) quality measure in mesh "
+    "statistics exported as post-processing views" },
+  { F|O, "PostSICN" , opt_print_pos_SIGE , 0. ,
+    "Save SIGE (signed inverse gradient error) quality measure in mesh "
+    "statistics exported as post-processing views" },
   { F|O, "PostDisto" , opt_print_pos_disto , 0. ,
     "Save Disto quality measure in mesh statistics exported as "
     "post-processing views" },
diff --git a/Common/GmshMessage.cpp b/Common/GmshMessage.cpp
index 24cbce9dc590e99ec85b3886c9e72d041052e5e0..0709a85dbb5597d112dd66ec8adcc9818860a1c0 100644
--- a/Common/GmshMessage.cpp
+++ b/Common/GmshMessage.cpp
@@ -773,10 +773,9 @@ void Msg::ProgressMeter(int n, int N, bool log, const char *fmt, ...)
               (n > N - 1) ? "" : str2);
       fflush(stdout);
     }
-
-#if defined(_OPENMP)
-#pragma omp barrier
-#endif
+    //#if defined(_OPENMP)
+    //#pragma omp barrier
+    //#endif
   }
 }
 
diff --git a/Common/Options.cpp b/Common/Options.cpp
index da06739e14cd8711f6931759f3c73277bab8778d..6e0885b9a97e7c23521e2b42460d713a14e2ced9 100644
--- a/Common/Options.cpp
+++ b/Common/Options.cpp
@@ -9182,11 +9182,18 @@ double opt_print_pos_eta(OPT_ARGS_NUM)
   return CTX::instance()->print.posEta;
 }
 
-double opt_print_pos_rho(OPT_ARGS_NUM)
+double opt_print_pos_SICN(OPT_ARGS_NUM)
 {
   if(action & GMSH_SET)
-    CTX::instance()->print.posRho = (int)val;
-  return CTX::instance()->print.posRho;
+    CTX::instance()->print.posSICN = (int)val;
+  return CTX::instance()->print.posSICN;
+}
+
+double opt_print_pos_SIGE(OPT_ARGS_NUM)
+{
+  if(action & GMSH_SET)
+    CTX::instance()->print.posSIGE = (int)val;
+  return CTX::instance()->print.posSIGE;
 }
 
 double opt_print_pos_disto(OPT_ARGS_NUM)
diff --git a/Common/Options.h b/Common/Options.h
index bdf53ffa1f505f8ea39618e40da62806ca4b66ef..1acf4fd406fdfa04087474ead536ce216374b1d6 100644
--- a/Common/Options.h
+++ b/Common/Options.h
@@ -719,7 +719,8 @@ double opt_print_pos_elementary(OPT_ARGS_NUM);
 double opt_print_pos_element(OPT_ARGS_NUM);
 double opt_print_pos_gamma(OPT_ARGS_NUM);
 double opt_print_pos_eta(OPT_ARGS_NUM);
-double opt_print_pos_rho(OPT_ARGS_NUM);
+double opt_print_pos_SICN(OPT_ARGS_NUM);
+double opt_print_pos_SIGE(OPT_ARGS_NUM);
 double opt_print_pos_disto(OPT_ARGS_NUM);
 double opt_print_gif_dither(OPT_ARGS_NUM);
 double opt_print_gif_sort(OPT_ARGS_NUM);
diff --git a/Fltk/fileDialogs.cpp b/Fltk/fileDialogs.cpp
index b0e7ce1e1c36e328819816fbb2a319dede208f61..7250892adaed22d526919038710c9592c969923d 100644
--- a/Fltk/fileDialogs.cpp
+++ b/Fltk/fileDialogs.cpp
@@ -912,7 +912,7 @@ int meshStatFileDialog(const char *name)
 {
   struct _meshStatFileDialog{
     Fl_Window *window;
-    Fl_Check_Button *b[7];
+    Fl_Check_Button *b[8];
     Fl_Button *ok, *cancel;
   };
   static _meshStatFileDialog *dialog = NULL;
@@ -921,7 +921,7 @@ int meshStatFileDialog(const char *name)
 
   if(!dialog){
     dialog = new _meshStatFileDialog;
-    int h = 3 * WB + 8 * BH, w = 2 * BBB + 3 * WB, y = WB;
+    int h = 3 * WB + 9 * BH, w = 2 * BBB + 3 * WB, y = WB;
     dialog->window = new Fl_Double_Window(w, h, "POS Options");
     dialog->window->box(GMSH_WINDOW_BOX);
     dialog->window->set_modal();
@@ -932,12 +932,14 @@ int meshStatFileDialog(const char *name)
     dialog->b[2] = new Fl_Check_Button
       (WB, y, 2 * BBB + WB, BH, "Print element numbers"); y += BH;
     dialog->b[3] = new Fl_Check_Button
-      (WB, y, 2 * BBB + WB, BH, "Print Gamma quality measure"); y += BH;
+      (WB, y, 2 * BBB + WB, BH, "Print SICN quality measure"); y += BH;
     dialog->b[4] = new Fl_Check_Button
-      (WB, y, 2 * BBB + WB, BH, "Print Eta quality measure"); y += BH;
+      (WB, y, 2 * BBB + WB, BH, "Print SIGE quality measure"); y += BH;
     dialog->b[5] = new Fl_Check_Button
-      (WB, y, 2 * BBB + WB, BH, "Print Rho quality measure"); y += BH;
+      (WB, y, 2 * BBB + WB, BH, "Print Gamma quality measure"); y += BH;
     dialog->b[6] = new Fl_Check_Button
+      (WB, y, 2 * BBB + WB, BH, "Print Eta quality measure"); y += BH;
+    dialog->b[7] = new Fl_Check_Button
       (WB, y, 2 * BBB + WB, BH, "Print Disto quality measure"); y += BH;
     for(int i = 0; i < 6; i++)
       dialog->b[i]->type(FL_TOGGLE_BUTTON);
@@ -950,9 +952,10 @@ int meshStatFileDialog(const char *name)
   dialog->b[0]->value(CTX::instance()->mesh.saveAll ? 1 : 0);
   dialog->b[1]->value(CTX::instance()->print.posElementary ? 1 : 0);
   dialog->b[2]->value(CTX::instance()->print.posElement ? 1 : 0);
-  dialog->b[3]->value(CTX::instance()->print.posGamma ? 1 : 0);
-  dialog->b[4]->value(CTX::instance()->print.posEta ? 1 : 0);
-  dialog->b[5]->value(CTX::instance()->print.posRho ? 1 : 0);
+  dialog->b[3]->value(CTX::instance()->print.posSICN ? 1 : 0);
+  dialog->b[4]->value(CTX::instance()->print.posSIGE ? 1 : 0);
+  dialog->b[5]->value(CTX::instance()->print.posGamma ? 1 : 0);
+  dialog->b[6]->value(CTX::instance()->print.posEta ? 1 : 0);
   dialog->window->show();
 
   while(dialog->window->shown()){
@@ -964,10 +967,13 @@ int meshStatFileDialog(const char *name)
         opt_mesh_save_all(0, GMSH_SET | GMSH_GUI, dialog->b[0]->value() ? 1 : 0);
         opt_print_pos_elementary(0, GMSH_SET | GMSH_GUI, dialog->b[1]->value() ? 1 : 0);
         opt_print_pos_element(0, GMSH_SET | GMSH_GUI, dialog->b[2]->value() ? 1 : 0);
-        opt_print_pos_gamma(0, GMSH_SET | GMSH_GUI, dialog->b[3]->value() ? 1 : 0);
-        opt_print_pos_eta(0, GMSH_SET | GMSH_GUI, dialog->b[4]->value() ? 1 : 0);
-        opt_print_pos_rho(0, GMSH_SET | GMSH_GUI, dialog->b[5]->value() ? 1 : 0);
-        opt_print_pos_disto(0, GMSH_SET | GMSH_GUI, dialog->b[6]->value() ? 1 : 0);
+        opt_print_pos_SICN(0, GMSH_SET | GMSH_GUI,
+                           dialog->b[3]->value() ? 1 : 0);
+        opt_print_pos_SIGE(0, GMSH_SET | GMSH_GUI,
+                           dialog->b[4]->value() ? 1 : 0);
+        opt_print_pos_gamma(0, GMSH_SET | GMSH_GUI, dialog->b[5]->value() ? 1 : 0);
+        opt_print_pos_eta(0, GMSH_SET | GMSH_GUI, dialog->b[6]->value() ? 1 : 0);
+        opt_print_pos_disto(0, GMSH_SET | GMSH_GUI, dialog->b[7]->value() ? 1 : 0);
         CreateOutputFile(name, FORMAT_POS);
         dialog->window->hide();
         return 1;
diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp
index cbd150631e3c0902108d43bba3996fe34660187c..f75ecfbacd3d28d0a62d90077a2d63ffb24ec9b7 100644
--- a/Fltk/graphicWindow.cpp
+++ b/Fltk/graphicWindow.cpp
@@ -2086,8 +2086,7 @@ static std::vector<std::string> getInfoStrings(MElement *ele)
     std::ostringstream sstream;
     sstream.precision(12);
     sstream << " Quality: "
-            << "gamma = " << ele->gammaShapeMeasure() << " "
-            << "rho = " << ele->rhoShapeMeasure();
+            << "gamma = " << ele->gammaShapeMeasure();
     info.push_back(sstream.str());
   }
   {
@@ -2098,6 +2097,14 @@ static std::vector<std::string> getInfoStrings(MElement *ele)
     sstream << " SICN range: " << sICNMin << " " << sICNMax;
     info.push_back(sstream.str());
   }
+  {
+    std::ostringstream sstream;
+    sstream.precision(12);
+    double sIGEMin, sIGEMax;
+    ele->signedInvGradErrorRange(sIGEMin, sIGEMax);
+    sstream << " SIGE range: " << sIGEMin << " " << sIGEMax;
+    info.push_back(sstream.str());
+  }
   {
     std::ostringstream sstream;
     sstream.precision(12);
diff --git a/Fltk/optionWindow.cpp b/Fltk/optionWindow.cpp
index 5f30aa793af0bef8549ecc26b5243e33bacfb214..e2358c070dbbf896caa71cdb692e4f854238cacb 100644
--- a/Fltk/optionWindow.cpp
+++ b/Fltk/optionWindow.cpp
@@ -2518,8 +2518,8 @@ optionWindow::optionWindow(int deltaFontSize)
 
       static Fl_Menu_Item menu_quality_type[] = {
         {"SICN", 0, 0, 0},
+        {"SIGE", 0, 0, 0},
         {"Gamma", 0, 0, 0},
-        {"Rho", 0, 0, 0},
         {"Disto", 0, 0, 0},
         {0}
       };
diff --git a/Fltk/statisticsWindow.cpp b/Fltk/statisticsWindow.cpp
index 7f5e88acd600976d58dc231997b23040a1749989..29364f45086ee459462720522910263ff5fd2bb7 100644
--- a/Fltk/statisticsWindow.cpp
+++ b/Fltk/statisticsWindow.cpp
@@ -18,7 +18,9 @@
 #include "OS.h"
 #include "Field.h"
 
-enum QM_HISTO {QMH_SICN_XY, QMH_SICN_3D, QMH_GAMMA_XY, QMH_GAMMA_3D, QMH_RHO_XY, QMH_RHO_3D};
+enum QM_HISTO {QMH_SICN_XY, QMH_SICN_3D,
+               QMH_GAMMA_XY, QMH_GAMMA_3D,
+               QMH_SIGE_XY, QMH_SIGE_3D};
 
 void statistics_cb(Fl_Widget *w, void *data)
 {
@@ -50,12 +52,12 @@ static void statistics_histogram_cb(Fl_Widget *w, void *data)
     }
     new PView("Gamma", "# Elements", x, y);
   }
-  else if (qmh == QMH_RHO_XY) {
+  else if (qmh == QMH_SIGE_XY) {
     for(int i = 0; i < 100; i++){
-      x.push_back((double)i / 99);
-      y.push_back(FlGui::instance()->stats->quality[2][i]);
+      x.push_back((double)(2*i-99) / 99);
+      y.push_back(FlGui::instance()->stats->quality[3][i]);
     }
-    new PView("Rho", "# Elements", x, y);
+    new PView("SIGE", "# Elements", x, y);
   }
   else {
     std::vector<GEntity*> entities_;
@@ -69,13 +71,13 @@ static void statistics_histogram_cb(Fl_Widget *w, void *data)
           d[e->getNum()].push_back(e->minSICNShapeMeasure());
         else if (qmh == QMH_GAMMA_3D)
           d[e->getNum()].push_back(e->gammaShapeMeasure());
-        else if (qmh == QMH_RHO_3D)
-          d[e->getNum()].push_back(e->rhoShapeMeasure());
+        else if (qmh == QMH_SIGE_3D)
+          d[e->getNum()].push_back(e->minSIGEShapeMeasure());
       }
     }
     std::string name = (qmh == QMH_SICN_3D) ? "SICN" :
                        (qmh == QMH_GAMMA_3D) ? "Gamma" :
-                       (qmh == QMH_RHO_3D) ? "Rho" : "";
+                       (qmh == QMH_SIGE_3D) ? "SIGE" : "";
     new PView(name, "ElementData", GModel::current(), d);
   }
 
@@ -128,8 +130,8 @@ statisticsWindow::statisticsWindow(int deltaFontSize)
       value[num]->tooltip("~ signed inverse condition number"); num++;
       value[num] = new Fl_Output(2 * WB, 2 * WB + 15 * BH, IW, BH, "Gamma");
       value[num]->tooltip("~ inscribed_radius / circumscribed_radius (simplices)"); num++;
-      value[num] = new Fl_Output(2 * WB, 2 * WB + 16 * BH, IW, BH, "Rho");
-      value[num]->tooltip("~ min_edge_length / max_edge_length"); num++;
+      value[num] = new Fl_Output(2 * WB, 2 * WB + 16 * BH, IW, BH, "SIGE");
+      value[num]->tooltip("~ signed inverse error on gradient FE solution"); num++;
 
       for(int i = 0; i < 3; i++){
         int ww = 3 * FL_NORMAL_SIZE;
@@ -141,7 +143,7 @@ statisticsWindow::statisticsWindow(int deltaFontSize)
           (width - ww - 2 * WB, 2 * WB + (14 + i) * BH, ww, BH, "3D");
       }
       static const QM_HISTO qmh0 = QMH_SICN_XY, qmh1 = QMH_SICN_3D, qmh2 = QMH_GAMMA_XY,
-                            qmh3 = QMH_GAMMA_3D, qmh4 = QMH_RHO_XY, qmh5 = QMH_RHO_3D;
+                            qmh3 = QMH_GAMMA_3D, qmh4 = QMH_SIGE_XY, qmh5 = QMH_SIGE_3D;
       butt[0]->callback(statistics_histogram_cb, (void*) &qmh0);
       butt[1]->callback(statistics_histogram_cb, (void*) &qmh1);
       butt[2]->callback(statistics_histogram_cb, (void*) &qmh2);
diff --git a/Fltk/viewButton.cpp b/Fltk/viewButton.cpp
index 36110cfca75235e354075de2bd579c212afcee0f..94af2572a2b25b3604a3e7a4f4894bc37b998881 100644
--- a/Fltk/viewButton.cpp
+++ b/Fltk/viewButton.cpp
@@ -32,7 +32,14 @@ static void view_toggle_cb(Fl_Widget *w, void *data)
   int num = (intptr_t)data;
   viewButton *but = FlGui::instance()->onelab->getViewButton(num);
   if(but){
-    opt_view_visible(num, GMSH_SET, but->value());
+    if(Fl::event_state(FL_SHIFT)){
+      for(int i = 0; i < PView::list.size(); i++){
+        if(i != num) opt_view_visible(i, GMSH_SET | GMSH_GUI, 0);
+        else opt_view_visible(i, GMSH_SET | GMSH_GUI, 1);
+      }
+    }
+    else
+      opt_view_visible(num, GMSH_SET, but->value());
     drawContext::global()->draw();
   }
 }
diff --git a/Geo/GModel.h b/Geo/GModel.h
index b0f99a3b724d2937e9873201fb8016663bf4a8c4..e292adf43f030b3fc9c63415c21ad805693b6038 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -633,8 +633,9 @@ class GModel {
 
   // mesh statistics (saved as a Gmsh post-processing view)
   int writePOS(const std::string &name, bool printElementary,
-               bool printElementNumber, bool printSICN, bool printGamma, bool printRho,
-               bool printDisto, bool saveAll=false, double scalingFactor=1.0);
+               bool printElementNumber, bool printSICN, bool printSIGE,
+               bool printGamma, bool printDisto, bool saveAll=false,
+               double scalingFactor=1.0);
 
   // Stereo lithography format
   int readSTL(const std::string &name, double tolerance=1.e-3);
diff --git a/Geo/GModelIO_POS.cpp b/Geo/GModelIO_POS.cpp
index 10b4fb39a3ad2fd0edc50d9a64f6d6a26ce82016..dfed5982be90e97f84e8a3c9354b09ce597bd951 100644
--- a/Geo/GModelIO_POS.cpp
+++ b/Geo/GModelIO_POS.cpp
@@ -9,8 +9,8 @@
 #include "MElement.h"
 
 int GModel::writePOS(const std::string &name, bool printElementary,
-                     bool printElementNumber, bool printSICN, bool printGamma,
-                     bool printRho, bool printDisto,
+                     bool printElementNumber, bool printSICN, bool printSIGE,
+                     bool printGamma, bool printDisto,
                      bool saveAll, double scalingFactor)
 {
   FILE *fp = Fopen(name.c_str(), "w");
@@ -36,32 +36,29 @@ int GModel::writePOS(const std::string &name, bool printElementary,
   }
   */
 
-  bool f[6] = {printElementary, printElementNumber, printSICN, printGamma, printRho,
-               printDisto};
-
   bool first = true;
   std::string names;
-  if(f[0]){
+  if(printElementary){
     if(first) first = false; else names += ",";
     names += "\"Elementary Entity\"";
   }
-  if(f[1]){
+  if(printElementNumber){
     if(first) first = false; else names += ",";
     names += "\"Element Number\"";
   }
-  if(f[2]){
+  if(printSICN){
     if(first) first = false; else names += ",";
     names += "\"SICN\"";
   }
-  if(f[3]){
+  if(printSIGE){
     if(first) first = false; else names += ",";
-    names += "\"Gamma\"";
+    names += "\"SIGE\"";
   }
-  if(f[4]){
+  if(printGamma){
     if(first) first = false; else names += ",";
-    names += "\"Rho\"";
+    names += "\"Gamma\"";
   }
-  if(f[5]){
+  if(printDisto){
     if(first) first = false; else names += ",";
     names += "\"Disto\"";
   }
@@ -79,7 +76,8 @@ int GModel::writePOS(const std::string &name, bool printElementary,
     if(saveAll || entities[i]->physicals.size())
       for(unsigned int j = 0; j < entities[i]->getNumMeshElements(); j++)
         entities[i]->getMeshElement(j)->writePOS
-          (fp, f[0], f[1], f[2], f[3], f[4], f[5], scalingFactor, entities[i]->tag());
+          (fp, printElementary, printElementNumber, printSICN, printSIGE,
+           printGamma, printDisto, scalingFactor, entities[i]->tag());
   fprintf(fp, "};\n");
 
   fclose(fp);
diff --git a/Geo/GModelVertexArrays.cpp b/Geo/GModelVertexArrays.cpp
index 21bde1de96bd979bbe5a9348fde0d21f525d0f4a..02567d774ba73d1a3bd333482b7ec07ee3e0ec22 100644
--- a/Geo/GModelVertexArrays.cpp
+++ b/Geo/GModelVertexArrays.cpp
@@ -106,9 +106,9 @@ bool isElementVisible(MElement *ele)
     if(CTX::instance()->mesh.qualityType == 3)
       q = ele->distoShapeMeasure();
     else if(CTX::instance()->mesh.qualityType == 2)
-      q = ele->rhoShapeMeasure();
-    else if(CTX::instance()->mesh.qualityType == 1)
       q = ele->gammaShapeMeasure();
+    else if(CTX::instance()->mesh.qualityType == 1)
+      q = ele->minSIGEShapeMeasure();
     else
       q = ele->minSICNShapeMeasure();
     if(q < CTX::instance()->mesh.qualityInf ||
diff --git a/Geo/Geo.cpp b/Geo/Geo.cpp
index e60ec2cd62ae8160da0ab252ed7d68402ccfaae9..8b6a0454c79a34c6edb285cb5ac1492fcae095fa 100644
--- a/Geo/Geo.cpp
+++ b/Geo/Geo.cpp
@@ -2429,6 +2429,7 @@ static void RemoveDegenerateSurfaces()
 	List_Delete (ll);
 	List_Delete (ll2);
       }
+      printf("Deleting Surface %d\n",s->Num);
       DeleteSurface(s->Num);
     }
   }
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index e76d4b04a7c5584cd355b831cb45ca8e69a01887..d71b0ff71dac7da7b3b55debdf944470e000bef8 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -116,16 +116,6 @@ double MElement::maxEdge()
   return m;
 }
 
-double MElement::rhoShapeMeasure()
-{
-  double min = minEdge();
-  double max = maxEdge();
-  if(max)
-    return min / max;
-  else
-    return 0.;
-}
-
 double MElement::maxDistToStraight() const
 {
   const nodalBasis *lagBasis = getFunctionSpace();
@@ -152,7 +142,7 @@ double MElement::maxDistToStraight() const
 double MElement::minIsotropyMeasure(bool knownValid, bool reversedOK)
 {
 #if defined(HAVE_MESH)
-  return jacobianBasedQuality::minIsotropyMeasure(this, knownValid, reversedOK);
+  return jacobianBasedQuality::minICNMeasure(this, knownValid, reversedOK);
 #else
   return 0.;
 #endif
@@ -161,7 +151,7 @@ double MElement::minIsotropyMeasure(bool knownValid, bool reversedOK)
 double MElement::minScaledJacobian(bool knownValid, bool reversedOK)
 {
 #if defined(HAVE_MESH)
-  return jacobianBasedQuality::minScaledJacobian(this, knownValid, reversedOK);
+  return jacobianBasedQuality::minIGEMeasure(this, knownValid, reversedOK);
 #else
   return 0.;
 #endif
@@ -175,7 +165,7 @@ double MElement::specialQuality()
   if (minJ <= 0.) return minJ;
 //  if (minJ < 0 && maxJ >= 0) return minJ/maxJ; // accept -inf as an answer
 //  if (minJ < 0 && maxJ < 0) return -std::numeric_limits<double>::infinity();
-  return jacobianBasedQuality::minIsotropyMeasure(this, true);
+  return jacobianBasedQuality::minICNMeasure(this, true);
 #else
   return 0;
 #endif
@@ -189,7 +179,7 @@ double MElement::specialQuality2()
   if (minJ <= 0.) return minJ;
 //  if (minJ < 0 && maxJ >= 0) return minJ/maxJ; // accept -inf as an answer
 //  if (minJ < 0 && maxJ < 0) return -std::numeric_limits<double>::infinity();
-  return jacobianBasedQuality::minScaledJacobian(this, true);
+  return jacobianBasedQuality::minIGEMeasure(this, true);
 #else
   return 0;
 #endif
@@ -334,6 +324,13 @@ void MElement::signedInvCondNumRange(double &iCNMin, double &iCNMax, GEntity *ge
 #endif
 }
 
+void MElement::signedInvGradErrorRange(double &minSIGE, double &maxSIGE)
+{
+  jacobianBasedQuality::sampleIGEMeasure(this, getPolynomialOrder(),
+                                         minSIGE, maxSIGE);
+  return;
+}
+
 void MElement::getNode(int num, double &u, double &v, double &w) const
 {
   // only for MElements that don't have a lookup table for this
@@ -1135,7 +1132,7 @@ void MElement::writeMSH2(FILE *fp, double version, bool binary, int num,
 }
 
 void MElement::writePOS(FILE *fp, bool printElementary, bool printElementNumber,
-                        bool printSICN, bool printGamma, bool printRho,
+                        bool printSICN, bool printSIGE, bool printGamma,
                         bool printDisto, double scalingFactor, int elementary)
 {
   const char *str = getStringForPOS();
@@ -1169,19 +1166,19 @@ void MElement::writePOS(FILE *fp, bool printElementary, bool printElementNumber,
       fprintf(fp, "%g", sICNMin);
     }
   }
-  if(printGamma){
-    double gamma = gammaShapeMeasure();
+  if(printSIGE){
+    double sIGEMin = minSIGEShapeMeasure();
     for(int i = 0; i < n; i++){
       if(first) first = false; else fprintf(fp, ",");
-      fprintf(fp, "%g", gamma);
-      //fprintf(fp, "%d", getVertex(i)->getNum());
+      fprintf(fp, "%g", sIGEMin);
     }
   }
-  if(printRho){
-    double rho = rhoShapeMeasure();
+  if(printGamma){
+    double gamma = gammaShapeMeasure();
     for(int i = 0; i < n; i++){
       if(first) first = false; else fprintf(fp, ",");
-      fprintf(fp, "%g", rho);
+      fprintf(fp, "%g", gamma);
+      //fprintf(fp, "%d", getVertex(i)->getNum());
     }
   }
   if(printDisto){
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 7fa7470a99a63229ff20e7c51b50bf684b5f1cab..20b7f37ffee9b91ce44b6cb17b833d9015387537 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -199,21 +199,26 @@ class MElement
 
   // get the quality measures
   double skewness();
-  virtual double rhoShapeMeasure();
   virtual double gammaShapeMeasure(){ return 0.; }
   virtual double etaShapeMeasure(){ return 0.; }
-  double distoShapeMeasure()
-  {
-    double jmin, jmax;
-    scaledJacRange(jmin, jmax);
-    return jmin;
-  }
   double minSICNShapeMeasure()
   {
     double sICNMin, sICNMax;
     signedInvCondNumRange(sICNMin, sICNMax);
     return sICNMin;
   }
+  double minSIGEShapeMeasure()
+  {
+    double minSIGE, maxSIGE;
+    signedInvGradErrorRange(minSIGE, maxSIGE);
+    return minSIGE;
+  }
+  double distoShapeMeasure()
+  {
+    double jmin, jmax;
+    scaledJacRange(jmin, jmax);
+    return jmin;
+  }
   double minIsotropyMeasure(bool knownValid = false, bool reversedOk = false);
   double minScaledJacobian(bool knownValid = false, bool reversedOk = false);
   double specialQuality();
@@ -222,6 +227,7 @@ class MElement
   virtual void scaledJacRange(double &jmin, double &jmax, GEntity *ge = 0) const;
   virtual void idealJacRange(double &jmin, double &jmax, GEntity *ge = 0);
   virtual void signedInvCondNumRange(double &iCNMin, double &iCNMax, GEntity *ge = 0);
+  virtual void signedInvGradErrorRange(double &minSIGE, double &maxSIGE);
 
   // get the radius of the inscribed circle/sphere if it exists,
   // otherwise get the minimum radius of all the circles/spheres
@@ -369,7 +375,7 @@ class MElement
                          int parentNum=0, int dom1Num = 0, int dom2Num = 0,
                          std::vector<short> *ghosts=0);
   virtual void writePOS(FILE *fp, bool printElementary, bool printElementNumber,
-                        bool printSICN, bool printGamma, bool printRho,
+                        bool printSICN, bool printSIGE, bool printGamma,
                         bool printDisto,double scalingFactor=1.0, int elementary=1);
   virtual void writeSTL(FILE *fp, bool binary=false, double scalingFactor=1.0);
   virtual void writeVRML(FILE *fp);
diff --git a/Mesh/Generator.cpp b/Mesh/Generator.cpp
index 0b4ddd66a987bba024c8255dc9eba68c2167587a..ac0c7aa834457fb1a1c1389a64329de11b8ea1dd 100644
--- a/Mesh/Generator.cpp
+++ b/Mesh/Generator.cpp
@@ -123,7 +123,7 @@ template<class T>
 static void GetQualityMeasure(std::vector<T*> &ele,
                               double &gamma, double &gammaMin, double &gammaMax,
                               double &minSICN, double &minSICNMin, double &minSICNMax,
-                              double &rho, double &rhoMin, double &rhoMax,
+                              double &minSIGE, double &minSIGEMin, double &minSIGEMax,
                               double quality[3][100])
 {
   for(unsigned int i = 0; i < ele.size(); i++){
@@ -135,14 +135,14 @@ static void GetQualityMeasure(std::vector<T*> &ele,
     minSICN += s;
     minSICNMin = std::min(minSICNMin, s);
     minSICNMax = std::max(minSICNMax, s);
-    double r = ele[i]->rhoShapeMeasure();
-    rho += r;
-    rhoMin = std::min(rhoMin, r);
-    rhoMax = std::max(rhoMax, r);
+    double e = ele[i]->minSIGEShapeMeasure();
+    minSIGE += e;
+    minSIGEMin = std::min(minSIGEMin, e);
+    minSIGEMax = std::max(minSIGEMax, e);
     for(int j = 0; j < 100; j++){
       if(s > (2*j-100) / 100. && s <= (2*j-98) / 100.) quality[0][j]++;
       if(g > j / 100. && g <= (j + 1) / 100.) quality[1][j]++;
-      if(r > j / 100. && r <= (j + 1) / 100.) quality[2][j]++;
+      if(e > (2*j-100) / 100. && e <= (2*j-98) / 100.) quality[2][j]++;
     }
   }
 }
@@ -190,39 +190,45 @@ void GetStatistics(double stat[50], double quality[3][100])
   stat[16] = CTX::instance()->meshTimer[2];
 
   if(quality){
-    for(int i = 0; i < 3; i++)
+    for(int i = 0; i < 4; i++)
       for(int j = 0; j < 100; j++)
         quality[i][j] = 0.;
     double minSICN = 0., minSICNMin = 1., minSICNMax = -1.;
+    double minSIGE = 0., minSIGEMin = 1., minSIGEMax = -1.;
     double gamma = 0., gammaMin = 1., gammaMax = 0.;
-    double rho = 0., rhoMin = 1., rhoMax = 0.;
 
     double N = stat[9] + stat[10] + stat[11] + stat[12] + stat[13];
     if(N){ // if we have 3D elements
       for(GModel::riter it = m->firstRegion(); it != m->lastRegion(); ++it){
         GetQualityMeasure((*it)->tetrahedra, gamma, gammaMin, gammaMax,
-                          minSICN, minSICNMin, minSICNMax, rho, rhoMin, rhoMax, quality);
+                          minSICN, minSICNMin, minSICNMax,
+                          minSIGE, minSIGEMin, minSIGEMax, quality);
         GetQualityMeasure((*it)->hexahedra, gamma, gammaMin, gammaMax,
-                          minSICN, minSICNMin, minSICNMax, rho, rhoMin, rhoMax, quality);
+                          minSICN, minSICNMin, minSICNMax,
+                          minSIGE, minSIGEMin, minSIGEMax, quality);
         GetQualityMeasure((*it)->prisms, gamma, gammaMin, gammaMax,
-                          minSICN, minSICNMin, minSICNMax, rho, rhoMin, rhoMax, quality);
+                          minSICN, minSICNMin, minSICNMax,
+                          minSIGE, minSIGEMin, minSIGEMax, quality);
         GetQualityMeasure((*it)->pyramids, gamma, gammaMin, gammaMax,
-                          minSICN, minSICNMin, minSICNMax, rho, rhoMin, rhoMax, quality);
+                          minSICN, minSICNMin, minSICNMax,
+                          minSIGE, minSIGEMin, minSIGEMax, quality);
       }
     }
     else{ // 2D elements
       N = stat[7] + stat[8];
       for(GModel::fiter it = m->firstFace(); it != m->lastFace(); ++it){
         GetQualityMeasure((*it)->quadrangles, gamma, gammaMin, gammaMax,
-                          minSICN, minSICNMin, minSICNMax, rho, rhoMin, rhoMax, quality);
+                          minSICN, minSICNMin, minSICNMax,
+                          minSIGE, minSIGEMin, minSIGEMax, quality);
         GetQualityMeasure((*it)->triangles, gamma, gammaMin, gammaMax,
-                          minSICN, minSICNMin, minSICNMax, rho, rhoMin, rhoMax, quality);
+                          minSICN, minSICNMin, minSICNMax,
+                          minSIGE, minSIGEMin, minSIGEMax, quality);
       }
     }
     if(N){
       stat[18] = minSICN / N; stat[19] = minSICNMin; stat[20] = minSICNMax;
       stat[21] = gamma / N;   stat[22] = gammaMin;   stat[23] = gammaMax;
-      stat[25] = rho / N;     stat[25] = rhoMin;     stat[26] = rhoMax;
+      stat[24] = minSIGE / N; stat[25] = minSIGEMin; stat[26] = minSIGEMax;
     }
   }
 
diff --git a/Mesh/delaunay3d.cpp b/Mesh/delaunay3d.cpp
index 4681034471aafc50aa4a7074f90229720d64473d..f47a7eb60aa4fe85cb0775351a6f587782139d65 100644
--- a/Mesh/delaunay3d.cpp
+++ b/Mesh/delaunay3d.cpp
@@ -1124,7 +1124,8 @@ void delaunayTrgl (const unsigned int numThreads,
 		   unsigned int Npts,
 		   std::vector<Vert*> assignTo[],
 		   tetContainer &allocator,
-		   edgeContainer *embeddedEdges)
+		   edgeContainer *embeddedEdges,
+		   bool filter)
 {
 #if defined(_VERBOSE)
   double totSearchGlob=0;
diff --git a/Mesh/delaunay3d_private.h b/Mesh/delaunay3d_private.h
index c67f9480d0fc5983d6bd6866f4beaf47cd71c689..0c7871bb8f34db8c4fffdd4e1936d2160c5e80ee 100644
--- a/Mesh/delaunay3d_private.h
+++ b/Mesh/delaunay3d_private.h
@@ -405,7 +405,8 @@ void delaunayTrgl(const unsigned int numThreads,
                   const unsigned int NPTS_AT_ONCE,
                   unsigned int Npts,
                   std::vector<Vert*> assignTo[],
-                  tetContainer &allocator, edgeContainer *embedded = 0);
+                  tetContainer &allocator, edgeContainer *embedded = 0,
+		  bool filter = false);
 void edgeSwapPass (int numThreads, tetContainer &allocator, edgeContainer &embeddedEdges);
 void vertexRelocationPass (int numThreads,   std::vector<Vert*> &v);
 
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index d7da61613f6dab1ccc7cd0874234f8c8be7ce7ce..41d2b7afa3845de83ce7ac55f1eeb51b8e3fbf89 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -2415,7 +2415,7 @@ void deMeshGFace::operator() (GFace *gf)
 }
 
 // for debugging, change value from -1 to -100;
-int debugSurface = -100; //-100;
+int debugSurface = -1; //-100;
 
 void meshGFace::operator() (GFace *gf, bool print)
 {
diff --git a/Mesh/meshGRegionDelaunayInsertion.cpp b/Mesh/meshGRegionDelaunayInsertion.cpp
index 3616c8105757256abc1ae9192195069eb5e334fe..8ea7dfe613a992e8e5da51a59b3fb34b98498e68 100644
--- a/Mesh/meshGRegionDelaunayInsertion.cpp
+++ b/Mesh/meshGRegionDelaunayInsertion.cpp
@@ -433,7 +433,7 @@ void printTets (const char *fn, std::list<MTet4*> &cavity, bool force = false )
       MTet4 *tet = *ittet;
       if (force || !tet->isDeleted()){
         MTetrahedron *t = tet->tet();
-        t->writePOS (f, false,false,false,true,false,false);
+        t->writePOS (f, false,false,false,false,true,false);
       }
       ittet++;
     }
@@ -855,12 +855,16 @@ void optimizeMesh(GRegion *gr, const qmTetrahedron::Measures &qm)
   std::set<MEdge, Less_Edge> allEmbeddedEdges;
   createAllEmbeddedEdges (gr, allEmbeddedEdges);
 
-  // daaaaaaamn slow !!!
-  //  connectTets(allTets.begin(),allTets.end(),allEmbeddedFaces.empty() ? NULL : &allEmbeddedFaces);
+  if (allEmbeddedFaces.empty())
   {
     std::vector<faceXtet> conn;
     connectTets_vector2(allTets, conn);
   }
+  else
+  {
+    // daaaaaaamn slow !!!
+    connectTets(allTets.begin(),allTets.end(),&allEmbeddedFaces);
+  }
 
   double t1 = Cpu();
   std::vector<MTet4*> illegals;
diff --git a/Mesh/meshGRegionRelocateVertex.cpp b/Mesh/meshGRegionRelocateVertex.cpp
index b4711b3f5a8bf0e36f241a9ea9b6daad17bc891d..4f5330e5bf5258f51aed56726486b3ee17c63597 100644
--- a/Mesh/meshGRegionRelocateVertex.cpp
+++ b/Mesh/meshGRegionRelocateVertex.cpp
@@ -27,7 +27,6 @@ static double objective_function (double xi, MVertex *ver,
     else
       //  minQual = std::min((lt[i]->specialQuality()), minQual);
       minQual = std::min(fabs(lt[i]->minSICNShapeMeasure())*.2, minQual);
-//    minQual = std::min(lt[i]->minAnisotropyMeasure(), minQual);
   }
   ver->x() = x;
   ver->y() = y;
diff --git a/Mesh/periodical.cpp b/Mesh/periodical.cpp
index 42e0c92972a70e0c81c86e7e0dcc84ebeb87a489..21833c682cbcf132e462f2bcd2c0c1133aa6a6a7 100644
--- a/Mesh/periodical.cpp
+++ b/Mesh/periodical.cpp
@@ -215,9 +215,9 @@ void voroMetal3D::execute(std::vector<SPoint3>& vertices,std::vector<double>& ra
       *pointer = cell;
       pointers.push_back(pointer);
       generators.push_back(SPoint3(x,y,z));
-	  printf("%d %d (%f,%f,%f)\n",loopA.pid()+1,number+1,x,y,z);
-	  table.insert(std::pair<int,int>(loopA.pid(),number));
-	  number++;
+      //      printf("%d %d (%f,%f,%f)\n",loopA.pid()+1,number+1,x,y,z);
+      table.insert(std::pair<int,int>(loopA.pid(),number));
+      number++;
     }while(loopA.inc());
   }
   else{
@@ -229,9 +229,9 @@ void voroMetal3D::execute(std::vector<SPoint3>& vertices,std::vector<double>& ra
       *pointer = cell;
       pointers.push_back(pointer);
       generators.push_back(SPoint3(x,y,z));
-	  printf("%d %d (%f,%f,%f)\n",loopB.pid()+1,number+1,x,y,z);
-	  table.insert(std::pair<int,int>(loopB.pid(),number));
-	  number++;
+      //	  printf("%d %d (%f,%f,%f)\n",loopB.pid()+1,number+1,x,y,z);
+      table.insert(std::pair<int,int>(loopB.pid(),number));
+      number++;
     }while(loopB.inc());
   }
 
@@ -257,7 +257,7 @@ void voroMetal3D::execute(std::vector<SPoint3>& vertices,std::vector<double>& ra
     }
   }
 
-  printf("\nSquared root of smallest face area : %.9f\n\n",sqrt(min_area));
+  //  printf("\nSquared root of smallest face area : %.9f\n\n",sqrt(min_area));
 
   std::ofstream file("MicrostructurePolycrystal3D.pos");
   file << "View \"test\" {\n";
@@ -407,6 +407,8 @@ int voroMetal3D::get_counter(){
 }
 
 void voroMetal3D::print_geo_point(int index,double x,double y,double z,std::ofstream& file){
+  file.precision(17);
+
   file << "Point(" << index << ")={"
   << x << "," << y << "," << z
   << ",c};\n";
@@ -707,11 +709,12 @@ void voroMetal3D::correspondance(double e, double xMax, double yMax, double zMax
 
   file << "};\n";
 
-  printf("\nNumber of exterior face periodicities : %d\n",2*count);
-  printf("Total number of exterior faces : %zu\n\n",faces.size());
+  //  printf("\nNumber of exterior face periodicities : %d\n",2*count);
+  //  printf("Total number of exterior faces : %zu\n\n",faces.size());
 
   std::ofstream file3;
   file3.open("MicrostructurePolycrystal3D.geo",std::ios::out | std::ios::app);
+  file3.precision(17);
 
   std::ofstream file4("MicrostructurePolycrystal3D2.pos");
   file4 << "View \"test\" {\n";
@@ -733,6 +736,24 @@ void voroMetal3D::correspondance(double e, double xMax, double yMax, double zMax
     gf1 = pairs[i].first;
     gf2 = pairs[i].second;
 
+    std::list<GVertex*> gv1 = gf1->vertices(); 
+    std::list<GVertex*> gv2 = gf2->vertices(); 
+
+    std::list<GVertex*>::iterator it1 = gv1.begin();
+    std::list<GVertex*>::iterator it2 = gv2.begin();
+
+    SPoint3 cg1 (0,0,0);
+    SPoint3 cg2 (0,0,0);
+    
+    for (; it1 != gv1.end(); it1++,it2++){
+      cg1 += SPoint3((*it1)->x(),(*it1)->y(),(*it1)->z());
+      cg2 += SPoint3((*it2)->x(),(*it2)->y(),(*it2)->z());
+    }
+
+    SVector3 dx = (cg2-cg1) * (1./gv1.size());
+    
+    //    printf("%g %g %g\n",dx.x(),dx.y(),dx.z());
+        
     edges1 = gf1->edges();
     edges2 = gf2->edges();
 
@@ -837,7 +858,7 @@ void voroMetal3D::correspondance(double e, double xMax, double yMax, double zMax
     if(indices1.size()!=indices2.size()){
       printf("Error\n\n");
     }
-
+    /*
     file3 << "Periodic Surface " << gf1->tag() << " {";
 
     for(j=0;j<indices1.size();j++){
@@ -852,6 +873,12 @@ void voroMetal3D::correspondance(double e, double xMax, double yMax, double zMax
     }
 
     file3 << "};\n";
+    */
+
+    
+    file3 << "Periodic Surface {" << gf1->tag() << " }={ " << gf2->tag() << " } Translate { " << -dx.x() << "," << -dx.y() << "," << -dx.z() << "};\n"; 
+
+    
   }
 
   file4 << "};\n";
diff --git a/Mesh/qualityMeasuresJacobian.cpp b/Mesh/qualityMeasuresJacobian.cpp
index 81c82855b25d85d7248832da8b75f9528dd32ce8..97eb1da16e508001473a02a6e1d30d1e91510fe8 100644
--- a/Mesh/qualityMeasuresJacobian.cpp
+++ b/Mesh/qualityMeasuresJacobian.cpp
@@ -15,21 +15,162 @@
 #include <iomanip>
 #include "pointsGenerators.h"
 #include "OS.h"
-#define TMBEG(n, what) static int I##n = 0, IND##n = _CoeffDataAnisotropy::mytimes.size(); \
-if (++I##n == 1) { \
-  Msg::Info("Time%d = "#what, IND##n); \
-  _CoeffDataAnisotropy::mytimes.push_back(0); \
-  _CoeffDataAnisotropy::mynumbers.push_back(0); \
-} \
-_CoeffDataAnisotropy::mynumbers[IND##n] += 1; \
-double TM##n = Cpu();
-#define TMEND(n) _CoeffDataAnisotropy::mytimes[IND##n] += Cpu() - TM##n;
 
-namespace jacobianBasedQuality {
+static const double cTri = 2/std::sqrt(3);
+static const double cTet = std::sqrt(2);
+static const double cPyr = std::sqrt(2);
+
+static inline void computeCoeffLengthVectors_(const fullMatrix<double> &mat,
+                                              fullMatrix<double> &coeff,
+                                              int type, int numCoeff = -1)
+{
+  int sz1 = numCoeff > -1 ? numCoeff : mat.size1();
 
-double _CoeffDataScaledJac::cTri = 2/std::sqrt(3);
-double _CoeffDataScaledJac::cTet = std::sqrt(2);
-double _CoeffDataScaledJac::cPyr = std::sqrt(2);
+  switch (type) {
+    case TYPE_QUA: coeff.resize(sz1, 2); break;
+    case TYPE_TRI: coeff.resize(sz1, 3); break;
+    case TYPE_HEX: coeff.resize(sz1, 3); break;
+    case TYPE_PRI: coeff.resize(sz1, 4); break;
+    case TYPE_TET: coeff.resize(sz1, 6); break;
+    case TYPE_PYR: coeff.resize(sz1, 6); break;
+    default:
+      Msg::Error("Unkown type for IGE computation");
+      coeff.resize(0, 0);
+      return;
+  }
+
+  if (type != TYPE_PYR) {
+    for (int i = 0; i < sz1; i++) {
+      coeff(i, 0) = std::sqrt(pow_int(mat(i, 0), 2) +
+                              pow_int(mat(i, 1), 2) +
+                              pow_int(mat(i, 2), 2)  );
+      coeff(i, 1) = std::sqrt(pow_int(mat(i, 3), 2) +
+                              pow_int(mat(i, 4), 2) +
+                              pow_int(mat(i, 5), 2)  );
+    }
+    if (mat.size2() > 6) { // if 3D
+      for (int i = 0; i < sz1; i++) {
+        coeff(i, 2) = std::sqrt(pow_int(mat(i, 6), 2) +
+                                pow_int(mat(i, 7), 2) +
+                                pow_int(mat(i, 8), 2)  );
+      }
+    }
+    else if (type == TYPE_TRI) {
+      for (int i = 0; i < sz1; i++) {
+        coeff(i, 2) = std::sqrt(pow_int(mat(i, 3) - mat(i, 0), 2) +
+                                pow_int(mat(i, 4) - mat(i, 1), 2) +
+                                pow_int(mat(i, 5) - mat(i, 2), 2)  );
+      }
+    }
+    switch (type) {
+      case TYPE_TET:
+      case TYPE_PRI:
+        for (int i = 0; i < sz1; i++) {
+          coeff(i, 3) = std::sqrt(pow_int(mat(i, 3) - mat(i, 0), 2) +
+                                  pow_int(mat(i, 4) - mat(i, 1), 2) +
+                                  pow_int(mat(i, 5) - mat(i, 2), 2)  );
+        }
+    }
+    if (type == TYPE_TET) {
+      for (int i = 0; i < sz1; i++) {
+        coeff(i, 4) = std::sqrt(pow_int(mat(i, 6) - mat(i, 0), 2) +
+                                pow_int(mat(i, 7) - mat(i, 1), 2) +
+                                pow_int(mat(i, 8) - mat(i, 2), 2)  );
+        coeff(i, 5) = std::sqrt(pow_int(mat(i, 6) - mat(i, 3), 2) +
+                                pow_int(mat(i, 7) - mat(i, 4), 2) +
+                                pow_int(mat(i, 8) - mat(i, 5), 2)  );
+      }
+    }
+  }
+  else {
+    for (int i = 0; i < sz1; i++) {
+      coeff(i, 0) = std::sqrt(pow_int(2*mat(i, 0), 2) +
+                              pow_int(2*mat(i, 1), 2) +
+                              pow_int(2*mat(i, 2), 2)  );
+      coeff(i, 1) = std::sqrt(pow_int(2*mat(i, 3), 2) +
+                              pow_int(2*mat(i, 4), 2) +
+                              pow_int(2*mat(i, 5), 2)  );
+      coeff(i, 2) = std::sqrt(pow_int(mat(i, 6) + mat(i, 0) + mat(i, 3), 2) +
+                              pow_int(mat(i, 7) + mat(i, 1) + mat(i, 4), 2) +
+                              pow_int(mat(i, 8) + mat(i, 2) + mat(i, 5), 2)  );
+      coeff(i, 3) = std::sqrt(pow_int(mat(i, 6) - mat(i, 0) + mat(i, 3), 2) +
+                              pow_int(mat(i, 7) - mat(i, 1) + mat(i, 4), 2) +
+                              pow_int(mat(i, 8) - mat(i, 2) + mat(i, 5), 2)  );
+      coeff(i, 4) = std::sqrt(pow_int(mat(i, 6) - mat(i, 0) - mat(i, 3), 2) +
+                              pow_int(mat(i, 7) - mat(i, 1) - mat(i, 4), 2) +
+                              pow_int(mat(i, 8) - mat(i, 2) - mat(i, 5), 2)  );
+      coeff(i, 5) = std::sqrt(pow_int(mat(i, 6) + mat(i, 0) - mat(i, 3), 2) +
+                              pow_int(mat(i, 7) + mat(i, 1) - mat(i, 4), 2) +
+                              pow_int(mat(i, 8) + mat(i, 2) - mat(i, 5), 2)  );
+    }
+  }
+}
+
+static inline void computeIGE_(const fullVector<double> &det,
+                               const fullMatrix<double> &v,
+                               fullVector<double> &ige,
+                               int type)
+{
+  int sz = std::min(det.size(), v.size1());
+  ige.resize(sz);
+
+  switch(type) {
+    case TYPE_QUA:
+      for (int i = 0; i < sz; i++) {
+        ige(i) = det(i)/v(i, 0)/v(i, 1);
+      }
+      break;
+    case TYPE_HEX:
+      for (int i = 0; i < sz; i++) {
+        ige(i) = det(i)/v(i, 0)/v(i, 1)/v(i, 2);
+      }
+      break;
+    case TYPE_TRI:
+      for (int i = 0; i < sz; i++) {
+        ige(i) = cTri * det(i) * (1/v(i,0)/v(i,1) +
+                                  1/v(i,0)/v(i,2) +
+                                  1/v(i,1)/v(i,2)) / 3;
+      }
+      break;
+    case TYPE_PRI:
+      for (int i = 0; i < sz; i++) {
+        ige(i) = cTri * det(i) * (1/v(i,0)/v(i,1)/v(i,2) +
+                                  1/v(i,0)/v(i,3)/v(i,2) +
+                                  1/v(i,1)/v(i,3)/v(i,2)) / 3;
+      }
+      break;
+    case TYPE_TET:
+      for (int i = 0; i < sz; i++) {
+        ige(i) = cTet * det(i) * (1/v(i,0)/v(i,5)/v(i,1) +
+                                  1/v(i,0)/v(i,5)/v(i,2) +
+                                  1/v(i,0)/v(i,5)/v(i,3) +
+                                  1/v(i,0)/v(i,5)/v(i,4) +
+                                  1/v(i,1)/v(i,4)/v(i,0) +
+                                  1/v(i,1)/v(i,4)/v(i,2) +
+                                  1/v(i,1)/v(i,4)/v(i,3) +
+                                  1/v(i,1)/v(i,4)/v(i,5) +
+                                  1/v(i,2)/v(i,3)/v(i,0) +
+                                  1/v(i,2)/v(i,3)/v(i,1) +
+                                  1/v(i,2)/v(i,3)/v(i,4) +
+                                  1/v(i,2)/v(i,3)/v(i,5))/ 12;
+      }
+      break;
+    case TYPE_PYR:
+      for (int i = 0; i < sz; i++) {
+        ige(i) = cPyr * det(i) * (1/v(i,0)/v(i,1)/v(i,2) +
+                                  1/v(i,0)/v(i,1)/v(i,3) +
+                                  1/v(i,0)/v(i,1)/v(i,4) +
+                                  1/v(i,0)/v(i,1)/v(i,5) +
+                                  1/v(i,2)/v(i,3)/v(i,4) +
+                                  1/v(i,2)/v(i,3)/v(i,5) +
+                                  1/v(i,4)/v(i,5)/v(i,2) +
+                                  1/v(i,4)/v(i,5)/v(i,3)  ) / 8;
+      }
+      break;
+  }
+}
+
+namespace jacobianBasedQuality {
 
 void minMaxJacobianDeterminant(MElement *el, double &min, double &max,
                                const fullMatrix<double> *normals)
@@ -65,10 +206,12 @@ void minMaxJacobianDeterminant(MElement *el, double &min, double &max,
   }
 }
 
-double minScaledJacobian(MElement *el, bool knownValid, bool reversedOk)
+double minIGEMeasure(MElement *el, bool knownValid, bool reversedOk)
 {
   bool isReversed = false;
   if (!knownValid) {
+    // Computation of the measure should never
+    // be performed to invalid elements (for which the measure is 0).
     double jmin, jmax;
     minMaxJacobianDeterminant(el, jmin, jmax);
     if (jmax < 0) {
@@ -77,8 +220,6 @@ double minScaledJacobian(MElement *el, bool knownValid, bool reversedOk)
     }
     else if (jmin <= 0) return 0;
   }
-  // Computation of the minimum (or maximum) of the scaled Jacobian should never
-  // be performed to invalid elements (for which the measure is 0).
 
   fullMatrix<double> nodesXYZ(el->getNumVertices(), 3);
   el->getNodesCoord(nodesXYZ);
@@ -113,7 +254,7 @@ double minScaledJacobian(MElement *el, bool knownValid, bool reversedOk)
     jacDetSpace = FuncSpaceData(el, false, jacOrder, jacOrder-3, &serendipFalse);
     break;
   default:
-    Msg::Error("Scaled Jacobian not implemented for type of element %d", el->getType());
+    Msg::Error("IGE measure not implemented for type of element %d", el->getType());
     return -1;
   }
   gradBasis = BasisFactory::getGradientBasis(jacMatSpace);
@@ -142,7 +283,7 @@ double minScaledJacobian(MElement *el, bool knownValid, bool reversedOk)
 
   std::vector<_CoeffData*> domains;
   domains.push_back(
-      new _CoeffDataScaledJac(coeffDetBez, coeffMatBez, jacBasis->getBezier(),
+      new _CoeffDataIGE(coeffDetBez, coeffMatBez, jacBasis->getBezier(),
                               gradBasis->getBezier(), 0, el->getType())
   );
 
@@ -164,12 +305,14 @@ double minScaledJacobian(MElement *el, bool knownValid, bool reversedOk)
   return min;
 }
 
-double minIsotropyMeasure(MElement *el,
-                          bool knownValid,
-                          bool reversedOk)
+double minICNMeasure(MElement *el,
+                     bool knownValid,
+                     bool reversedOk)
 {
   bool isReversed = false;
   if (!knownValid) {
+    // Computation of the measure should never
+    // be performed to invalid elements (for which the measure is 0).
     double jmin, jmax;
     minMaxJacobianDeterminant(el, jmin, jmax);
     if (jmax < 0) {
@@ -178,8 +321,6 @@ double minIsotropyMeasure(MElement *el,
     }
     else if (jmin <= 0) return 0;
   }
-  // Computation of the minimum (or maximum) of the scaled Jacobian should never
-  // be performed to invalid elements (for which the measure is 0).
 
   fullMatrix<double> nodesXYZ(el->getNumVertices(), 3);
   el->getNodesCoord(nodesXYZ);
@@ -214,7 +355,7 @@ double minIsotropyMeasure(MElement *el,
     jacDetSpace = FuncSpaceData(el, false, jacOrder, jacOrder-3, &serendipFalse);
     break;
   default:
-    Msg::Error("Isotropy not implemented for type of element %d", el->getType());
+    Msg::Error("ICN not implemented for type of element %d", el->getType());
     return -1;
   }
   gradBasis = BasisFactory::getGradientBasis(jacMatSpace);
@@ -243,7 +384,7 @@ double minIsotropyMeasure(MElement *el,
 
   std::vector<_CoeffData*> domains;
   domains.push_back(
-      new _CoeffDataIsotropy(coeffDetBez, coeffMatBez, jacBasis->getBezier(),
+      new _CoeffDataICN(coeffDetBez, coeffMatBez, jacBasis->getBezier(),
                              gradBasis->getBezier(), 0)
   );
 
@@ -263,25 +404,59 @@ double minIsotropyMeasure(MElement *el,
   return min;
 }
 
-//double minSampledAnisotropyMeasure(MElement *el, int deg, bool writeInFile)//fordebug
-//{
-//  fullMatrix<double> samplingPoints;
-//  bool serendip = false;
-//  gmshGeneratePoints(FuncSpaceData(el, deg, &serendip), samplingPoints);
-//
-//  double values[3];
-//  double min = std::numeric_limits<double>::infinity();
-//  for (int i = 0; i < samplingPoints.size1(); ++i) {
-//    min = std::min(min, el->getEigenvaluesMetric(samplingPoints(i, 0),
-//                                                 samplingPoints(i, 1),
-//                                                 samplingPoints(i, 2),
-//                                                 values));
-//  }
-//
-//  return min;
-//}
+void sampleIGEMeasure(MElement *el, int deg, double &min, double &max)
+{
+  fullMatrix<double> nodesXYZ(el->getNumVertices(), 3);
+  el->getNodesCoord(nodesXYZ);
+
+  const bool serendipFalse = false;
+  FuncSpaceData jacMatSpace, jacDetSpace;
+
+  const int type = el->getType();
+  switch(type) {
+  case TYPE_TRI:
+  case TYPE_TET:
+  case TYPE_QUA:
+  case TYPE_HEX:
+  case TYPE_PRI:
+    jacMatSpace = FuncSpaceData(el, deg, &serendipFalse);
+    jacDetSpace = FuncSpaceData(el, deg, &serendipFalse);
+    break;
+  case TYPE_PYR:
+    jacMatSpace = FuncSpaceData(el, true, deg-1, 1, &serendipFalse);
+    jacDetSpace = FuncSpaceData(el, true, deg-1, 1, &serendipFalse);
+    break;
+  default:
+    Msg::Error("ICN not implemented for type of element %d", el->getType());
+    return;
+  }
+
+  const GradientBasis *gradBasis = BasisFactory::getGradientBasis(jacMatSpace);
+  const JacobianBasis *jacBasis = BasisFactory::getJacobianBasis(jacDetSpace);
+
+  fullVector<double> coeffDeterminant(jacBasis->getNumJacNodes());
+  jacBasis->getSignedJacobian(nodesXYZ, coeffDeterminant);
+
+  fullMatrix<double> coeffMatLag(gradBasis->getNumSamplingPoints(), 9);
+  gradBasis->getAllGradientsFromNodes(nodesXYZ, coeffMatLag);
+
+  fullMatrix<double> v;
+  computeCoeffLengthVectors_(coeffMatLag, v, type);
 
-double minSampledIsotropyMeasure(MElement *el, int deg, bool writeInFile)//fordebug
+  fullVector<double> ige;
+  computeIGE_(coeffDeterminant, v, ige, type);
+
+  min = std::numeric_limits<double>::infinity();
+  max = -min;
+  for (int i = 0; i < ige.size(); ++i) {
+    min = std::min(min, ige(i));
+    max = std::max(max, ige(i));
+  }
+
+  return;
+}
+
+double minSampledICNMeasure(MElement *el, int deg)//fordebug
 {
   fullMatrix<double> nodesXYZ(el->getNumVertices(), 3);
   el->getNodesCoord(nodesXYZ);
@@ -310,7 +485,7 @@ double minSampledIsotropyMeasure(MElement *el, int deg, bool writeInFile)//forde
 //    jacDetSpace = FuncSpaceData(el, false, jacOrder, jacOrder-3, &serendipFalse);
     break;
   default:
-    Msg::Error("Isotropy not implemented for type of element %d", el->getType());
+    Msg::Error("ICN not implemented for type of element %d", el->getType());
     return -1;
   }
   gradBasis = BasisFactory::getGradientBasis(jacMatSpace);
@@ -340,7 +515,7 @@ double minSampledIsotropyMeasure(MElement *el, int deg, bool writeInFile)//forde
   return min;
 }
 
-double minSampledScaledJacobian(MElement *el, int deg, bool writeInFile)//fordebug
+double minSampledIGEMeasure(MElement *el, int deg)//fordebug
 {
   fullMatrix<double> nodesXYZ(el->getNumVertices(), 3);
   el->getNodesCoord(nodesXYZ);
@@ -369,7 +544,7 @@ double minSampledScaledJacobian(MElement *el, int deg, bool writeInFile)//fordeb
 //    jacDetSpace = FuncSpaceData(el, false, jacOrder, jacOrder-3, &serendipFalse);
     break;
   default:
-    Msg::Error("Isotropy not implemented for type of element %d", el->getType());
+    Msg::Error("ICN not implemented for type of element %d", el->getType());
     return -1;
   }
   gradBasis = BasisFactory::getGradientBasis(jacMatSpace);
@@ -469,8 +644,8 @@ void _CoeffDataJac::getSubCoeff(std::vector<_CoeffData*> &v) const
   }
 }
 
-// Scaled Jacobian (quality of quads and hexes)
-_CoeffDataScaledJac::_CoeffDataScaledJac(fullVector<double> &det,
+// IGE measure (Inverse Gradient Error)
+_CoeffDataIGE::_CoeffDataIGE(fullVector<double> &det,
                                          fullMatrix<double> &mat,
                                          const bezierBasis *bfsDet,
                                          const bezierBasis *bfsMat,
@@ -480,7 +655,7 @@ _CoeffDataScaledJac::_CoeffDataScaledJac(fullVector<double> &det,
   _bfsDet(bfsDet), _bfsMat(bfsMat), _type(type)
 {
   if (!det.getOwnData() || !mat.getOwnData()) {
-    Msg::Fatal("Cannot create an instance of _CoeffDataScaledJac from a "
+    Msg::Fatal("Cannot create an instance of _CoeffDataIGE from a "
                "fullVector or a fullMatrix that does not own its data.");
   }
   // _coeffsJacDet and _coeffsJacMat reuse data, this avoid to allocate new
@@ -499,13 +674,13 @@ _CoeffDataScaledJac::_CoeffDataScaledJac(fullVector<double> &det,
   // computation of _maxB not implemented for now
 }
 
-bool _CoeffDataScaledJac::boundsOk(double minL, double maxL) const
+bool _CoeffDataIGE::boundsOk(double minL, double maxL) const
 {
   static double tol = 1e-3;
   return minL - _minB < tol;
 }
 
-void _CoeffDataScaledJac::getSubCoeff(std::vector<_CoeffData*> &v) const
+void _CoeffDataIGE::getSubCoeff(std::vector<_CoeffData*> &v) const
 {
   v.clear();
   v.reserve(_bfsDet->getNumDivision());
@@ -522,74 +697,30 @@ void _CoeffDataScaledJac::getSubCoeff(std::vector<_CoeffData*> &v) const
     fullMatrix<double> coeffM(szM1, szM2);
     coeffD.copy(subCoeffD, i * szD, szD, 0);
     coeffM.copy(subCoeffM, i * szM1, szM1, 0, szM2, 0, 0);
-    _CoeffDataScaledJac *newData;
-    newData = new _CoeffDataScaledJac(coeffD, coeffM, _bfsDet, _bfsMat,
+    _CoeffDataIGE *newData;
+    newData = new _CoeffDataIGE(coeffD, coeffM, _bfsDet, _bfsMat,
                                       _depth+1, _type);
     v.push_back(newData);
   }
 }
 
-void _CoeffDataScaledJac::_computeAtCorner(double &min, double &max) const
+void _CoeffDataIGE::_computeAtCorner(double &min, double &max) const
 {
-  min = std::numeric_limits<double>::infinity();
-  max = -min;
-
   fullMatrix<double> v;
-  _getCoeffLengthVectors(v, true);
+  computeCoeffLengthVectors_(_coeffsJacMat, v, _type, _bfsDet->getNumLagCoeff());
 
-  for (int i = 0; i < _bfsDet->getNumLagCoeff(); i++) {
-    double sJ;
-    switch(_type) {
-    case TYPE_QUA:
-      sJ =  _coeffsJacDet(i)/v(i, 0)/v(i,1);
-      break;
-    case TYPE_HEX:
-      sJ = _coeffsJacDet(i)/v(i,0)/v(i,1)/v(i,2);
-      break;
-    case TYPE_TRI:
-      sJ = cTri * _coeffsJacDet(i) * (1/v(i,0)/v(i,1) +
-                                      1/v(i,0)/v(i,2) +
-                                      1/v(i,1)/v(i,2)) / 3;
-      break;
-    case TYPE_TET:
-      sJ = cTet * _coeffsJacDet(i) * (1/v(i,0)/v(i,5)/v(i,1) +
-                                      1/v(i,0)/v(i,5)/v(i,2) +
-                                      1/v(i,0)/v(i,5)/v(i,3) +
-                                      1/v(i,0)/v(i,5)/v(i,4) +
-                                      1/v(i,1)/v(i,4)/v(i,0) +
-                                      1/v(i,1)/v(i,4)/v(i,2) +
-                                      1/v(i,1)/v(i,4)/v(i,3) +
-                                      1/v(i,1)/v(i,4)/v(i,5) +
-                                      1/v(i,2)/v(i,3)/v(i,0) +
-                                      1/v(i,2)/v(i,3)/v(i,1) +
-                                      1/v(i,2)/v(i,3)/v(i,4) +
-                                      1/v(i,2)/v(i,3)/v(i,5)) / 12;
-      break;
-    case TYPE_PRI:
-      sJ = cTri * _coeffsJacDet(i) * (1/v(i,0)/v(i,1)/v(i,2) +
-                                      1/v(i,0)/v(i,3)/v(i,2) +
-                                      1/v(i,1)/v(i,3)/v(i,2)) / 3;
-      break;
-    case TYPE_PYR:
-      sJ = cPyr * _coeffsJacDet(i) * (1/v(i,0)/v(i,1)/v(i,2) +
-                                      1/v(i,0)/v(i,1)/v(i,3) +
-                                      1/v(i,0)/v(i,1)/v(i,4) +
-                                      1/v(i,0)/v(i,1)/v(i,5) +
-                                      1/v(i,2)/v(i,3)/v(i,4) +
-                                      1/v(i,2)/v(i,3)/v(i,5) +
-                                      1/v(i,4)/v(i,5)/v(i,2) +
-                                      1/v(i,4)/v(i,5)/v(i,3)  ) / 8;
-      break;
-    default:
-      Msg::Error("Unkown type for scaled jac computation");
-      return;
-    }
-    min = std::min(min, sJ);
-    max = std::max(max, sJ);
+  fullVector<double> ige;
+  computeIGE_(_coeffsJacDet, v, ige, _type);
+
+  min = std::numeric_limits<double>::infinity();
+  max = -min;
+  for (int i = 0; i < ige.size(); ++i) {
+    min = std::min(min, ige(i));
+    max = std::max(max, ige(i));
   }
 }
 
-double _CoeffDataScaledJac::_computeLowerBound() const
+double _CoeffDataIGE::_computeLowerBound() const
 {
   // Speedup: If one coeff _coeffsJacDet is negative, without bounding
   // J^2/(a^2+b^2), we would get with certainty a negative lower bound.
@@ -601,7 +732,7 @@ double _CoeffDataScaledJac::_computeLowerBound() const
   }
 
   fullMatrix<double> v;
-  _getCoeffLengthVectors(v, false);
+  computeCoeffLengthVectors_(_coeffsJacMat, v, _type);
 
   fullVector<double> prox[6];
   for (int i = 0; i < v.size2(); ++i) {
@@ -706,12 +837,12 @@ double _CoeffDataScaledJac::_computeLowerBound() const
   }
 
   default:
-    Msg::Info("Unknown type for scaled Jacobian (%d)", _type);
+    Msg::Info("Unknown type for IGE (%d)", _type);
     return -1;
   }
 }
 
-void _CoeffDataScaledJac::_getCoeffLengthVectors(fullMatrix<double> &coeff,
+void _CoeffDataIGE::_getCoeffLengthVectors(fullMatrix<double> &coeff,
                                                  bool corners) const
 {
   int sz1 = corners ? _bfsDet->getNumLagCoeff() : _coeffsJacMat.size1();
@@ -724,7 +855,7 @@ void _CoeffDataScaledJac::_getCoeffLengthVectors(fullMatrix<double> &coeff,
     case TYPE_TET: coeff.resize(sz1, 6); break;
     case TYPE_PYR: coeff.resize(sz1, 6); break;
     default:
-      Msg::Error("Unkown type for scaled jac computation");
+      Msg::Error("Unkown type for IGE computation");
       coeff.resize(0, 0);
       return;
   }
@@ -798,8 +929,8 @@ void _CoeffDataScaledJac::_getCoeffLengthVectors(fullMatrix<double> &coeff,
   }
 }
 
-// Isotropy measure
-_CoeffDataIsotropy::_CoeffDataIsotropy(fullVector<double> &det,
+// ICN measure (Inverse Condition Number)
+_CoeffDataICN::_CoeffDataICN(fullVector<double> &det,
                                        fullMatrix<double> &mat,
                                        const bezierBasis *bfsDet,
                                        const bezierBasis *bfsMat,
@@ -809,7 +940,7 @@ _CoeffDataIsotropy::_CoeffDataIsotropy(fullVector<double> &det,
   _bfsDet(bfsDet), _bfsMat(bfsMat)
 {
   if (!det.getOwnData() || !mat.getOwnData()) {
-    Msg::Fatal("Cannot create an instance of _CoeffDataScaledJac from a "
+    Msg::Fatal("Cannot create an instance of _CoeffDataIGE from a "
                "fullVector or a fullMatrix that does not own its data.");
   }
   // _coeffsJacDet and _coeffsMetric reuse data, this avoid to allocate new
@@ -832,13 +963,13 @@ _CoeffDataIsotropy::_CoeffDataIsotropy(fullVector<double> &det,
   // _maxB not used for now
 }
 
-bool _CoeffDataIsotropy::boundsOk(double minL, double maxL) const
+bool _CoeffDataICN::boundsOk(double minL, double maxL) const
 {
   static double tol = 1e-3;
   return minL < tol*1e-3 || (_minB > minL-tol && _minB > minL*(1-100*tol));
 }
 
-void _CoeffDataIsotropy::getSubCoeff(std::vector<_CoeffData*> &v) const
+void _CoeffDataICN::getSubCoeff(std::vector<_CoeffData*> &v) const
 {
   v.clear();
   v.reserve(_bfsMat->getNumDivision());
@@ -855,13 +986,13 @@ void _CoeffDataIsotropy::getSubCoeff(std::vector<_CoeffData*> &v) const
     fullMatrix<double> coeffM(szM1, szM2);
     coeffD.copy(subCoeffD, i * szD, szD, 0);
     coeffM.copy(subCoeffM, i * szM1, szM1, 0, szM2, 0, 0);
-    _CoeffDataIsotropy *newData
-        = new _CoeffDataIsotropy(coeffD, coeffM, _bfsDet, _bfsMat, _depth+1);
+    _CoeffDataICN *newData
+        = new _CoeffDataICN(coeffD, coeffM, _bfsDet, _bfsMat, _depth+1);
     v.push_back(newData);
   }
 }
 
-void _CoeffDataIsotropy::_computeAtCorner(double &min, double &max) const
+void _CoeffDataICN::_computeAtCorner(double &min, double &max) const
 {
   min = std::numeric_limits<double>::infinity();
   max = -min;
@@ -881,7 +1012,7 @@ void _CoeffDataIsotropy::_computeAtCorner(double &min, double &max) const
   }
 }
 
-double _CoeffDataIsotropy::_computeLowerBound() const
+double _CoeffDataICN::_computeLowerBound() const
 {
   // Speedup: If one coeff _coeffsJacDet is negative, we would get
   // a negative lower bound. For now, returning 0.
diff --git a/Mesh/qualityMeasuresJacobian.h b/Mesh/qualityMeasuresJacobian.h
index 2ed23400530756962ad0bc52b2c3ff5d2875acc7..6c3b62992a1df10b80eed5c812d02207a1c11103 100644
--- a/Mesh/qualityMeasuresJacobian.h
+++ b/Mesh/qualityMeasuresJacobian.h
@@ -17,25 +17,22 @@ namespace jacobianBasedQuality {
 
 void minMaxJacobianDeterminant(MElement *el, double &min, double &max,
                                const fullMatrix<double> *normals = NULL);
-double minScaledJacobian(MElement *el,
-                         bool knownValid = false,
-                         bool reversedOk = false);
-double minIsotropyMeasure(MElement *el,
-                          bool knownValid = false,
-                          bool reversedOk = false);
-//double minSampledAnisotropyMeasure(MElement *el, int order,//fordebug
-//                                   bool writeInFile = false);
-double minSampledIsotropyMeasure(MElement *el, int order,//fordebug
-                                 bool writeInFile = false);
-double minSampledScaledJacobian(MElement *el, int order,//fordebug
-                                bool writeInFile = false);
+double minIGEMeasure(MElement *el,
+                     bool knownValid = false,
+                     bool reversedOk = false);
+double minICNMeasure(MElement *el,
+                     bool knownValid = false,
+                     bool reversedOk = false);
+void sampleIGEMeasure(MElement *el, int order, double &min, double &max);
+double minSampledICNMeasure(MElement *el, int order);//fordebug
+double minSampledIGEMeasure(MElement *el, int order);//fordebug
 
 class _CoeffData
 {
 protected:
   double _minL, _maxL; //Extremum of Jac at corners
   double _minB, _maxB; //Extremum of bezier coefficients
-  int _depth;
+  const int _depth;
 
 public:
   _CoeffData(int depth) : _minL(0), _maxL(0), _minB(0), _maxB(0),
@@ -75,24 +72,21 @@ public:
   int getNumMeasure() const {return 1;}//fordebug
 };
 
-class _CoeffDataScaledJac: public _CoeffData
+class _CoeffDataIGE: public _CoeffData
 {
 private:
   const fullVector<double> _coeffsJacDet;
   const fullMatrix<double> _coeffsJacMat;
   const bezierBasis *_bfsDet, *_bfsMat;
-  int _type;
-  static double cTri;
-  static double cTet;
-  static double cPyr;
+  const int _type;
 
 public:
-  _CoeffDataScaledJac(fullVector<double> &det,
+  _CoeffDataIGE(fullVector<double> &det,
                      fullMatrix<double> &mat,
                      const bezierBasis *bfsDet,
                      const bezierBasis *bfsMat,
                      int depth, int type);
-  ~_CoeffDataScaledJac() {}
+  ~_CoeffDataIGE() {}
 
   bool boundsOk(double minL, double maxL) const;
   void getSubCoeff(std::vector<_CoeffData*>&) const;
@@ -102,11 +96,9 @@ private:
   void _computeAtCorner(double &min, double &max) const;
   double _computeLowerBound() const;
   void _getCoeffLengthVectors(fullMatrix<double> &, bool corners = false) const;
-  void _getCoeffScaledJacobian(const fullMatrix<double> &coeffLengthVectors,
-                               fullMatrix<double> &coeffScaledJacobian) const;
 };
 
-class _CoeffDataIsotropy: public _CoeffData
+class _CoeffDataICN: public _CoeffData
 {
 private:
   const fullVector<double> _coeffsJacDet;
@@ -114,12 +106,12 @@ private:
   const bezierBasis *_bfsDet, *_bfsMat;
 
 public:
-  _CoeffDataIsotropy(fullVector<double> &det,
+  _CoeffDataICN(fullVector<double> &det,
                      fullMatrix<double> &metric,
                      const bezierBasis *bfsDet,
                      const bezierBasis *bfsMet,
                      int depth);
-  ~_CoeffDataIsotropy() {}
+  ~_CoeffDataICN() {}
 
   bool boundsOk(double minL, double maxL) const;
   void getSubCoeff(std::vector<_CoeffData*>&) const;
diff --git a/Mesh/yamakawa.cpp b/Mesh/yamakawa.cpp
index 983fbf4695d3714b58685e0fed39829ab81f8ff3..12e5f2c7462b74d784f42036e84b390b5ab35c67 100644
--- a/Mesh/yamakawa.cpp
+++ b/Mesh/yamakawa.cpp
@@ -1477,7 +1477,7 @@ double Recombinator::min_scaled_jacobian(Hex &hex) {
   /*MHexahedron *h1 = new MHexahedron(a, b, c, d, e, f, g, h);
   MHexahedron *h2 = new MHexahedron(e, f, g, h, a, b, c, d);
   double min1 = jacobianBasedQuality::minScaledJacobian(h1);
-  double min2 = jacobianBasedQuality::minScaledJacobian(h2);
+  double min2 = jacobianBasedQuality::minIGEMeasure(h2);
   for(i=0;i<8;i++){
     file << jacobians[i] << " ";
   }
@@ -2980,7 +2980,7 @@ double Supplementary::min_scaled_jacobian(Prism prism) {
   /*MPrism *p1 = new MPrism(a, b, c, d, e, f);
   MPrism *p2 = new MPrism(d, e, f, a, b, c);
   double min1 = jacobianBasedQuality::minScaledJacobian(p1);
-  double min2 = jacobianBasedQuality::minScaledJacobian(p2);
+  double min2 = jacobianBasedQuality::minIGEMeasure(p2);
   for(i=0;i<6;i++){
     file << jacobians[i] << " ";
   }
diff --git a/Mesh/yamakawa.h b/Mesh/yamakawa.h
index 9025a5029bffbaf44f91a7643337c9f6b596f601..c1420bfe260aa1c3fde3e378751d55a5810c4073 100644
--- a/Mesh/yamakawa.h
+++ b/Mesh/yamakawa.h
@@ -40,7 +40,7 @@ class Hex {
   void compute_quality()
   {
     MHexahedron elt(vertices_);
-    quality = jacobianBasedQuality::minScaledJacobian(&elt, false, true);
+    quality = jacobianBasedQuality::minIGEMeasure(&elt, false, true);
   }
   void initialize()
   {
diff --git a/Plugin/AnalyseCurvedMesh.cpp b/Plugin/AnalyseCurvedMesh.cpp
index c85cafc660ac259413b928f439d81849f564dc1e..3a49ddb3afd1954d9d541c94c68006cdbd2d75d2 100644
--- a/Plugin/AnalyseCurvedMesh.cpp
+++ b/Plugin/AnalyseCurvedMesh.cpp
@@ -24,8 +24,8 @@ class bezierBasis;
 
 StringXNumber CurvedMeshOptions_Number[] = {
   {GMSH_FULLRC, "Jacobian determinant", NULL, 1},
-  {GMSH_FULLRC, "Scaled Jacobian", NULL, 0},
-  {GMSH_FULLRC, "Isotropy", NULL, 1},
+  {GMSH_FULLRC, "IGE measure", NULL, 1},
+  {GMSH_FULLRC, "ICN measure", NULL, 1},
   {GMSH_FULLRC, "Hidding threshold", NULL, 9},
   {GMSH_FULLRC, "Draw PView", NULL, 0},
   {GMSH_FULLRC, "Recompute", NULL, 0},
@@ -54,36 +54,41 @@ std::string GMSH_AnalyseCurvedMeshPlugin::getHelp() const
 {
   return "Plugin(AnalyseCurvedMesh) analyse all elements of a given dimension. "
     "According to what is asked, it computes the minimum of the Jacobian "
-    "determinant (J), of the scaled Jacobian and/or of the isotropy measure. "
-    "Statistics are printed and if asked a Pview is created for each measure. "
+    "determinant (J), the IGE quality measure (Inverse Gradient Error) and/or "
+    "the ICN quality measure (Inverse Condition Number). "
+    "Statistics are printed and, if asked, a Pview is created for each measure. "
     "The plugin hides elements for which the measure mu > 'Hidding threshold', "
-    "where mu is the isotropy measure if asked otherwise the scaled Jacobian if "
+    "where mu is the ICN measure if asked otherwise the IGE measure if "
     "asked otherwise the Jacobian determinant.\n"
     "\n"
-    "J is faster to compute but gives informations only on validity while the "
-    "other measure gives also informations on quality.\n"
-    "Warning: the scaled Jacobian is experimental for triangles, tetrahedra, "
-    "prisms and pyramids. Computation may take a lot of time for those "
-    "elements!\n"
+    "J is faster to compute but gives information only on validity while the "
+    "other measure gives also information on quality.\n"
+    "The IGE measure is related to the error on the gradient of the finite "
+    "element solution. It is the scaled Jacobian for quads and hexes and a new "
+    "measure for triangles and tetrahedra.\n"
+    "The ICN measure is related to the condition number of the stiffness matrix.\n"
+    "(See article \"Efficient computation of the minimum of shape quality "
+    "measures on curvilinear finite elements\" for details.)\n"
     "\n"
     "Parameters:\n"
     "\n"
     "- Jacobian determinant = {0, 1}\n"
-    "- Scaled Jacobian = {0, 1}\n"
-    "- Isotropy = {0, 1}\n"
     "\n"
-    "- Hidding threshold = [0, 1]: Does nothing if Isotropy == 0 and Scaled "
-    "Jacobian == 0. Otherwise, hides all element for which min(mu) is "
-    "strictly greater than the threshold, where mu is the isotropy if Isotropy "
-    "== 1, otherwise it is the Scaled Jacobian. If threshold == 1, no effect, "
-    "if == 0 hide all elements except invalid.\n"
+    "- IGE measure = {0, 1}\n"
     "\n"
-    "- Draw PView = {0, 1}: Creates a PView of min(J)/max(J), min(scaled Jac) "
-    "and/or min(isotropy) according to what is asked. If 'Recompute' = 1, a "
-    "new PView is redrawed.\n"
+    "- ICN measure = {0, 1}\n"
     "\n"
-    "- Recompute = {0,1}: If the mesh has changed, set to 1 to recompute the "
-    "bounds.\n"
+    "- Hidding threshold = [0, 1]: Hides all element for which min(mu) is "
+    "strictly greater than the threshold, where mu is the ICN if ICN measure == 1, "
+    "otherwise mu is the IGE it IGE measure == 1, "
+    "otherwise mu is the Jacobian determinant.\n"
+    "If threshold == 0, hides all elements except invalid.\n"
+    "\n"
+    "- Draw PView = {0, 1}: Creates a PView of min(J)/max(J), min(IGE) "
+    "and/or min(ICN) according to what is asked. If 'Recompute' = 1, "
+    "new PViews are created.\n"
+    "\n"
+    "- Recompute = {0,1}: Should be 1 if the mesh has changed.\n"
     "\n"
     "- Dimension = {-1, 1, 2, 3, 4}: If == -1, analyse element of the greater "
     "dimension. If == 4, analyse 2D and 3D elements.";
@@ -92,33 +97,33 @@ std::string GMSH_AnalyseCurvedMeshPlugin::getHelp() const
 PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
 {
   _m = GModel::current();
-  bool computeJac       = static_cast<int>(CurvedMeshOptions_Number[0].def);
-  bool computeScaledJac = static_cast<int>(CurvedMeshOptions_Number[1].def);
-  bool computeIsotropy  = static_cast<int>(CurvedMeshOptions_Number[2].def);
-  _threshold     = static_cast<double>(CurvedMeshOptions_Number[3].def);
-  bool drawPView = static_cast<int>(CurvedMeshOptions_Number[4].def);
-  bool recompute = static_cast<bool>(CurvedMeshOptions_Number[5].def);
-  int askedDim   = static_cast<int>(CurvedMeshOptions_Number[6].def);
+  bool computeJac = static_cast<int>(CurvedMeshOptions_Number[0].def);
+  bool computeIGE = static_cast<int>(CurvedMeshOptions_Number[1].def);
+  bool computeICN = static_cast<int>(CurvedMeshOptions_Number[2].def);
+  _threshold      = static_cast<double>(CurvedMeshOptions_Number[3].def);
+  bool drawPView  = static_cast<int>(CurvedMeshOptions_Number[4].def);
+  bool recompute  = static_cast<bool>(CurvedMeshOptions_Number[5].def);
+  int askedDim    = static_cast<int>(CurvedMeshOptions_Number[6].def);
 
   if (askedDim < 0 || askedDim > 4) askedDim = _m->getDim();
 
   if (recompute) {
     _data.clear();
     if (askedDim < 4) {
-      _computedJ[askedDim-1] = false;
-      _computedS[askedDim-1] = false;
-      _computedI[askedDim-1] = false;
-      _PViewJ[askedDim-1] = false;
-      _PViewS[askedDim-1] = false;
-      _PViewI[askedDim-1] = false;
+      _computedJac[askedDim-1] = false;
+      _computedIGE[askedDim-1] = false;
+      _computedICN[askedDim-1] = false;
+      _PViewJac[askedDim-1] = false;
+      _PViewIGE[askedDim-1] = false;
+      _PViewICN[askedDim-1] = false;
     }
     else {
-      _computedJ[1] = _computedJ[2] = false;
-      _computedS[1] = _computedS[2] = false;
-      _computedI[1] = _computedI[2] = false;
-      _PViewJ[1] = _PViewJ[2] = false;
-      _PViewS[1] = _PViewS[2] = false;
-      _PViewI[1] = _PViewI[2] = false;
+      _computedJac[1] = _computedJac[2] = false;
+      _computedIGE[1] = _computedIGE[2] = false;
+      _computedICN[1] = _computedICN[2] = false;
+      _PViewJac[1] = _PViewJac[2] = false;
+      _PViewIGE[1] = _PViewIGE[2] = false;
+      _PViewICN[1] = _PViewICN[2] = false;
     }
   }
 
@@ -128,7 +133,7 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
   bool printStatI = false;
   for (int dim = 1; dim <= 3 && dim <= _m->getDim(); ++dim) {
     if ((askedDim == 4 && dim > 1) || dim == askedDim) {
-      if (!_computedJ[dim-1]) {
+      if (!_computedJac[dim-1]) {
         double time = Cpu();
         Msg::StatusBar(true, "Computing Jacobian for %dD elements...", dim);
         _computeMinMaxJandValidity(dim);
@@ -136,34 +141,34 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
                        dim, Cpu()-time);
         printStatJ = true;
       }
-      if (computeScaledJac && !_computedS[dim-1]) {
+      if (computeIGE && !_computedIGE[dim-1]) {
         double time = Cpu();
-        Msg::StatusBar(true, "Computing scaled Jacobian for %dD elements...", dim);
-        _computeMinScaledJac(dim);
-        Msg::StatusBar(true, "Done computing scaled Jacobian for %dD elements (%g s)",
+        Msg::StatusBar(true, "Computing IGE for %dD elements...", dim);
+        _computeMinIGE(dim);
+        Msg::StatusBar(true, "Done computing IGE for %dD elements (%g s)",
                        dim, Cpu()-time);
         printStatS = true;
       }
-      if (computeIsotropy && !_computedI[dim-1]) {
+      if (computeICN && !_computedICN[dim-1]) {
         double time = Cpu();
-        Msg::StatusBar(true, "Computing isotropy for %dD elements...", dim);
-        _computeMinIsotropy(dim);
-        Msg::StatusBar(true, "Done computing isotropy for %dD elements (%g s)",
+        Msg::StatusBar(true, "Computing ICN for %dD elements...", dim);
+        _computeMinICN(dim);
+        Msg::StatusBar(true, "Done computing ICN for %dD elements (%g s)",
                        dim, Cpu()-time);
         printStatI = true;
       }
     }
   }
   if (printStatJ) _printStatJacobian();
-  if (printStatS) _printStatScaledJac();
-  if (printStatI) _printStatIsotropy();
+  if (printStatS) _printStatIGE();
+  if (printStatI) _printStatICN();
 
   // Create PView
   if (drawPView)
   for (int dim = 1; dim <= 3; ++dim) {
     if ((askedDim == 4 && dim > 1) || dim == askedDim) {
-      if (!_PViewJ[dim-1] && computeJac) {
-        _PViewJ[dim-1] = true;
+      if (!_PViewJac[dim-1] && computeJac) {
+        _PViewJac[dim-1] = true;
         std::map<int, std::vector<double> > dataPV;
         for (unsigned int i = 0; i < _data.size(); ++i) {
           MElement *const el = _data[i].element();
@@ -176,8 +181,8 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
           new PView(name.str().c_str(), "ElementData", _m, dataPV);
         }
       }
-      if (!_PViewS[dim-1] && computeScaledJac) {
-        _PViewS[dim-1] = true;
+      if (!_PViewIGE[dim-1] && computeIGE) {
+        _PViewIGE[dim-1] = true;
         std::map<int, std::vector<double> > dataPV;
         for (unsigned int i = 0; i < _data.size(); ++i) {
           MElement *const el = _data[i].element();
@@ -186,12 +191,12 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
         }
         if (dataPV.size()) {
           std::stringstream name;
-          name << "Scaled Jacobian " << dim << "D";
+          name << "IGE " << dim << "D";
           new PView(name.str().c_str(), "ElementData", _m, dataPV);
         }
       }
-      if (!_PViewI[dim-1] && computeIsotropy) {
-        _PViewI[dim-1] = true;
+      if (!_PViewICN[dim-1] && computeICN) {
+        _PViewICN[dim-1] = true;
         std::map<int, std::vector<double> > dataPV;
         for (unsigned int i = 0; i < _data.size(); ++i) {
           MElement *const el = _data[i].element();
@@ -200,7 +205,7 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
         }
         if (dataPV.size()) {
           std::stringstream name;
-          name << "Isotropy " << dim << "D";
+          name << "ICN " << dim << "D";
           new PView(name.str().c_str(), "ElementData", _m, dataPV);
         }
       }
@@ -210,8 +215,8 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
   // Hide elements
 #if defined(HAVE_OPENGL)
   _hideWithThreshold(askedDim,
-      computeIsotropy ? 2 :
-          computeScaledJac ? 1 :
+      computeICN ? 2 :
+          computeIGE ? 1 :
               computeJac ? 0 : -1);
   CTX::instance()->mesh.changed = (ENT_ALL);
   drawContext::global()->draw();
@@ -222,7 +227,7 @@ PView* GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
 
 void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(int dim)
 {
-  if (_computedJ[dim-1]) return;
+  if (_computedJac[dim-1]) return;
 
   std::set<GEntity*, GEntityLessThan> entities;
   switch (dim) {
@@ -337,12 +342,12 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinMaxJandValidity(int dim)
     }
     delete normals;
   }
-  _computedJ[dim-1] = true;
+  _computedJac[dim-1] = true;
 }
 
-void GMSH_AnalyseCurvedMeshPlugin::_computeMinScaledJac(int dim)
+void GMSH_AnalyseCurvedMeshPlugin::_computeMinIGE(int dim)
 {
-  if (_computedS[dim-1]) return;
+  if (_computedIGE[dim-1]) return;
 
   MsgProgressStatus progress(_data.size());
 
@@ -353,17 +358,17 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinScaledJac(int dim)
       _data[i].setMinS(0);
     }
     else {
-      _data[i].setMinS(jacobianBasedQuality::minScaledJacobian(el, true));
+      _data[i].setMinS(jacobianBasedQuality::minIGEMeasure(el, true));
     }
     progress.next();
   }
 
-  _computedS[dim-1] = true;
+  _computedIGE[dim-1] = true;
 }
 
-void GMSH_AnalyseCurvedMeshPlugin::_computeMinIsotropy(int dim)
+void GMSH_AnalyseCurvedMeshPlugin::_computeMinICN(int dim)
 {
-  if (_computedI[dim-1]) return;
+  if (_computedICN[dim-1]) return;
 
   MsgProgressStatus progress(_data.size());
 
@@ -374,12 +379,12 @@ void GMSH_AnalyseCurvedMeshPlugin::_computeMinIsotropy(int dim)
       _data[i].setMinI(0);
     }
     else {
-      _data[i].setMinI(jacobianBasedQuality::minIsotropyMeasure(el, true));
+      _data[i].setMinI(jacobianBasedQuality::minICNMeasure(el, true));
     }
     progress.next();
   }
 
-  _computedI[dim-1] = true;
+  _computedICN[dim-1] = true;
 }
 
 int GMSH_AnalyseCurvedMeshPlugin::_hideWithThreshold(int askedDim, int whichMeasure)
@@ -451,17 +456,17 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatJacobian()
   avgratJ /= count;
   avgratJc /= countc;
 
-  Msg::Info("Min Jac. det. (minJ): %6.3g, %6.3g, %6.3g (= min, avg, max)",
+  Msg::Info("minJ      = %8.3g, %8.3g, %8.3g (min, avg, max)",
             infminJ, avgminJ, supminJ);
-  Msg::Info("Ratio minJ/maxJ     : %6.3f, %6.3f, %6.3f (= worst, avg, best)",
-            infratJ, avgratJ, supratJ);
   if (countc && countc < count)
-    Msg::Info("                      (avg = %.3f"
-              " on the %d non-constant elements)",
+    Msg::Info("minJ/maxJ =           %8.3f           (avg on the %d "
+                      "non-constant elements)",
               avgratJc, countc);
+  Msg::Info("minJ/maxJ = %8.3f, %8.3f, %8.3f (worst, avg, best)",
+            infratJ, avgratJ, supratJ);
 }
 
-void GMSH_AnalyseCurvedMeshPlugin::_printStatScaledJac()
+void GMSH_AnalyseCurvedMeshPlugin::_printStatIGE()
 {
   if (_data.empty()) {
     Msg::Info("No stat to print.");
@@ -477,11 +482,11 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatScaledJac()
   }
   avgminS /= _data.size();
 
-  Msg::Info("Scaled Jacobian     : %6.3f, %6.3f, %6.3f (= worst, avg, best)",
-      infminS, avgminS, supminS);
+  Msg::Info("IGE       = %8.3f, %8.3f, %8.3f (worst, avg, best)",
+            infminS, avgminS, supminS);
 }
 
-void GMSH_AnalyseCurvedMeshPlugin::_printStatIsotropy()
+void GMSH_AnalyseCurvedMeshPlugin::_printStatICN()
 {
   if (_data.empty()) {
     Msg::Info("No stat to print.");
@@ -497,8 +502,8 @@ void GMSH_AnalyseCurvedMeshPlugin::_printStatIsotropy()
   }
   avgminI /= _data.size();
 
-  Msg::Info("Isotropy            : %6.3f, %6.3f, %6.3f (= worst, avg, best)",
-      infminI, avgminI, supminI);
+  Msg::Info("ICN       = %8.3f, %8.3f, %8.3f (worst, avg, best)",
+            infminI, avgminI, supminI);
 }
 
 #endif
diff --git a/Plugin/AnalyseCurvedMesh.h b/Plugin/AnalyseCurvedMesh.h
index 17aa641503509de110cc41d4c77580666cfcd786..d1aac032a5306c5db3438f49739f82779a8e130d 100644
--- a/Plugin/AnalyseCurvedMesh.h
+++ b/Plugin/AnalyseCurvedMesh.h
@@ -19,21 +19,21 @@ class data_elementMinMax
 {
 private:
   MElement *_el;
-  double _minJ, _maxJ, _minS, _minI;
+  double _minJac, _maxJac, _minIGE, _minICN;
 public:
   data_elementMinMax(MElement *e,
                      double minJ = 2,
                      double maxJ = 0,
-                     double minS = -1,
-                     double minI = -1)
-    : _el(e), _minJ(minJ), _maxJ(maxJ), _minS(minS), _minI(minI) {}
-  void setMinS(double r) { _minS = r; }
-  void setMinI(double r) { _minI = r; }
+                     double minIGE = -1,
+                     double minICN = -1)
+    : _el(e), _minJac(minJ), _maxJac(maxJ), _minIGE(minIGE), _minICN(minICN) {}
+  void setMinS(double r) { _minIGE = r; }
+  void setMinI(double r) { _minICN = r; }
   MElement* element() { return _el; }
-  double minJ() { return _minJ; }
-  double maxJ() { return _maxJ; }
-  double minS() { return _minS; }
-  double minI() { return _minI; }
+  double minJ() { return _minJac; }
+  double maxJ() { return _maxJac; }
+  double minS() { return _minIGE; }
+  double minI() { return _minICN; }
 };
 
 class GMSH_AnalyseCurvedMeshPlugin : public GMSH_PostPlugin
@@ -43,8 +43,8 @@ private :
   double _threshold;
 
   // for 1d, 2d, 3d
-  bool _computedJ[3], _computedS[3], _computedI[3];
-  bool _PViewJ[3], _PViewS[3], _PViewI[3];
+  bool _computedJac[3], _computedIGE[3], _computedICN[3];
+  bool _PViewJac[3], _PViewIGE[3], _PViewICN[3];
 
   std::vector<data_elementMinMax> _data;
 
@@ -54,18 +54,18 @@ public :
     _m = NULL;
     _threshold = -1;
     for (int i = 0; i < 3; ++i) {
-      _computedJ[i] = false;
-      _computedS[i] = false;
-      _computedI[i] = false;
-      _PViewJ[i] = false;
-      _PViewS[i] = false;
-      _PViewI[i] = false;
+      _computedJac[i] = false;
+      _computedIGE[i] = false;
+      _computedICN[i] = false;
+      _PViewJac[i] = false;
+      _PViewIGE[i] = false;
+      _PViewICN [i] = false;
     }
   }
   std::string getName() const { return "AnalyseCurvedMesh"; }
   std::string getShortHelp() const
   {
-    return "Compute bounds on Jacobian and metric quality.";
+    return "Compute validity and quality of curved elements.";
   }
   std::string getHelp() const;
   std::string getAuthor() const { return "Amaury Johnen"; }
@@ -75,12 +75,12 @@ public :
 
 private :
   void _computeMinMaxJandValidity(int dim);
-  void _computeMinScaledJac(int dim);
-  void _computeMinIsotropy(int dim);
+  void _computeMinIGE(int dim);
+  void _computeMinICN(int dim);
   int _hideWithThreshold(int askedDim, int whichMeasure);
   void _printStatJacobian();
-  void _printStatScaledJac();
-  void _printStatIsotropy();
+  void _printStatIGE();
+  void _printStatICN();
 };
 
 #endif
diff --git a/contrib/mobile/Android/app/src/main/AndroidManifest.xml b/contrib/mobile/Android/app/src/main/AndroidManifest.xml
index 463f90e4aad52c8ea88a63397068cec9dceefcca..5ed362e26a2101a858f3ca92505f340f2802e61f 100644
--- a/contrib/mobile/Android/app/src/main/AndroidManifest.xml
+++ b/contrib/mobile/Android/app/src/main/AndroidManifest.xml
@@ -1,7 +1,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="org.geuz.onelab"
           android:versionName="2.0.0"
-          android:versionCode="32"
+          android:versionCode="36"
           android:installLocation="auto" >
   
   <uses-sdk android:minSdkVersion="14"
diff --git a/contrib/mobile/androidUtils.cpp b/contrib/mobile/androidUtils.cpp
index 6620401bd53168c927de4a9f39ed26f91899947c..53bdb54bc22a987115660d39b2aa8d7f0407dfc1 100644
--- a/contrib/mobile/androidUtils.cpp
+++ b/contrib/mobile/androidUtils.cpp
@@ -48,10 +48,10 @@ public:
          !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
       jstring jstr = env->NewStringUTF(message.c_str());
       jclass jClass = env->FindClass("org/geuz/onelab/Gmsh");
-      if(jClass == 0)
+      if(jClass == 0 || env->ExceptionCheck())
         return;
       jmethodID mid = env->GetMethodID(jClass, "ShowPopup", "(Ljava/lang/String;)V");
-      if (mid == 0)
+      if (mid == 0 || env->ExceptionCheck())
         return;
       env->CallVoidMethod(gCallbackObject, mid, jstr);
       env->DeleteLocalRef(jstr);
@@ -64,10 +64,10 @@ public:
          !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
       jstring jstr = env->NewStringUTF(message.c_str());
       jclass jClass = env->FindClass("org/geuz/onelab/Gmsh");
-      if(jClass == 0)
+      if(jClass == 0 || env->ExceptionCheck())
         return;
       jmethodID mid = env->GetMethodID(jClass, "SetLoading", "(Ljava/lang/String;)V");
-      if (mid == 0)
+      if (mid == 0 || env->ExceptionCheck())
         return;
       env->CallVoidMethod(gCallbackObject, mid, jstr);
       env->DeleteLocalRef(jstr);
@@ -90,10 +90,10 @@ void requestRender()
   if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK ||
      !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
   jclass jClass = env->FindClass("org/geuz/onelab/Gmsh");
-  if(jClass == 0)
+  if(jClass == 0 || env->ExceptionCheck())
     return;
   jmethodID mid = env->GetMethodID(jClass, "RequestRender", "()V");
-  if (mid == 0)
+  if (mid == 0 || env->ExceptionCheck())
     return;
   env->CallVoidMethod(gCallbackObject, mid);
   env->DeleteLocalRef(jClass);
@@ -106,19 +106,27 @@ void getBitmapFromString(const char *text, int textsize, unsigned char **map,
   if(gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK ||
      !gCallbackObject || (gJavaVM->AttachCurrentThread(&env, NULL)) < 0) return;
   jclass jClass = env->FindClass("org/geuz/onelab/StringTexture");
-  if(jClass == 0)
+  if(jClass == 0 || env->ExceptionCheck())
     return;
   jstring jtext = env->NewStringUTF(text);
   jmethodID mid = env->GetStaticMethodID(jClass, "getHeightFromString",
                                          "(Ljava/lang/String;I)I");
+  if(mid == 0 || env->ExceptionCheck())
+    return;
   *height = env->CallStaticIntMethod(jClass, mid, jtext, textsize);
   mid = env->GetStaticMethodID(jClass, "getWidthFromString", "(Ljava/lang/String;I)I");
+  if(mid == 0 || env->ExceptionCheck())
+    return;
   *width = env->CallStaticIntMethod(jClass, mid, jtext, textsize);
   if(realWidth != NULL){
     mid = env->GetStaticMethodID(jClass, "getRealWidthFromString", "(Ljava/lang/String;I)I");
+    if(mid == 0 || env->ExceptionCheck())
+      return;
     *realWidth = env->CallStaticIntMethod(jClass, mid, jtext, textsize);
   }
   mid = env->GetStaticMethodID(jClass, "getBytesFromString", "(Ljava/lang/String;I)[B");
+  if(mid == 0 || env->ExceptionCheck())
+    return;
   jobject jbuffer = env->CallStaticObjectMethod(jClass, mid, jtext, textsize);
   jbyteArray *jarray = reinterpret_cast<jbyteArray*>(&jbuffer);
   int ms = (*height) * (*width);
diff --git a/doc/gmsh.html b/doc/gmsh.html
index d3a24e0137b5d6a3a820016ff537ec4eb1f4e297..1daa362300f77e4e1fc9afcd1cf7ebfdceec02d3 100644
--- a/doc/gmsh.html
+++ b/doc/gmsh.html
@@ -99,13 +99,13 @@ Public License (GPL)</a>:
 <ul>
   <li>
     <p class="highlight">
-      Current stable release (version 3.0.2, May 13 2017):
-      <a href="bin/Windows/gmsh-3.0.2-Windows64.zip">Windows</a>
-      (<a href="bin/Windows/gmsh-3.0.2-Windows32.zip">32 bit</a>),
-      <a href="bin/Linux/gmsh-3.0.2-Linux64.tgz">Linux</a>,
-      <a href="bin/MacOSX/gmsh-3.0.2-MacOSX.dmg">MacOS</a>
+      Current stable release (version 3.0.3, June 23 2017):
+      <a href="bin/Windows/gmsh-3.0.3-Windows64.zip">Windows</a>
+      (<a href="bin/Windows/gmsh-3.0.3-Windows32.zip">32 bit</a>),
+      <a href="bin/Linux/gmsh-3.0.3-Linux64.tgz">Linux</a>,
+      <a href="bin/MacOSX/gmsh-3.0.3-MacOSX.dmg">MacOS</a>
       and
-      <a href="src/gmsh-3.0.2-source.tgz">source code</a>
+      <a href="src/gmsh-3.0.3-source.tgz">source code</a>
     </p>
     <p>
       <em>A <a href="doc/texinfo/gmsh.html#Tutorial"><strong>tutorial</strong></a>
diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index d9902b9dee73dbc5ed2f9eb32b47e3cf5ea1acbb..07ce0734c8c89567e65e787c36e73823ac4d62d1 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -5483,13 +5483,15 @@ coefficients A,B,C,D of the equation A*x+B*y+C*y+D=0, which can be
 adjusted interactively by dragging the mouse in the input
 fields.
 
-@item What is the signification of Rho, Eta and Gamma in Tools->Statistics?
+@item What is the signification of SICN, Gamma and SIGE in Tools->Statistics?
 
 They measure the quality of the tetrahedra in a mesh:
 
+SICN ~ signed inverse condition number
+
 Gamma ~ inscribed_radius / circumscribed_radius
-Eta ~ volume^(2/3) / sum_edge_length^2
-Rho ~ min_edge_length / max_edge_length
+
+SIGE ~ signed inverse error on the gradient of FE solution
 
 For the exact definitions, see Geo/MElement.cpp. The graphs plot the
 the number of elements vs. the quality measure.
diff --git a/doc/texinfo/opt_geometry.texi b/doc/texinfo/opt_geometry.texi
index 4b9c983a425d66a68c0cd650d9e959d3daa1e807..d571f0bdb67797d5bd0364dcfb1bee3241ae0f5d 100644
--- a/doc/texinfo/opt_geometry.texi
+++ b/doc/texinfo/opt_geometry.texi
@@ -251,7 +251,7 @@ Saved in: @code{General.OptionsFileName}
 
 @item Geometry.SurfaceType
 Surface display type (0=cross, 1=wireframe, 2=solid)@*
-Default value: @code{2}@*
+Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
 @item Geometry.Tangents
diff --git a/doc/texinfo/opt_mesh.texi b/doc/texinfo/opt_mesh.texi
index 6e43a4da4b5659bac09688708090ea2c02af2838..a7965733d333f2d9b5783de8e82b6586c95bd830 100644
--- a/doc/texinfo/opt_mesh.texi
+++ b/doc/texinfo/opt_mesh.texi
@@ -500,7 +500,7 @@ Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
 @item Mesh.QualityType
-Type of quality measure (0=gamma~vol/sum_face/max_edge, 1=eta~vol^(2/3)/sum_edge^2, 2=rho~min_edge/max_edge)@*
+Type of quality measure (0=SICN~signed inverse condition number, 1=SIGE~signed inverse gradient error, 2=gamma~vol/sum_face/max_edge, 3=Disto~minJ/maxJ@*
 Default value: @code{2}@*
 Saved in: @code{General.OptionsFileName}
 
diff --git a/doc/texinfo/opt_plugin.texi b/doc/texinfo/opt_plugin.texi
index 9ad6a01c619369d16b9b3879a4fd360ef5607088..05f989ce6710ea7f634a5ed1a228eac0715adcda 100644
--- a/doc/texinfo/opt_plugin.texi
+++ b/doc/texinfo/opt_plugin.texi
@@ -5,31 +5,36 @@
 
 @ftable @code
 @item Plugin(AnalyseCurvedMesh)
-Plugin(AnalyseCurvedMesh) analyse all elements of a given dimension. According to what is asked, it computes the minimum of the Jacobian determinant (J), of the scaled Jacobian and/or of the isotropy measure. Statistics are printed and if asked a Pview is created for each measure. The plugin hides elements for which the measure mu > 'Hidding threshold', where mu is the isotropy measure if asked otherwise the scaled Jacobian if asked otherwise the Jacobian determinant.@*
+Plugin(AnalyseCurvedMesh) analyse all elements of a given dimension. According to what is asked, it computes the minimum of the Jacobian determinant (J), the IGE quality measure (Inverse Gradient Error) and/or the ICN quality measure (Inverse Condition Number). Statistics are printed and, if asked, a Pview is created for each measure. The plugin hides elements for which the measure mu > 'Hidding threshold', where mu is the ICN measure if asked otherwise the IGE measure if asked otherwise the Jacobian determinant.@*
 @*
-J is faster to compute but gives informations only on validity while the other measure gives also informations on quality.@*
-Warning: the scaled Jacobian is experimental for triangles, tetrahedra, prisms and pyramids. Computation may take a lot of time for those elements!@*
+J is faster to compute but gives information only on validity while the other measure gives also information on quality.@*
+The IGE measure is related to the error on the gradient of the finite element solution. It is the scaled Jacobian for quads and hexes and a new measure for triangles and tetrahedra.@*
+The ICN measure is related to the condition number of the stiffness matrix.@*
+(See article "Efficient computation of the minimum of shape quality measures on curvilinear finite elements" for details.)@*
 @*
 Parameters:@*
 @*
 - Jacobian determinant = @{0, 1@}@*
-- Scaled Jacobian = @{0, 1@}@*
-- Isotropy = @{0, 1@}@*
 @*
-- Hidding threshold = [0, 1]: Does nothing if Isotropy == 0 and Scaled Jacobian == 0. Otherwise, hides all element for which min(mu) is strictly greater than the threshold, where mu is the isotropy if Isotropy == 1, otherwise it is the Scaled Jacobian. If threshold == 1, no effect, if == 0 hide all elements except invalid.@*
+- IGE measure = @{0, 1@}@*
 @*
-- Draw PView = @{0, 1@}: Creates a PView of min(J)/max(J), min(scaled Jac) and/or min(isotropy) according to what is asked. If 'Recompute' = 1, a new PView is redrawed.@*
+- ICN measure = @{0, 1@}@*
 @*
-- Recompute = @{0,1@}: If the mesh has changed, set to 1 to recompute the bounds.@*
+- Hidding threshold = [0, 1]: Hides all element for which min(mu) is strictly greater than the threshold, where mu is the ICN if ICN measure == 1, otherwise mu is the IGE it IGE measure == 1, otherwise mu is the Jacobian determinant.@*
+If threshold == 0, hides all elements except invalid.@*
+@*
+- Draw PView = @{0, 1@}: Creates a PView of min(J)/max(J), min(IGE) and/or min(ICN) according to what is asked. If 'Recompute' = 1, new PViews are created.@*
+@*
+- Recompute = @{0,1@}: Should be 1 if the mesh has changed.@*
 @*
 - Dimension = @{-1, 1, 2, 3, 4@}: If == -1, analyse element of the greater dimension. If == 4, analyse 2D and 3D elements.
 Numeric options:
 @table @code
 @item Jacobian determinant
 Default value: @code{1}
-@item Scaled Jacobian
-Default value: @code{0}
-@item Isotropy
+@item IGE measure
+Default value: @code{1}
+@item ICN measure
 Default value: @code{1}
 @item Hidding threshold
 Default value: @code{9}
diff --git a/doc/texinfo/opt_print.texi b/doc/texinfo/opt_print.texi
index b9e51319f6415f16e0c43a19eae57c07281b93ed..88ba43f8221ac98f3ea5d616a501d3d9bf8f36f1 100644
--- a/doc/texinfo/opt_print.texi
+++ b/doc/texinfo/opt_print.texi
@@ -164,8 +164,13 @@ Save Eta quality measure in mesh statistics exported as post-processing views@*
 Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
-@item Print.PostRho
-Save Rho quality measure in mesh statistics exported as post-processing views@*
+@item Print.PostSICN
+Save SICN (signed inverse condition number) quality measure in mesh statistics exported as post-processing views@*
+Default value: @code{0}@*
+Saved in: @code{General.OptionsFileName}
+
+@item Print.PostSICN
+Save SIGE (signed inverse gradient error) quality measure in mesh statistics exported as post-processing views@*
 Default value: @code{0}@*
 Saved in: @code{General.OptionsFileName}
 
diff --git a/utils/misc/gource.sh b/utils/misc/gource.sh
index 83967f90b66a0e88f214e1f0dbe4b8407dc9ad31..6c9d541c9ea5e73ffb739ac0185040dd7c9a74e9 100755
--- a/utils/misc/gource.sh
+++ b/utils/misc/gource.sh
@@ -3,3 +3,6 @@
 ### -f --start-date '2006-01-01'
 
 gource -f --time-scale 2 -b 000000 --seconds-per-day 0.0001 --hide filenames --file-filter projects --file-filter data --file-filter branches --file-filter benchmarks_private --file-filter benchmarks_kst --highlight-user geuzaine -1280x720 -o - | ffmpeg -y -r 60 -f image2pipe -vcodec ppm -i - -vcodec libx264 -preset ultrafast -pix_fmt yuv420p -crf 1 -threads 0 -bf 0 gource.mp4
+
+# resample to make it 4 x faster
+ffmpeg -i gource.mp4 -filter:v "setpts=0.25*PTS" gource_x4speed.mp4