diff --git a/Common/OpenFile.cpp b/Common/OpenFile.cpp
index d0098daf3f31f08ac23fea9d8c6322331a3bfda6..b84169170aa8d4085806eacaa59de64fb423ef18 100644
--- a/Common/OpenFile.cpp
+++ b/Common/OpenFile.cpp
@@ -340,6 +340,9 @@ int MergeFile(std::string fileName, bool warnIfMissing)
   else if(ext == ".ply2"){
     status = GModel::current()->readPLY2(fileName);
   }
+  else if(ext == ".ply"){
+    status = GModel::current()->readPLY(fileName);
+  }
   else {
     CTX::instance()->geom.draw = 1;
     if(!strncmp(header, "$PTS", 4) || !strncmp(header, "$NO", 3) || 
diff --git a/Fltk/statisticsWindow.cpp b/Fltk/statisticsWindow.cpp
index 1f00a940b4e83e83c1c54ea3f3aa76dda209d9d0..546439453fe39fb445b54e0462a8b4a431a86ce2 100644
--- a/Fltk/statisticsWindow.cpp
+++ b/Fltk/statisticsWindow.cpp
@@ -239,7 +239,8 @@ void statisticsWindow::compute(bool elementQuality)
     dMax = std::max(nbE, dMax);
     if (nbE == 4) d4 += 1;
   }
-  printf("Stats degree vertices: dMin=%d , dMax=%d, d4=%g \n", dMin, dMax, (double)d4/nbElems);
+  if (nbElems > 0)
+    printf("Stats degree vertices: dMin=%d , dMax=%d, d4=%g \n", dMin, dMax, (double)d4/nbElems);
   //end emi hack
 
   int num = 0;
diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp
index ee14cf5c7f9feee62a62d2bd7571690a4c2d34e7..002f5232ff7b8eeb5beb10688b124be48c845420 100644
--- a/Geo/GFaceCompound.cpp
+++ b/Geo/GFaceCompound.cpp
@@ -664,19 +664,18 @@ bool GFaceCompound::parametrize() const
     fillNeumannBCS();
     bool noOverlap = parametrize_conformal_spectral() ;
     if (!noOverlap){
-      //buildOct(); exit(1);
       Msg::Warning("!!! Overlap: parametrization switched to 'FE conformal' map");
       noOverlap = parametrize_conformal();
     }
     // if (!noOverlap) {
-    //   Msg::Warning("!!! Overlap: parametrization switched to 'nonLIN conformal' map");
-    //   noOverlap = parametrize_conformal_nonLinear() ;
-    // }
-    if ( !noOverlap || !checkOrientation(0) ){
-      Msg::Warning("$$$ Overlap: parametrization switched to 'harmonic' map");
-      parametrize(ITERU,HARMONIC); 
-      parametrize(ITERV,HARMONIC);
-    }
+       //   Msg::Warning("!!! Overlap: parametrization switched to 'nonLIN conformal' map");
+       //   noOverlap = parametrize_conformal_nonLinear() ;
+    //}
+     if ( !noOverlap || !checkOrientation(0) ){
+       Msg::Warning("$$$ Overlap: parametrization switched to 'harmonic' map");
+       parametrize(ITERU,HARMONIC); 
+       parametrize(ITERV,HARMONIC);
+     }
   }
 
   buildOct();  
@@ -1079,9 +1078,22 @@ void GFaceCompound::parametrize(iterationStep step, typeOfMapping tom) const
 {  
   
   dofManager<double> myAssembler(_lsys);
+  
+  // EMI-test for paper Dong: fix only 2 vertices
+  // MVertex *v1;
+  // MVertex *v2;
+  // double zmin = 1.e6;
+  // double zmax = 0.0;
+  // for(std::set<MVertex *>::iterator itv = allNodes.begin(); itv !=allNodes.end() ; ++itv){
+  //   MVertex  *v = *itv;
+  //   double z = v->z();
+  //   if (z > zmax){ zmax = z; v2 = v;}
+  //   if (z < zmin){ zmin = z; v1 = v;}
+  // }
+  // myAssembler.fixVertex(v1, 0, 1, 0.0);
+  // myAssembler.fixVertex(v2, 0, 1, 1.0);
 
   if(_type == UNITCIRCLE){
-    //map to a unit circle
     for(unsigned int i = 0; i < _ordered.size(); i++){
       MVertex *v = _ordered[i];
       const double theta = 2 * M_PI * _coords[i];
@@ -1954,58 +1966,6 @@ void GFaceCompound::getTriangle(double u, double v,
   _v = X[1];
 }
 
-void GFaceCompound::partitionFaceCM() 
-{
-
-  if(!oct) parametrize();
-	
-  double CMu = 0.0;
-  double sumArea = 0.0;
-	  
-  std::list<GFace*>::const_iterator it = _compound.begin();
-  for( ; it != _compound.end() ; ++it){
-    for(unsigned int i = 0; i < (*it)->triangles.size(); ++i){
-      MTriangle *t = (*it)->triangles[i];
-      std::map<MVertex*,SPoint3>::const_iterator it0 = coordinates.find(t->getVertex(0));
-      std::map<MVertex*,SPoint3>::const_iterator it1 = coordinates.find(t->getVertex(1));
-      std::map<MVertex*,SPoint3>::const_iterator it2 = coordinates.find(t->getVertex(2));
-      double q0[3] = {it0->second.x(), it0->second.y(), 0.0}; 
-      double q1[3] = {it1->second.x(), it1->second.y(), 0.0};
-      double q2[3] = {it2->second.x(), it2->second.y(), 0.0};
-      double area = 1/fabs(triangle_area(q0, q1, q2));
-      double cg_u = (q0[0]+q1[0]+q2[0])/3.;
-      CMu += cg_u*area;
-      sumArea += area;
-    }
-    CMu /= sumArea;
-  }
-	
-  //printf("min size partition =%d \n", (int)allNodes.size()/2);
-  model()->setMinPartitionSize((int)allNodes.size()/2);
-  model()->setMaxPartitionSize((int)allNodes.size()/2+1);
-	
-  it = _compound.begin();
-  for( ; it != _compound.end() ; ++it){
-    for(unsigned int i = 0; i < (*it)->triangles.size(); ++i){
-      MTriangle *t = (*it)->triangles[i];
-      std::map<MVertex*,SPoint3>::const_iterator it0 = coordinates.find(t->getVertex(0));
-      std::map<MVertex*,SPoint3>::const_iterator it1 = coordinates.find(t->getVertex(1));
-      std::map<MVertex*,SPoint3>::const_iterator it2 = coordinates.find(t->getVertex(2));
-      double cg_u = (it0->second.x()+it1->second.x()+it2->second.x())/3.;
-      if (cg_u <= CMu)
-	t->setPartition(1);
-      else 
-	t->setPartition(2);
-    }
-  }
-	
-  model()->recomputeMeshPartitions();
-	
-  CreateOutputFile("toto.msh", CTX::instance()->mesh.fileFormat);
-  Msg::Exit(1);
-	 
-  return;
-}
 
 void GFaceCompound::buildOct() const
 {
@@ -2079,7 +2039,6 @@ bool GFaceCompound::checkTopology() const
   // FIXME!!! I think those things are wrong with cross-patch reparametrization
   //if ((*(_compound.begin()))->geomType() != GEntity::DiscreteSurface)return true;  
   
-
   //TODO: smthg to exit here for lloyd remeshing
   
   bool correctTopo = true;
diff --git a/Geo/GFaceCompound.h b/Geo/GFaceCompound.h
index 47304e85e72b5c53240a2f7b12563798d7dff90b..2613de7a4d31e39768a715208d40585a3218a979 100644
--- a/Geo/GFaceCompound.h
+++ b/Geo/GFaceCompound.h
@@ -131,7 +131,6 @@ class GFaceCompound : public GFace {
   bool parametrize() const ;
   void coherenceNormals();
   void coherencePatches() const;
-  void partitionFaceCM();
   virtual std::list<GFace*> getCompounds() const { return _compound; }
   mutable int nbSplit;
   int getNbSplit() const { return nbSplit; }
diff --git a/Geo/GModel.h b/Geo/GModel.h
index f4445d0def335bfb0ced1e4d2ad14fb0b72530c9..8a1297ea358f7e0bda994fcde11720086cfb54d0 100644
--- a/Geo/GModel.h
+++ b/Geo/GModel.h
@@ -491,7 +491,8 @@ class GModel
   int writeSTL(const std::string &name, bool binary=false,
                bool saveAll=false, double scalingFactor=1.0);
 
-  // PLY2 format (asciii text format)
+  // PLY(2) format (ascii text format)
+  int readPLY(const std::string &name);
   int readPLY2(const std::string &name);
   int writePLY2(const std::string &name);
 
diff --git a/Geo/GModelIO_Mesh.cpp b/Geo/GModelIO_Mesh.cpp
index 77b6043e99d8033dc5358eb7a4dc990919cb9d82..718d3f1374895adb3cb97ce90668fdcbecd19d45 100644
--- a/Geo/GModelIO_Mesh.cpp
+++ b/Geo/GModelIO_Mesh.cpp
@@ -29,6 +29,9 @@
 #include "discreteFace.h"
 #include "discreteRegion.h"
 #include "MVertexPositionSet.h"
+#include "PView.h"
+#include "PViewData.h"
+#include "PViewDataList.h"
 
 void GModel::_storePhysicalTagsInEntities(int dim,
                                           std::map<int, std::map<int, std::string> > &map)
@@ -53,6 +56,14 @@ void GModel::_storePhysicalTagsInEntities(int dim,
   }
 }
 
+ static void replaceCommaByDot(const std::string name){
+   char myCommand[1000], myCommand2[1000];
+   sprintf(myCommand, "sed 's/,/./g' %s > temp.txt", name.c_str());
+   system(myCommand);
+   sprintf(myCommand2, "mv temp.txt %s ", name.c_str());
+   system(myCommand2);
+ }
+
 static bool getVertices(int num, int *indices, std::map<int, MVertex*> &map,
                         std::vector<MVertex*> &vertices)
 {
@@ -80,6 +91,19 @@ static bool getVertices(int num, int *indices, std::vector<MVertex*> &vec,
   }
   return true;
 }
+static bool getProperties(int num, int *indices, std::vector<double> &vec,
+                        std::vector<double> &properties)
+{
+  for(int i = 0; i < num; i++){
+    if(indices[i] < 0 || indices[i] > (int)(vec.size() - 1)){
+      Msg::Error("Wrong vertex index %d", indices[i]);
+      return false;
+    }
+    else
+      properties.push_back(vec[indices[i]]);
+  }
+  return true;
+}
 
 static MElement *createElementMSH(GModel *m, int num, int typeMSH, int physical,
                                   int reg, int part, std::vector<MVertex*> &v,
@@ -1226,6 +1250,131 @@ static int readElementsVRML(FILE *fp, std::vector<MVertex*> &vertexVector, int r
   return 1;
 }
 
+int GModel::readPLY(const std::string &name)
+{
+
+  replaceCommaByDot(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];
+  std::map<int, std::vector<double> > properties;
+
+  char buffer[256], str[256], str2[256], str3[256];
+  std::string s1;
+  int elementary = getMaxElementaryNumber(-1) + 1;
+  int nbv, nbf;
+  int nbprop = 0;
+  int nbView = 0;
+  std::vector<std::string> propName;
+  while(!feof(fp)) {
+    if(!fgets(buffer, sizeof(buffer), fp)) break;
+    if(buffer[0] != '#'){ // skip comments
+      sscanf(buffer, "%s %s", str, str2);
+      if(!strcmp(str, "element") && !strcmp(str2, "vertex")){
+	sscanf(buffer, "%s %s %d", str, str2, &nbv);
+      } 
+      if(!strcmp(str, "format") && strcmp(str2, "ascii")){
+	Msg::Error("Only reading of ascii PLY files implemented");
+	return 0;
+      }
+      if(!strcmp(str, "property") && strcmp(str2, "list")){
+	nbprop++;
+	sscanf(buffer, "%s %s %s", str, str2, str3);
+	if (nbprop > 3) propName.push_back(s1+str3);
+      } 
+      if(!strcmp(str, "element") && !strcmp(str2, "face")){
+	sscanf(buffer, "%s %s %d", str, str2, &nbf);
+      } 
+      if(!strcmp(str, "end_header")){
+	nbView = nbprop -3;
+	Msg::Info("%d elements", nbv);
+	Msg::Info("%d triangles", nbf);
+	Msg::Info("%d properties", nbView);
+
+	//printf("*********READING VERTEX \n");
+	vertexVector.resize(nbv);
+	for(int i = 0; i < nbv; i++) {
+	  double x,y,z;
+	  char line[10000], *pEnd, *pEnd2, *pEnd3;
+	  fgets(line, sizeof(line), fp);
+	  x = strtod(line, &pEnd);
+	  y = strtod(pEnd, &pEnd2);
+	  z = strtod(pEnd2, &pEnd3);
+	  //printf("xyz=%g %g %g \n", x,y,z);
+	  vertexVector[i] = new MVertex(x, y, z);
+
+	  pEnd = pEnd3;
+	  double prop[nbView];
+	  for (int k=0; k< nbView; k++){
+	    prop[k]=strtod(pEnd, &pEnd2);
+	    pEnd = pEnd2;
+	    properties[k].push_back(prop[k]);
+	  }
+	}
+
+	//printf("*********READING ELEMS \n");
+	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]);
+	  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);
+
+
+  //Create PViews here 
+  std::vector<GEntity*> _entities;
+  getEntities(_entities);
+  for (int iV=0; iV< nbView; iV++){
+    PView *view = new PView();
+    PViewDataList *data = dynamic_cast<PViewDataList*>(view->getData());
+    for(unsigned int ii = 0; ii < _entities.size(); ii++){
+	for(unsigned int i = 0; i < _entities[ii]->getNumMeshElements(); i++){ 
+	  MElement *e = _entities[ii]->getMeshElement(i);	  
+	  int numNodes = e->getNumVertices();
+	  std::vector<double> x(numNodes), y(numNodes), z(numNodes);
+	  std::vector<double> *out = data->incrementList(1, e->getType());
+	  for(int nod = 0; nod < numNodes; nod++) out->push_back((e->getVertex(nod))->x()); 
+	  for(int nod = 0; nod < numNodes; nod++) out->push_back((e->getVertex(nod))->y()); 
+	  for(int nod = 0; nod < numNodes; nod++) out->push_back((e->getVertex(nod))->z());
+	  std::vector<double> props;
+	  int n[3];
+	  n[0] = e->getVertex(0)->getNum()-1;
+	  n[1] = e->getVertex(1)->getNum()-1;
+	  n[2] = e->getVertex(2)->getNum()-1;
+	  if(!getProperties(3, n, properties[iV], props)) return 0;
+	  for(int nod = 0; nod < numNodes; nod++) out->push_back(props[nod]);
+	}
+    }
+    data->setName(propName[iV]);
+    data->Time.push_back(0);
+    data->setFileName("property.pos");
+    data->finalize();
+  }
+
+  fclose(fp);
+
+  return 1;
+}
+
 int GModel::readPLY2(const std::string &name)
 {
   FILE *fp = fopen(name.c_str(), "r");
diff --git a/Mesh/meshPartition.cpp b/Mesh/meshPartition.cpp
index b336104087a0a7973eea00a9359889de653e8c98..8e88e8cf462103c4f5c7c7b014b77afb892a66d5 100644
--- a/Mesh/meshPartition.cpp
+++ b/Mesh/meshPartition.cpp
@@ -460,7 +460,7 @@ int PartitionGraph(Graph &graph, meshPartitionOptions &options)
           }
           break;
         case 3:  // Nodal weight
-          printf("METIS with weights\n");
+          //printf("METIS with weights\n");
           metisOptions[0] = 1;
           metisOptions[1] = options.edge_matching;
           metisOptions[2] = 1;
diff --git a/Mesh/multiscalePartition.cpp b/Mesh/multiscalePartition.cpp
index 96751985b04a1b3d7c44a026d25d568571a16c51..fed14108c18b73cca93c9848dc793951930266cc 100644
--- a/Mesh/multiscalePartition.cpp
+++ b/Mesh/multiscalePartition.cpp
@@ -5,6 +5,7 @@
 #include "MEdge.h"
 #include "MElement.h"
 #include "multiscaleLaplace.h"
+#include "GFaceCompound.h"
 #include "Numeric.h"
 #include "Context.h"
 
@@ -299,6 +300,11 @@ multiscalePartition::multiscalePartition(std::vector<MElement *> &elements,
     options.global_method = 1;// 1 Multilevel-KL, 2 Spectral
     options.mesh_dims[0] = nbParts;
   }
+  else if (options.partitioner == 2){
+    options.algorithm = 2;//1 recursive, 2=kway, 3=nodal weights
+    options.refine_algorithm=2;
+    options.edge_matching = 3;
+  }
   
   partitionLevel *level = new partitionLevel;
   level->elements.insert(level->elements.begin(),elements.begin(),elements.end());
@@ -364,7 +370,7 @@ 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 > AR_MAX || genus == 0  &&  NB > 1){
       int nbParts = 2;
       if(!onlyMultilevel){
 	Msg::Info("Mesh partition: level (%d-%d)  is ZERO-GENUS (AR=%d NB=%d) ---> LAPLACIAN partition %d parts",
diff --git a/Numeric/polynomialBasis.h b/Numeric/polynomialBasis.h
index 3779c6716aa73fcba9622598b5ec0401a4acf0d1..a3fb4edf1be5bb7f3a00290f1c496525bcf10da6 100644
--- a/Numeric/polynomialBasis.h
+++ b/Numeric/polynomialBasis.h
@@ -12,6 +12,8 @@
 #include "fullMatrix.h"
 #include <iostream>
 
+#define SQU(a)  ((a)*(a))
+
 inline double pow_int(const double &a, const int &n)
 {
   switch (n) {