diff --git a/Plugin/AnalyseCurvedMesh.cpp b/Plugin/AnalyseCurvedMesh.cpp
index d228c2a20168cf4b728c7a5d9d2bf901a3b01bc9..4042d81b64bea0ee0006106530ad6a053e290103 100644
--- a/Plugin/AnalyseCurvedMesh.cpp
+++ b/Plugin/AnalyseCurvedMesh.cpp
@@ -26,12 +26,12 @@
 
 StringXNumber JacobianOptions_Number[] = {
   {GMSH_FULLRC, "Dim", NULL, -1},
-  /*{GMSH_FULLRC, "Analysis", NULL, 1},*/
+  {GMSH_FULLRC, "Analysis", NULL, 1},
   {GMSH_FULLRC, "Effect", NULL, 6},
   {GMSH_FULLRC, "MaxDepth", NULL, 10},
   {GMSH_FULLRC, "JacBreak", NULL, .0},
   {GMSH_FULLRC, "BezBreak", NULL, .0},
-  /*{GMSH_FULLRC, "Tolerance", NULL, 1e-5}*/
+  {GMSH_FULLRC, "Tolerance", NULL, 1e-5}
 };
 
 extern "C"
@@ -55,15 +55,10 @@ std::string GMSH_AnalyseCurvedMeshPlugin::getHelp() const
 {
   return "Plugin(AnalyseCurvedMesh) check the jacobian of all elements of dimension 'Dim' or "
     "the greater model dimension if 'Dim' is either <0 or >3.\n\n "
-    //"Elements for which we are absolutely certain that they are good (positive jacobian) are ignored. "
-    //"Others are wrong or suppose to be wrong.\n\n"
-    //"Plugin(AnalyseCurvedMesh) write in the console which elements are wrong. "
-    //"(if labels of analysed type of elements are set visible, only wrong elements will be visible)\n\n"
-    /*"Analysis : 0 do nothing\n"
+    "Analysis : 0 do nothing\n"
     "          +1 find invalid elements (*)\n"
-    "          +2 compute min and max of all elements and print some statistics\n\n"*/
-    /*"Effect (for *) : 0 do nothing\n"*/
-    "Effect : 0 do nothing\n"
+    "          +2 compute J_min and J_max of all elements and print some statistics\n\n"
+    "Effect (for *) : 0 do nothing\n"
     "                +1 print a list of invalid elements\n"
     "                +2 print some statistics\n"
     "                +4 hide valid elements (for GUI)\n\n"
@@ -75,7 +70,7 @@ std::string GMSH_AnalyseCurvedMeshPlugin::getHelp() const
     "the element is said to be invalid\n\n"
     "BezBreak = [0,JacBreak[ : if all Bezier coefficients are > 'BezBreak', "
     "the element is said to be valid\n\n"
-    /*"Tolerance = R+ , << 1 : tolerance (relatively to J_avg.) used during the computation of min and max"*/;
+    "Tolerance = R+ , << 1 : tolerance (relatively to J_min and J_max) used during the computation of J_min and J_max";
 }
 
 // Miscellaneous method
@@ -221,7 +216,7 @@ static void setJacobian(MElement *el, const JacobianBasis *jfs, fullVector<doubl
 
 
 
-void setJacobian(MElement *const *el, const JacobianBasis *jfs, fullMatrix<double> &jacobian)
+static void setJacobian(MElement *const *el, const JacobianBasis *jfs, fullMatrix<double> &jacobian)
 {
   int numEl = jacobian.size2();
   int numVertices = el[0]->getNumVertices();
@@ -334,13 +329,12 @@ PView *GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
   _dim = (int) JacobianOptions_Number[0].def;
   if (_dim < 0 || _dim > 3)
     _dim = _m->getDim();
-  /*int analysis = (int) JacobianOptions_Number[1].def % 2;*/
-  int analysis = 1;
+  int analysis = (int) JacobianOptions_Number[1].def % 2;
   int toDo = (int) JacobianOptions_Number[1].def % 8;
   _maxDepth = (int) JacobianOptions_Number[2].def;
   _jacBreak = (double) JacobianOptions_Number[3].def;
   _bezBreak = (double) JacobianOptions_Number[4].def;
-  _tol = 1;/*(double) JacobianOptions_Number[5].def;*/
+  _tol = (double) JacobianOptions_Number[5].def;
   
   if (analysis % 2) {
     double t = Cpu();
@@ -349,7 +343,10 @@ PView *GMSH_AnalyseCurvedMeshPlugin::execute(PView *v)
     Msg::Info("Done validity check (%fs)", Cpu()-t);
   }
   if (analysis / 2) {
+    double t = Cpu();
+    Msg::Info("Strating computation J_min / J_max...");
     computeMinMax();
+    Msg::Info("Done computation J_min / J_max (%fs)", Cpu()-t);
   }
 }
   
@@ -518,6 +515,19 @@ void GMSH_AnalyseCurvedMeshPlugin::checkValidity(int toDo)
     
     case 2 :
       Msg::Warning("2D elements must be in a z=cst plane ! If they aren't, results won't be correct.");
+      
+				for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) {
+					GFace *f = *it;
+					
+					unsigned int numType[3] = {0, 0, 0};
+					f->getNumMeshElements(numType);
+					
+					for (int type = 0; type < 3; type++) {
+						MElement *const *el = f->getStartElementType(type);
+						for (int jo = 0; jo < numType[type]; jo++)
+							el[jo]->setVolumePositive();
+					}
+				}		
       for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) {
         GFace *f = *it;
         unsigned int numType[3] = {0, 0, 0};
@@ -648,73 +658,74 @@ void GMSH_AnalyseCurvedMeshPlugin::hideValid_ShowInvalid(std::vector<MElement*>
   invalids.pop_back();
 }
 
-void GMSH_AnalyseCurvedMeshPlugin::computeMinMax()
+void GMSH_AnalyseCurvedMeshPlugin::
+  checkValidity(MElement *const*el, int numEl, std::vector<MElement*> &invalids)
 {
-  _numAnalysedEl = 0;
-  _numInvalid = 0;
-  _numValid = 0;
-  _numUncertain = 0;
-  _min_Javg = .0, _max_Javg = .0;
-  _min_pJmin = .0, _avg_pJmin = .0;
-  _min_ratioJ = .0, _avg_ratioJ = .0;
+  if (numEl < 1)
+    return;
   
-  switch (_dim) {
-    case 3 :
-      for(GModel::riter it = _m->firstRegion(); it != _m->lastRegion(); it++) {
-        GRegion *r = *it;
-        unsigned int numType[5] = {0, 0, 0, 0, 0};
-        r->getNumMeshElements(numType);
-        
-        for(int type = 0; type < 5; type++) {
-          MElement *const *el = r->getStartElementType(type);
-          computeMinMax(el, numType[type]);
-          _numAnalysedEl += numType[type];
-        }
-      }
-      break;
+  const JacobianBasis *jfs = el[0]->getJacobianFuncSpace(-1);
+  if (!jfs) {
+    Msg::Error("Jacobian function space not implemented for type of element %d", el[0]->getNum());
+    return;
+  }
+  const bezierBasis *bb = jfs->bezier;
+  
+  int numSamplingPt = bb->points.size1();
+  int dim = bb->points.size2();
+  fullVector<double> jacobian(numSamplingPt);
+  fullVector<double> jacBez(numSamplingPt);
+  
+  for (int k = 0; k < numEl; ++k) {
+    setJacobian(el[k], jfs, jacobian);
     
-    case 2 :
-      Msg::Warning("2D elements must be in a z=cst plane ! If they aren't, results won't be correct.");
-      for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) {
-        GFace *f = *it;
-        unsigned int numType[3] = {0, 0, 0};
-        f->getNumMeshElements(numType);
-        
-        for (int type = 0; type < 3; type++) {
-          MElement *const *el = f->getStartElementType(type);
-          computeMinMax(el, numType[type]);
-          _numAnalysedEl += numType[type];
-        }
-      }
-      break;
+    int i;
+    for (i = 0; i < numSamplingPt && jacobian(i) > _jacBreak; ++i);
+    if (i < numSamplingPt) {
+      invalids.push_back(el[k]);
+      ++_numInvalid;
+      continue;
+    }
     
-    case 1 :
-      Msg::Warning("1D elements must be on a y=cst & z=cst line ! If they aren't, results won't be correct.");
-      for (GModel::eiter it = _m->firstEdge(); it != _m->lastEdge(); it++) {
-        GEdge *e = *it;
-        unsigned int numElement = e->getNumMeshElements();
-        MElement *const *el = e->getStartElementType(0);
-        computeMinMax(el, numElement);
-        _numAnalysedEl += numElement;
-      }
-      break;
+    if (_maxDepth < 1) {
+      invalids.push_back(el[k]);
+      ++_numUncertain;
+      continue;
+    }
     
-    default :
-      Msg::Error("I can't analyse any element.");
-      return;
+    bb->matrixLag2Bez.mult(jacobian, jacBez);
+    
+    for (i = 0; i < jacBez.size() && jacBez(i) > _bezBreak; ++i);
+    if (i >= jacBez.size()) {
+      ++_numValid;
+      continue;
+    }
+    
+    if (_maxDepth < 2) {
+      invalids.push_back(el[k]);
+      ++_numUncertain;
+      continue;
+    }
+    else {
+      int result = subDivision(bb, jacBez, _maxDepth-1);
+      if (result < 0) {
+        invalids.push_back(el[k]);
+        ++_numInvalid;
+        continue;
+      }
+      if (result > 0) {
+        ++_numValid;
+        continue;
+      }
+      invalids.push_back(el[k]);
+      ++_numUncertain;
+      continue;
+    }
   }
-  Msg::Info("Extrema of J_avg : %g, %g", _min_Javg, _max_Javg);
-  Msg::Info("Minimum of min(distortion) : %g", _min_pJmin);
-  Msg::Info("Average of min(distortion) : %g", _avg_pJmin / _numAnalysedEl);
-  Msg::Info("Minimum of min(J) / max(J) : %g", _min_ratioJ);
-  Msg::Info("Average of min(J) / max(J) : %g", _avg_ratioJ / _numAnalysedEl);
 }
 
-
-
-
 void GMSH_AnalyseCurvedMeshPlugin::
-  checkValidity(MElement *const*el, int numEl, std::vector<MElement*> &invalids)
+  checkValidity_BLAS(MElement *const*el, int numEl, std::vector<MElement*> &invalids)
 {
   if (numEl < 1)
     return;
@@ -728,15 +739,14 @@ void GMSH_AnalyseCurvedMeshPlugin::
   
   int numSamplingPt = bb->points.size1();
   int dim = bb->points.size2();
-  fullVector<double> jacobian(numSamplingPt);
-  fullVector<double> jacBez(numSamplingPt);
+  fullMatrix<double> jacobian(numSamplingPt, numEl);
+  fullVector<double> jacBez(numSamplingPt), proxJac(numSamplingPt);
+  setJacobian(el, jfs, jacobian);
   
   for (int k = 0; k < numEl; ++k) {
-    setJacobian(el[k], jfs, jacobian);
-    
     int i;
-    for (i = 0; i < jacobian.size() && jacobian(i) > _jacBreak; ++i);
-    if (i < jacobian.size()) {
+    for (i = 0; i < numSamplingPt && jacobian(i, k) > _jacBreak; ++i);
+    if (i < numSamplingPt) {
       invalids.push_back(el[k]);
       ++_numInvalid;
       continue;
@@ -748,7 +758,8 @@ void GMSH_AnalyseCurvedMeshPlugin::
       continue;
     }
     
-    bb->matrixLag2Bez.mult(jacobian, jacBez);
+    proxJac.setAsProxy(jacobian, k);
+    bb->matrixLag2Bez.mult(proxJac, jacBez);
     
     for (i = 0; i < jacBez.size() && jacBez(i) > _bezBreak; ++i);
     if (i >= jacBez.size()) {
@@ -825,9 +836,71 @@ int GMSH_AnalyseCurvedMeshPlugin::
 }
 
 
+void GMSH_AnalyseCurvedMeshPlugin::computeMinMax()
+{/*
+  _numAnalysedEl = 0;
+  _numInvalid = 0;
+  _numValid = 0;
+  _numUncertain = 0;
+  _min_Javg = .0, _max_Javg = .0;
+  _min_pJmin = .0, _avg_pJmin = .0;
+  _min_ratioJ = .0, _avg_ratioJ = .0;
+  
+  switch (_dim) {
+    case 3 :
+      for(GModel::riter it = _m->firstRegion(); it != _m->lastRegion(); it++) {
+        GRegion *r = *it;
+        unsigned int numType[5] = {0, 0, 0, 0, 0};
+        r->getNumMeshElements(numType);
+        
+        for(int type = 0; type < 5; type++) {
+          MElement *const *el = r->getStartElementType(type);
+          computeMinMax(el, numType[type]);
+          _numAnalysedEl += numType[type];
+        }
+      }
+      break;
+    
+    case 2 :
+      Msg::Warning("2D elements must be in a z=cst plane ! If they aren't, results won't be correct.");
+      for (GModel::fiter it = _m->firstFace(); it != _m->lastFace(); it++) {
+        GFace *f = *it;
+        unsigned int numType[3] = {0, 0, 0};
+        f->getNumMeshElements(numType);
+        
+        for (int type = 0; type < 3; type++) {
+          MElement *const *el = f->getStartElementType(type);
+          computeMinMax(el, numType[type]);
+          _numAnalysedEl += numType[type];
+        }
+      }
+      break;
+    
+    case 1 :
+      Msg::Warning("1D elements must be on a y=cst & z=cst line ! If they aren't, results won't be correct.");
+      for (GModel::eiter it = _m->firstEdge(); it != _m->lastEdge(); it++) {
+        GEdge *e = *it;
+        unsigned int numElement = e->getNumMeshElements();
+        MElement *const *el = e->getStartElementType(0);
+        computeMinMax(el, numElement);
+        _numAnalysedEl += numElement;
+      }
+      break;
+    
+    default :
+      Msg::Error("I can't analyse any element.");
+      return;
+  }
+  Msg::Info("Extrema of J_avg : %g, %g", _min_Javg, _max_Javg);
+  Msg::Info("Minimum of min(~distortion) : %g", _min_pJmin);
+  Msg::Info("Average of min(~distortion) : %g", _avg_pJmin / _numAnalysedEl);
+  Msg::Info("Minimum of min(J) / max(J) : %g", _min_ratioJ);
+  Msg::Info("Average of min(J) / max(J) : %g", _avg_ratioJ / _numAnalysedEl);
+ */}
+
 void GMSH_AnalyseCurvedMeshPlugin::
   computeMinMax(MElement *const*el, int numEl)
-{
+{/*
   if (numEl < 1)
     return;
   
@@ -843,73 +916,124 @@ void GMSH_AnalyseCurvedMeshPlugin::
   
   fullMatrix<double> jacobian(numSamplingPt, numEl);
   fullMatrix<double> jacBez(numSamplingPt, numEl);
+  fullVector<double> proxBez(numSamplingPt);
   setJacobian(el, jfs, jacobian);
   bb->matrixLag2Bez.mult(jacobian, jacBez);
   
-  fullVector<double> prox(numSamplingPt);
-  
   for (int k = 0; k < numEl; ++k) {
-    prox.setAsProxy(jacBez, k);
+    proxBez.setAsProxy(jacBez, k);
+    double minJ, maxJ = minJ = jacobian(0,k);
     
-    double minJ, maxJ = minJ = jacobian(0,k);//, avgJac = 0;
     for (int i = 1; i < jacobian.size1(); ++i) {
       if (jacobian(i,k) < minJ) minJ = jacobian(i,k);
       if (jacobian(i,k) > maxJ) maxJ = jacobian(i,k);
-      //avgJac += prox(i);
     }
-    //avgJac /= jacobian.size1();
     
+    double minB, maxB = minB = jacBez(0,k), avgJ = .0;
     
+    for (int i = 1; i < proxBez.size1(); ++i) {
+      if (proxBez(i,k) < minB) minB = proxBez(i,k);
+      if (proxBez(i,k) > maxB) maxB = proxBez(i,k);
+      avgJ += jacBez(i,k);
+    }
+    avgJ /= proxBez.size1();
+    _min_Javg = std::min(_min_Javg, avgJ);
+    _max_Javg = std::max(_max_Javg, avgJ);
     
-    //int minJ, maxJ = minJ = prox(0);
-    //
-    //for (int i = 1; i < prox.size(); ++i) {
-    //  if (prox(i) > maxJ) maxJ = prox(i);
-    //  if (prox(i) < minJ) minJ = prox(i);
-    //}
-    
-    //for (int i = 0; i < jacobian.size(); i++)
-    //if (jacobian(i) <= _jacBreak) {
-    //  invalids.push_back(el[k]);
-    //  ++_numInvalid;
-    //  continue;
-    //}
-    //
-    //if (_maxDepth < 1) {
-    //  ++_numUncertain;
-    //  continue;
-    //}
-    //
-    //bb->matrixLag2Bez.mult(jacobian, jacBez);
-    //
-    //int i = 0;
-    //while (i < jacBez.size() && jacBez(i) > _bezBreak)
-    //  ++i;
-    //if (i >= jacBez.size()) {
-    //  ++_numValid;
-    //  continue;
-    //}
-    //
-    //if (_maxDepth < 2) {
-    //  ++_numUncertain;
-    //  continue;
-    //}
-    //else {
-    //  int result = subDivision(bb, jacBez, _maxDepth-1);
-    //  if (result < 0) {
-    //    invalids.push_back(el[k]);
-    //    ++_numInvalid;
-    //    continue;
-    //  }
-    //  if (result > 0) {
-    //    ++_numValid;
-    //    continue;
-    //  }
-    //  ++_numUncertain;
-    //  continue;
-    //}
+    if (_maxDepth > 1 &&
+        (minJ - minB > _tol * (std::abs(minJ) + std::abs(minB)) / 2 ||
+         maxB - maxJ > _tol * (std::abs(maxJ) + std::abs(maxB)) / 2   )) {
+      
+      
+      
+      
+      
+      
+      
+      // Set and map creation :
+      // The set is sorted in such a way that the first key should be the 
+      // better to partition.
+      // The map keep in memory the Bezier minimum and maximum for all part of the element.
+      BezierJacobian *bj = new BezierJacobian(proxBez, jfs, 0);
+      std::list<BezierJacobian> myset;
+      myset.insert(*bj);
+      std::pair<double,double> minmaxB(bj->minB(),bj->maxB());
+      std::map< int, std::pair<double,double> > map_minmaxB;
+      map_minmaxB.insert(std::pair< int, std::pair<double,double> >(bj->num(),minmaxB));
+      
+      bj->setMinMaxBounds(minLB, minUB, maxLB, maxUB);
+      if (min < minUB) minUB = min;
+      if (max > maxLB) maxLB = max;
+      
+      fullVector<double> newJacBez(jfs->divisor.size1());
+      fullVector<double> prox(numSamplingPt);
+      
+      int currentDepth, maxDepth = 0, k = 0;
+      
+      while ((minUB-minLB > tol || maxUB-maxLB > tol)) {
+        // Note that it is not optimized.
+        // When one interval reach tolerance, myset is certainly
+        // no more the more efficiently sorted 
+        // (the fault of BezierJacobian.operator<(...))
+        std::set<BezierJacobian>::iterator it = myset.begin();
+        (*it).partition(newJacBez, jfs);
+        currentDepth = (*it).depth() + 1;
+        if (maxDepth < currentDepth) maxDepth = currentDepth;
+        map_minmaxB.erase((*it).num());
+        myset.erase(it);
+        k++;
+        
+        for (int i = 0; i < jfs->numDivisions; i++) {
+          prox.setAsProxy(newJacBez, i * jacBez.size(), jacBez.size());
+          bj = new BezierJacobian(prox, jfs, currentDepth);
+          if (maxLB < bj->maxJ()) maxLB = bj->maxJ();
+          if (minUB > bj->minJ()) minUB = bj->minJ();
+          myset.insert(*bj);
+          minmaxB = std::make_pair(bj->minB(),bj->maxB());
+          map_minmaxB.insert(std::pair< int, std::pair<double,double> >(bj->num(),minmaxB));
+        }
+        
+        // Deletion of obsolet BezierJacobian
+        it = myset.begin();
+        if ((*it).isObsolet(maxLB, minUB, tol))
+          myset.erase(it++);
+        else ++it;
+        while (it != myset.end()) {
+          if ((*it).isObsolet(maxLB, minUB, tol))
+            myset.erase(it++);
+          else
+            ++it;
+        }
+        
+        // Update of Bezier bounds
+        minLB = minUB;
+        maxUB = maxLB;
+        std::map< int, std::pair<double,double> >::iterator mit;
+        for (mit = map_minmaxB.begin(); mit != map_minmaxB.end(); mit++) {
+          if (minLB > mit->second.first) minLB = mit->second.first;
+          if (maxUB < mit->second.second) maxUB = mit->second.second;
+        }
+      }
+      
+      double *a = new double[6];
+      a[0] = minLB, a[1] = minUB, a[2] = maxLB, a[3] = maxUB;
+      a[4] = (double)k; a[5] = (double)maxDepth;
+      return a;
+      
+      
+      
+      
+      
+      
+      
+      
+    }
+    _min_pJmin = std::min(_min_pJmin, (minJ+minB)/2);
+    _avg_pJmin += (minJ+minB)/2;
+    _min_ratioJ = std::min(_min_ratioJ, (minJ+minB)/(maxB+maxJ));
+    _avg_ratioJ += (minJ+minB)/(maxB+maxJ);
   }
-}
+ */}
 
 //int *GMSH_AnalyseCurvedMeshPlugin::checkJacobian
 //(MElement *const *el, int numEl, int maxDepth, int method)
diff --git a/Plugin/AnalyseCurvedMesh.h b/Plugin/AnalyseCurvedMesh.h
index ba3d966fc80ecef10fdeb37a6679d1f159208cb5..3d4e16fcdd38343425a4168e2aff6d9aa994982a 100644
--- a/Plugin/AnalyseCurvedMesh.h
+++ b/Plugin/AnalyseCurvedMesh.h
@@ -28,6 +28,7 @@ class GMSH_AnalyseCurvedMeshPlugin : public GMSH_PostPlugin
     double _min_Javg, _max_Javg;
     double _min_pJmin, _avg_pJmin;
     double _min_ratioJ, _avg_ratioJ;
+    //
     
   public :
     GMSH_AnalyseCurvedMeshPlugin(){}
@@ -42,6 +43,7 @@ class GMSH_AnalyseCurvedMeshPlugin : public GMSH_PostPlugin
     StringXNumber *getOption(int);  
     PView *execute(PView *);
     void checkValidity(MElement *const *, int numEl, std::vector<MElement*> &invalids);
+    void checkValidity_BLAS(MElement *const *, int numEl, std::vector<MElement*> &invalids);
     
   private :
     void checkValidity(int toDo);
@@ -62,4 +64,37 @@ class GMSH_AnalyseCurvedMeshPlugin : public GMSH_PostPlugin
     */
 };
 
+class BezierJacobian
+{
+private:
+  fullVector<double> _jacBez;
+  double _minJ, _maxJ, _minB, _maxB; //Extremum of Jac at corners and of bezier values
+  int _depthSub;
+  int _num; // Used for map of minmaxB
+  static int _globalNum;
+  
+public:
+  BezierJacobian(fullVector<double> &, const JacobianBasis *, int depth);
+  inline bool operator<(const BezierJacobian &other) const
+    {return other._maxB - _maxB - other._minB + _minB < 0;}
+  void partition(fullVector<double> &, const JacobianBasis *) const;
+  inline bool isObsolet(double maxLB, double minUB, double tol) const
+    {return _maxB - maxLB < tol &&  minUB - _minB < tol;}
+  
+  int num() const {return _num;}
+  int depth() const {return _depthSub;}
+  double minJ() const {return _minJ;}
+  double minB() const {return _minB;}
+  double maxJ() const {return _maxJ;}
+  double maxB() const {return _maxB;}
+  double setMinMaxBounds(double &minLB, double &minUB, double &maxLB, double &maxUB) const
+  {
+    /*Msg::Info("setminmax : %g = %g - %g",_minJ-_minB,_minJ,_minB);
+    Msg::Info("setminmax : %g = %g - %g",_maxB-_maxJ,_maxB,_maxJ);Msg::Info(" ");
+    
+    int g;
+    std::cin >> g;*/
+      minUB = _minJ; minLB = _minB; maxUB = _maxB; maxLB = _maxJ;}
+};
+
 #endif