From c65d59fbcfa5c9cf4657b20aeb9d7a07b00b21bb Mon Sep 17 00:00:00 2001
From: Emilie Marchandise <emilie.marchandise@uclouvain.be>
Date: Wed, 18 Nov 2009 19:40:43 +0000
Subject: [PATCH]

---
 Geo/GFaceCompound.cpp          | 176 ++++++++++++++++++++++-----------
 Geo/GFaceCompound.h            |   9 +-
 Geo/GModel.cpp                 |   2 +-
 Geo/SOrientedBoundingBox.cpp   |   5 +
 Geo/SOrientedBoundingBox.h     |   1 +
 Mesh/meshPartition.cpp         |  17 +---
 Mesh/multiscalePartition.cpp   | 135 ++++++++++++++++++++-----
 Solver/convexCombinationTerm.h |   1 +
 8 files changed, 249 insertions(+), 97 deletions(-)

diff --git a/Geo/GFaceCompound.cpp b/Geo/GFaceCompound.cpp
index 6afed65789..aae88152ff 100644
--- a/Geo/GFaceCompound.cpp
+++ b/Geo/GFaceCompound.cpp
@@ -188,6 +188,59 @@ static void myPolygon(std::vector<MElement*> &vTri, std::vector<MVertex*> &vPoly
 
 }
 
+void GFaceCompound::fillNeumannBCS() const
+{
+
+  //close neuman bcs
+  for(std::list<std::list<GEdge*> >::const_iterator iloop = _interior_loops.begin(); 
+      iloop != _interior_loops.end(); iloop++){
+    std::list<GEdge*> loop = *iloop;
+    if (loop != _U0 ){
+      //--- center of Neumann interior loop
+      int nb = 0;
+      double x=0.; 
+      double y=0.; 
+      double z=0.;
+      for (std::list<GEdge*>::iterator ite = loop.begin(); ite != loop.end(); ite++){
+	for (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++;
+	}
+      }
+      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 (int i= 0; i< (*ite)->getNumMeshElements(); i++){
+	  MVertex *v0 = (*ite)->getMeshElement(i)->getVertex(0);
+	  MVertex *v1 = (*ite)->getMeshElement(i)->getVertex(1);
+	  MTriangle *myTri  = new MTriangle(v0,v1, c); 
+	  fillTris.push_back(myTri);
+	}
+      }
+    }
+  }
+  
+//   FILE * ftri = fopen("fillTris.pos","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);
+
+}
+
 bool GFaceCompound::trivial() const
 {
   if(_compound.size() == 1 && 
@@ -255,7 +308,7 @@ bool GFaceCompound::checkOrientation(int iter) const
   //Only check orientation for stl files (1 patch)
   //  if(_compound.size() > 1.0) return true;
 
-  return true; 
+  //return true; 
 
   std::list<GFace*>::const_iterator it = _compound.begin();
   double a_old = 0, a_new;
@@ -370,34 +423,6 @@ void GFaceCompound::one2OneMap() const
       SPoint3 p_cg(u_cg,v_cg,0);
       coordinates[v] = p_cg;
       
-//      printf("Kernel CG: ucg=%g vcg=%g \n", u_cg, v_cg);
-//      bool testbadCavity = checkCavity(vTri);
-//      if(testbadCavity == true ) printf("**** New cavity is KO \n");
-//      else  printf("-- New cavity is OK \n"); 
-
-//      for(int i=0; i<  vTri.size(); i++){
-//        MTriangle *t = (MTriangle*) vTri[i];
-//        SPoint3 v1 = coordinates[t->getVertex(0)];
-//        SPoint3 v2 = coordinates[t->getVertex(1)];
-//        SPoint3 v3 = coordinates[t->getVertex(2)];
-       
-//        printf("//////////////////// \n " );
-//        double p1[2] = {v1[0],v1[1]};
-//        double p2[2] = {v2[0],v2[1]};
-//        double p3[2] = {v3[0],v3[1]};
-//        double a_new = robustPredicates::orient2d(p1, p2, p3);
-//        MVertex *e1=t->getVertex(0);	MVertex *e2=t->getVertex(1);	MVertex *e3=t->getVertex(2);
-//        printf("Point(%d)={%g, %g, 0}; \n ",e1->getNum(), v1[0],v1[1] );
-//        printf("Point(%d)={%g, %g, 0}; \n ",e2->getNum(), v2[0],v2[1] );
-//        printf("Point(%d)={%g, %g, 0}; \n ",e3->getNum(), v3[0],v3[1] );
-//        printf("Line(%d)={%d,%d}; \n", e1->getNum()+e2->getNum() , e1->getNum(), e2->getNum());
-//        printf("Line(%d)={%d,%d}; \n", e2->getNum()+e3->getNum() , e2->getNum(), e3->getNum());
-//        printf("Line(%d)={%d,%d}; \n", e3->getNum()+e1->getNum() , e3->getNum(), e1->getNum());
-//        printf("Surface(%d)={%d,%d, %d}; \n", e3->getNum()+e1->getNum() + e2->getNum(), e3->getNum(), e1->getNum()+e2->getNum() , 
-// 	      e2->getNum()+e3->getNum() , e3->getNum()+e1->getNum() );
-//        printf("//Area=%g \n", a_new);
-//      }
-      
     }
   }
 #endif
@@ -418,7 +443,7 @@ bool GFaceCompound::parametrize() const
   //-----------------
   if (_mapping == HARMONIC){
     Msg::Info("Parametrizing surface %d with 'harmonic map'", tag());
-    parametrize(ITERU,HARMONIC);
+    parametrize(ITERU,HARMONIC); 
     parametrize(ITERV,HARMONIC);
   }
   //Conformal map parametrization
@@ -441,8 +466,11 @@ bool GFaceCompound::parametrize() const
   if (!checkOrientation(0)){
     Msg::Info("Parametrization failed using standard techniques : moving to convex combination");
     coordinates.clear(); 
+    Octree_Delete(oct);
+    fillNeumannBCS();
     parametrize(ITERU,CONVEXCOMBINATION);
     parametrize(ITERV,CONVEXCOMBINATION);
+    buildOct();
   }
 
   computeNormals();  
@@ -464,7 +492,7 @@ void GFaceCompound::getBoundingEdges()
   l_edges.clear();
 
   if(_U0.size()){
-    //in case the bounding edges are explicitely given
+    //--- in case the bounding edges are explicitely given
     std::list<GEdge*>::const_iterator it = _U0.begin();
     for( ; it != _U0.end() ; ++it){
       l_edges.push_back(*it);
@@ -480,40 +508,64 @@ void GFaceCompound::getBoundingEdges()
     while(!_unique.empty())  computeALoop(_unique,loop);
   }
   else{
-    //in case the bounding edges are NOT explicitely given
+    //--- in case the bounding edges are NOT explicitely given
     std::set<GEdge*>::iterator itf = _unique.begin(); 
     for( ; itf != _unique.end(); ++itf){
-      //printf("for Compound face %d add U0 bounding edge %d \n", tag(), (*itf)->tag());
       l_edges.push_back(*itf);
       (*itf)->addFace(this);
     }
-    computeALoop(_unique, _U0);
-    while(!_unique.empty())  computeALoop(_unique,_U1);
+    std::list<GEdge*> loop;
+    computeALoop(_unique,loop); //_U0); 
+    while(!_unique.empty())  computeALoop(_unique, loop); //_U1); 
+
+    //assign Derichlet BC (_U0) to bound with largest size
+     double maxSize = 0.0;
+     for(std::list<std::list<GEdge*> >::iterator it = _interior_loops.begin();
+ 	it != _interior_loops.end(); it++){
+       double size = getSizeBB(*it);
+       if (size > maxSize) {
+	 _U0 = *it;
+	 maxSize = size;
+       }
+     }
+      
   }
 
   return;
 
 }
-SBoundingBox3d GFaceCompound::bound_U0() const
+
+double GFaceCompound::getSizeBB(const std::list<GEdge* > &elist) const
+{
+   
+  SOrientedBoundingBox obboxD = obb_boundEdges(elist);
+  double D = obboxD.getMaxSize();
+
+  //SOrientedBoundingBox bboxD = boundEdges(elist);
+  //double D = norm(SVector3(bboxD.max(), bboxD.min()));
+
+  return D;
+
+}
+SBoundingBox3d GFaceCompound::boundEdges(const std::list<GEdge* > &elist) const
 {
 
   SBoundingBox3d res;
-  std::list<GEdge*>::const_iterator it = _U0.begin();
-  for(; it != _U0.end(); it++)
+  std::list<GEdge*>::const_iterator it = elist.begin();
+  for(; it != elist.end(); it++)
     res += (*it)->bounds();
 
   return res;
 }
-SOrientedBoundingBox GFaceCompound::obb_bound_U0() const
+SOrientedBoundingBox GFaceCompound::obb_boundEdges(const std::list<GEdge* > &elist) const
 {
 
  SOrientedBoundingBox res;
  std::vector<SPoint3> vertices;
 
-
-std::list<GEdge*>::const_iterator it = _U0.begin();
-for(; it != _U0.end(); it++) {
-
+ std::list<GEdge*>::const_iterator it = elist.begin();
+ for(; it != elist.end(); it++) {
+   
    if((*it)->getNumMeshVertices() > 0) {
      int N = (*it)->getNumMeshVertices();
      for (int i = 0; i < N; i++) {
@@ -921,7 +973,16 @@ void GFaceCompound::parametrize(iterationStep step, typeOfMapping tom) const
       myAssembler.numberVertex(t->getVertex(1), 0, 1);
       myAssembler.numberVertex(t->getVertex(2), 0, 1); 
     }    
-  }    
+  }
+  if (tom == CONVEXCOMBINATION){
+    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);
+      myAssembler.numberVertex(t->getVertex(2), 0, 1); 
+    }   
+  }
+  
 
   Msg::Debug("Creating term %d dofs numbered %d fixed",
              myAssembler.sizeOfR(), myAssembler.sizeOfF());
@@ -937,6 +998,10 @@ void GFaceCompound::parametrize(iterationStep step, typeOfMapping tom) const
 	laplace.addToMatrix(myAssembler, &se);
       }
     }
+    for (std::list<MTriangle*>::iterator it2 = fillTris.begin(); it2 !=fillTris.end(); it2++ ){
+      SElement se((*it2));
+      laplace.addToMatrix(myAssembler, &se);
+    }
   }
   else {
     laplaceTerm laplace(model(), 1, &ONE);
@@ -1046,8 +1111,6 @@ void GFaceCompound::parametrize_conformal() const
     double value2 = myAssembler.getDofValue(v,0,2);
     coordinates[v] = SPoint3(value1,value2,0.0);
   }
-  // printStuff();
-  //exit(1);
 
   _lsys->clear();
 
@@ -1360,7 +1423,7 @@ void GFaceCompound::getTriangle(double u, double v,
 void GFaceCompound::buildOct() const
 {
   printStuff();
-
+ 
   SBoundingBox3d bb;
   int count = 0;
   std::list<GFace*>::const_iterator it = _compound.begin();
@@ -1424,8 +1487,8 @@ void GFaceCompound::buildOct() const
 bool GFaceCompound::checkTopology() const
 {
   // FIXME!!! I think those things are wrong with cross-patch reparametrization
-  //if ((*(_compound.begin()))->geomType() != GEntity::DiscreteSurface)return true;
-  
+  //if ((*(_compound.begin()))->geomType() != GEntity::DiscreteSurface)return true;  
+
   bool correctTopo = true;
 
   int Nb = _interior_loops.size();
@@ -1434,7 +1497,7 @@ bool GFaceCompound::checkTopology() const
 
   if (!correctTopo){
     Msg::Warning("Wrong topology: Genus=%d and N boundary=%d", G, Nb);
-    nbSplit = std::max(G+1, 2);
+    nbSplit = G+2; //std::max(G+2, 2);
     Msg::Info("Split surface %d in %d parts with Mesh partitioner", tag(), nbSplit);
   }
   else
@@ -1452,7 +1515,7 @@ bool GFaceCompound::checkAspectRatio() const
   bool paramOK = true;
   if(allNodes.empty()) buildAllNodes();
   
-  double limit =  1.e17 ;
+  double limit =  1.e15 ;
   double areaMax = 0.0;
   int nb = 0;
   std::list<GFace*>::const_iterator it = _compound.begin();
@@ -1483,12 +1546,11 @@ bool GFaceCompound::checkAspectRatio() const
   if (areaMax > limit && nb > 10) {
     Msg::Warning("Geometrical aspect ratio too high (1/area_2D=%g)", areaMax);
     SBoundingBox3d bboxH = bounds();
-    SOrientedBoundingBox obboxD = obb_bound_U0();
-    double H = norm(SVector3(bboxH.max(), bboxH.min())); 
-    double D = obboxD.getMaxSize();
-    int split =  (int)ceil(.3*H/D);
+    double H = norm(SVector3(bboxH.max(), bboxH.min()));
+    double D = getSizeBB(_U0);
+    int split =  (int)ceil(.7*H/D);
     nbSplit = std::max(split,2); 
-    printf("H=%g, D=%g split=%d nbSplit=%d \n", H, D, split, nbSplit);
+    //printf("H=%g, D=%g split=%d nbSplit=%d \n", H, D, split, nbSplit);
     Msg::Info("Partition geometry in N=%d parts", nbSplit);
     paramOK = false;
   }
@@ -1594,7 +1656,7 @@ int GFaceCompound::genusGeom() const
 void GFaceCompound::printStuff() const
 {
   std::list<GFace*>::const_iterator it = _compound.begin();
-
+ 
   char name0[256], name1[256], name2[256], name3[256];
   char name4[256], name5[256], name6[256];
   sprintf(name0, "UVAREA-%d.pos", (*it)->tag());
diff --git a/Geo/GFaceCompound.h b/Geo/GFaceCompound.h
index 73c44debe8..7efa430cb5 100644
--- a/Geo/GFaceCompound.h
+++ b/Geo/GFaceCompound.h
@@ -66,6 +66,7 @@ class GFaceCompound : public GFace {
   mutable bool mapv2Tri;
   mutable std::map<MVertex*, SPoint3> coordinates;
   mutable std::map<MVertex*, SVector3> _normals;
+  mutable std::list<MTriangle*> fillTris;
   void buildOct() const ;
   void buildAllNodes() const; 
   void parametrize(iterationStep, typeOfMapping) const;
@@ -85,9 +86,11 @@ class GFaceCompound : public GFace {
   void printStuff() const;
   bool trivial() const ;
   linearSystem <double> *_lsys;
-  SBoundingBox3d bound_U0() const;
-  SOrientedBoundingBox obb_bound_U0() const;
- public:
+  double getSizeBB(const std::list<GEdge* > &elist) const;
+  SBoundingBox3d boundEdges(const std::list<GEdge* > &elist) const;
+  SOrientedBoundingBox obb_boundEdges(const std::list<GEdge* > &elist) const;
+  void fillNeumannBCS() const;
+ public: 
   GFaceCompound(GModel *m, int tag, std::list<GFace*> &compound,
                 std::list<GEdge*> &U0, std::list<GEdge*> &U1,
                 std::list<GEdge*> &V0, std::list<GEdge*> &V1,
diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp
index eee25937eb..aece6243d6 100644
--- a/Geo/GModel.cpp
+++ b/Geo/GModel.cpp
@@ -1230,7 +1230,7 @@ void GModel::createTopologyFromFaces(std::vector<discreteFace*> &discFaces)
       
       int numE = maxEdgeNum()+1;
       discreteEdge *e = new discreteEdge(this, numE, 0, 0);
-      printf("*** Created discreteEdge %d \n", numE);
+      //printf("*** Created discreteEdge %d \n", numE);
       add(e);
       discEdges.push_back(e);
       
diff --git a/Geo/SOrientedBoundingBox.cpp b/Geo/SOrientedBoundingBox.cpp
index 7a9dad595e..128ae0637f 100644
--- a/Geo/SOrientedBoundingBox.cpp
+++ b/Geo/SOrientedBoundingBox.cpp
@@ -152,6 +152,11 @@ double SOrientedBoundingBox::getMaxSize()
   return (std::max(size[0], std::max(size[1], size[2])));
 }
 
+double SOrientedBoundingBox::getMinSize()
+{
+  return (std::min(size[0], std::min(size[1], size[2])));
+}
+
 SVector3 SOrientedBoundingBox::getAxis(int axis)
 {
   SVector3 ret;
diff --git a/Geo/SOrientedBoundingBox.h b/Geo/SOrientedBoundingBox.h
index e2fd50b979..2d9265772e 100644
--- a/Geo/SOrientedBoundingBox.h
+++ b/Geo/SOrientedBoundingBox.h
@@ -64,6 +64,7 @@ class SOrientedBoundingBox {
   double getCenterZ(){ return center[2]; }
   SVector3 getSize(){ return size; }
   double getMaxSize();
+  double getMinSize();
 
   // valid values for axis are 0 (X-axis), 1 (Y-axis) or 2 (Z-axis)
   SVector3 getAxis(int axis);
diff --git a/Mesh/meshPartition.cpp b/Mesh/meshPartition.cpp
index ddcd14e326..b9707b7b8f 100644
--- a/Mesh/meshPartition.cpp
+++ b/Mesh/meshPartition.cpp
@@ -114,6 +114,8 @@ bool PartitionZeroGenus(std::list<GFace*> &cFaces, int &nbParts){
      options.mesh_dims[0] = nbParts;
    }
 
+//   PartitionMeshFace(cFaces, options);
+
    std::vector<MElement *> elements;
    for (std::list<GFace*>::iterator it = cFaces.begin(); it != cFaces.end(); it++)
      for(unsigned int j = 0; j < (*it)->getNumMeshElements(); j++)
@@ -124,19 +126,6 @@ bool PartitionZeroGenus(std::list<GFace*> &cFaces, int &nbParts){
 
 }
 
-// bool PartitionZeroGenus(std::list<GFace*> &cFaces, int &nbParts){
-//   meshPartitionOptions options;
-//   options = CTX::instance()->partitionOptions;
-//   options.num_partitions = nbParts;
-//   options.partitioner = 1;//1 CHACO //2 METIS
-//   if ( options.partitioner == 1){
-//     options.global_method = 2;// 1 Multilevel-KL 2 Spectral
-//     options.mesh_dims[0] = nbParts;
-//   }
-//   PartitionMeshFace(cFaces, options);
-//   return true;  
-// }
-
 int PartitionMeshElements( std::vector<MElement*> &elements, meshPartitionOptions &options){
 
  GModel *tmp_model = new GModel();
@@ -1097,7 +1086,7 @@ void createPartitionFaces(GModel *model, GFaceCompound *gf, int N,
   std::vector<std::set<MVertex*> > allNodes;
   int numMax = model->maxFaceNum() + 1;
   for( int i =0; i < N;  i++){
-    printf("*** Created discreteFace %d \n", numMax+i);
+    //printf("*** Created discreteFace %d \n", numMax+i);
     discreteFace *face = new discreteFace(model, numMax+i);
     discreteFaces.push_back(face);
     model->add(face);//delete this    
diff --git a/Mesh/multiscalePartition.cpp b/Mesh/multiscalePartition.cpp
index a772b78acc..84d282eaa3 100644
--- a/Mesh/multiscalePartition.cpp
+++ b/Mesh/multiscalePartition.cpp
@@ -2,12 +2,53 @@
 #include "GmshConfig.h"
 #include "GmshDefines.h"
 #include "meshPartition.h"
+#include "MEdge.h"
 #include "MElement.h"
 
-static bool zeroGenus (std::vector<MElement *> &elements){
+static void recur_connect (MVertex *v,
+			   std::multimap<MVertex*,MEdge> &v2e,
+			   std::set<MEdge,Less_Edge> &group,
+			   std::set<MVertex*> &touched){
 
-  //TODO
-  return true; 
+  if (touched.find(v) != touched.end())return;
+
+  touched.insert(v);
+  for (std::multimap <MVertex*,MEdge>::iterator it = v2e.lower_bound(v); 
+       it != v2e.upper_bound(v) ; ++it){
+    group.insert(it->second);
+    for (int i=0;i<it->second.getNumVertices();++i){
+      recur_connect (it->second.getVertex(i),v2e,group,touched);
+    }
+  }
+
+}
+
+static int connected_bounds (std::vector<MEdge> &edges)
+{
+
+  std::vector<std::vector<MEdge> > regions;
+  
+  std::multimap<MVertex*,MEdge> v2e;
+  for (int i=0;i<edges.size();++i){
+    for (int j=0;j<edges[i].getNumVertices();j++){
+      v2e.insert(std::make_pair(edges[i].getVertex(j),edges[i]));
+    }
+  }
+  while (!v2e.empty()){
+    std::set<MEdge, Less_Edge> group;
+    std::set<MVertex*> touched;
+    recur_connect (v2e.begin()->first,v2e,group,touched);
+    std::vector<MEdge> temp;
+    temp.insert(temp.begin(), group.begin(), group.end());
+    regions.push_back(temp);
+    for ( std::set<MVertex*>::iterator it = touched.begin() ; it != touched.end();++it)
+      v2e.erase(*it);
+  }
+
+  return regions.size();
+}
+
+static int getGenus (std::vector<MElement *> &elements){ 
 
  //We suppose MElements are simply connected
  
@@ -28,19 +69,51 @@ static bool zeroGenus (std::vector<MElement *> &elements){
   int poincare = vs.size() - es.size() + N; 
 
   //compute connected boundaries 
-  //....
   int nbBounds = 0;
-  //....
-
+  std::vector<MEdge> bEdges;  
+  for(unsigned int i = 0; i < elements.size(); i++){
+    for(unsigned int j = 0; j < elements[i]->getNumEdges(); j++){
+      MEdge me =  elements[i]->getEdge(j);
+      if(std::find(bEdges.begin(), bEdges.end(), me) == bEdges.end())
+	 bEdges.push_back(me);
+      else
+	 bEdges.erase(std::find(bEdges.begin(), bEdges.end(),me));
+    }    
+  }    
+  nbBounds = connected_bounds(bEdges);
   int genus = (int)(-poincare + 2 - nbBounds)/2;
+
+  //printf("************** partition has %d boundaries and genus =%d \n", nbBounds, genus);
   
-  if (genus == 0)
-    return true;
-  else
-    return false;
+  return genus;
 
 }
 
+// static int getGeomAspectRatio (std::vector<MElement *> &elements){ 
+
+//   std::set<MVertex*> vs;
+//   for(unsigned int i = 0; i < elements.size(); i++){
+//     MElement *e = elements[i];
+//     for(int j = 0; j < e->getNumVertices(); j++){
+//       vs.insert(e->getVertex(j));
+//     }
+//   }
+  
+//   std::vector<SPoint3> vertices;
+//   for (std::set<MVertex* >::iterator it = vs.begin(); it != vs.end(); it++){
+//     SPoint3 pt((*it)->x(),(*it)->y(), (*it)->z());
+//     vertices.push_back(pt);
+//   }
+
+//   SOrientedBoundingBox obbox = SOrientedBoundingBox::buildOBB(vertices);
+//   double eta = obbox.getMaxSize()/obbox.getMinSize();
+  
+//   printf("aspect ratio = %g (max=%g, min=%g)\n", eta, obbox.getMaxSize(), obbox.getMinSize() );
+
+//   return eta;
+
+// }
+
 static void partitionRegions (std::vector<MElement*> &elements, 
 			      std::vector<std::vector<MElement*> > &regions){
   
@@ -89,16 +162,21 @@ void multiscalePartition::partition(partitionLevel & level){
 
     levels.push_back(nextLevel);
 
-     if (!zeroGenus(regions[i])){
-       Msg::Info("Multiscale partition, level %d region %d not ZERO-GENUS",
-		 nextLevel->recur,nextLevel->region);
-       partition(*nextLevel);
-     }
-     else {
-       Msg::Info("Multiscale Partition, level %d, region %d is ZERO-GENUS", 
-		 nextLevel->recur,nextLevel->region);
-     }
-
+    int genus = getGenus(regions[i]);
+    if (genus < 0) {
+      Msg::Error("Genus partition is negative G=%d!", genus);
+      exit(1);
+    }
+    if (genus != 0 ){
+      Msg::Info("Multiscale partition, level %d region %d  is %d-GENUS -> partition",
+		nextLevel->recur,nextLevel->region, genus);
+      partition(*nextLevel);
+    }
+    else {
+      Msg::Info("Multiscale Partition, level %d, region %d is ZERO-GENUS", 
+		nextLevel->recur,nextLevel->region);
+    }
+     
 }
 
 #endif
@@ -106,8 +184,21 @@ void multiscalePartition::partition(partitionLevel & level){
 
 int multiscalePartition::assembleAllPartitions(){
 
-  int nbParts =  options.num_partitions;;
+  int nbParts =  1;   
+  //int nbLevel = options.num_partitions;
+
+  for (int i = 0; i< levels.size(); i++){
+    partitionLevel *iLevel = levels[i];
+    if(iLevel->elements.size() > 0){
+      for (int j = 0; j < iLevel->elements.size(); j++){
+	MElement *e = iLevel->elements[j];
+	int part = e->getPartition();
+	e->setPartition(nbParts);
+      }
+      nbParts++;
+    }
+  }
 
-  return nbParts;
+  return nbParts-1;
 
 }
diff --git a/Solver/convexCombinationTerm.h b/Solver/convexCombinationTerm.h
index 2e3e068f5b..d27de599cc 100644
--- a/Solver/convexCombinationTerm.h
+++ b/Solver/convexCombinationTerm.h
@@ -1,3 +1,4 @@
+
 // Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
 //
 // See the LICENSE.txt file for license information. Please report all
-- 
GitLab