From 6091a8d35e46ff1c78b0559da4f7526147cac418 Mon Sep 17 00:00:00 2001
From: Matti Pellika <matti.pellikka@tut.fi>
Date: Tue, 19 May 2009 11:24:33 +0000
Subject: [PATCH] Code cleanup.

Added cell combining methods (about O(n^2)) to further reduce the size of
the cell complex before applying Smith normal form computation.

(Don't know why there seems to be some benchmarks/ files modified too,
Somebody else committed between my update and commit?)
---
 Geo/CellComplex.cpp       | 834 +++++++++++++++-----------------------
 Geo/CellComplex.h         | 423 ++++++++++++++-----
 Geo/ChainComplex.cpp      |  72 +++-
 Geo/ChainComplex.h        |  10 +
 utils/misc/celldriver.cpp |   9 +
 5 files changed, 727 insertions(+), 621 deletions(-)

diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp
index 1d6337ad85..02a7c12836 100644
--- a/Geo/CellComplex.cpp
+++ b/Geo/CellComplex.cpp
@@ -70,9 +70,9 @@ CellComplex::CellComplex( std::vector<GEntity*> domain, std::vector<GEntity*> su
     
   // insert cells into cell complex
   // subdomain need to be inserted first!
-  insert_cells2(true, true);
-  insert_cells2(false, true);
-  insert_cells2(false, false);
+  insert_cells(true, true);
+  insert_cells(false, true);
+  insert_cells(false, false);
   
   // find mesh vertices in the domain
   for(unsigned int j=0; j < domain.size(); j++) {  
@@ -93,94 +93,20 @@ CellComplex::CellComplex( std::vector<GEntity*> domain, std::vector<GEntity*> su
   }
   
   
-  // attach induvivial tags to cells
+  // attach individual tags to cells
   int tag = 1;
   for(int i = 0; i < 4; i++){
     for(citer cit = firstCell(i); cit != lastCell(i); cit++){
       Cell* cell = *cit;
       cell->setTag(tag);
       tag++;
-      
-      // make sure that boundary and coboundary information is coherent
-      std::list<Cell*> boundary = cell->getBoundary();
-      boundary.sort(Less_Cell());
-      boundary.unique(Equal_Cell());
-      cell->setBoundary(boundary);
-      
-      std::list<Cell*> coboundary = cell->getCoboundary();
-      coboundary.sort(Less_Cell());
-      coboundary.unique(Equal_Cell());
-      cell->setCoboundary(coboundary);
-      
-      
     }
-    
-    
     _originalCells[i] = _cells[i];
   }
   
-  
-  _simplicial = true;
-  
-}
-void CellComplex::insert_cells(bool subdomain, bool boundary){  
-  
-  std::vector<GEntity*> domain;
-  
-  if(subdomain) domain = _subdomain;
-  else if(boundary) domain = _boundary;
-  else domain = _domain;
-  
-  std::vector<int> vertices;
-  int vertex = 0;
-  
-  std::pair<citer, bool> insertInfo;
-  
-  for(unsigned int j=0; j < domain.size(); j++) {  
-    for(unsigned int i=0; i < domain.at(j)->getNumMeshElements(); i++){ 
-      vertices.clear();
-      
-      for(int k=0; k < domain.at(j)->getMeshElement(i)->getNumVertices(); k++){              
-        MVertex* vertex = domain.at(j)->getMeshElement(i)->getVertex(k);
-        vertices.push_back(vertex->getNum()); 
-        //_cells[0].insert(new ZeroSimplex(vertex->getNum(), subdomain, vertex->x(), vertex->y(), vertex->z() )); // Add vertices
-        Cell* cell = new ZeroSimplex(vertex->getNum(), subdomain, boundary);
-        insertInfo = _cells[0].insert(cell);
-        if(!insertInfo.second) delete cell;
-      }
-      if(domain.at(j)->getMeshElement(i)->getDim() == 3){
-        Cell* cell = new ThreeSimplex(vertices, subdomain, boundary); // Add volumes
-        insertInfo = _cells[3].insert(cell);
-        if(!insertInfo.second) delete cell;
-      }
-      for(int k=0; k < domain.at(j)->getMeshElement(i)->getNumFaces(); k++){
-        vertices.clear();
-        for(int l=0; l < domain.at(j)->getMeshElement(i)->getFace(k).getNumVertices(); l++){
-          vertex = domain.at(j)->getMeshElement(i)->getFace(k).getVertex(l)->getNum();
-          vertices.push_back(vertex); 
-        } 
-        Cell* cell = new TwoSimplex(vertices, subdomain, boundary); // Add faces
-        insertInfo = _cells[2].insert(cell);
-        if(!insertInfo.second) delete cell;
-      }
-      
-      for(int k=0; k < domain.at(j)->getMeshElement(i)->getNumEdges(); k++){
-        vertices.clear();
-        for(int l=0; l < domain.at(j)->getMeshElement(i)->getEdge(k).getNumVertices(); l++){
-          vertex = domain.at(j)->getMeshElement(i)->getEdge(k).getVertex(l)->getNum();
-          vertices.push_back(vertex); 
-        }
-        Cell* cell = new OneSimplex(vertices, subdomain, boundary); // Add edges
-        insertInfo = _cells[1].insert(cell);
-        if(!insertInfo.second) delete cell;
-      }
-            
-    }               
-  }
-  
 }
 
-void CellComplex::insert_cells2(bool subdomain, bool boundary){
+void CellComplex::insert_cells(bool subdomain, bool boundary){
   
   // works only for simplcial meshes at the moment!
   
@@ -208,10 +134,10 @@ void CellComplex::insert_cells2(bool subdomain, bool boundary){
       int dim = domain.at(j)->getMeshElement(i)->getDim();
       int type = domain.at(j)->getMeshElement(i)->getTypeForMSH();
       Cell* cell;
-      if(dim == 3) cell = new ThreeSimplex(vertices, subdomain, boundary);
-      else if(dim == 2) cell = new TwoSimplex(vertices, subdomain, boundary);
-      else if(dim == 1) cell = new OneSimplex(vertices, subdomain, boundary);
-      else cell = new ZeroSimplex(vertices.at(0), subdomain, boundary);
+      if(dim == 3) cell = new ThreeSimplex(vertices, 0, subdomain, boundary);
+      else if(dim == 2) cell = new TwoSimplex(vertices, 0, subdomain, boundary);
+      else if(dim == 1) cell = new OneSimplex(vertices, 0, subdomain, boundary);
+      else cell = new ZeroSimplex(vertices.at(0), 0, subdomain, boundary);
       insertInfo = _cells[dim].insert(cell);
       if(!insertInfo.second) delete cell;
     }
@@ -225,19 +151,23 @@ void CellComplex::insert_cells2(bool subdomain, bool boundary){
       for(int i = 0; i < cell->getNumFacets(); i++){ 
         cell->getFacetVertices(i, vertices);
         Cell* newCell;
-        if(dim == 3) newCell = new TwoSimplex(vertices, subdomain, boundary);
-        else if(dim == 2) newCell = new OneSimplex(vertices, subdomain, boundary);
-        else if(dim == 1) newCell = new ZeroSimplex(vertices.at(0), subdomain, boundary);
+        if(dim == 3) newCell = new TwoSimplex(vertices, 0, subdomain, boundary);
+        else if(dim == 2) newCell = new OneSimplex(vertices, 0, subdomain, boundary);
+        else if(dim == 1) newCell = new ZeroSimplex(vertices.at(0), 0, subdomain, boundary);
         insertInfo = _cells[dim-1].insert(newCell);
         if(!insertInfo.second){
           delete newCell;
           Cell* oldCell = *(insertInfo.first);
-          oldCell->addCoboundaryCell(cell);
-          cell->addBoundaryCell(oldCell);
+          if(!subdomain && !boundary){
+            int ori = cell->kappa(oldCell);
+            oldCell->addCoboundaryCell( ori, cell );
+            cell->addBoundaryCell( ori, oldCell);
+          }
         }
-        else{
-          cell->addBoundaryCell(newCell);
-          newCell->addCoboundaryCell(cell);
+        else if(!subdomain && !boundary) {
+          int ori = cell->kappa(newCell);
+          cell->addBoundaryCell( ori, newCell );
+          newCell->addCoboundaryCell( ori, cell);
         }
       }
     }
@@ -249,6 +179,7 @@ void CellComplex::insertCell(Cell* cell){
   _cells[cell->getDim()].insert(cell);
 }
 
+
 int Simplex::kappa(Cell* tau) const{
   for(int i=0; i < tau->getNumVertices(); i++){
     if( !(this->hasVertex(tau->getVertex(i))) ) return 0;
@@ -258,12 +189,88 @@ int Simplex::kappa(Cell* tau) const{
   
   int value=1;
   for(int i=0; i < tau->getNumVertices(); i++){
-    if(this->getVertex(i) != tau->getVertex(i)) return value;
+    if(this->getSortedVertex(i) != tau->getSortedVertex(i)) return value;
     value = value*-1;
   }
   
   return value;  
 }
+
+/*
+int Simplex::kappa(Cell* tau) const{
+  for(int i=0; i < tau->getNumVertices(); i++){
+    if( !(this->hasVertex(tau->getVertex(i))) ) return 0;
+  }
+  
+  if(this->getDim() - tau->getDim() != 1) return 0;
+  
+  int value=1;
+  
+  for(int i = 0; i < this->getNumFacets(); i++){
+    std::vector<int> vTau = tau->getVertexVector(); 
+    std::vector<int> v;
+    this->getFacetVertices(i, v);
+    value = -1;
+    
+    do {
+      value = value*-1;
+      if(v == vTau) return value;
+    }
+    while (std::next_permutation(vTau.begin(), vTau.end()) );
+    
+    vTau = tau->getVertexVector();
+    value = -1;
+    do {
+      value = value*-1;
+      if(v == vTau) return value;
+    }
+    while (std::prev_permutation(vTau.begin(), vTau.end()) );
+    
+    
+  }
+  
+  return 0;
+}
+
+int OneSimplex::kappa(Cell* tau) const{
+  for(int i=0; i < tau->getNumVertices(); i++){
+    if( !(this->hasVertex(tau->getVertex(i))) ) return 0;
+  }
+  
+  if(tau->getDim() != 0) return 0;
+  
+  if(tau->getVertex(0) == this->getVertex(0)) return -1;
+  else return 1;
+    
+}
+*/
+
+int Quadrangle::kappa(Cell* tau) const{
+  for(int i=0; i < tau->getNumVertices(); i++){
+    if( !(this->hasVertex(tau->getVertex(i))) ) return 0;
+  }
+  
+  if(tau->getDim() != 1) return 0;
+  
+  int value=1;
+  
+  std::vector<int> vTau = tau->getVertexVector();
+  
+  for(int i = 0; i < this->getNumFacets(); i++){
+    std::vector<int> v;
+    this->getFacetVertices(i, v);
+    value = -1;
+    do {
+      value = value*-1;
+      if(v == vTau) return value;
+    }
+    while (std::next_permutation(v.begin(), v.end()) );
+  }
+    
+  return value;
+}
+
+
 std::set<Cell*, Less_Cell>::iterator CellComplex::findCell(int dim, std::vector<int>& vertices, bool original){
   Cell* cell;
   
@@ -294,122 +301,8 @@ std::set<Cell*, Less_Cell>::iterator CellComplex::findCell(int dim, int vertex,
 }
 
 
-std::vector<Cell*> CellComplex::bd(Cell* sigma){  
-  std::vector<Cell*> boundary;
-  int dim = sigma->getDim();
-  if(dim < 1) return boundary;
-  
-  if(simplicial()){ // faster
-    std::vector<int> vertices = sigma->getVertexVector();
-    
-    for(int j=0; j < vertices.size(); j++){
-      std::vector<int> bVertices;
-      
-      // simplicial mesh assumed here!
-      for(int k=0; k < vertices.size(); k++){
-        if (k !=j ) bVertices.push_back(vertices.at(k));
-      }
-      citer cit2  = findCell(dim-1, bVertices);
-      if(cit2 != lastCell(dim-1)){
-        boundary.push_back(*cit2);
-        if(boundary.size() == sigma->getBdMaxSize()){
-          return boundary;
-        }
-      }
-    }
-    
-  }
-  else{
-    citer start = findCell(dim-1, sigma->getVertex(0), 0);
-    if(start == lastCell(dim-1)) return boundary;
-    
-    citer end = findCell(dim-1, sigma->getVertex(sigma->getNumVertices()-1), sigma->getVertex(sigma->getNumVertices()-1));
-    if(end != lastCell(dim-1)) end++;
-    
-    //for(citer cit = firstCell(dim-1); cit != lastCell(dim-1); cit++){
-    for(citer cit = start; cit != end; cit++){
-      //if(kappa(sigma, *cit) != 0){
-      if(sigma->kappa(*cit) != 0){
-        boundary.push_back(*cit);
-        if(boundary.size() == sigma->getBdMaxSize()){
-          return boundary;
-        }
-      }
-    }
-  }
-  return boundary;    
-}
-std::vector< std::set<Cell*, Less_Cell>::iterator > CellComplex::bdIt(Cell* sigma){
-  
-  int dim = sigma->getDim();  
-  std::vector< std::set<Cell*, Less_Cell>::iterator >  boundary;
-  if(dim < 1){
-    return boundary;
-  }
-  
-  citer start = findCell(dim-1, sigma->getVertex(0), 0);
-  if(start == lastCell(dim-1)) return boundary;
-  
-  citer end = findCell(dim-1, sigma->getVertex(sigma->getNumVertices()-1), sigma->getVertex(sigma->getNumVertices()-1));
-  if(end != lastCell(dim-1)) end++;
-    
-  for(citer cit = start; cit != end; cit++){
-    if(kappa(sigma, *cit) != 0){
-      boundary.push_back(cit);
-      if(boundary.size() == sigma->getBdMaxSize()){
-        return boundary;
-      }
-    }
-  }
-  
-  return boundary;
-}
-
-
-
-std::vector<Cell*> CellComplex::cbd(Cell* tau){  
-  std::vector<Cell*> coboundary;
-  int dim = tau->getDim();
-  if(dim > 2){
-    return coboundary;
-  }
-  
-  for(citer cit = firstCell(dim+1); cit != lastCell(dim+1); cit++){
-    //if(kappa(*cit, tau) != 0){
-    Cell* cell = *cit;
-    if(cell->kappa(tau) != 0){
-      coboundary.push_back(*cit);
-      if(coboundary.size() == tau->getCbdMaxSize()){
-        return coboundary;
-      }
-    }
-  }
-  
-  return coboundary;    
-}
-
-std::vector< std::set<Cell*, Less_Cell>::iterator > CellComplex::cbdIt(Cell* tau){
-  
-  std::vector< std::set<Cell*, Less_Cell>::iterator >  coboundary;
-  int dim = tau->getDim();
-  if(dim > 2){
-    return coboundary;
-  }
-  
-  for(citer cit = firstCell(dim+1); cit != lastCell(dim+1); cit++){
-    if(kappa(*cit, tau) != 0){
-      coboundary.push_back(cit);
-      if(coboundary.size() == tau->getCbdMaxSize()){
-        return coboundary;
-      }
-    }
-  }
-  
-  return coboundary;
-}
-
-
 void CellComplex::removeCell(Cell* cell){
+  
   _cells[cell->getDim()].erase(cell);
   
   std::list<Cell*> coboundary = cell->getCoboundary();
@@ -419,34 +312,18 @@ void CellComplex::removeCell(Cell* cell){
     Cell* cbdCell = *it;
     cbdCell->removeBoundaryCell(cell);
   }
+  
   for(std::list<Cell*>::iterator it = boundary.begin(); it != boundary.end(); it++){
     Cell* bdCell = *it;
     bdCell->removeCoboundaryCell(cell);
   }
   
-}
-void CellComplex::removeCellIt(std::set<Cell*, Less_Cell>::iterator cell){
-  Cell* c = *cell;
-  int dim = c->getDim();
-  _cells[dim].erase(cell);
-
 }
 
 void CellComplex::removeCellQset(Cell*& cell, std::set<Cell*, Less_Cell>& Qset){
    Qset.erase(cell);
 }
 
-void CellComplex::enqueueCellsIt(std::vector< std::set<Cell*, Less_Cell>::iterator >& cells, 
-                               std::queue<Cell*>& Q, std::set<Cell*, Less_Cell>& Qset){
-  for(unsigned int i=0; i < cells.size(); i++){
-    Cell* cell = *cells.at(i);
-    citer cit = Qset.find(cell);
-    if(cit == Qset.end()){
-      Qset.insert(cell);
-      Q.push(cell);
-    } 
-  }
-}
 void CellComplex::enqueueCells(std::list<Cell*>& cells, std::queue<Cell*>& Q, std::set<Cell*, Less_Cell>& Qset){
   for(std::list<Cell*>::iterator cit = cells.begin(); cit != cells.end(); cit++){
     Cell* cell = *cit;
@@ -458,18 +335,6 @@ void CellComplex::enqueueCells(std::list<Cell*>& cells, std::queue<Cell*>& Q, st
   }
 }
 
-void CellComplex::enqueueCells(std::list<Cell*>& cells, std::list<Cell*>& Q){
-  for(std::list<Cell*>::iterator cit = cells.begin(); cit != cells.end(); cit++){
-    Cell* cell = *cit;
-    std::list<Cell*>::iterator it = std::find(Q.begin(), Q.end(), cell);
-    if(it == Q.end()){
-      Q.push_back(cell);
-    }
-  }
-}
-
-
-
 int CellComplex::coreductionMrozek(Cell* generator){
   
   int coreductions = 0;
@@ -482,6 +347,7 @@ int CellComplex::coreductionMrozek(Cell* generator){
   //removeCell(generator);
   
   std::list<Cell*> bd_s;
+  //std::list< std::pair<int, Cell*> >bd_s;
   std::list<Cell*> cbd_c;
   Cell* s;
   int round = 0;
@@ -512,145 +378,11 @@ int CellComplex::coreductionMrozek(Cell* generator){
   return coreductions;
 }
 
-int CellComplex::coreductionMrozek2(Cell* generator){
-  
-  int coreductions = 0;
-  
-  std::list<Cell*> Q;
-  
-  Q.push_back(generator);
-  
-  std::list<Cell*> bd_s;
-  std::list<Cell*> cbd_c;
-  Cell* s;
-  int round = 0;
-  while( !Q.empty() ){
-    round++;
-    //printf("%d ", round);
-    s = Q.front();
-    Q.pop_front();
-    bd_s = s->getBoundary();
-    if( bd_s.size() == 1 && inSameDomain(s, bd_s.front()) ){
-      removeCell(s);
-      cbd_c = bd_s.front()->getCoboundary();
-      enqueueCells(cbd_c, Q);
-      removeCell(bd_s.front());
-      coreductions++;
-    }
-    else if(bd_s.empty()){
-      cbd_c = s->getCoboundary();
-      enqueueCells(cbd_c, Q);
-    }
-    
-    //Q.unique(Equal_Cell());
-  
-  }
-  //printf("Coreduction: %d loops with %d coreductions\n", round, coreductions);
-  return coreductions;
-}
-
-int CellComplex::coreductionMrozek3(Cell* generator){
-  
-  int coreductions = 0;
-  
-  std::queue<Cell*> Q;
-  std::set<Cell*, Less_Cell> Qset;
-  
-  Q.push(generator);
-  Qset.insert(generator);
-  
-  std::vector< std::set<Cell*, Less_Cell>::iterator > bd_s;
-  std::vector< std::set<Cell*, Less_Cell>::iterator > cbd_c;
-  
-  Cell* s;
-  int round = 0;
-  while( !Q.empty() ){
-    round++;
-    //printf("%d ", round);
-    s = Q.front();
-    Q.pop();
-    removeCellQset(s, Qset);
-    
-    bd_s = bdIt(s);
-    if( bd_s.size() == 1 && inSameDomain(s, *bd_s.at(0)) ){
-      removeCell(s);
-      cbd_c = cbdIt(*bd_s.at(0));
-      enqueueCellsIt(cbd_c, Q, Qset);
-      removeCellIt(bd_s.at(0));
-      coreductions++;
-    }
-    else if(bd_s.empty()){
-      cbd_c = cbdIt(s);
-      enqueueCellsIt(cbd_c, Q, Qset);
-    }
-  }
-  //printf("Coreduction: %d loops with %d coreductions\n", round, coreductions);
-  return coreductions;
-}
 int CellComplex::coreduction(int dim){
   
   if(dim < 0 || dim > 2) return 0;
   
-  std::vector<Cell*> bd_c;
-  int count = 0;
-  
-  bool coreduced = true;
-  while (coreduced){
-    coreduced = false;
-    for(citer cit = firstCell(dim+1); cit != lastCell(dim+1); cit++){
-      Cell* cell = *cit;
-      
-      bd_c = bd(cell);
-      if(bd_c.size() == 1 && inSameDomain(cell, bd_c.at(0)) ){
-        removeCell(cell);
-        removeCell(bd_c.at(0));
-        count++;
-        coreduced = true;
-      }
-      
-    }
-  }
-  
-  return count;
-    
-}
-
-int CellComplex::coreduction(int dim, std::set<Cell*, Less_Cell>& removedCells){
-  
-  if(dim < 0 || dim > 2) return 0;
-  
-  std::vector<Cell*> bd_c;
-  int count = 0;
-  
-  bool coreduced = true;
-  while (coreduced){
-    coreduced = false;
-    for(citer cit = firstCell(dim+1); cit != lastCell(dim+1); cit++){
-      Cell* cell = *cit;
-      
-      bd_c = bd(cell);
-      if(bd_c.size() == 1 && inSameDomain(cell, bd_c.at(0)) ){
-        removedCells.insert(cell);
-        removedCells.insert(bd_c.at(0));
-        removeCell(cell);
-        removeCell(bd_c.at(0));
-        count++;
-        coreduced = true;
-      }
-      
-    }
-  }
-  
-  return count;
-  
-}
-
-int CellComplex::coreduction2(int dim){
-
-  if(dim < 0 || dim > 2) return 0;
-  
   std::list<Cell*> bd_c;
-  
   int count = 0;
   
   bool coreduced = true;
@@ -669,40 +401,14 @@ int CellComplex::coreduction2(int dim){
       
     }
   }
+  
   return count;
+    
 }
 
-
-
 int CellComplex::reduction(int dim){
   if(dim < 1 || dim > 3) return 0;
   
-  std::vector<Cell*> cbd_c;
-  std::vector<Cell*> bd_c;
-  int count = 0;
-  
-  bool reduced = true;
-  while (reduced){
-    reduced = false;
-    for(citer cit = firstCell(dim-1); cit != lastCell(dim-1); cit++){
-      Cell* cell = *cit;
-      cbd_c = cbd(cell);
-      if(cbd_c.size() == 1 && inSameDomain(cell, cbd_c.at(0)) ){
-        removeCell(cell);
-        removeCell(cbd_c.at(0));
-        count++;
-        reduced = true;
-      }
-    }
-  }
-  return count;  
-}
-
-
-int CellComplex::reduction2(int dim){
-    if(dim < 1 || dim > 3) return 0;
-  
-  std::list<Cell*> bd_c;
   std::list<Cell*> cbd_c;
   int count = 0;
   
@@ -728,48 +434,13 @@ int CellComplex::reduction2(int dim){
 void CellComplex::reduceComplex(){
   printf("Cell complex before reduction: %d volumes, %d faces, %d edges and %d vertices.\n",
          getSize(3), getSize(2), getSize(1), getSize(0));
-  reduction2(3);
-  reduction2(2);
-  reduction2(1);
+  reduction(3);
+  reduction(2);
+  reduction(1);
   printf("Cell complex after reduction: %d volumes, %d faces, %d edges and %d vertices.\n",
          getSize(3), getSize(2), getSize(1), getSize(0));
 }
 
-void CellComplex::coreduceComplex(int generatorDim, std::set<Cell*, Less_Cell>& removedCells){
-  
-  std::set<Cell*, Less_Cell> generatorCells[4];
-  
-  printf("Cell complex before coreduction: %d volumes, %d faces, %d edges and %d vertices.\n",
-         getSize(3), getSize(2), getSize(1), getSize(0));
-  
-  int i = generatorDim;
-  while (getSize(i) != 0){
-    citer cit = firstCell(i);
-    Cell* cell = *cit;
-    while(!cell->inSubdomain() && cit != lastCell(i)){
-      cell = *cit;
-      cit++;
-    }
-    generatorCells[i].insert(cell);
-    removedCells.insert(cell);
-    removeCell(cell);
-    coreduction(0, removedCells);
-    coreduction(1, removedCells);
-    coreduction(2, removedCells);
-  }
-  
-  
-  for(citer cit = generatorCells[i].begin(); cit != generatorCells[i].end(); cit++){
-    Cell* cell = *cit;
-    if(!cell->inSubdomain()) _cells[i].insert(cell);
-    if(!cell->inSubdomain()) removedCells.insert(cell);
-  }
-  printf("Cell complex after coreduction: %d volumes, %d faces, %d edges and %d vertices.\n",
-         getSize(3), getSize(2), getSize(1), getSize(0));
-  
-  return;
-  
-}
 void CellComplex::coreduceComplex(int generatorDim){
 
   std::set<Cell*, Less_Cell> generatorCells[4];
@@ -788,26 +459,210 @@ void CellComplex::coreduceComplex(int generatorDim){
       generatorCells[i].insert(cell);
       removeCell(cell);
 
-      //coreduction2(0);
-      //coreduction2(1);
-      //coreduction2(2);
+      //coreduction(0);
+      //coreduction(1);
+      //coreduction(2);
       coreductionMrozek(cell);
     }
     if(generatorDim == i) break;
     
   }
+  /*
   for(int i = 0; i < 4; i++){
     for(citer cit = generatorCells[i].begin(); cit != generatorCells[i].end(); cit++){
       Cell* cell = *cit;
-      //if(!cell->inSubdomain()) _cells[i].insert(cell); 
+      if(!cell->inSubdomain()) _cells[i].insert(cell); 
     }
   }
+  */
   printf("Cell complex after coreduction: %d volumes, %d faces, %d edges and %d vertices.\n",
          getSize(3), getSize(2), getSize(1), getSize(0));
   
   return;
 }
 
+
+void CellComplex::replaceCells(Cell* c1, Cell* c2, Cell* newCell, bool orMatch, bool co){
+
+  int dim = c1->getDim();
+  
+  std::list< std::pair<int, Cell*> > coboundary1 = c1->getOrientedCoboundary();
+  std::list< std::pair<int, Cell*> > coboundary2 = c2->getOrientedCoboundary();
+  std::list< std::pair<int, Cell*> > boundary1 = c1->getOrientedBoundary();
+  std::list< std::pair<int, Cell*> > boundary2 = c2->getOrientedBoundary();
+  
+  
+  for(std::list< std::pair<int, Cell*> >::iterator it = coboundary1.begin(); it != coboundary1.end(); it++){
+    Cell* cbdCell = (*it).second;
+    int ori = (*it).first;
+    cbdCell->removeBoundaryCell(c1);
+    cbdCell->addBoundaryCell(ori, newCell);
+  }
+  for(std::list< std::pair<int, Cell*> >::iterator it = coboundary2.begin(); it != coboundary2.end(); it++){
+    Cell* cbdCell = (*it).second;
+    int ori  = (*it).first;
+    if(!orMatch) ori = -1*ori;
+    cbdCell->removeBoundaryCell(c2);
+    if(!co){
+      bool old = false;
+      for(std::list< std::pair<int, Cell* > >::iterator it2 = coboundary1.begin(); it2 != coboundary1.end(); it2++){
+        Cell* cell2 = (*it2).second;
+        if(*cell2 == *cbdCell) old = true;
+      }
+      if(!old) cbdCell->addBoundaryCell(ori, newCell);
+    }
+    else cbdCell->addBoundaryCell(ori, newCell);
+  }
+  
+  for(std::list< std::pair<int, Cell* > >::iterator it = boundary1.begin(); it != boundary1.end(); it++){
+    Cell* bdCell = (*it).second;
+    int ori = (*it).first;
+    bdCell->removeCoboundaryCell(c1);
+    bdCell->addCoboundaryCell(ori, newCell);
+  }
+  for(std::list< std::pair<int, Cell* > >::iterator it = boundary2.begin(); it != boundary2.end(); it++){
+    Cell* bdCell = (*it).second;
+    int ori = (*it).first;
+    if(!orMatch) ori = -1*ori;
+    bdCell->removeCoboundaryCell(c2);
+    if(co){
+      bool old = false;
+      for(std::list< std::pair<int, Cell* > >::iterator it2 = boundary1.begin(); it2 != boundary1.end(); it2++){
+        Cell* cell2 = (*it2).second;
+        if(*cell2 == *bdCell) old = true;
+      }
+      if(!old)  bdCell->addCoboundaryCell(ori, newCell);
+    }
+    else bdCell->addCoboundaryCell(ori, newCell);
+    
+  }
+  
+  _cells[dim].erase(c1);
+  _cells[dim].erase(c2);
+  _cells[dim].insert(newCell);
+  
+  
+  
+  return;
+}
+
+int CellComplex::cocombine(int dim){
+ 
+  printf("Cell complex before cocombining: %d volumes, %d faces, %d edges and %d vertices.\n",
+         getSize(3), getSize(2), getSize(1), getSize(0));
+    
+  if(dim < 1 || dim > 3) return 0;
+  
+  std::queue<Cell*> Q;
+  std::set<Cell*, Less_Cell> Qset;
+  std::list<Cell*> cbd_c;
+  std::list< std::pair< int, Cell*> > bd_c;
+  int count = 0;
+  
+  for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
+  
+    Cell* cell = *cit;
+    cbd_c = cell->getCoboundary();
+    enqueueCells(cbd_c, Q, Qset);
+    while(Q.size() != 0){
+
+      Cell* s = Q.front();
+      Q.pop();
+      
+      bd_c = s->getOrientedBoundary();
+      
+      if(bd_c.size() == 2 && !(*(bd_c.front().second) == *(bd_c.back().second)) 
+         && inSameDomain(s, bd_c.front().second) && inSameDomain(s, bd_c.back().second) ){
+        
+        Cell* c1 = bd_c.front().second;
+        Cell* c2 = bd_c.back().second;
+        
+        cbd_c = c1->getCoboundary();
+        enqueueCells(cbd_c, Q, Qset);
+        cbd_c = c2->getCoboundary();
+        enqueueCells(cbd_c, Q, Qset);
+        
+        int or1 = bd_c.front().first;
+        int or2 = bd_c.back().first;
+                
+        removeCell(s);
+        CombinedCell* newCell = new CombinedCell(c1, c2, (or1 != or2), true );
+        replaceCells(c1, c2, newCell, (or1 != or2), true);
+        
+        cit = firstCell(dim);
+        count++;
+      }
+      removeCellQset(s, Qset);
+      
+    }
+  }
+  
+  printf("Cell complex after cocombining: %d volumes, %d faces, %d edges and %d vertices.\n",
+         getSize(3), getSize(2), getSize(1), getSize(0));
+  
+  return count;
+}
+
+int CellComplex::combine(int dim){
+  
+  printf("Cell complex before combining: %d volumes, %d faces, %d edges and %d vertices.\n",
+         getSize(3), getSize(2), getSize(1), getSize(0));
+    
+  if(dim < 1 || dim > 3) return 0;
+  
+  std::queue<Cell*> Q;
+  std::set<Cell*, Less_Cell> Qset;
+  std::list< std::pair<int, Cell*> > cbd_c;
+  std::list<Cell*> bd_c;
+  int count = 0;
+  
+  
+  for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
+  
+    Cell* cell = *cit;
+    bd_c = cell->getBoundary();
+    enqueueCells(bd_c, Q, Qset);
+    while(Q.size() != 0){
+
+      Cell* s = Q.front();
+      Q.pop();
+      
+      cbd_c = s->getOrientedCoboundary();
+        
+      if(cbd_c.size() == 2 && !(*(cbd_c.front().second) == *(cbd_c.back().second)) 
+         && inSameDomain(s, cbd_c.front().second) && inSameDomain(s, cbd_c.back().second) ){
+        
+        Cell* c1 = cbd_c.front().second;
+        Cell* c2 = cbd_c.back().second;
+        
+        bd_c = c1->getBoundary();
+        enqueueCells(bd_c, Q, Qset);
+        bd_c = c2->getBoundary();
+        enqueueCells(bd_c, Q, Qset);
+        
+        int or1 = cbd_c.front().first;
+        int or2 = cbd_c.back().first;
+        
+        removeCell(s);
+        CombinedCell* newCell = new CombinedCell(c1, c2, (or1 != or2) );
+        replaceCells(c1, c2, newCell, (or1 != or2));
+        
+        cit = firstCell(dim);
+        count++;
+      }
+      removeCellQset(s, Qset);
+      
+    }
+  }
+  
+  printf("Cell complex after combining: %d volumes, %d faces, %d edges and %d vertices.\n",
+          getSize(3), getSize(2), getSize(1), getSize(0));
+  
+  
+  return count;
+}
+
+
 void CellComplex::repairComplex(int i){
   
   printf("Cell complex before repair: %d volumes, %d faces, %d edges and %d vertices.\n",
@@ -851,61 +706,24 @@ void CellComplex::swapSubdomain(){
     }
   }
   
-  return;
-}
-
-
-void CellComplex::getDomainVertices(std::set<MVertex*, Less_MVertex>& domainVertices, bool subdomain){
-
-  std::vector<GEntity*> domain;
-  if(subdomain) domain = _subdomain;
-  else domain = _domain;
-  
-  for(unsigned int j=0; j < domain.size(); j++) {
-    for(unsigned int i=0; i < domain.at(j)->getNumMeshElements(); i++){
-      for(int k=0; k < domain.at(j)->getMeshElement(i)->getNumVertices(); k++){
-        MVertex* vertex = domain.at(j)->getMeshElement(i)->getVertex(k);
-        domainVertices.insert(vertex);
-      }
-    }
-  }
-      
-/*  for(unsigned int j=0; j < _domain.size(); j++) { 
-    for(unsigned int i=0; i < _domain.at(j)->getNumMeshVertices(); i++){
-      MVertex* vertex =  _domain.at(j)->getMeshVertex(i);
-      domainVertices.insert(vertex);
-    }
-    
-    std::list<GFace*> faces = _domain.at(j)->faces();
-    for(std::list<GFace*>::iterator fit = faces.begin(); fit != faces.end(); fit++){
-      GFace* face = *fit;
-      for(unsigned int i=0; i < face->getNumMeshVertices(); i++){
-        MVertex* vertex =  face->getMeshVertex(i);
-        domainVertices.insert(vertex);
-      }
-    }
-    std::list<GEdge*> edges = _domain.at(j)->edges();
-    for(std::list<GEdge*>::iterator eit = edges.begin(); eit != edges.end(); eit++){
-      GEdge* edge = *eit;
-      for(unsigned int i=0; i < edge->getNumMeshVertices(); i++){
-        MVertex* vertex =  edge->getMeshVertex(i);
-        domainVertices.insert(vertex);
-      }
-    }
-    std::list<GVertex*> vertices = _domain.at(j)->vertices();
-    for(std::list<GVertex*>::iterator vit = vertices.begin(); vit != vertices.end(); vit++){
-      GVertex* vertex = *vit;
-      for(unsigned int i=0; i < vertex->getNumMeshVertices(); i++){
-        MVertex* mvertex =  vertex->getMeshVertex(i);
-        domainVertices.insert(mvertex);
+  // make subdomain closed
+  for(int i = 0; i < 4; i++){
+    for(citer cit = firstCell(i); cit != lastCell(i); cit++){
+      Cell* cell = *cit;
+      if(cell->inSubdomain()){
+        std::list<Cell*> boundary = cell->getBoundary();
+        for(std::list<Cell*>::iterator it = boundary.begin(); it != boundary.end(); it++){
+          Cell* bdCell = *it;
+          bdCell->setInSubdomain(true);
+        }
       }
     }
-    
   }
- */
+  
   return;
 }
 
+
 int CellComplex::writeComplexMSH(const std::string &name){
   
     
@@ -923,10 +741,6 @@ int CellComplex::writeComplexMSH(const std::string &name){
   
   fprintf(fp, "$Nodes\n");
   
-  //std::set<MVertex*, Less_MVertex> domainVertices;
-  //getDomainVertices(domainVertices, true);
-  //getDomainVertices(domainVertices, false);
-  
   fprintf(fp, "%d\n", _domainVertices.size());
   
   for(std::set<MVertex*, Less_MVertex>::iterator vit = _domainVertices.begin(); vit != _domainVertices.end(); vit++){
@@ -938,7 +752,15 @@ int CellComplex::writeComplexMSH(const std::string &name){
   fprintf(fp, "$EndNodes\n");
   fprintf(fp, "$Elements\n");
 
-  fprintf(fp, "%d\n", _cells[0].size() + _cells[1].size() + _cells[2].size() + _cells[3].size());
+  int count = 0;
+  for(int i = 0; i < 4; i++){
+    for(citer cit = firstCell(i); cit != lastCell(i); cit++){
+      Cell* cell = *cit;
+      count = count + cell->getNumCells();
+    }
+  }
+      
+  fprintf(fp, "%d\n", count);
 
   int physical = 0;
   
@@ -950,13 +772,17 @@ int CellComplex::writeComplexMSH(const std::string &name){
      fprintf(fp, "%d %d %d %d %d %d %d\n", vertex->getTag(), 15, 3, 0, 0, physical, vertex->getVertex(0));
   }
   
-  
+  std::list< std::pair<int, Cell*> > cells;
   for(citer cit = firstCell(1); cit != lastCell(1); cit++) {
     Cell* edge = *cit;
     if(edge->inSubdomain()) physical = 3;
     else if(edge->onDomainBoundary()) physical = 2;
     else physical = 1;
-    fprintf(fp, "%d %d %d %d %d %d %d %d\n", edge->getTag(), 1, 3, 0, 0, physical, edge->getVertex(0), edge->getVertex(1));
+    cells = edge->getCells();
+    for(std::list< std::pair<int, Cell*> >::iterator it = cells.begin(); it != cells.end(); it++){
+      Cell* cell = (*it).second;
+      fprintf(fp, "%d %d %d %d %d %d %d %d\n", cell->getTag(), 1, 3, 0, 0, physical, cell->getVertex(0), cell->getVertex(1));
+    }
   }
   
   for(citer cit = firstCell(2); cit != lastCell(2); cit++) {
@@ -964,14 +790,22 @@ int CellComplex::writeComplexMSH(const std::string &name){
     if(face->inSubdomain()) physical = 3;
     else if(face->onDomainBoundary()) physical = 2;
     else physical = 1;
-    fprintf(fp, "%d %d %d %d %d %d %d %d %d\n", face->getTag(), 2, 3, 0, 0, physical, face->getVertex(0), face->getVertex(1), face->getVertex(2));
+    cells = face->getCells();
+    for(std::list< std::pair<int, Cell*> >::iterator it = cells.begin(); it != cells.end(); it++){
+      Cell* cell = (*it).second;
+      fprintf(fp, "%d %d %d %d %d %d %d %d %d\n", cell->getTag(), 2, 3, 0, 0, physical, cell->getVertex(0), cell->getVertex(1), cell->getVertex(2));
+    }
   }
   for(citer cit = firstCell(3); cit != lastCell(3); cit++) {
     Cell* volume = *cit;
     if(volume->inSubdomain()) physical = 3;
     else if(volume->onDomainBoundary()) physical = 2;
     else physical = 1;
-    fprintf(fp, "%d %d %d %d %d %d %d %d %d %d\n", volume->getTag(), 4, 3, 0, 0, physical, volume->getVertex(0), volume->getVertex(1), volume->getVertex(2), volume->getVertex(3));
+    cells = volume->getCells();
+    for(std::list< std::pair<int, Cell*> >::iterator it = cells.begin(); it != cells.end(); it++){
+      Cell* cell = (*it).second;
+      fprintf(fp, "%d %d %d %d %d %d %d %d %d %d\n", cell->getTag(), 4, 3, 0, 0, physical, cell->getVertex(0), cell->getVertex(1), cell->getVertex(2), cell->getVertex(3));
+    }
   }
     
   fprintf(fp, "$EndElements\n");
@@ -982,11 +816,11 @@ int CellComplex::writeComplexMSH(const std::string &name){
 }
 
 
-void CellComplex::printComplex(int dim, bool subcomplex){
+void CellComplex::printComplex(int dim){
   for (citer cit = firstCell(dim); cit != lastCell(dim); cit++){
     Cell* cell = *cit;
     for(int i = 0; i < cell->getNumVertices(); i++){
-      if(!subcomplex && !cell->inSubdomain()) printf("%d ", cell->getVertex(i));
+      printf("%d ", cell->getVertex(i));
     }
     printf("\n");
   }
diff --git a/Geo/CellComplex.h b/Geo/CellComplex.h
index ebeafaedec..9ab40aadf5 100644
--- a/Geo/CellComplex.h
+++ b/Geo/CellComplex.h
@@ -21,7 +21,7 @@
 #include "GFace.h"
 #include "GVertex.h"
 
-// Abstract class representing a cell of a cell complex.
+// Abstract class representing an elemtary cell of a cell complex.
 class Cell
 {  
   protected:
@@ -40,12 +40,16 @@ class Cell
    // whether this cell belongs to the boundary of a cell complex
    bool _onDomainBoundary;
    
+   bool _combined; 
+   
    // unique tag for each cell
    int _tag;
+   int _index; 
    
    // cells on the boundary and on the coboundary of thhis cell
-   std::list<Cell*> _boundary;
-   std::list<Cell*> _coboundary;
+   std::list< std::pair<int, Cell*> > _boundary;
+   std::list< std::pair<int, Cell*> > _coboundary;
+   
    
   public:
    Cell(){}
@@ -54,11 +58,14 @@ class Cell
    virtual int getDim() const { return _dim; };
    virtual int getTag() const { return _tag; };
    virtual void setTag(int tag) { _tag = tag; };
+   virtual int getIndex() const { return _index; };
+   virtual void setIndex(int index) { _index = index; };
+   
    
    // get the number of vertices this cell has
    virtual int getNumVertices() const = 0; //{return _vertices.size();}
-   
    virtual int getVertex(int vertex) const = 0; //{return _vertices.at(vertex);}
+   virtual int getSortedVertex(int vertex) const = 0; 
    virtual std::vector<int> getVertexVector() const = 0;
    
    // returns 1 or -1 if lower dimensional cell tau is on the boundary of this cell
@@ -67,37 +74,58 @@ class Cell
    virtual int kappa(Cell* tau) const = 0;
    
    // true if this cell has given vertex
-   virtual bool hasVertex(int vertex) const = 0;
-   
+   virtual bool hasVertex(int vertex) const =0;
+  
    virtual unsigned int getBdMaxSize() const { return _bdMaxSize; };
    virtual unsigned int getCbdMaxSize() const { return _cbdMaxSize; };
 
    virtual int getBoundarySize() { return _boundary.size(); }
    virtual int getCoboundarySize() { return _coboundary.size(); }
-      
-   virtual void setBoundary(std::list<Cell*> boundary){ _boundary = boundary; }
-   virtual void setBoundary(std::vector<Cell*> boundary){ 
-     for(int i = 0; i < boundary.size(); i++) _boundary.push_back(boundary.at(i)); }
-   virtual void setCoboundary(std::list<Cell*> coboundary){ _coboundary = coboundary; }
-   virtual void setCoboundary(std::vector<Cell*> coboundary){ 
-          for(int i = 0; i < coboundary.size(); i++) _coboundary.push_back(coboundary.at(i)); }
-   virtual std::list<Cell*> getBoundary() { return _boundary; }
-   virtual std::list<Cell*> getCoboundary() { return _coboundary; }
-   virtual void addBoundaryCell(Cell* cell) { _boundary.push_back(cell); }
-   virtual void addCoboundaryCell(Cell* cell) { _coboundary.push_back(cell); }
+   
+   virtual std::list< std::pair<int, Cell*> > getOrientedBoundary() { return _boundary; }
+   virtual std::list< Cell* > getBoundary() {
+     std::list<Cell*> boundary;
+     for( std::list< std::pair<int, Cell*> >::iterator it= _boundary.begin();it!= _boundary.end();it++){
+       Cell* cell = (*it).second;
+       boundary.push_back(cell);
+     }
+     return boundary;
+   }
+   virtual std::list<std::pair<int, Cell*> >getOrientedCoboundary() { return _coboundary; }
+   virtual std::list< Cell* > getCoboundary() {
+     std::list<Cell*> coboundary;
+     for( std::list< std::pair<int, Cell*> >::iterator it= _coboundary.begin();it!= _coboundary.end();it++){
+       Cell* cell = (*it).second;
+       coboundary.push_back(cell);
+     }
+     return coboundary;
+   }
+   
+   virtual void addBoundaryCell(int orientation, Cell* cell) { _boundary.push_back( std::make_pair(orientation, cell)); }
+   virtual void addCoboundaryCell(int orientation, Cell* cell) { _coboundary.push_back( std::make_pair(orientation, cell)); }
+   
    virtual void removeBoundaryCell(Cell* cell) {
-     for(std::list<Cell*>::iterator it = _boundary.begin(); it != _boundary.end(); it++){
-       Cell* cell2 = *it;
-       if(cell2->getTag() == cell->getTag()) { _boundary.erase(it); break; }
+     for(std::list< std::pair<int, Cell*> >::iterator it = _boundary.begin(); it != _boundary.end(); it++){
+       Cell* cell2 = (*it).second;
+       if(*cell2 == *cell) { _boundary.erase(it); break; }
      }
    }
    virtual void removeCoboundaryCell(Cell* cell) { 
-     for(std::list<Cell*>::iterator it = _coboundary.begin(); it != _coboundary.end(); it++){
-       Cell* cell2 = *it;
-       if(cell2->getTag() == cell->getTag()) { _coboundary.erase(it); break; }
+     for(std::list< std::pair<int, Cell*> >::iterator it = _coboundary.begin(); it != _coboundary.end(); it++){
+       Cell* cell2 = (*it).second;
+       if(*cell2 == *cell) { _coboundary.erase(it); break; }
      }
    }
       
+   virtual void printBoundary() {  
+     for(std::list< std::pair<int, Cell*> >::iterator it = _boundary.begin(); it != _boundary.end(); it++){
+       printf("Boundary cell orientation: %d ", (*it).first);
+       Cell* cell2 = (*it).second;
+       cell2->printCell();
+     }
+   }
+   
+   
    virtual bool inSubdomain() const { return _inSubdomain; }
    virtual void setInSubdomain(bool subdomain)  { _inSubdomain = subdomain; }
    
@@ -114,26 +142,30 @@ class Cell
    
    virtual int getNumFacets() const { return 0; }
    virtual void getFacetVertices(const int num, std::vector<int> &v) const {};
-         
-   bool operator==(const Cell* c2){
-     if(this->getNumVertices() != c2->getNumVertices()){
+   
+   virtual bool combined() { return _combined; }
+   virtual std::list< std::pair<int, Cell*> > getCells() {  std::list< std::pair<int, Cell*> >cells; cells.push_back( std::make_pair(1, this)); return cells; }
+   virtual int getNumCells() {return 1;}
+   
+   bool operator==(const Cell& c2){
+     if(this->getNumVertices() != c2.getNumVertices()){
        return false;
      }
      for(int i=0; i < this->getNumVertices();i++){
-       if(this->getVertex(i) != c2->getVertex(i)){
+       if(this->getSortedVertex(i) != c2.getSortedVertex(i)){
          return false;
        }
      }
      return true;
    }
    
-   bool operator<(const Cell* c2) const {
-     if(this->getNumVertices() != c2->getNumVertices()){
-       return (this->getNumVertices() < c2->getNumVertices());
+   bool operator<(const Cell& c2) const {
+     if(this->getNumVertices() != c2.getNumVertices()){
+       return (this->getNumVertices() < c2.getNumVertices());
      }
      for(int i=0; i < this->getNumVertices();i++){
-       if(this->getVertex(i) < c2->getVertex(i)) return true;
-       else if (this->getVertex(i) > c2->getVertex(i)) return false;
+       if(this->getSortedVertex(i) < c2.getSortedVertex(i)) return true;
+       else if (this->getSortedVertex(i) > c2.getSortedVertex(i)) return false;
      }
      return false;
    }
@@ -141,15 +173,16 @@ class Cell
    
 };
 
+
 // Simplicial cell type.
 class Simplex : public Cell
 { 
    
  public:
    Simplex() : Cell() {
-     
+     _combined = false;
    }
-   virtual ~Simplex(){}  
+   ~Simplex(){}  
   
    // kappa for simplices
    // checks whether lower dimensional simplex tau is on the boundary of this cell
@@ -168,8 +201,9 @@ class ZeroSimplex : public Simplex
    double _x, _y, _z;
  public:
    
-   ZeroSimplex(int vertex, bool subdomain=false, bool boundary=false, double x=0, double y=0, double z=0) : Simplex(){
+   ZeroSimplex(int vertex, int tag=0, bool subdomain=false, bool boundary=false, double x=0, double y=0, double z=0) : Simplex(){
      _v = vertex;
+     _tag = tag;
      _dim = 0;
      _bdMaxSize = 0;
      _cbdMaxSize = 1000; // big number
@@ -179,20 +213,22 @@ class ZeroSimplex : public Simplex
      _inSubdomain = subdomain;
      _onDomainBoundary = boundary;
    }
-   virtual ~ZeroSimplex(){}
+   ~ZeroSimplex(){}
    
-   virtual int getDim() const { return 0; }
-   virtual int getNumVertices() const { return 1; }
-   virtual int getVertex(int vertex) const {return _v; }
-   virtual bool hasVertex(int vertex) const {return (_v == vertex); }
+   int getDim() const { return 0; }
+   int getNumVertices() const { return 1; }
+   int getVertex(int vertex) const {return _v; }
+   int getSortedVertex(int vertex) const {return _v; }
+   bool hasVertex(int vertex) const {return (_v == vertex); }
    
-   virtual std::vector<int> getVertexVector() const { return std::vector<int>(1,_v); }
-
-   virtual inline double x() const { return _x; }
-   virtual inline double y() const { return _y; }
-   virtual inline double z() const { return _z; }
+   std::vector<int> getVertexVector() const { return std::vector<int>(1,_v); }
+   std::vector<int> getSortedVertexVector() const { return std::vector<int>(1,_v); }
    
-   virtual void printCell()const { printf("Vertices: %d\n", _v); }
+   inline double x() const { return _x; }
+   inline double y() const { return _y; }
+   inline double z() const { return _z; }
+   
+   void printCell() const { printf("Vertices: %d, in subdomain: %d \n", _v, _inSubdomain); }
    
 };
 
@@ -203,12 +239,16 @@ class OneSimplex : public Simplex
    // numbers of the vertices of this simplex
    // same as the corresponding vertices in the finite element mesh
    int _v[2];
+   int _vs[2];
   public:
    
-   OneSimplex(std::vector<int> vertices, bool subdomain=false, bool boundary=false) : Simplex(){
-     sort(vertices.begin(), vertices.end());
+   OneSimplex(std::vector<int> vertices, int tag=0, bool subdomain=false, bool boundary=false) : Simplex(){
      _v[0] = vertices.at(0);
      _v[1] = vertices.at(1);
+     sort(vertices.begin(), vertices.end());
+     _vs[0] = vertices.at(0);
+     _vs[1] = vertices.at(1);
+     _tag = tag;
      _dim = 1;
      _bdMaxSize = 2;
      _cbdMaxSize = 1000;
@@ -222,8 +262,8 @@ class OneSimplex : public Simplex
    // used to find another definite one simplex from the cell complex
    // first vertex gives the lower bound from where to look
    OneSimplex(int vertex, int dummy){
-     _v[0] = vertex;
-     _v[1] = dummy;
+     _vs[0] = vertex;
+     _vs[1] = dummy;
    }
    
    ~OneSimplex(){}
@@ -232,18 +272,23 @@ class OneSimplex : public Simplex
    int getNumVertices() const { return 2; }
    int getNumFacets() const {  return 2; }
    int getVertex(int vertex) const {return _v[vertex]; }
+   int getSortedVertex(int vertex) const {return _vs[vertex]; }
    bool hasVertex(int vertex) const {return (_v[0] == vertex || _v[1] == vertex); }
    
    std::vector<int> getVertexVector() const { 
      return std::vector<int>(_v, _v + sizeof(_v)/sizeof(int) ); }
+   std::vector<int> getSortedVertexVector() const {
+     return std::vector<int>(_vs, _vs + sizeof(_vs)/sizeof(int) ); 
+   }
    
    void getFacetVertices(const int num, std::vector<int> &v) const {
      v.resize(1);
      v[0] = _v[num];
    }
    
+   //int kappa(Cell* tau) const;
    
-   void printCell() const { printf("Vertices: %d %d\n", _v[0], _v[1]); }
+   void printCell() const { printf("Vertices: %d %d, in subdomain: %d \n", _v[0], _v[1], _inSubdomain); }
 };
 
 // Two simplex cell type.
@@ -253,6 +298,7 @@ class TwoSimplex : public Simplex
    // numbers of the vertices of this simplex
    // same as the corresponding vertices in the finite element mesh
    int _v[3];
+   int _vs[3];
    
    int edges_tri(const int edge, const int vert) const{
      static const int e[3][2] = {
@@ -265,11 +311,15 @@ class TwoSimplex : public Simplex
    
   public:
    
-   TwoSimplex(std::vector<int> vertices, bool subdomain=false, bool boundary=false) : Simplex(){
-     sort(vertices.begin(), vertices.end());
+   TwoSimplex(std::vector<int> vertices, int tag=0, bool subdomain=false, bool boundary=false) : Simplex(){
      _v[0] = vertices.at(0);
      _v[1] = vertices.at(1);
      _v[2] = vertices.at(2);
+     sort(vertices.begin(), vertices.end());
+     _vs[0] = vertices.at(0);
+     _vs[1] = vertices.at(1);
+     _vs[2] = vertices.at(2);
+     _tag = tag;
      _dim = 2;
      _bdMaxSize = 3;
      _cbdMaxSize = 2;
@@ -289,10 +339,14 @@ class TwoSimplex : public Simplex
    int getNumVertices() const { return 3; }
    int getNumFacets() const { return 3; }
    int getVertex(int vertex) const {return _v[vertex]; }
+   int getSortedVertex(int vertex) const {return _vs[vertex]; }
    bool hasVertex(int vertex) const {return 
        (_v[0] == vertex || _v[1] == vertex || _v[2] == vertex); }
    std::vector<int> getVertexVector() const { 
      return std::vector<int>(_v, _v + sizeof(_v)/sizeof(int) ); }
+   std::vector<int> getSortedVertexVector() const {
+     return std::vector<int>(_vs, _vs + sizeof(_vs)/sizeof(int) ); 
+   }
    
    void getFacetVertices(const int num, std::vector<int> &v) const {
      v.resize(2);
@@ -300,7 +354,7 @@ class TwoSimplex : public Simplex
      v[1] = _v[edges_tri(num, 1)];
    }
    
-   void printCell() const { printf("Vertices: %d %d %d\n", _v[0], _v[1], _v[2]); }
+   void printCell() const { printf("Vertices: %d %d %d, in subdomain: %d\n", _v[0], _v[1], _v[2], _inSubdomain); }
 };
 
 // Three simplex cell type.
@@ -310,6 +364,7 @@ class ThreeSimplex : public Simplex
    // numbers of the vertices of this simplex
    // same as the corresponding vertices in the finite element mesh
    int _v[4];
+   int _vs[4];
    
    int faces_tetra(const int face, const int vert) const{
      static const int f[4][3] = {
@@ -323,12 +378,17 @@ class ThreeSimplex : public Simplex
    
   public:
    
-   ThreeSimplex(std::vector<int> vertices, bool subdomain=false, bool boundary=false) : Simplex(){
-     sort(vertices.begin(), vertices.end());
+   ThreeSimplex(std::vector<int> vertices, int tag=0, bool subdomain=false, bool boundary=false) : Simplex(){
      _v[0] = vertices.at(0);
      _v[1] = vertices.at(1);
      _v[2] = vertices.at(2);
      _v[3] = vertices.at(3);
+     sort(vertices.begin(), vertices.end());
+     _vs[0] = vertices.at(0);
+     _vs[1] = vertices.at(1);
+     _vs[2] = vertices.at(2);
+     _vs[3] = vertices.at(3);
+     _tag = tag;
      _dim = 3;
      _bdMaxSize = 4;
      _cbdMaxSize = 0;
@@ -349,10 +409,13 @@ class ThreeSimplex : public Simplex
    int getNumVertices() const { return 4; }
    int getNumFacets() const { return 4; }
    int getVertex(int vertex) const {return _v[vertex]; }
+   int getSortedVertex(int vertex) const {return _vs[vertex]; }
    bool hasVertex(int vertex) const {return 
        (_v[0] == vertex || _v[1] == vertex || _v[2] == vertex || _v[3] == vertex); }
    std::vector<int> getVertexVector() const { 
      return std::vector<int>(_v, _v + sizeof(_v)/sizeof(int) ); }
+   std::vector<int> getSortedVertexVector() const {
+     return std::vector<int>(_vs, _vs + sizeof(_vs)/sizeof(int) ); }
    
    void getFacetVertices(const int num, std::vector<int> &v) const {
      v.resize(3);
@@ -361,34 +424,107 @@ class ThreeSimplex : public Simplex
      v[2] = _v[faces_tetra(num, 2)];
    }
    
-   virtual void printCell() const { printf("Vertices: %d %d %d %d\n", _v[0], _v[1], _v[2], _v[3]); }
+   virtual void printCell() const { printf("Vertices: %d %d %d %d, in subdomain: %d \n", _v[0], _v[1], _v[2], _v[3], _inSubdomain); }
 };
 
+
+class Quadrangle : public Cell
+{
+ private:
+   
+   int _v[4];
+   int _vs[4];
+   
+   int edges_quad(const int edge, const int vert) const{
+     static const int e[4][2] = {
+       {0, 1},
+       {1, 2},
+       {2, 3},
+       {3, 0}
+     };
+     return e[edge][vert];
+   }
+   
+ public:
+   
+   Quadrangle(std::vector<int> vertices, int tag=0, bool subdomain=false, bool boundary=false) : Cell(){
+     _v[0] = vertices.at(0);
+     _v[1] = vertices.at(1);
+     _v[2] = vertices.at(2);
+     _v[3] = vertices.at(3);
+     sort(vertices.begin(), vertices.end());
+     _vs[0] = vertices.at(0);
+     _vs[1] = vertices.at(1);
+     _vs[2] = vertices.at(2);
+     _vs[3] = vertices.at(3);
+     _tag = tag;
+     _dim = 2;
+     _bdMaxSize = 4;
+     _cbdMaxSize = 2;
+     _inSubdomain = subdomain;
+     _onDomainBoundary = boundary;
+   }
+   ~Quadrangle(){}
+   
+   int getDim() const { return 2; }
+   int getNumVertices() const { return 4; }
+   int getNumFacets() const { return 4; }
+   int getVertex(int vertex) const {return _v[vertex]; }
+   int getSortedVertex(int vertex) const { return _vs[vertex]; }
+   int kappa(Cell* tau) const;
+   
+   bool hasVertex(int vertex) const {return
+       (_v[0] == vertex || _v[1] == vertex || _v[2] == vertex || _v[3] == vertex); }
+   std::vector<int> getVertexVector() const {
+     return std::vector<int>(_v, _v + sizeof(_v)/sizeof(int) ); }
+   std::vector<int> getSortedVertexVector() const {
+     return std::vector<int>(_vs, _vs + sizeof(_vs)/sizeof(int) ); }
+   
+   void getFacetVertices(const int num, std::vector<int> &v) const {
+     v.resize(2);
+     v[0] = _v[edges_quad(num, 0)];
+     v[1] = _v[edges_quad(num, 1)];
+   }
+   
+};
+
+
 // Ordering for the cells.
 class Less_Cell{
   public:
    bool operator()(const Cell* c1, const Cell* c2) const {
      
-     // subcomplex cells in the end
-     //if(c1->inSubdomain() != c2->inSubdomain()){
-     //  if(c1->inSubdomain()) return false;
-     //  else return true;
-     //}
-      
      // cells with fever vertices first
+     
      if(c1->getNumVertices() != c2->getNumVertices()){
        return (c1->getNumVertices() < c2->getNumVertices());
      }
-          
+     
+     
+     
      // "natural number" -like ordering (the number of a vertice corresponds a digit)
+     
      for(int i=0; i < c1->getNumVertices();i++){
-       if(c1->getVertex(i) < c2->getVertex(i)) return true;
-       else if (c1->getVertex(i) > c2->getVertex(i)) return false;
+       if(c1->getSortedVertex(i) < c2->getSortedVertex(i)) return true;
+       else if (c1->getSortedVertex(i) > c2->getSortedVertex(i)) return false;
+     }
+     
+     /*
+     std::vector<int> c1v = c1->getVertexVector();
+     std::vector<int> c2v = c2->getVertexVector();
+     std::sort(c1v.begin(), c1v.end());
+     std::sort(c2v.begin(), c2v.end());
+     
+     for(int i=0; i < c1v.size();i++){
+       if(c1v.at(i) < c2v.at(i)) return true;
+       else if (c1v.at(i) > c2v.at(i)) return false;
      }
+     */
      return false;
    }
 };
 
+
 class Equal_Cell{
   public:
    bool operator ()(const Cell* c1, const Cell* c2){
@@ -396,7 +532,7 @@ class Equal_Cell{
        return false;
      }
      for(int i=0; i < c1->getNumVertices();i++){
-       if(c1->getVertex(i) != c2->getVertex(i)){
+       if(c1->getSortedVertex(i) != c2->getSortedVertex(i)){
          return false;
        }
      }
@@ -413,6 +549,104 @@ class Less_MVertex{
    }
 };
 
+class CombinedCell : public Cell{
+ 
+  private:
+   std::vector<int> _v;
+   std::vector<int> _vs;
+   std::list< std::pair<int, Cell*> > _cells;
+   
+  public:
+   
+   CombinedCell(Cell* c1, Cell* c2, bool orMatch, bool co=false) : Cell(){
+     _tag = c1->getTag();
+     _dim = c1->getDim();
+     _bdMaxSize = 1000000;
+     _cbdMaxSize = 1000000;
+     _inSubdomain = c1->inSubdomain();
+     _onDomainBoundary = c1->onDomainBoundary();
+     _combined = true;
+     
+     _v = c1->getVertexVector();
+     for(int i = 0; i < c2->getNumVertices(); i++){
+       if(!this->hasVertex(c2->getVertex(i))) _v.push_back(c2->getVertex(i));
+     }
+     
+     _vs = _v;
+     std::sort(_vs.begin(), _vs.end());
+     
+     _cells = c1->getCells();
+     std::list< std::pair<int, Cell*> > c2Cells = c2->getCells();
+     for(std::list< std::pair<int, Cell*> >::iterator it = c2Cells.begin(); it != c2Cells.end(); it++){
+       if(!orMatch) (*it).first = -1*(*it).first;
+       _cells.push_back(*it);
+     }
+     
+     _boundary = c1->getOrientedBoundary();
+     std::list< std::pair<int, Cell*> > c2Boundary = c2->getOrientedBoundary();
+     for(std::list< std::pair<int, Cell*> >::iterator it = c2Boundary.begin(); it != c2Boundary.end(); it++){
+       if(!orMatch) (*it).first = -1*(*it).first;
+       Cell* cell = (*it).second;
+       if(co){
+         bool old = false;
+         for(std::list< std::pair<int, Cell* > >::iterator it2 = _boundary.begin(); it2 != _boundary.end(); it2++){
+           Cell* cell2 = (*it2).second;
+           if(*cell2 == *cell) old = true;
+         }
+         if(!old) _boundary.push_back(*it);
+       }
+       else _boundary.push_back(*it);
+     }
+     
+     _coboundary = c1->getOrientedCoboundary();
+     std::list< std::pair<int, Cell*> > c2Coboundary = c2->getOrientedCoboundary();
+     for(std::list< std::pair<int, Cell* > >::iterator it = c2Coboundary.begin(); it != c2Coboundary.end(); it++){
+       if(!orMatch) (*it).first = -1*(*it).first;
+       Cell* cell = (*it).second;
+       if(!co){
+         bool old = false;
+         for(std::list< std::pair<int, Cell* > >::iterator it2 = _coboundary.begin(); it2 != _coboundary.end(); it2++){
+           Cell* cell2 = (*it2).second;
+           if(*cell2 == *cell) old = true;
+         }
+         if(!old) _coboundary.push_back(*it);
+       }
+       else _coboundary.push_back(*it);
+     }
+     
+   }
+  
+   ~CombinedCell(){} 
+   
+   int getNumVertices() const { return _v.size(); } 
+   int getVertex(int vertex) const { return _v.at(vertex); }
+   int getSortedVertex(int vertex) const { return _vs.at(vertex); }
+   std::vector<int> getVertexVector() const { return _v; }
+   
+   int kappa(Cell* tau) const { return 0; }
+   
+   // true if this cell has given vertex
+   bool hasVertex(int vertex) const {
+     for(int i = 0; i < _v.size(); i++){
+       if(_v.at(i) == vertex) return true;
+     }
+     return false;
+   }
+   
+   virtual void printCell() const {
+     printf("Vertices: ");
+     for(int i = 0; i < this->getNumVertices(); i++){
+       printf("%d ", this->getVertex(i));
+     }
+     printf(", in subdomain: %d\n", _inSubdomain);
+   }
+   
+   std::list< std::pair<int, Cell*> > getCells() { return _cells; }
+   int getNumCells() {return _cells.size();}
+      
+   
+};
+
 // A class representing a cell complex made out of a finite element mesh.
 class CellComplex
 {
@@ -434,8 +668,6 @@ class CellComplex
    
    std::set<Cell*, Less_Cell>  _originalCells[4];
    
-   bool _simplicial;
-   
   public:
    // iterator for the cells of same dimension
    typedef std::set<Cell*, Less_Cell>::iterator citer;
@@ -444,16 +676,12 @@ class CellComplex
    // enqueue cells in queue if they are not there already
    virtual void enqueueCells(std::list<Cell*>& cells, 
                              std::queue<Cell*>& Q, std::set<Cell*, Less_Cell>& Qset);
-   virtual void enqueueCells(std::list<Cell*>& cells, std::list<Cell*>& Q);
-   virtual void enqueueCellsIt(std::vector< std::set<Cell*, Less_Cell>::iterator >& cells,
-                               std::queue<Cell*>& Q, std::set<Cell*, Less_Cell>& Qset);
-     
    // remove cell from the queue set
    virtual void removeCellQset(Cell*& cell, std::set<Cell*, Less_Cell>& Qset);
       
    // insert cells into this cell complex
+   //virtual void insert_cells(bool subdomain, bool boundary);
    virtual void insert_cells(bool subdomain, bool boundary);
-   virtual void insert_cells2(bool subdomain, bool boundary);
    
   public: 
    CellComplex(  std::vector<GEntity*> domain, std::vector<GEntity*> subdomain, std::set<Cell*, Less_Cell> cells ) {
@@ -467,16 +695,12 @@ class CellComplex
    CellComplex( std::vector<GEntity*> domain, std::vector<GEntity*> subdomain );
    virtual ~CellComplex(){}
    
-   virtual bool simplicial() {  return _simplicial; }
    
    // get the number of certain dimensional cells
    virtual int getSize(int dim){ return _cells[dim].size(); }
    
    virtual std::set<Cell*, Less_Cell> getCells(int dim){ return _cells[dim]; }
-   
-   // get all the finite element mesh vertices in the domain of this cell complex
-   virtual void getDomainVertices(std::set<MVertex*, Less_MVertex>& domainVertices, bool subdomain);
-   
+      
    // iterators to the first and last cells of certain dimension
    virtual citer firstCell(int dim) {return _cells[dim].begin(); }
    virtual citer lastCell(int dim) {return _cells[dim].end(); }
@@ -489,16 +713,10 @@ class CellComplex
    // implementation will vary depending on cell type
    virtual inline int kappa(Cell* sigma, Cell* tau) const { return sigma->kappa(tau); }
    
-   // cells on the boundary of a cell
-   virtual std::vector<Cell*> bd(Cell* sigma);
-   virtual std::vector< std::set<Cell*, Less_Cell>::iterator > bdIt(Cell* sigma);
-   // cells on the coboundary of a cell
-   virtual std::vector<Cell*> cbd(Cell* tau);
-   virtual std::vector< std::set<Cell*, Less_Cell>::iterator > cbdIt(Cell* tau);
-   
    // remove a cell from this cell complex
    virtual void removeCell(Cell* cell);
-   virtual void removeCellIt(std::set<Cell*, Less_Cell>::iterator cell);
+   virtual void replaceCells(Cell* c1, Cell* c2, Cell* newCell, bool orMatch, bool co=false);
+   
    
    virtual void insertCell(Cell* cell);
    
@@ -509,54 +727,35 @@ class CellComplex
    // coreduction of this cell complex
    // removes corection pairs of cells of dimension dim and dim+1
    virtual int coreduction(int dim);
-   virtual int coreduction2(int dim);
+   
    // stores removed cells
-   virtual int coreduction(int dim, std::set<Cell*, Less_Cell>& removedCells);
+   
    // reduction of this cell complex
    // removes reduction pairs of cell of dimension dim and dim-1
    virtual int reduction(int dim);
-   virtual int reduction2(int dim);
    
    // useful functions for (co)reduction of cell complex
    virtual void reduceComplex();
    // coreduction up to generators of dimension generatorDim
    virtual void coreduceComplex(int generatorDim=3);
    
-   // stores cells removed after removal of generatos of dimension generatorDim
-   virtual void coreduceComplex(int generatorDim, std::set<Cell*, Less_Cell>& removedCells);
-  
-   
    // queued coreduction presented in Mrozek's paper
    // slower, but produces cleaner result
    virtual int coreductionMrozek(Cell* generator);
-   virtual int coreductionMrozek2(Cell* generator);
-   virtual int coreductionMrozek3(Cell* generator);
-   
-   // never use, O(n^2) complexity 
-   virtual void restoreComplex(){ 
-     for(int i = 0; i < 4; i++) _cells[i] = _originalCells[i];
-     
-     for(int i = 0; i < 4; i++){
-       for(citer cit = firstCell(i); cit != lastCell(i); cit++){
-         Cell* cell = *cit;
-         cell->setBoundary(bd(cell));
-         cell->setCoboundary(cbd(cell));
-       }
-     }
-     
-   }
-   
+      
    // add every volume, face and edge its missing boundary cells
    virtual void repairComplex(int i=3);
    // change non-subdomain cells to be in subdomain, subdomain cells to not to be in subdomain
    virtual void swapSubdomain();
    
    // print the vertices of cells of certain dimension
-   virtual void printComplex(int dim, bool subcomplex);
+   virtual void printComplex(int dim);
    
    // write this cell complex in 2.0 MSH ASCII format
    virtual int writeComplexMSH(const std::string &name); 
    
+   virtual int combine(int dim);
+   virtual int cocombine(int dim);
    
 };
 
diff --git a/Geo/ChainComplex.cpp b/Geo/ChainComplex.cpp
index c0eae87ce5..88d02b75d2 100644
--- a/Geo/ChainComplex.cpp
+++ b/Geo/ChainComplex.cpp
@@ -24,15 +24,26 @@ ChainComplex::ChainComplex(CellComplex* cellComplex){
     unsigned int rows =  cellComplex->getSize(dim-1);
   
     
-    
+    int index = 1;
     // ignore subdomain cells
     for(std::set<Cell*, Less_Cell>::iterator cit = cellComplex->firstCell(dim); cit != cellComplex->lastCell(dim); cit++){
       Cell* cell = *cit;
-      if(cell->inSubdomain()) cols--;
+      cell->setIndex(index);
+      index++;
+      if(cell->inSubdomain()){
+        index--;
+        cols--;
+      }
     }
+    index = 1;
     for(std::set<Cell*, Less_Cell>::iterator cit = cellComplex->firstCell(dim-1); cit != cellComplex->lastCell(dim-1); cit++){
       Cell* cell = *cit;
-      if(cell->inSubdomain()) rows--;
+      cell->setIndex(index);
+      index++;
+      if(cell->inSubdomain()){
+        index--;
+        rows--;
+      }
     }
     
     
@@ -45,7 +56,34 @@ ChainComplex::ChainComplex(CellComplex* cellComplex){
       //_HMatrix[dim] = NULL;
     }
     
+    else{
+     
+      mpz_t elem;
+      mpz_init(elem);
+      
+      _HMatrix[dim] = create_gmp_matrix_zero(rows, cols);
+      for( std::set<Cell*, Less_Cell>::iterator cit = cellComplex->firstCell(dim); cit != cellComplex->lastCell(dim); cit++){
+        Cell* cell = *cit;
+        if(!cell->inSubdomain()){
+          std::list< std::pair<int,Cell*> >bdCell = cell->getOrientedBoundary();
+          for(std::list< std::pair<int, Cell*> >::iterator it = bdCell.begin(); it != bdCell.end(); it++){
+            Cell* bdCell = (*it).second;
+            if(!bdCell->inSubdomain()){
+              int old_elem = 0;
+              gmp_matrix_get_elem(elem, bdCell->getIndex(), cell->getIndex(), _HMatrix[dim]);
+              old_elem = mpz_get_si(elem);
+              mpz_set_si(elem, old_elem + (*it).first);
+              gmp_matrix_set_elem(elem, bdCell->getIndex(), cell->getIndex(), _HMatrix[dim]);
+            }
+          }
+        }
+      }
+      
+      mpz_clear(elem);
+      
+    }
     
+    /*
     else{
       
       long int elems[rows*cols];
@@ -59,6 +97,16 @@ ChainComplex::ChainComplex(CellComplex* cellComplex){
           Cell* lowcell = *low;
           Cell* highcell = *high;
           if(!(highcell->inSubdomain() || lowcell->inSubdomain())){
+            
+            
+            std::list< std::pair<int, Cell*> >bdHigh = highcell->getBoundary();
+            for(std::list< std::pair<int, Cell*> >::iterator it = bdHigh.begin(); it != bdHigh.end(); it++){
+              Cell* bdCell = (*it).second;
+              if(bdCell->getTag() == lowcell->getTag()) elems[i] = (*it).first;
+              else elems[i] = 0;
+            }
+            
+              
             elems[i] = cellComplex->kappa(*high, *low);
             i++;
           }
@@ -69,7 +117,9 @@ ChainComplex::ChainComplex(CellComplex* cellComplex){
       }
       _HMatrix[dim] = create_gmp_matrix_int(rows, cols, elems);      
     }
-    
+    */
+
+
     _kerH[dim] = NULL;
     _codH[dim] = NULL;
     _JMatrix[dim] = NULL;
@@ -220,7 +270,7 @@ void ChainComplex::Quotient(int dim){
   
   mpz_t elem;
   mpz_init(elem);
-  
+
   for(int i = 1; i <= cols; i++){
     gmp_matrix_get_elem(elem, i, i, normalForm->canonical);
     if(mpz_cmp_si(elem,0) == 0){
@@ -414,13 +464,17 @@ int Chain::writeChainMSH(const std::string &name){
   fprintf(fp, "4 \n");
   fprintf(fp, "0 \n");
   fprintf(fp, "1 \n");
-  fprintf(fp, "%d \n", getSize());
+  fprintf(fp, "%d \n", getNumCells());
   fprintf(fp, "0 \n");
   
+  std::list< std::pair<int, Cell*> > cells;
   for(int i = 0; i < getSize(); i++){
-    
-    fprintf(fp, "%d %d \n", getCell(i)->getTag(), getCoeff(i));
-    
+    Cell* cell = getCell(i);
+    cells = cell->getCells();
+    for(std::list< std::pair<int, Cell*> >::iterator it = cells.begin(); it != cells.end(); it++){
+      Cell* cell2 = (*it).second;
+      fprintf(fp, "%d %d \n", cell2->getTag(), getCoeff(i)*(*it).first );
+    }
   }
   
   fprintf(fp, "$EndElementData\n");
diff --git a/Geo/ChainComplex.h b/Geo/ChainComplex.h
index 0ae7756866..adc5450660 100644
--- a/Geo/ChainComplex.h
+++ b/Geo/ChainComplex.h
@@ -142,6 +142,16 @@ class Chain{
    // number of cells in this chain 
    virtual int getSize() { return _cells.size(); }
    
+   virtual int getNumCells() {
+     int count = 0;
+     for(std::vector< std::pair <Cell*, int> >::iterator it = _cells.begin(); it != _cells.end(); it++){
+       Cell* cell = (*it).first;
+       count = count + cell->getNumCells();
+     }
+     return count;
+   }
+   
+   
    // get/set chain name
    virtual std::string getName() { return _name; }
    virtual void setName(std::string name) { _name=name; }
diff --git a/utils/misc/celldriver.cpp b/utils/misc/celldriver.cpp
index 14040cae5b..5bc4920a9a 100755
--- a/utils/misc/celldriver.cpp
+++ b/utils/misc/celldriver.cpp
@@ -68,6 +68,11 @@ int main(int argc, char **argv)
   // reduce the complex in order to ease homology computation
   complex->reduceComplex();
   
+  // perform series of cell combinatios in order to further ease homology computation
+  complex->combine(3);
+  complex->combine(2);
+  complex->combine(1);
+  
   // create a chain complex of a cell complex (construct boundary operator matrices)
   ChainComplex* chains = new ChainComplex(complex);
   // compute the homology using the boundary operator matrices
@@ -101,6 +106,10 @@ int main(int argc, char **argv)
   // reduce the complex by coreduction, this removes all vertices, hence 0 as an argument 
   complex2->coreduceComplex(0);
   
+  // perform series of "dual complex" cell combinations in order to ease homology computation
+  complex2->cocombine(1);
+  complex2->cocombine(2);
+  
   // create a chain complex of a cell complex (construct boundary operator matrices)
   ChainComplex* dualChains = new ChainComplex(complex2);
   
-- 
GitLab