diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp
index c99ac805b0a3db56e8bcff9667d75445059a73e7..7fb7b2c816f579b4d623b1108014e7d39bedcbb2 100644
--- a/Common/CommandLine.cpp
+++ b/Common/CommandLine.cpp
@@ -518,6 +518,8 @@ void GetOptions(int argc, char *argv[])
             CTX::instance()->mesh.fileFormat = FORMAT_UNV;
           else if(!strcmp(argv[i], "vrml"))
             CTX::instance()->mesh.fileFormat = FORMAT_VRML;
+	  else if(!strcmp(argv[i], "ply2"))
+	    CTX::instance()->mesh.fileFormat = FORMAT_PLY2;
           else if(!strcmp(argv[i], "stl"))
             CTX::instance()->mesh.fileFormat = FORMAT_STL;
           else if(!strcmp(argv[i], "mesh"))
diff --git a/Common/CreateFile.cpp b/Common/CreateFile.cpp
index c359a1d0a030c72a027da7b920ecac3f5cfef1f4..29bb6d9a0013e23beace59ad6b84dd3d111a69ee 100644
--- a/Common/CreateFile.cpp
+++ b/Common/CreateFile.cpp
@@ -48,6 +48,7 @@ int GuessFileFormatFromFileName(std::string fileName)
   else if(ext == ".p3d")  return FORMAT_P3D;
   else if(ext == ".wrl")  return FORMAT_VRML;
   else if(ext == ".vrml") return FORMAT_VRML;
+  else if(ext == ".ply2") return FORMAT_PLY2;
   else if(ext == ".gif")  return FORMAT_GIF;
   else if(ext == ".jpg")  return FORMAT_JPEG;
   else if(ext == ".jpeg") return FORMAT_JPEG;
@@ -90,6 +91,7 @@ std::string GetDefaultFileName(int format)
   case FORMAT_INP:  name += ".inp"; break;
   case FORMAT_P3D:  name += ".p3d"; break;
   case FORMAT_VRML: name += ".wrl"; break;
+  case FORMAT_PLY2: name += ".ply2"; break;
   case FORMAT_GIF:  name += ".gif"; break;
   case FORMAT_JPEG: name += ".jpg"; break;
   case FORMAT_MPEG: name += ".mpg"; break;
@@ -202,6 +204,10 @@ void CreateOutputFile(std::string fileName, int format)
       (fileName, CTX::instance()->mesh.saveAll, CTX::instance()->mesh.scalingFactor);
     break;
 
+  case FORMAT_PLY2:
+    GModel::current()->writePLY2(fileName);
+    break;
+
   case FORMAT_UNV:
     GModel::current()->writeUNV
       (fileName, CTX::instance()->mesh.saveAll, CTX::instance()->mesh.saveGroupsOfNodes,
diff --git a/Common/DefaultOptions.h b/Common/DefaultOptions.h
index ceda6e2fbc63ba030c8559f408f3a36b18f4fbca..f188b5deb490f8b791b028568cb0d6b78d6b5b01 100644
--- a/Common/DefaultOptions.h
+++ b/Common/DefaultOptions.h
@@ -1095,7 +1095,7 @@ StringXNumber MeshOptions_Number[] = {
 
   { F|O, "Format" , opt_mesh_file_format , FORMAT_AUTO , 
     "Mesh output format (1=msh, 2=unv, 10=automatic, 19=vrml, 27=stl, 30=mesh, 31=bdf, "
-    "32=cgns, 33=med)" },
+    "32=cgns, 33=med, 40=ply2)" },
 
   { F|O, "Hexahedra" , opt_mesh_hexahedra , 1. , 
     "Display mesh hexahedra?" },
diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h
index ff39bdc25d41ae795950d6022be4eb0f5c148e44..6baf3c1854d4bd34e878c1c68a11b68236a9e46b 100644
--- a/Common/GmshDefines.h
+++ b/Common/GmshDefines.h
@@ -43,6 +43,7 @@
 #define FORMAT_IGES  37
 #define FORMAT_IR3   38
 #define FORMAT_INP   39
+#define FORMAT_PLY2  40
 
 // Element types
 #define TYPE_PNT     1
diff --git a/Common/OpenFile.cpp b/Common/OpenFile.cpp
index 00218141cfbb4efd2e77342cc9cbecccff398c33..d0098daf3f31f08ac23fea9d8c6322331a3bfda6 100644
--- a/Common/OpenFile.cpp
+++ b/Common/OpenFile.cpp
@@ -337,6 +337,9 @@ int MergeFile(std::string fileName, bool warnIfMissing)
     status = binding::instance()->readFile(fileName.c_str());
   }
 #endif
+  else if(ext == ".ply2"){
+    status = GModel::current()->readPLY2(fileName);
+  }
   else {
     CTX::instance()->geom.draw = 1;
     if(!strncmp(header, "$PTS", 4) || !strncmp(header, "$NO", 3) || 
diff --git a/Fltk/menuWindow.cpp b/Fltk/menuWindow.cpp
index c4c7db394f457527cb1262ed4baa568ca902dd41..306071679230c9e9bbb781b4848641b66bb46982 100644
--- a/Fltk/menuWindow.cpp
+++ b/Fltk/menuWindow.cpp
@@ -127,6 +127,7 @@ static const char *input_formats =
   "STL Surface Mesh" TT "*.stl" NN
   "VTK Mesh" TT "*.vtk" NN
   "VRML Surface Mesh" TT "*.{wrl,vrml}" NN
+  "PLY2 Surface Mesh" TT "*.{ply2}" NN
   SEPARATOR_IN
   "BMP" TT "*.bmp" NN
 #if defined(HAVE_LIBJPEG)
@@ -271,6 +272,8 @@ static int _save_stl(const char *name){ return genericMeshFileDialog
     (name, "STL Options", FORMAT_STL, true, false); }
 static int _save_vrml(const char *name){ return genericMeshFileDialog
     (name, "VRML Options", FORMAT_VRML, false, false); }
+static int _save_ply2(const char *name){ return genericMeshFileDialog
+    (name, "PLY2 Options", FORMAT_PLY2, false, false); }
 static int _save_eps(const char *name){ return gl2psFileDialog
     (name, "EPS Options", FORMAT_EPS); }
 static int _save_gif(const char *name){ return gifFileDialog(name); }
@@ -309,6 +312,7 @@ static int _save_auto(const char *name)
   case FORMAT_IR3  : return _save_ir3(name);
   case FORMAT_STL  : return _save_stl(name);
   case FORMAT_VRML : return _save_vrml(name);
+  case FORMAT_PLY2 : return _save_ply2(name);
   case FORMAT_EPS  : return _save_eps(name);
   case FORMAT_GIF  : return _save_gif(name);
   case FORMAT_JPEG : return _save_jpeg(name);
@@ -357,6 +361,7 @@ static void file_save_as_cb(Fl_Widget *w, void *data)
     {"STL Surface Mesh" TT "*.stl", _save_stl},
     {"VRML Surface Mesh" TT "*.wrl", _save_vrml},
     {"VTK Mesh" TT "*.vtk", _save_vtk},
+    {"PLY2 Mesh" TT "*.ply2", _save_ply2},
     SEPARATOR_OUT
     {"Encapsulated PostScript" TT "*.eps", _save_eps},
     {"GIF" TT "*.gif", _save_gif},
diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp
index 292deca07ec9518b91fea889f70450f80f4c2b9a..76648d43e0d4cf488042531eb539c6c881d1ff11 100644
--- a/Geo/GFaceCompound.cpp
+++ b/Geo/GFaceCompound.cpp
@@ -81,6 +81,70 @@ static int intersection_segments (SPoint3 &p1, SPoint3 &p2,
   } 
   
 }
+
+//--------------------------------------------------------------
+static bool orderVertices(const std::list<GEdge*> &e, std::vector<MVertex*> &l,
+                          std::vector<double> &coord)
+{
+  l.clear();
+  coord.clear();
+
+  std::list<GEdge*>::const_iterator it = e.begin();
+  std::list<MLine*> temp;
+  double tot_length = 0;
+  for( ; it != e.end(); ++it ){
+    for(unsigned int i = 0; i < (*it)->lines.size(); i++ ){
+      temp.push_back((*it)->lines[i]);
+      MVertex *v0 = (*it)->lines[i]->getVertex(0);
+      MVertex *v1 = (*it)->lines[i]->getVertex(1);    
+      const double length = sqrt((v0->x() - v1->x()) * (v0->x() - v1->x()) + 
+                                 (v0->y() - v1->y()) * (v0->y() - v1->y()) +
+                                 (v0->z() - v1->z()) * (v0->z() - v1->z()));
+      tot_length += length;
+    }
+  }
+    
+  MVertex *first_v = (*temp.begin())->getVertex(0);
+  MVertex *current_v = (*temp.begin())->getVertex(1);
+  
+  l.push_back(first_v);
+  coord.push_back(0.0);
+  temp.erase(temp.begin());
+
+  while(temp.size()){
+    bool found = false;
+    for(std::list<MLine*>::iterator itl = temp.begin(); itl != temp.end(); ++itl){
+      MLine *ll = *itl;
+      MVertex *v0 = ll->getVertex(0);
+      MVertex *v1 = ll->getVertex(1);
+      if(v0 == current_v){
+        found = true;
+        l.push_back(current_v);
+        current_v = v1;
+        temp.erase(itl);
+        const double length = sqrt((v0->x() - v1->x()) * (v0->x() - v1->x()) + 
+                                   (v0->y() - v1->y()) * (v0->y() - v1->y()) +
+                                   (v0->z() - v1->z()) * (v0->z() - v1->z()));  
+        coord.push_back(coord[coord.size()-1] + length / tot_length);
+        break;
+      }
+      else if(v1 == current_v){
+        found = true;
+        l.push_back(current_v);
+        current_v = v0;
+        temp.erase(itl);
+        const double length = sqrt((v0->x() - v1->x()) * (v0->x() - v1->x()) + 
+                                   (v0->y() - v1->y()) * (v0->y() - v1->y()) +
+                                   (v0->z() - v1->z()) * (v0->z() - v1->z()));
+        coord.push_back(coord[coord.size()-1] + length / tot_length);
+        break;
+      }
+    }
+    if(!found) return false;
+  }    
+  return true;
+}
+
 //--------------------------------------------------------------
 static void computeCGKernelPolygon(std::map<MVertex*,SPoint3> &coordinates, 
                                    std::vector<MVertex*> &cavV, double &ucg, double &vcg)
@@ -269,12 +333,18 @@ void GFaceCompound::fillNeumannBCS() const
 {
 
   fillTris.clear();
+  fillNodes.clear();
 
-  //close neuman bcs
+  //closed interior loops
   for(std::list<std::list<GEdge*> >::const_iterator iloop = _interior_loops.begin(); 
       iloop != _interior_loops.end(); iloop++){
+    std::list<MTriangle*> loopfillTris;
     std::list<GEdge*> loop = *iloop;
     if (loop != _U0 ){
+      std::vector<MVertex*> ordered;
+      std::vector<double> coords;  
+      bool success = orderVertices(*iloop, ordered, coords);
+
       //--- center of Neumann interior loop
       int nb = 0;
       double x=0.; 
@@ -282,65 +352,116 @@ void GFaceCompound::fillNeumannBCS() const
       double z=0.;
       //EMI- TODO FIND KERNEL OF POLYGON AND PLACE AT CG KERNEL !
       //IF NO KERNEL -> DO NOT FILL TRIS
-      for (std::list<GEdge*>::iterator ite = loop.begin(); ite != loop.end(); ite++){
-        for (unsigned int k= 0; k< (*ite)->getNumMeshElements(); k++){
-          MVertex *v0 = (*ite)->getMeshElement(k)->getVertex(0);
-          MVertex *v1 = (*ite)->getMeshElement(k)->getVertex(1);
-          x += .5*(v0->x() + v1->x()); 
-          y += .5*(v0->y() + v1->y()); 
-          z += .5*(v0->z() + v1->z()); 
-          nb++;
-        }
+      for(unsigned int i = 0; i < ordered.size(); ++i){
+	MVertex *v0 = ordered[i];
+	MVertex *v1 = (i==ordered.size()-1) ? ordered[0]: ordered[i+1];
+	x += .5*(v0->x() + v1->x()); 
+	y += .5*(v0->y() + v1->y()); 
+	z += .5*(v0->z() + v1->z()); 
+	nb++;
       }
       x/=nb; y/=nb;  z/=nb;
       MVertex *c = new MVertex(x, y, z);
          
       //--- create new triangles
-      for (std::list<GEdge*>::iterator ite = loop.begin(); ite != loop.end(); ite++){
-        for (unsigned int i= 0; i< (*ite)->getNumMeshElements(); i++){
-          MVertex *v0 = (*ite)->getMeshElement(i)->getVertex(0);
-          MVertex *v1 = (*ite)->getMeshElement(i)->getVertex(1);
+      for(unsigned int i = 0; i < ordered.size(); ++i){
+	MVertex *v0 = ordered[i];
+	MVertex *v1 = (i==ordered.size()-1) ? ordered[0]: ordered[i+1];
   
-//        fillTris.push_back(new MTriangle(v0,v1, c));
-
-          MVertex *v2 = new MVertex(.5*(v0->x()+c->x()), .5*(v0->y()+c->y()), .5*(v0->z()+c->z()));
-          MVertex *v3 = new MVertex(.5*(v1->x()+c->x()), .5*(v1->y()+c->y()), .5*(v1->z()+c->z()));
-          fillTris.push_back(new MTriangle(v0,v2,v3));
-          fillTris.push_back(new MTriangle(v2,c, v3));
-          fillTris.push_back(new MTriangle(v0,v3, v1)) ;
-
-//        MVertex *v2 = new MVertex(.66*v0->x()+.33*c->x(), .66*v0->y()+.33*c->y(), .66*v0->z()+.33*c->z());
-//        MVertex *v3 = new MVertex(.66*v1->x()+.33*c->x(), .66*v1->y()+.33*c->y(), .66*v1->z()+.33*c->z());
-//        MVertex *v4 = new MVertex(.33*v0->x()+.66*c->x(), .33*v0->y()+.66*c->y(), .33*v0->z()+.66*c->z());
-//        MVertex *v5 = new MVertex(.33*v1->x()+.66*c->x(), .33*v1->y()+.66*c->y(), .33*v1->z()+.66*c->z()); 
-//        fillTris.push_back(new MTriangle(v0,v2,v3));
-//        fillTris.push_back(new MTriangle(v2,v5,v3));
-//        fillTris.push_back(new MTriangle(v2,v4,v5));
-//        fillTris.push_back(new MTriangle(v4,c,v5));
-//        fillTris.push_back(new MTriangle(v0,v3,v1));
-
-        }
+	//loopfillTris.push_back(new MTriangle(v0,v1, c));
+
+	// MVertex *v2 = new MVertex(.5*(v0->x()+c->x()), .5*(v0->y()+c->y()), .5*(v0->z()+c->z()));
+	// MVertex *v3 = new MVertex(.5*(v1->x()+c->x()), .5*(v1->y()+c->y()), .5*(v1->z()+c->z()));
+	// fillNodes.insert(c); fillNodes.insert(v2); fillNodes.insert(v3);
+	// loopfillTris.push_back(new MTriangle(v0,v2,v3));
+	// loopfillTris.push_back(new MTriangle(v2,c, v3));
+	// loopfillTris.push_back(new MTriangle(v0,v3, v1));
+
+	double k = 1/3.; double kk = 2/3.;
+	MVertex *v2 = new MVertex(kk*v0->x()+k*c->x(), kk*v0->y()+k*c->y(),kk*v0->z()+k*c->z());
+	MVertex *v3 = new MVertex(kk*v1->x()+k*c->x(), kk*v1->y()+k*c->y(),kk*v1->z()+k*c->z());
+	MVertex *v4 = new MVertex(k*v0->x()+kk*c->x(), k*v0->y()+kk*c->y(),k*v0->z()+kk*c->z());
+	MVertex *v5 = new MVertex(k*v1->x()+kk*c->x(), k*v1->y()+kk*c->y(),k*v1->z()+kk*c->z()); 
+	fillNodes.insert(c); fillNodes.insert(v2); fillNodes.insert(v3);
+	fillNodes.insert(v4); fillNodes.insert(v5);
+	loopfillTris.push_back(new MTriangle(v0,v2,v3));
+	loopfillTris.push_back(new MTriangle(v2,v5,v3));
+	loopfillTris.push_back(new MTriangle(v2,v4,v5));
+	loopfillTris.push_back(new MTriangle(v4,c,v5));
+	loopfillTris.push_back(new MTriangle(v0,v3,v1));
       }
+      
     }
-  }
-  
 
-  if (fillTris.size() > 0){
-    FILE * ftri = fopen("fillTris.pos","a");
-    fprintf(ftri,"View \"\"{\n");
-    for (std::list<MTriangle*>::iterator it2 = fillTris.begin(); it2 !=fillTris.end(); it2++ ){
-      MTriangle *t = (*it2);
-      fprintf(ftri,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
-              t->getVertex(0)->x(), t->getVertex(0)->y(), t->getVertex(0)->z(),
-              t->getVertex(1)->x(), t->getVertex(1)->y(), t->getVertex(1)->z(),
-              t->getVertex(2)->x(), t->getVertex(2)->y(), t->getVertex(2)->z(),
-              1., 1., 1.);
+    //check normal orientations of loopfillTris
+    bool invertTris = false;
+    std::map<MEdge, std::set<MTriangle*>, Less_Edge > edge2tris;
+    for(std::list<MTriangle*>::iterator t= loopfillTris.begin(); t!=loopfillTris.end(); t++){
+      for (int j = 0; j < 3; j++){
+	MEdge me = (*t)->getEdge(j);
+	std::map<MEdge, std::set<MTriangle*, std::less<MTriangle*> >, Less_Edge >::iterator it = edge2tris.find(me);
+	if (it == edge2tris.end()) {
+	  std::set<MTriangle*, std::less<MTriangle*> > mySet;
+	  mySet.insert(*t);
+	  edge2tris.insert(std::make_pair(me, mySet));
+	}
+	else{
+	  std::set<MTriangle*, std::less<MTriangle*> > mySet = it->second;
+	  mySet.insert(*t);
+	  it->second = mySet;
+	}
+      }
+    }
+    int iE, si, iE2, si2;
+    std::list<GFace*>::const_iterator itf = _compound.begin();
+    for( ; itf != _compound.end(); ++itf){
+      for(unsigned int i = 0; i < (*itf)->triangles.size(); ++i){
+	MTriangle *t = (*itf)->triangles[i];
+	for (int j = 0; j < 3; j++){
+	  MEdge me = t->getEdge(j);
+	  std::map<MEdge, std::set<MTriangle*>, Less_Edge >::iterator it = edge2tris.find(me);
+	  if(it != edge2tris.end()){
+	    t->getEdgeInfo(me, iE,si);
+	    MTriangle* t2 = *((it->second).begin());
+	    t2->getEdgeInfo(me,iE2,si2);
+	    if(si == si2) {
+	      invertTris = true;
+	      break;
+	    }
+	  }
+	}
+      } 
+    }
+    if (invertTris){
+      for (std::list<MTriangle*>::iterator it = loopfillTris.begin(); it !=loopfillTris.end(); it++ )
+	(*it)->revert();
+    }
+    
+    fillTris.insert(fillTris.begin(),loopfillTris.begin(),loopfillTris.end());
+
+  }
+
+  //printing
+  if( !CTX::instance()->mesh.saveAll){
+    if (fillTris.size() > 0){
+      char name[256];
+      std::list<GFace*>::const_iterator itf = _compound.begin();
+      sprintf(name, "fillTris-%d.pos", (*itf)->tag());
+      FILE * ftri = fopen(name,"w");
+      fprintf(ftri,"View \"\"{\n");
+      for (std::list<MTriangle*>::iterator it2 = fillTris.begin(); it2 !=fillTris.end(); it2++ ){
+	MTriangle *t = (*it2);
+	fprintf(ftri,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
+		t->getVertex(0)->x(), t->getVertex(0)->y(), t->getVertex(0)->z(),
+		t->getVertex(1)->x(), t->getVertex(1)->y(), t->getVertex(1)->z(),
+		t->getVertex(2)->x(), t->getVertex(2)->y(), t->getVertex(2)->z(),
+		1., 1., 1.);
+      }
+      fprintf(ftri,"};\n");
+      fclose(ftri);
     }
-    fprintf(ftri,"};\n");
-    fclose(ftri);
   }
 
-
 }
 
 
@@ -358,31 +479,42 @@ bool GFaceCompound::trivial() const
 }
 
 
-//For the conformal map the linear system cannot guarantee there is no folding 
+//For the conformal map the linear system cannot guarantee there is no overlapping
 //of triangles
-bool GFaceCompound::checkFolding(std::vector<MVertex*> &ordered) const
+bool GFaceCompound::checkOverlap(std::vector<MVertex*> &ordered) const
 {
 
-  bool has_no_folding = true;
-
-  for(unsigned int i = 0; i < ordered.size()-1; ++i){
-    SPoint3 p1 = coordinates[ordered[i]];
-    SPoint3 p2 = coordinates[ordered[i+1]];
-    int maxSize = (i==0) ? ordered.size()-2: ordered.size()-1;
-    for(int k = i+2; k < maxSize; ++k){
-      SPoint3 q1 = coordinates[ordered[k]];
-      SPoint3 q2 = coordinates[ordered[k+1]];
-      double x[2];
-      int inters = intersection_segments (p1,p2,q1,q2,x);
-      if (inters > 0) has_no_folding = false;
+  bool has_no_overlap = true;
+
+  for(std::list<std::list<GEdge*> >::const_iterator iloop = _interior_loops.begin(); 
+      iloop != _interior_loops.end(); iloop++){
+    std::vector<MVertex*> ordered;
+    std::vector<double> coords;  
+    bool success = orderVertices(*iloop, ordered, coords);
+    
+    for(unsigned int i = 0; i < ordered.size()-1; ++i){
+      SPoint3 p1 = coordinates[ordered[i]];
+      SPoint3 p2 = coordinates[ordered[i+1]];
+      int maxSize = (i==0) ? ordered.size()-2: ordered.size()-1;
+      for(int k = i+2; k < maxSize; ++k){
+	SPoint3 q1 = coordinates[ordered[k]];
+	SPoint3 q2 = coordinates[ordered[k+1]];
+	double x[2];
+	int inters = intersection_segments (p1,p2,q1,q2,x);
+	if (inters > 0){
+	  has_no_overlap = false; 
+	  break;
+	}
+      }
     }
+    
   }
   
-  if ( !has_no_folding ) {
-    Msg::Warning("$$$ Folding for compound face %d", this->tag());
+  if ( !has_no_overlap ) {
+    Msg::Warning("$$$ Overlap for compound face %d", this->tag());
   }
 
-  return has_no_folding;
+  return has_no_overlap;
 
 }
 
@@ -424,15 +556,15 @@ bool GFaceCompound::checkOrientation(int iter) const
     }    
   }  
 
-  int iterMax = 10;
+  int iterMax = 15;
   if(!oriented && iter < iterMax){
-    if (iter == 0) Msg::Warning("--- Parametrization is flipping : applying cavity checks.");
+    if (iter == 0) Msg::Info("--- Parametrization is flipping : applying cavity checks.");
     Msg::Debug("--- Cavity Check - iter %d -",iter);
     one2OneMap();
     return checkOrientation(iter+1);
   }
   else if (oriented && iter < iterMax){
-    Msg::Info("Parametrization has no flips :-)");
+    //Msg::Info("Parametrization is bijective (no flips)");
     //printStuff(); 
   }
 
@@ -518,11 +650,11 @@ bool GFaceCompound::parametrize() const
   else if (_mapping == CONFORMAL){
     Msg::Debug("Parametrizing surface %d with 'conformal map'", tag());
     fillNeumannBCS();
-    bool withoutFolding = parametrize_conformal_spectral() ;
-    //bool withoutFolding = parametrize_conformal();
-    if ( withoutFolding == false ){
+    bool withoutOverlap = parametrize_conformal_spectral() ;
+    //bool withoutOverlap = parametrize_conformal();
+    if ( withoutOverlap == false || !checkOrientation(0) ){
       Msg::Warning("$$$ Parametrization switched to harmonic map");
-      parametrize(ITERU,HARMONIC); 
+       parametrize(ITERU,HARMONIC); 
       parametrize(ITERV,HARMONIC);
       //buildOct(); exit(1);
     }
@@ -531,7 +663,7 @@ bool GFaceCompound::parametrize() const
   buildOct();  
 
   if (!checkOrientation(0)){
-    Msg::Info("--- Parametrization switched to convex combination map");
+    Msg::Info("### Parametrization switched to convex combination map");
     coordinates.clear(); 
     Octree_Delete(oct);
     fillNeumannBCS();
@@ -544,8 +676,7 @@ bool GFaceCompound::parametrize() const
 
   double AR = checkAspectRatio();
   if (floor(AR)  > AR_MAX){
-    Msg::Warning("Geometrical aspect ratio too high AR=%d ", (int)AR);
-    //exit(1);
+    Msg::Warning("Geometrical aspect ratio is high AR=%d ", (int)AR);
     paramOK = true; //false;
   }
 
@@ -834,68 +965,6 @@ GFaceCompound::~GFaceCompound()
   if (_lsys)delete _lsys;
 }
 
-// order vertices of a closed loop
-static bool orderVertices(const std::list<GEdge*> &e, std::vector<MVertex*> &l,
-                          std::vector<double> &coord)
-{
-  l.clear();
-  coord.clear();
-
-  std::list<GEdge*>::const_iterator it = e.begin();
-  std::list<MLine*> temp;
-  double tot_length = 0;
-  for( ; it != e.end(); ++it ){
-    for(unsigned int i = 0; i < (*it)->lines.size(); i++ ){
-      temp.push_back((*it)->lines[i]);
-      MVertex *v0 = (*it)->lines[i]->getVertex(0);
-      MVertex *v1 = (*it)->lines[i]->getVertex(1);    
-      const double length = sqrt((v0->x() - v1->x()) * (v0->x() - v1->x()) + 
-                                 (v0->y() - v1->y()) * (v0->y() - v1->y()) +
-                                 (v0->z() - v1->z()) * (v0->z() - v1->z()));
-      tot_length += length;
-    }
-  }
-    
-  MVertex *first_v = (*temp.begin())->getVertex(0);
-  MVertex *current_v = (*temp.begin())->getVertex(1);
-  
-  l.push_back(first_v);
-  coord.push_back(0.0);
-  temp.erase(temp.begin());
-
-  while(temp.size()){
-    bool found = false;
-    for(std::list<MLine*>::iterator itl = temp.begin(); itl != temp.end(); ++itl){
-      MLine *ll = *itl;
-      MVertex *v0 = ll->getVertex(0);
-      MVertex *v1 = ll->getVertex(1);
-      if(v0 == current_v){
-        found = true;
-        l.push_back(current_v);
-        current_v = v1;
-        temp.erase(itl);
-        const double length = sqrt((v0->x() - v1->x()) * (v0->x() - v1->x()) + 
-                                   (v0->y() - v1->y()) * (v0->y() - v1->y()) +
-                                   (v0->z() - v1->z()) * (v0->z() - v1->z()));  
-        coord.push_back(coord[coord.size()-1] + length / tot_length);
-        break;
-      }
-      else if(v1 == current_v){
-        found = true;
-        l.push_back(current_v);
-        current_v = v0;
-        temp.erase(itl);
-        const double length = sqrt((v0->x() - v1->x()) * (v0->x() - v1->x()) + 
-                                   (v0->y() - v1->y()) * (v0->y() - v1->y()) +
-                                   (v0->z() - v1->z()) * (v0->z() - v1->z()));
-        coord.push_back(coord[coord.size()-1] + length / tot_length);
-        break;
-      }
-    }
-    if(!found) return false;
-  }    
-  return true;
-}
 
 SPoint2 GFaceCompound::getCoordinates(MVertex *v) const 
 { 
@@ -1058,7 +1127,7 @@ void GFaceCompound::parametrize(iterationStep step, typeOfMapping tom, double al
     }    
   }
 
-  for (std::list<MTriangle*>::iterator it2 = fillTris.begin(); it2 !=fillTris.end(); it2++ ){
+   for (std::list<MTriangle*>::iterator it2 = fillTris.begin(); it2 !=fillTris.end(); it2++ ){
     MTriangle *t = (*it2);
     myAssembler.numberVertex(t->getVertex(0), 0, 1);
     myAssembler.numberVertex(t->getVertex(1), 0, 1);
@@ -1160,6 +1229,12 @@ bool GFaceCompound::parametrize_conformal_spectral() const
     myAssembler.numberVertex(v, 0, 2);
   }
 
+  for(std::set<MVertex *>::iterator itv = fillNodes.begin(); itv !=fillNodes.end() ; ++itv){
+    MVertex *v = *itv;
+    myAssembler.numberVertex(v, 0, 1);
+    myAssembler.numberVertex(v, 0, 2);
+  }
+
   simpleFunction<double> ONE(1.0);
   simpleFunction<double> MONE(-1.0 );
   laplaceTerm laplace1(model(), 1, &ONE);
@@ -1176,6 +1251,15 @@ bool GFaceCompound::parametrize_conformal_spectral() const
       cross21.addToMatrix(myAssembler, &se);
     }
   }
+
+  for (std::list<MTriangle*>::iterator it2 = fillTris.begin(); it2 !=fillTris.end(); it2++ ){
+    SElement se((*it2));
+    laplace1.addToMatrix(myAssembler, &se);
+    laplace2.addToMatrix(myAssembler, &se);
+    cross12.addToMatrix(myAssembler, &se);
+    cross21.addToMatrix(myAssembler, &se);
+  }
+
   double epsilon = 1.e-7;
   for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){
       MVertex *v = *itv;
@@ -1184,6 +1268,13 @@ bool GFaceCompound::parametrize_conformal_spectral() const
         myAssembler.assemble(v, 0, 2, v, 0, 2,  epsilon);
       }
   }
+  for(std::set<MVertex *>::iterator itv = fillNodes.begin(); itv !=fillNodes.end() ; ++itv){
+      MVertex *v = *itv;
+      if (std::find(ordered.begin(), ordered.end(), v) == ordered.end() ){
+        myAssembler.assemble(v, 0, 1, v, 0, 1,  epsilon);
+        myAssembler.assemble(v, 0, 2, v, 0, 2,  epsilon);
+      }
+  }
 
   //-------------------------------
    myAssembler.setCurrentMatrix("B");
@@ -1200,6 +1291,11 @@ bool GFaceCompound::parametrize_conformal_spectral() const
        myAssembler.assemble(v, 0, 2, v, 0, 2,  1.0);
      }
    } 
+   for(std::set<MVertex *>::iterator itv = fillNodes.begin(); itv !=fillNodes.end() ; ++itv){
+     MVertex *v = *itv;
+     myAssembler.assemble(v, 0, 1, v, 0, 1,  small);
+     myAssembler.assemble(v, 0, 2, v, 0, 2,  small);
+   }
 
    //mettre max NC contraintes par bord
    int NB = ordered.size();
@@ -1243,7 +1339,7 @@ bool GFaceCompound::parametrize_conformal_spectral() const
      lsysA->clear();
      lsysB->clear();
 
-     return checkFolding(ordered);
+     return checkOverlap(ordered);
 
    }
    else return false;
@@ -1344,8 +1440,8 @@ bool GFaceCompound::parametrize_conformal() const
 
   _lsys->clear();
 
-  //check for folding
-  return checkFolding(ordered);
+  //check for overlapping triangles
+  return checkOverlap(ordered);
 
 }
 
@@ -1840,15 +1936,20 @@ bool GFaceCompound::checkTopology() const
       Msg::Info("--- Split surface %d in %d parts with Multilevel Mesh partitioner", tag(), nbSplit);
     }
   }
-   else if (G == 0 && AR > AR_MAX){
-     correctTopo = false;
-     nbSplit = -2;
-     Msg::Warning("Wrong topology: Genus=%d, Nb boundaries=%d, AR=%d", G, Nb, AR);
-     if (_allowPartition){
-       Msg::Info("-----------------------------------------------------------");
-       Msg::Info("--- Split surface %d in 2 parts with Laplacian Mesh partitioner", tag());
-     }
-   }
+  else if (G == 0 && AR > AR_MAX){
+    correctTopo = false;
+    Msg::Warning("Wrong topology: Genus=%d, Nb boundaries=%d, AR=%d", G, Nb, AR);
+    if (_allowPartition == 1){
+      nbSplit = -2;
+      Msg::Info("-----------------------------------------------------------");
+      Msg::Info("--- Split surface %d in 2 parts with Laplacian Mesh partitioner", tag());
+    }
+    else if (_allowPartition == 2){
+      nbSplit = 2;
+      Msg::Info("-----------------------------------------------------------");
+      Msg::Info("--- Split surface %d in %d parts with Multilevel Mesh partitioner", tag(), nbSplit);
+    }
+  }
   else{
     Msg::Debug("Correct topology: Genus=%d and Nb boundaries=%d, AR=%g", G, Nb, H/D);
   }
@@ -1865,7 +1966,7 @@ double GFaceCompound::checkAspectRatio() const
 
   if(allNodes.empty()) buildAllNodes();
   
-  double limit =  1.e-17;
+  double limit =  1.e-20;
   double areaMin = 1.e20;
   double area3D = 0.0;
   int nb = 0;
@@ -2029,9 +2130,7 @@ void GFaceCompound::printStuff() const
   sprintf(name5, "XYZV-%d.pos", (*it)->tag());
   sprintf(name6, "XYZC-%d.pos", (*it)->tag());
 
-  sprintf(name7, "UVME-%d.pos", (*it)->tag());
-  sprintf(name8, "UVMF-%d.pos", (*it)->tag());
-  sprintf(name9, "UVMG-%d.pos", (*it)->tag());
+  sprintf(name7, "UVM-%d.pos", (*it)->tag());
 
   FILE * uva = fopen(name0,"w");
   FILE * uvx = fopen(name1,"w");
@@ -2040,9 +2139,7 @@ void GFaceCompound::printStuff() const
   FILE * xyzu = fopen(name4,"w");
   FILE * xyzv = fopen(name5,"w");
   FILE * xyzc = fopen(name6,"w");
-  FILE * uvme = fopen(name7,"w");
-  FILE * uvmf = fopen(name8,"w");
-  FILE * uvmg = fopen(name9,"w");
+  FILE * uvm = fopen(name7,"w");
 
 
   fprintf(uva,"View \"\"{\n");
@@ -2052,10 +2149,7 @@ void GFaceCompound::printStuff() const
   fprintf(xyzu,"View \"\"{\n");
   fprintf(xyzv,"View \"\"{\n");
   fprintf(xyzc,"View \"\"{\n");
-  fprintf(uvme,"View \"\"{\n");
-  fprintf(uvmf,"View \"\"{\n");  
-  fprintf(uvmg,"View \"\"{\n");
-
+  fprintf(uvm,"View \"\"{\n");
 
   for( ; it != _compound.end() ; ++it){
     for(unsigned int i = 0; i < (*it)->triangles.size(); ++i){
@@ -2108,27 +2202,35 @@ void GFaceCompound::printStuff() const
       double metric2f = dot(der2.second()*(1./norm(der2.second())), der2.first()*(1./norm(der2.first())));
       double metric2g = dot(der2.second(), der2.second());
       
+      double mat0[2][2], eig0[2];
+      double mat1[2][2], eig1[2];
+      double mat2[2][2], eig2[2];
+      mat0[0][0]  = metric0e;  mat0[0][1]  =  metric0f;  
+      mat0[1][0]  =  metric0f;  mat0[1][1]  =  metric0g;  
+      eigenvalue2x2(mat0, eig0);
+      mat1[0][0]  = metric1e;  mat1[0][1]  = metric1f; 
+      mat1[1][0]  = metric1f;  mat1[1][1]  = metric1g; 
+      eigenvalue2x2(mat1, eig1);
+      mat2[0][0]  = metric2e;  mat2[0][1]  = metric2f; 
+      mat2[1][0]  = metric2f;  mat2[1][1]  = metric2g; 
+      eigenvalue2x2(mat2, eig2);
+
+      double disp0 = sqrt(.5*(eig0[0]*eig0[0]+ (eig0[1]*eig0[1])));
+      double disp1 = sqrt(.5*(eig1[0]*eig1[0]+ (eig1[1]*eig1[1])));
+      double disp2 = sqrt(.5*(eig2[0]*eig2[0]+ (eig2[1]*eig2[1])));
+      double mdisp = .333*(disp0+disp1+disp2);
+     
       fprintf(uva,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
               it0->second.x(), it0->second.y(), 0.0,
               it1->second.x(), it1->second.y(), 0.0,
               it2->second.x(), it2->second.y(), 0.0,
               area, area, area);   
 
-      fprintf(uvme,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
+      fprintf(uvm,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
               it0->second.x(), it0->second.y(), 0.0,
               it1->second.x(), it1->second.y(), 0.0,
               it2->second.x(), it2->second.y(), 0.0, 
-	      0.3*(metric0e+metric1e+metric2e),  0.3*(metric0e+metric1e+metric2e),  0.3*(metric0e+metric1e+metric2e) );    
-      fprintf(uvmf,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
-	      it0->second.x(), it0->second.y(), 0.0,
-              it1->second.x(), it1->second.y(), 0.0,
-              it2->second.x(), it2->second.y(), 0.0,
-	      0.3*(metric0f+metric1f+metric2f),  0.3*(metric0f+metric1f+metric2f),  0.3*(metric0f+metric1f+metric2f) ); 
-      fprintf(uvmg,"ST(%g,%g,%g,%g,%g,%g,%g,%g,%g){%g,%g,%g};\n",
-              it0->second.x(), it0->second.y(), 0.0,
-              it1->second.x(), it1->second.y(), 0.0,
-              it2->second.x(), it2->second.y(), 0.0,
-	      0.3*(metric0g+metric1g+metric2g),  0.3*(metric0g+metric1g+metric2g),  0.3*(metric0g+metric1g+metric2g) ); 
+	      mdisp, mdisp, mdisp);    
       
       fprintf(uvx,"ST(%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E,%22.15E){%22.15E,%22.15E,%22.15E};\n",
               it0->second.x(), it0->second.y(), 0.0,
@@ -2161,48 +2263,8 @@ void GFaceCompound::printStuff() const
   fclose(xyzv);
   fprintf(xyzc,"};\n");
   fclose(xyzc);
-  fprintf(uvme,"};\n");
-  fclose(uvme);
-  fprintf(uvmf,"};\n");
-  fclose(uvmf);
-  fprintf(uvmg,"};\n");
-  fclose(uvmg);
-
-
-  //debug cecile rbf
-  // it = _compound.begin();
-  // char nameM[256], nameF[256];
-  // sprintf(nameM, "mappedMesh-%d.msh", (*it)->tag());
-  // sprintf(nameF, "XYZfunction-%d.txt", (*it)->tag());
-  // FILE * myF = fopen(nameM,"w");
-  // FILE * myF2 = fopen(nameF,"w");
-  // fprintf(myF,"$MeshFormat\n");
-  // fprintf(myF,"2.2 0 8\n");
-  // fprintf(myF,"$EndMeshFormat\n");
-  // fprintf(myF,"$Nodes\n");
-  // fprintf(myF,"%d\n", (int)allNodes.size());
-  // for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){
-  //     std::map<MVertex*,SPoint3>::const_iterator it0 =  coordinates.find(*itv);
-  //     fprintf(myF,"%d %g %g %g \n", (*itv)->getNum(), it0->second.x(), it0->second.y(), 0.0);
-  //     fprintf(myF2,"%d %g %g %g \n", (*itv)->getNum(), (*itv)->x(), (*itv)->y(), (*itv)->z());
-  // }
-  // fprintf(myF,"$EndNodes\n");
-  // fprintf(myF,"$Elements\n");
-  // int nbTris = 0;
-  // for( ; it != _compound.end() ; ++it) nbTris += (*it)->triangles.size();
-  // fprintf(myF, "%d \n", nbTris);
-  // int k = 1;
-  // for(it = _compound.begin(); it != _compound.end() ; ++it){
-  //   for(unsigned int i = 0; i < (*it)->triangles.size(); ++i){
-  //     MTriangle *t = (*it)->triangles[i];
-  //     fprintf(myF,"%d 2 2 0 1 %d %d %d \n", k, t->getVertex(0)->getNum(), t->getVertex(1)->getNum(), t->getVertex(2)->getNum());
-  //     k++;
-  //   }
-  // }
-  // fprintf(myF,"$EndElements\n");
-  // fclose(myF);
-  // fclose(myF2);
-
+  fprintf(uvm,"};\n");
+  fclose(uvm);;
 
 }
 
diff --git a/Geo/GFaceCompound.h b/Geo/GFaceCompound.h
index 1e43c0fd7cbbb6aebd2b076161dcc484cacfb1f9..7f4c347f01dc240628901d19332109e7a30cce4f 100644
--- a/Geo/GFaceCompound.h
+++ b/Geo/GFaceCompound.h
@@ -70,6 +70,7 @@ class GFaceCompound : public GFace {
   mutable std::map<SPoint3,SPoint3 > _coordPoints;
   mutable std::map<MVertex*, SVector3> _normals;
   mutable std::list<MTriangle*> fillTris;
+  mutable std::set<MVertex*> fillNodes;
   void buildOct() const ;
   void buildAllNodes() const; 
   void parametrize(iterationStep, typeOfMapping, double alpha=0.) const;
@@ -77,7 +78,7 @@ class GFaceCompound : public GFace {
   bool parametrize_conformal_spectral() const;
   void compute_distance() const;
   bool checkOrientation(int iter) const;
-  bool checkFolding(std::vector<MVertex*> &ordered) const;
+  bool checkOverlap(std::vector<MVertex*> &ordered) const;
   void one2OneMap() const;
   double checkAspectRatio() const;
   void computeNormals () const;
diff --git a/Geo/GModel.h b/Geo/GModel.h
index bfc416c9fd01fd06c2488f0b276e8e38714cffb0..35b9a7131df97c77c069dd2247c795664a99dff7 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -488,6 +488,10 @@ class GModel
   int writeSTL(const std::string &name, bool binary=false,
                bool saveAll=false, double scalingFactor=1.0);
 
+  // PLY2 format (asciii text format)
+  int readPLY2(const std::string &name);
+  int writePLY2(const std::string &name);
+
   // Inventor/VRML format
   int readVRML(const std::string &name);
   int writeVRML(const std::string &name,
diff --git a/Geo/GModelIO_Geo.cpp b/Geo/GModelIO_Geo.cpp
index 8c5d0c15a6665ad62f1786363a1eb2cdcee84573..f9c2c42ab997d7ad3f10306cb659e5920e348dc5 100644
--- a/Geo/GModelIO_Geo.cpp
+++ b/Geo/GModelIO_Geo.cpp
@@ -180,8 +180,9 @@ int GModel::importGEOInternals()
             if(ge) b[j].push_back(ge);
           }
         }
-        int allowPartition = 1;
-        if (abs(s->TypeOfMapping) != 1) allowPartition = 0;
+        int allowPartition = 1; //allow 
+        if (abs(s->TypeOfMapping) == 2) allowPartition = 0;//not allow
+	if (abs(s->TypeOfMapping) == 3) allowPartition = 2;//only metis
 
         f = new GFaceCompound(this, s->Num, comp,
                               b[0], b[1], b[2], b[3], 0,
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index 138dd33a0200da3978c192792b5b4d85a5339e45..ebdaa804e5ee63dde13ebc672dd91f8d61556482 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -1208,6 +1208,69 @@ static int readElementsVRML(FILE *fp, std::vector<MVertex*> &vertexVector, int r
   return 1;
 }
 
+int GModel::readPLY2(const std::string &name)
+{
+  FILE *fp = fopen(name.c_str(), "r");
+  if(!fp){
+    Msg::Error("Unable to open file '%s'", name.c_str());
+    return 0;
+  }
+
+  std::vector<MVertex*> vertexVector;
+  std::map<int, std::vector<MElement*> > elements[5];
+
+  char buffer[256], str[256];
+  int elementary = getMaxElementaryNumber(-1) + 1;
+  int nbv, nbf;
+  while(!feof(fp)) {
+    if(!fgets(buffer, sizeof(buffer), fp)) break;
+    if(buffer[0] != '#'){ // skip comments
+      sscanf(buffer, "%d", &nbv);
+      if(!fgets(buffer, sizeof(buffer), fp)) break;
+      sscanf(buffer, "%d", &nbf);
+      Msg::Info("%d vertices", nbv);
+      Msg::Info("%d triangles", nbf);
+      vertexVector.resize(nbv);
+      for(int i = 0; i < nbv; i++) {
+	if(!fgets(buffer, sizeof(buffer), fp)) break;
+	double x, y, z;
+	int nb = sscanf(buffer, "%lf %lf %lf", &x, &y, &z);
+	if (nb !=3){
+	  if(!fgets(buffer, sizeof(buffer), fp)) break;
+	  sscanf(buffer, "%lf",  &y);
+	  if(!fgets(buffer, sizeof(buffer), fp)) break;
+	  sscanf(buffer, "%lf",  &z);
+	}
+	vertexVector[i] = new MVertex(x, y, z);
+      }
+      for(int i = 0; i < nbf; i++) {
+	if(!fgets(buffer, sizeof(buffer), fp)) break;
+	int n[3], nbe;
+	int nb = sscanf(buffer, "%d %d %d %d", &nbe, &n[0], &n[1], &n[2]);
+	if (nb !=4){
+	  if(!fgets(buffer, sizeof(buffer), fp)) break;
+	  sscanf(buffer, "%d",  &n[0]);
+	  if(!fgets(buffer, sizeof(buffer), fp)) break;
+	  sscanf(buffer, "%d",  &n[1]);
+	  if(!fgets(buffer, sizeof(buffer), fp)) break;
+	  sscanf(buffer, "%d",  &n[2]);
+	}
+	std::vector<MVertex*> vertices;
+	if(!getVertices(3, n, vertexVector, vertices)) return 0;
+	elements[0][elementary].push_back(new MTriangle(vertices));
+      }     
+    }
+  }
+
+  for(int i = 0; i < (int)(sizeof(elements) / sizeof(elements[0])); i++)
+    _storeElementsInEntities(elements[i]);
+  _associateEntityWithMeshVertices();
+  _storeVerticesInEntities(vertexVector);
+
+  fclose(fp);
+  return 1;
+}
+
 int GModel::readVRML(const std::string &name)
 {
   FILE *fp = fopen(name.c_str(), "r");
@@ -1279,6 +1342,38 @@ int GModel::readVRML(const std::string &name)
   return 1;
 }
 
+int GModel::writePLY2(const std::string &name)
+{
+  FILE *fp = fopen(name.c_str(), "w");
+  if(!fp){
+    Msg::Error("Unable to open file '%s'", name.c_str());
+    return 0;
+  }
+
+  int numVertices = indexMeshVertices(true);
+  int numTriangles = 0.0;
+  for(fiter it = firstFace(); it != lastFace(); ++it){
+      numTriangles += (*it)->triangles.size();
+  }
+
+  fprintf(fp, "%d\n", numVertices);
+  fprintf(fp, "%d\n", numTriangles);
+
+  std::vector<GEntity*> entities;
+  getEntities(entities);
+  for(unsigned int i = 0; i < entities.size(); i++)
+    for(unsigned int j = 0; j < entities[i]->mesh_vertices.size(); j++)
+      entities[i]->mesh_vertices[j]->writePLY2(fp);
+
+  for(fiter it = firstFace(); it != lastFace(); ++it){
+      for(unsigned int i = 0; i < (*it)->triangles.size(); i++)
+        (*it)->triangles[i]->writePLY2(fp);
+  }
+
+  fclose(fp);
+  return 1;
+}
+
 int GModel::writeVRML(const std::string &name, bool saveAll, double scalingFactor)
 {
   FILE *fp = fopen(name.c_str(), "w");
diff --git a/Geo/Geo.h b/Geo/Geo.h
index fe5d0bc2ac391a93f88b8692c07adbc8056489d3..c40272fd46a483fb9ffa55165460a2a2a2727762 100644
--- a/Geo/Geo.h
+++ b/Geo/Geo.h
@@ -148,8 +148,9 @@ class Surface{
   int Method;
   int Recombine;
   int Recombine_Dir; // -1 is left, +1 is right, 0 is alternated
-  int TypeOfMapping; // +1 is harmonic, -1 is conformal, +2 harmonic_NoSplit,
-                     // -2 conformal_NoSplit
+  int TypeOfMapping; // +1 is harmonic, -1 is conformal,
+                     //+2 harmonic_NoSplit, -2 conformal_NoSplit, 
+                     //+3 harmonic_SplitMetis, -3 conformal_SplitMetis, 
   double RecombineAngle;
   int TransfiniteSmoothing;
   List_T *Generatrices;
diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp
index 6bea2b0079bfc37d6b8be3893a9905b58ec79ce1..48ee94d70d2205d924087dc043f7f98433cb584b 100644
--- a/Geo/MElement.cpp
+++ b/Geo/MElement.cpp
@@ -646,6 +646,14 @@ void MElement::writeSTL(FILE *fp, bool binary, double scalingFactor)
     }
   }
 }
+void MElement::writePLY2(FILE *fp)
+{
+  setVolumePositive();
+  fprintf(fp, "3 ");
+  for(int i = 0; i < getNumVertices(); i++)
+    fprintf(fp, " %d", getVertex(i)->getIndex() - 1);
+  fprintf(fp, "\n");
+}
 
 void MElement::writeVRML(FILE *fp)
 {
diff --git a/Geo/MElement.h b/Geo/MElement.h
index 7f0992c0af1877fe9c8420f19cc4d8e92b6e3360..4b0bcb558599130b7cb7037c559309a3483e1373 100644
--- a/Geo/MElement.h
+++ b/Geo/MElement.h
@@ -274,6 +274,7 @@ class MElement
                         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);
+  virtual void writePLY2(FILE *fp);
   virtual void writeUNV(FILE *fp, int num=0, int elementary=1, int physical=1);
   virtual void writeVTK(FILE *fp, bool binary=false, bool bigEndian=false);
   virtual void writeMESH(FILE *fp, int elementTagType=1, int elementary=1,
diff --git a/Geo/MVertex.cpp b/Geo/MVertex.cpp
index ac1a6a256bd377dbe70c4c1140a8619e18306485..bfdedec319d9ee6bfbea6a8ddd4e9a1e8cc8ef93 100644
--- a/Geo/MVertex.cpp
+++ b/Geo/MVertex.cpp
@@ -108,6 +108,13 @@ void MVertex::writeMSH(FILE *fp, bool binary, bool saveParametric, double scalin
         fprintf(fp, "\n");          
   }
 }
+void MVertex::writePLY2(FILE *fp)
+{
+  if(_index < 0) return; // negative index vertices are never saved
+
+  fprintf(fp, "%.16g %.16g %.16g\n",
+          x(), y(), z());
+}
 
 void MVertex::writeVRML(FILE *fp, double scalingFactor)
 {
diff --git a/Geo/MVertex.h b/Geo/MVertex.h
index 40c8d4fd934d8e875bcf8475e066226f8e340d53..a568d7aa7eafe3a7e278386904abc240a1c54cb7 100644
--- a/Geo/MVertex.h
+++ b/Geo/MVertex.h
@@ -107,6 +107,7 @@ class MVertex{
   // IO routines
   void writeMSH(FILE *fp, bool binary=false, bool saveParametric=false,
                 double scalingFactor=1.0);
+  void writePLY2(FILE *fp);
   void writeVRML(FILE *fp, double scalingFactor=1.0);
   void writeUNV(FILE *fp, double scalingFactor=1.0);
   void writeVTK(FILE *fp, bool binary=false, double scalingFactor=1.0,
diff --git a/Mesh/meshGFace.cpp b/Mesh/meshGFace.cpp
index fa25e3e3625f94867255b15205a526a8c78d934a..fc51040902c5d9e3fd655a882b0caa3008d66348 100644
--- a/Mesh/meshGFace.cpp
+++ b/Mesh/meshGFace.cpp
@@ -1624,9 +1624,9 @@ void partitionAndRemesh(GFaceCompound *gf)
   if(gf->nbSplit > 0) method = MULTILEVEL;
   else method = LAPLACIAN;
     
-  multiscalePartition *msp = new multiscalePartition(elements, abs(gf->nbSplit), method);
-
-  //gf->partitionFaceCM(); 
+  int allowType = gf->allowPartition();
+  multiscalePartition *msp = new multiscalePartition(elements, abs(gf->nbSplit), 
+						     method, allowType);
 
   int NF = msp->getNumberOfParts();
   int numv = gf->model()->getMaxElementaryNumber(0) + 1;
@@ -1781,8 +1781,8 @@ void partitionAndRemesh(GFaceCompound *gf)
   }
 
   double t3 = Cpu();
-  Msg::Info("*** Mesh of surface %d done by assembly remeshed faces (%g s)",
-            gf->tag(), t3-t2);
+  Msg::Info("*** Mesh of surface %d done by assembly %d remeshed faces (%g s)",
+            gf->tag(), NF, t3-t2);
   Msg::Info("-----------------------------------------------------------");
  
   gf->coherenceNormals();
diff --git a/Mesh/meshGRegion.cpp b/Mesh/meshGRegion.cpp
index de64974bef8706185b35beb1295b37d5b98977d0..06005de6fad87f41dc1828c1c255b136181a36d4 100644
--- a/Mesh/meshGRegion.cpp
+++ b/Mesh/meshGRegion.cpp
@@ -26,7 +26,99 @@
 #include "ANN/ANN.h"
 #endif
 
-void voronoiDual(GRegion *gr)
+void printVoronoi(GRegion *gr)
+{
+  std::vector<MTetrahedron*> elements = gr->tetrahedra;
+  std::list<GFace*> allFaces = gr->faces();
+
+  std::set<SPoint3> candidates;
+
+  //building maps
+  std::map<MVertex*, std::set<MTetrahedron*> > node2Tet;
+  std::map<MFace, std::vector<MTetrahedron*> , Less_Face> face2Tet;
+  for(unsigned int i = 0; i < elements.size(); i++){
+    MTetrahedron *ele = elements[i];
+    for (int j=0; j<4; j++){
+      MVertex *v = ele->getVertex(j);
+      std::map<MVertex*, std::set<MTetrahedron*> >::iterator itmap = node2Tet.find(v);
+      if (itmap == node2Tet.end()){
+  	std::set<MTetrahedron*>  oneTet;
+  	oneTet.insert(ele);
+  	node2Tet.insert(std::make_pair(v, oneTet));
+      } 
+      else{
+  	std::set<MTetrahedron*>  allTets = itmap->second;
+  	allTets.insert(allTets.begin(), ele);
+  	itmap->second = allTets;
+      }
+    }
+    for (int j=0; j<4; j++){
+      MFace f = ele->getFace(j);
+      std::map<MFace, std::vector<MTetrahedron*>, Less_Face >::iterator itmap = face2Tet.find(f);
+      if (itmap == face2Tet.end()){
+  	std::vector<MTetrahedron*>  oneTet;
+  	oneTet.push_back(ele);
+  	face2Tet.insert(std::make_pair(f, oneTet));
+      } 
+      else{
+  	std::vector<MTetrahedron*>  allTets = itmap->second;
+  	allTets.insert(allTets.begin(), ele);
+  	itmap->second = allTets;
+      }
+    }
+  }
+
+  //print voronoi nodes
+  FILE *outfile;
+  outfile = fopen("nodes.pos", "w");
+  fprintf(outfile, "View \"voronoi nodes\" {\n");
+  std::map<MVertex*, std::set<MTetrahedron*> >::iterator itmap = node2Tet.begin();
+  for(; itmap != node2Tet.end(); itmap++){
+    MVertex *v = itmap->first;
+    std::set<MTetrahedron*>  allTets = itmap->second;
+    std::set<MTetrahedron*>::const_iterator it = allTets.begin();
+    MTetrahedron *poleTet = *it;
+    double maxRadius = poleTet->getCircumRadius();
+    for(; it != allTets.end(); it++){
+      double radius =  (*it)->getCircumRadius();
+      if (radius > maxRadius){
+    	maxRadius = radius;
+    	poleTet = *it;
+      }
+    }
+    SPoint3 pc = poleTet->circumcenter();
+    fprintf(outfile,"SP(%g,%g,%g)  {%g};\n",
+    	    pc.x(), pc.y(), pc.z(), maxRadius);
+    candidates.insert(pc);
+    //}//uncomment this
+   
+  }
+  fprintf(outfile,"};\n");  
+  fclose(outfile);
+
+  //print scalar lines
+  FILE *outfile2;
+  outfile2 = fopen("edges.pos", "w");
+  fprintf(outfile2, "View \"voronoi edges\" {\n");
+  std::map<MFace, std::vector<MTetrahedron*> , Less_Face >::iterator itmap2 = face2Tet.begin();
+  for(; itmap2 != face2Tet.end(); itmap2++){
+    std::vector<MTetrahedron*>  allTets = itmap2->second;
+    if (allTets.size() !=2 ) continue;
+    SPoint3 pc1 = allTets[0]->circumcenter();
+    SPoint3 pc2 = allTets[1]->circumcenter();
+    std::set<SPoint3>::const_iterator it1 = candidates.find(pc1);
+    std::set<SPoint3>::const_iterator it2 = candidates.find(pc2);
+    if( it1 != candidates.end() || it2 != candidates.end())
+      fprintf(outfile2,"SL(%g,%g,%g,%g,%g,%g)  {%g,%g};\n",
+  	      pc1.x(), pc1.y(), pc1.z(), pc2.x(), pc2.y(), pc2.z(),
+  	      allTets[0]->getCircumRadius(),allTets[1]->getCircumRadius());
+  }
+  fprintf(outfile2,"};\n");  
+  fclose(outfile2);
+
+}
+
+void skeletonFromVoronoi(GRegion *gr)
 {
 
   std::vector<MTetrahedron*> elements = gr->tetrahedra;
@@ -50,10 +142,10 @@ void voronoiDual(GRegion *gr)
   }
   printf("Dmax =%g \n", Dmax);
 
-  printf("printing nodes \n");
+  printf("printing skeleton nodes \n");
   FILE *outfile;
-  outfile = fopen("nodes.pos", "w");
-  fprintf(outfile, "View \"voronoi nodes\" {\n");
+  outfile = fopen("skeletonNodes.pos", "w");
+  fprintf(outfile, "View \"skeleton nodes\" {\n");
   for(unsigned int i = 0; i < elements.size(); i++){
     MTetrahedron *ele = elements[i];
     SPoint3 pc = ele->circumcenter();
@@ -62,7 +154,7 @@ void voronoiDual(GRegion *gr)
     ele->xyz2uvw(x, uvw);
     if(ele->isInside(uvw[0], uvw[1], uvw[2])){
       double radius =  ele->getCircumRadius();
-      if(radius > Dmax/5.) {
+      if(radius > Dmax/10.) {
       	candidates.insert(pc);
 	fprintf(outfile,"SP(%g,%g,%g)  {%g};\n",
 		pc.x(), pc.y(), pc.z(),  radius);
@@ -72,151 +164,76 @@ void voronoiDual(GRegion *gr)
   fprintf(outfile,"};\n");  
   fclose(outfile);
 
-  // printf("building maps \n");
-  // std::map<MVertex*, std::set<MTetrahedron*> > node2Tet;
-  // std::map<MFace, std::vector<MTetrahedron*> , Less_Face> face2Tet;
-  // for(unsigned int i = 0; i < elements.size(); i++){
-  //   MTetrahedron *ele = elements[i];
-  //   for (int j=0; j<4; j++){
-  //     MVertex *v = ele->getVertex(j);
-  //     std::map<MVertex*, std::set<MTetrahedron*> >::iterator itmap = node2Tet.find(v);
-  //     if (itmap == node2Tet.end()){
-  // 	std::set<MTetrahedron*>  oneTet;
-  // 	oneTet.insert(ele);
-  // 	node2Tet.insert(std::make_pair(v, oneTet));
-  //     } 
-  //     else{
-  // 	std::set<MTetrahedron*>  allTets = itmap->second;
-  // 	allTets.insert(allTets.begin(), ele);
-  // 	itmap->second = allTets;
-  //     }
-  //   }
-  //   for (int j=0; j<4; j++){
-  //     MFace f = ele->getFace(j);
-  //     std::map<MFace, std::vector<MTetrahedron*>, Less_Face >::iterator itmap = face2Tet.find(f);
-  //     if (itmap == face2Tet.end()){
-  // 	std::vector<MTetrahedron*>  oneTet;
-  // 	oneTet.push_back(ele);
-  // 	face2Tet.insert(std::make_pair(f, oneTet));
-  //     } 
-  //     else{
-  // 	std::vector<MTetrahedron*>  allTets = itmap->second;
-  // 	allTets.insert(allTets.begin(), ele);
-  // 	itmap->second = allTets;
-  //     }
-  //   }
-  // }
-
-  //print only poles
-  // FILE *outfile;
-  // outfile = fopen("nodes.pos", "w");
-  // fprintf(outfile, "View \"voronoi nodes\" {\n");
-  // std::map<MVertex*, std::set<MTetrahedron*> >::iterator itmap = node2Tet.begin();
-  // for(; itmap != node2Tet.end(); itmap++){
-  //   MVertex *v = itmap->first;
-  //   std::set<MTetrahedron*>  allTets = itmap->second;
-  //   std::set<MTetrahedron*>::const_iterator it = allTets.begin();
-  //   MTetrahedron *poleTet = *it;
-  //   double maxRadius = poleTet->getCircumRadius();
-  //   for(; it != allTets.end(); it++){
-  //     double radius =  (*it)->getCircumRadius();
-  //     if (radius > maxRadius){
-  // 	maxRadius = radius;
-  // 	poleTet = *it;
-  //     }
-  //   }
-  //   SPoint3 pc = poleTet->circumcenter();
-  //   fprintf(outfile,"SP(%g,%g,%g)  {%g};\n",
-  //   	    pc.x(), pc.y(), pc.z(), maxRadius);
-  //   candidates.insert(pc);
-  // }
-  // fprintf(outfile,"};\n");  
-  // fclose(outfile);
-  
   printf("Ann computation of neighbours and writing edges\n");
  #if defined(HAVE_ANN)
-//   FILE *outfile2;
-//   outfile2 = fopen("edges.pos", "w");
-//   fprintf(outfile2, "View \"voronoi edges\" {\n");
-
-//   ANNkd_tree *_kdtree;
-//   ANNpointArray _zeronodes;
-//   ANNidxArray _index;
-//   ANNdistArray _dist;
-
-//   std::set<SPoint3>::iterator itseed = seeds.begin();
-//   SPoint3 beginPt=*itseed;
-//   seeds.erase(itseed);
-//   itseed = seeds.begin();
-//   for(; itseed != seeds.end(); itseed++){
-//     printf("seed =%g %g %g \n", (*itseed).x(), (*itseed).y(), (*itseed).z());
-//     candidates.insert(*itseed);
-//   }
-//   printf("begin seed =%g %g %g \n", beginPt.x(), beginPt.y(), beginPt.z());
-
-//   double color = 1.;
-//   while(candidates.size()>0){
-
-//   _zeronodes = annAllocPts(candidates.size(), 3);
-//   std::set<SPoint3>::iterator itset = candidates.begin();
-//   int i=0;
-//   for(; itset != candidates.end(); itset++){
-//     _zeronodes[i][0] = (*itset).x();
-//     _zeronodes[i][1] = (*itset).y();
-//     _zeronodes[i][2] = (*itset).z();
-//     i++;
-//   }
-//   _kdtree = new ANNkd_tree(_zeronodes, candidates.size(), 3);
-//   _index = new ANNidx[1];
-//   _dist = new ANNdist[1];
-
-//   double xyz[3] = {beginPt.x(), beginPt.y(), beginPt.z()};
-//   _kdtree->annkSearch(xyz, 1, _index, _dist);
-//   SPoint3 endPt( _zeronodes[_index[0]][0], _zeronodes[_index[0]][1], _zeronodes[_index[0]][2]);
-//   fprintf(outfile2,"SL(%g,%g,%g,%g,%g,%g)  {%g,%g};\n",
-// 	  beginPt.x(), beginPt.y(), beginPt.z(),
-// 	  endPt.x(), endPt.y(), endPt.z(),
-// 	  color, color);
+  FILE *outfile2;
+  outfile2 = fopen("skeletonEdges.pos", "w");
+  fprintf(outfile2, "View \"skeleton edges\" {\n");
+
+  ANNkd_tree *_kdtree;
+  ANNpointArray _zeronodes;
+  ANNidxArray _index;
+  ANNdistArray _dist;
+
+  std::set<SPoint3>::iterator itseed = seeds.begin();
+  SPoint3 beginPt=*itseed;
+  seeds.erase(itseed);
+  itseed = seeds.begin();
+  for(; itseed != seeds.end(); itseed++){
+    printf("seed =%g %g %g \n", (*itseed).x(), (*itseed).y(), (*itseed).z());
+    candidates.insert(*itseed);
+  }
+  printf("begin seed =%g %g %g \n", beginPt.x(), beginPt.y(), beginPt.z());
+
+  double color = 1.;
+  while(candidates.size()>0){
+
+  _zeronodes = annAllocPts(candidates.size(), 3);
+  std::set<SPoint3>::iterator itset = candidates.begin();
+  int i=0;
+  for(; itset != candidates.end(); itset++){
+    _zeronodes[i][0] = (*itset).x();
+    _zeronodes[i][1] = (*itset).y();
+    _zeronodes[i][2] = (*itset).z();
+    i++;
+  }
+  _kdtree = new ANNkd_tree(_zeronodes, candidates.size(), 3);
+  _index = new ANNidx[1];
+  _dist = new ANNdist[1];
+
+  double xyz[3] = {beginPt.x(), beginPt.y(), beginPt.z()};
+  _kdtree->annkSearch(xyz, 1, _index, _dist);
+  SPoint3 endPt( _zeronodes[_index[0]][0], _zeronodes[_index[0]][1], _zeronodes[_index[0]][2]);
+  fprintf(outfile2,"SL(%g,%g,%g,%g,%g,%g)  {%g,%g};\n",
+	  beginPt.x(), beginPt.y(), beginPt.z(),
+	  endPt.x(), endPt.y(), endPt.z(),
+	  color, color);
  
-//    std::set<SPoint3>::iterator itse=seeds.find(endPt);
-//    std::set<SPoint3>::iterator its=candidates.find (endPt);
-//    if(itse != seeds.end()){
-//      seeds.erase(itse);
-//      beginPt = *(seeds.begin());
-//      std::set<SPoint3>::iterator itsee=candidates.find(beginPt);
-//      candidates.erase(itsee);
-//      color=color*2.;
-//    }
-//    else   beginPt=endPt;
+   std::set<SPoint3>::iterator itse=seeds.find(endPt);
+   std::set<SPoint3>::iterator its=candidates.find(endPt);
+   if(itse != seeds.end()){
+     printf("found seed =%g %g %g \n", endPt.x(), endPt.y(), endPt.z());
+     seeds.erase(itse);
+     beginPt = *(seeds.begin());
+     std::set<SPoint3>::iterator itsee=candidates.find(beginPt);
+     if (itsee != candidates.end()) candidates.erase(itsee);
+     color=color*2.;
+   }
+   else   beginPt=endPt;
  
-//    if(its != candidates.end()) {
-//      candidates.erase(its);
-//    }
-
-//   delete _kdtree;
-//   annDeallocPts(_zeronodes);
-//   delete [] _index;
-//   delete [] _dist;
-//   }
-
-//   fprintf(outfile2,"};\n");  
-//   fclose(outfile2);
+   if(its != candidates.end()) candidates.erase(its);
+
+  delete _kdtree;
+  annDeallocPts(_zeronodes);
+  delete [] _index;
+  delete [] _dist;
+  }
+
+  fprintf(outfile2,"};\n");  
+  fclose(outfile2);
 #endif
 
-  //print scalar lines
-  // std::map<MFace, std::vector<MTetrahedron*> , Less_Face >::iterator itmap2 = face2Tet.begin();
-  // for(; itmap2 != face2Tet.end(); itmap2++){
-  //   std::vector<MTetrahedron*>  allTets = itmap2->second;
-  //   if (allTets.size() !=2 ) continue;
-  //   SPoint3 pc1 = allTets[0]->circumcenter();
-  //   SPoint3 pc2 = allTets[1]->circumcenter();
-  //   std::set<SPoint3>::const_iterator it1 = candidates.find(pc1);
-  //   std::set<SPoint3>::const_iterator it2 = candidates.find(pc2);
-  //   if( it1 != candidates.end() || it2 != candidates.end())
-  //     fprintf(outfile2,"SL(%g,%g,%g,%g,%g,%g)  {%g,%g};\n",
-  // 	      pc1.x(), pc1.y(), pc1.z(), pc2.x(), pc2.y(), pc2.z(),
-  // 	      allTets[0]->getCircumRadius(),allTets[1]->getCircumRadius());
-  // }
+
 
 
 }
@@ -527,7 +544,10 @@ void MeshDelaunayVolume(std::vector<GRegion*> &regions)
   gr->set(faces);
 
   //EMI VORONOI FOR CENRTERLINE
-  if (Msg::GetVerbosity() == 20)  voronoiDual(gr);
+  if (Msg::GetVerbosity() == 20) {
+    printVoronoi(gr);
+    skeletonFromVoronoi(gr);
+  }
 
   // now do insertion of points
   insertVerticesInRegion(gr);
diff --git a/Mesh/multiscalePartition.cpp b/Mesh/multiscalePartition.cpp
index 4d901129d1808cb78352f9f7db7b0988c8a264eb..96751985b04a1b3d7c44a026d25d568571a16c51 100644
--- a/Mesh/multiscalePartition.cpp
+++ b/Mesh/multiscalePartition.cpp
@@ -189,7 +189,7 @@ static int getAspectRatio(std::vector<MElement *> &elements,
   //double H = obbox.getMaxSize(); 
   
   double D = H;
-  if (boundaries.size()  > 0 ) D = 0.0;
+  if (boundaries.size()  > 0 ) D = 10e4;
   for (unsigned int i = 0; i < boundaries.size(); i++){
     std::set<MVertex*> vb;
     std::vector<MEdge> iBound = boundaries[i];
@@ -206,7 +206,7 @@ static int getAspectRatio(std::vector<MElement *> &elements,
       bb +=pt;
     }
     double iD = norm(SVector3(bb.max(), bb.min()));
-    D = std::max(D, iD);
+    D = std::min(D, iD);
     
     //SOrientedBoundingBox obboxD = SOrientedBoundingBox::buildOBB(vBounds); 
     //D = std::max(D, obboxD.getMaxSize());
@@ -289,7 +289,8 @@ static void printLevel(std::vector<MElement *> &elements, int recur, int region)
 }
 
 multiscalePartition::multiscalePartition(std::vector<MElement *> &elements,
-                                         int nbParts, typeOfPartition method)
+                                         int nbParts, typeOfPartition method, 
+					 int allowPartition)
 {
   options = CTX::instance()->partitionOptions;
   options.num_partitions = nbParts;
@@ -305,6 +306,8 @@ multiscalePartition::multiscalePartition(std::vector<MElement *> &elements,
   level->region = 0;
 
   levels.push_back(level);
+  onlyMultilevel = false;
+  if (allowPartition == 2)  onlyMultilevel = true;
 
   partition(*level, nbParts, method);
 
@@ -361,12 +364,18 @@ void multiscalePartition::partition(partitionLevel & level, int nbParts,
                 nextLevel->recur,nextLevel->region, genus, AR, nbParts);  
       partition(*nextLevel, nbParts, MULTILEVEL);
     }
-    else if (genus == 0  &&  AR > 5  || genus == 0  &&  NB > 1){
+    else if (genus == 0  &&  AR > 5 ){//|| genus == 0  &&  NB > 1){
       int nbParts = 2;
-      Msg::Info("Mesh partition: level (%d-%d)  is ZERO-GENUS (AR=%d NB=%d) ---> LAPLACIAN partition %d parts",
-                nextLevel->recur,nextLevel->region, AR, NB, nbParts);  
-      //partition(*nextLevel, nbParts, MULTILEVEL);
-      partition(*nextLevel, nbParts, LAPLACIAN);
+      if(!onlyMultilevel){
+	Msg::Info("Mesh partition: level (%d-%d)  is ZERO-GENUS (AR=%d NB=%d) ---> LAPLACIAN partition %d parts",
+		  nextLevel->recur,nextLevel->region, AR, NB, nbParts); 
+	partition(*nextLevel, nbParts, LAPLACIAN);
+      } 
+      else {
+      Msg::Info("Mesh partition: level (%d-%d)  is ZERO-GENUS (AR=%d NB=%d) ---> MULTILEVEL partition %d parts",
+                nextLevel->recur,nextLevel->region, AR, NB, nbParts); 
+        partition(*nextLevel, nbParts, MULTILEVEL);
+      }
     }
     else {
       Msg::Info("*** Mesh partition: level (%d-%d) is ZERO-GENUS (AR=%d, NB=%d)", 
diff --git a/Mesh/multiscalePartition.h b/Mesh/multiscalePartition.h
index 15c4cecfa06a1632f63a622935646cb84cbe0e7e..f1ff46b60461e7d1203a75142dc1911abf2254d5 100644
--- a/Mesh/multiscalePartition.h
+++ b/Mesh/multiscalePartition.h
@@ -29,10 +29,12 @@ class multiscalePartition{
   std::vector<partitionLevel*> levels;
   void partition(partitionLevel &level, int nbParts,  typeOfPartition method);
   int totalParts;
+  bool onlyMultilevel;
   meshPartitionOptions options;
 
  public:
-  multiscalePartition(std::vector<MElement *> &elements, int nbParts, typeOfPartition method);
+  multiscalePartition(std::vector<MElement *> &elements, int nbParts, 
+		      typeOfPartition method, int allowPartition);
   int assembleAllPartitions();
   void setNumberOfPartitions(int &nbParts);
   int getNumberOfParts(){return totalParts;}
diff --git a/Numeric/Numeric.cpp b/Numeric/Numeric.cpp
index 14fd1cc78045ea3ef20336487e77a38c42203bd1..25ae05b37053ddfaae5ce583f40d4d766d93b2c5 100644
--- a/Numeric/Numeric.cpp
+++ b/Numeric/Numeric.cpp
@@ -476,6 +476,20 @@ double ComputeScalarRep(int numComp, double *val)
   return 0.;
 }
 
+void eigenvalue2x2(double mat[2][2], double v[2])
+{ 
+
+  double a=1;
+  double b=-(mat[0][0]+mat[1][1]);
+  double c= (mat[0][0]*mat[1][1])-(mat[0][1]*mat[1][0]);
+  
+  double det = b*b-4.*a*c;
+
+  v[0] = (-b+sqrt(det))/(2*a);
+  v[1] = (-b-sqrt(det))/(2*a);
+
+}
+
 void eigenvalue(double mat[3][3], double v[3])
 {            
   // characteristic polynomial of T : find v root of
diff --git a/Numeric/Numeric.h b/Numeric/Numeric.h
index 33643dd6184f094a12bcb3166e82ed6f74d7dc6b..7aa6d64fbb5228cf9ee30c9dd102e74f899ab3ad 100644
--- a/Numeric/Numeric.h
+++ b/Numeric/Numeric.h
@@ -72,6 +72,7 @@ void planarQuad_xyz2xy(double *x, double *y, double *z, double *xn, double *yn);
 double computeInnerRadiusForQuad(double *x, double *y, int i);
 char float2char(float f);
 float char2float(char c);
+void eigenvalue2x2(double mat[2][2], double v[2]);
 void eigenvalue(double mat[3][3], double re[3]);
 void FindCubicRoots(const double coeff[4], double re[3], double im[3]);
 void eigsort(double d[3]);
diff --git a/Parser/Gmsh.tab.cpp b/Parser/Gmsh.tab.cpp
index 7e76eb6bb6e006b91828e9fb16d3090517c6b924..2a6ccc7f83788000c321e6e356e248df38244b65 100644
--- a/Parser/Gmsh.tab.cpp
+++ b/Parser/Gmsh.tab.cpp
@@ -7145,6 +7145,10 @@ yyreduce:
         (yyval.i) = 2;
       else if(!strcmp((yyvsp[(1) - (1)].c), "Conformal_NoSplit"))
         (yyval.i) = -2;
+      else if(!strcmp((yyvsp[(1) - (1)].c), "Harmonic_SplitMetis"))
+        (yyval.i) = 3;
+      else if(!strcmp((yyvsp[(1) - (1)].c), "Conformal_SplitMetis"))
+        (yyval.i) = -3;
       Free((yyvsp[(1) - (1)].c));
     ;}
     break;
diff --git a/Parser/Gmsh.y b/Parser/Gmsh.y
index 6a1e97ee8b0469b8890d18a4f5097253c2a37e79..b3b056ad2d507eaba90c7d709b3fdd654eb39bad 100644
--- a/Parser/Gmsh.y
+++ b/Parser/Gmsh.y
@@ -2899,6 +2899,10 @@ CompoundMap :
         $$ = 2;
       else if(!strcmp($1, "Conformal_NoSplit"))
         $$ = -2;
+     else if(!strcmp($1, "Harmonic_SplitMetis"))
+        $$ = 3;
+      else if(!strcmp($1, "Conformal_SplitMetis"))
+        $$ = -3;
       Free($1);
     }
 ;
diff --git a/Solver/multiscaleLaplace.cpp b/Solver/multiscaleLaplace.cpp
index d23372a6b722d6cd90f23b69a3b866a30b17f37e..ff10d5525737aea6727f469c3cc24596c7a5dc4e 100644
--- a/Solver/multiscaleLaplace.cpp
+++ b/Solver/multiscaleLaplace.cpp
@@ -706,6 +706,7 @@ static void printLevel_onlysmall(const char* fn,
 				 std::map<MVertex*,SPoint2> *coordinates,
 				 double version,
 				 double tolerance){
+
   std::vector<MElement *> small;
   double dx[3] = {0,0,0};
   int COUNT = 0;
@@ -1101,12 +1102,12 @@ void multiscaleLaplace::parametrize (multiscaleLaplaceLevel & level){
   }
 
   //Save multiscale meshes
-  std::string name1(level._name+"real.msh");
-  std::string name2(level._name+"param.msh");
-  std::string name3(level._name+"param_small.msh");
-  printLevel (name1.c_str(),level.elements,0,2.2);
-  printLevel (name2.c_str(),level.elements,&level.coordinates,2.2);
-  printLevel_onlysmall (name3.c_str(),level.elements,&level.coordinates,2.2,1.e-15);
+  // std::string name1(level._name+"real.msh");
+  // std::string name2(level._name+"param.msh");
+  // std::string name3(level._name+"param_small.msh");
+  // printLevel (name1.c_str(),level.elements,0,2.2);
+  // printLevel (name2.c_str(),level.elements,&level.coordinates,2.2);
+  // printLevel_onlysmall (name3.c_str(),level.elements,&level.coordinates,2.2,1.e-15);
 
   //For every small region compute a new parametrization
   Msg::Info("Level (%d-%d): %d connected small regions",level.recur, level.region, regions.size());
@@ -1215,22 +1216,22 @@ void multiscaleLaplace::cut (std::vector<MElement *> &elements)
   recur_cut_ (1.0, M_PI, 0.0, root,left,right);
   connected_left_right(left, right);
 
-  printLevel ("Rootcut-left.msh",left,0,2.2);  
-  printLevel ("Rootcut-right.msh",right,0,2.2);  
-  printLevel ("Rootcut-all.msh",elements, 0,2.2);  
+  // printLevel ("Rootcut-left.msh",left,0,2.2);  
+  // printLevel ("Rootcut-right.msh",right,0,2.2);  
+  // printLevel ("Rootcut-all.msh",elements, 0,2.2);  
 
-  printLevel ("Rootcut-left-param.msh",left,&root->coordinates,2.2);
-  printLevel_onlysmall ("Rootcut-left-param10.msh",left,&root->coordinates,2.2,1.e-10);
-  printLevel_onlysmall ("Rootcut-left-param12.msh",left,&root->coordinates,2.2,1.e-12);
-  printLevel_onlysmall ("Rootcut-left-param15.msh",left,&root->coordinates,2.2,1.e-15);
+  // printLevel ("Rootcut-left-param.msh",left,&root->coordinates,2.2);
+  // printLevel_onlysmall ("Rootcut-left-param10.msh",left,&root->coordinates,2.2,1.e-10);
+  // printLevel_onlysmall ("Rootcut-left-param12.msh",left,&root->coordinates,2.2,1.e-12);
+  // printLevel_onlysmall ("Rootcut-left-param15.msh",left,&root->coordinates,2.2,1.e-15);
 
-  printLevel ("Rootcut-right-param.msh",right,&root->coordinates,2.2);
-  printLevel_onlysmall ("Rootcut-right-param10.msh",right,&root->coordinates,2.2,1.e-10);
-  printLevel_onlysmall ("Rootcut-right-param12.msh",right,&root->coordinates,2.2,1.e-12);
-  printLevel_onlysmall ("Rootcut-right-param15.msh",right,&root->coordinates,2.2,1.e-15);
+  // printLevel ("Rootcut-right-param.msh",right,&root->coordinates,2.2);
+  // printLevel_onlysmall ("Rootcut-right-param10.msh",right,&root->coordinates,2.2,1.e-10);
+  // printLevel_onlysmall ("Rootcut-right-param12.msh",right,&root->coordinates,2.2,1.e-12);
+  // printLevel_onlysmall ("Rootcut-right-param15.msh",right,&root->coordinates,2.2,1.e-15);
 
-  printLevel_onlysmall ("Rootcut-all-param12.msh",elements,&root->coordinates,2.2,1.e-12);
-  printLevel_onlysmall ("Rootcut-all-param15.msh",elements,&root->coordinates,2.2,1.e-15);
+  // printLevel_onlysmall ("Rootcut-all-param12.msh",elements,&root->coordinates,2.2,1.e-12);
+  // printLevel_onlysmall ("Rootcut-all-param15.msh",elements,&root->coordinates,2.2,1.e-15);
 
   if ( elements.size() != left.size()+right.size()) {
     Msg::Error("Cutting laplace wrong nb elements (%d) != left + right (%d)",  elements.size(), left.size()+right.size());
diff --git a/benchmarks/stl/squirrel.stl b/benchmarks/stl/squirrel.stl
new file mode 100644
index 0000000000000000000000000000000000000000..a238048c4a1648d9dcc25489d5c552bfb22a64a0
Binary files /dev/null and b/benchmarks/stl/squirrel.stl differ