diff --git a/Geo/Cell.h b/Geo/Cell.h
index 94e771b480d8d459af4b8c5dcc3457698c5c1642..fe02f850c076b178404f4e8779e2915f7595df5b 100644
--- a/Geo/Cell.h
+++ b/Geo/Cell.h
@@ -16,10 +16,12 @@
 #include <string>
 #include <algorithm>
 #include <set>
+#include <list>
+#include <map>
 #include <queue>
 #include "CellComplex.h"
 #include "MElement.h"
-#include "GModel.h"
+//#include "GModel.h"
 
 class Cell;
 
diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp
index d6e0918e503a0b9318b62d7be05fd04e60b19ee4..7d99b7f51b9c5173f60c1bb4e8c0fbd890910fbb 100644
--- a/Geo/CellComplex.cpp
+++ b/Geo/CellComplex.cpp
@@ -6,13 +6,9 @@
 // Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
 
 #include "CellComplex.h"
-#include "OS.h"
-#include "Context.h"
 
 #if defined(HAVE_KBIPACK)
 
-
-
 CellComplex::CellComplex( std::vector<GEntity*> domain, 
 			  std::vector<GEntity*> subdomain)
 {
@@ -140,13 +136,6 @@ void CellComplex::insert_cells(std::vector<GEntity*>& domain,
       int dim = element->getDim();
       int type = element->getTypeForMSH();
       
-      if(CTX::instance()->mesh.radiusSup){
-	double max = CTX::instance()->mesh.radiusSup;
-	double min = CTX::instance()->mesh.radiusInf;
-	double r = element->maxEdge();
-	if(r < min || r > max) continue;
-      }
-
       Cell* cell;
       // simplex types
       if(type == MSH_LIN_2 || type == MSH_TRI_3 || type == MSH_TET_4
@@ -204,6 +193,8 @@ void CellComplex::insert_cells(std::vector<GEntity*>& domain,
           else if(type == MSH_HEX_8) newtype = MSH_QUA_4;
           /*else if(type == MSH_HEX_20) newtype = MSH_QUA_8;
           else if(type == MSH_HEX_27) newtype = MSH_QUA_9;*/
+	  else if(type == MSH_PRI_6 && vertices.size() == 3) newtype = MSH_TRI_3;
+	  else if(type == MSH_PRI_6 && vertices.size() == 4) newtype = MSH_QUA_4;
         }
         else if(dim == 2){
            if(type == MSH_TRI_3 || type == MSH_QUA_4) newtype = MSH_LIN_2;
@@ -260,21 +251,6 @@ CellComplex::~CellComplex()
   _newcells.clear();
 }
 
-/*
-CellComplex::CellComplex(CellComplex* cellComplex)
-{
-  _domain = cellComplex->getDomain();
-  _subdomain = cellComplex->getSubdomain();
-  _boundary = cellComplex->getBoundary();
-
-  for(int i = 0; i < 4; i++){
-    _betti[i] = cellComplex->getBetti(i);
-    _ocells[i] = cellComplex->getOcells(i);
-  }
-  _dim = cellComplex->getDim();
-  restoreComplex();
-  }*/
-
 void CellComplex::insertCell(Cell* cell)
 {
   _newcells.push_back(cell);      
@@ -377,9 +353,7 @@ int CellComplex::reduction(int dim, int omitted)
     while(cit != lastCell(dim-1)){
       Cell* cell = *cit;
       if( cell->getCoboundarySize() == 1 
-	  && inSameDomain(cell, cell->firstCoboundary()->first)
-	  && !cell->getImmune() 
-	  && !cell->firstCoboundary()->first->getImmune()){
+	  && inSameDomain(cell, cell->firstCoboundary()->first)){
 	++cit;
 	if(dim == getDim() && omitted > 0){
 	  _store.at(omitted-1).insert(cell->firstCoboundary()->first);    
@@ -477,30 +451,6 @@ void CellComplex::removeSubdomain()
   }
   for(unsigned int i = 0; i < toRemove.size(); i++) removeCell(toRemove[i]);
 }
-/*
-void CellComplex::setSubdomain(std::vector<GEntity*>& subdomain){
-  for(int i = 3; i > -1; i--){
-    for(citer cit = firstCell(i); cit != lastCell(i); cit++){
-      Cell* cell = *cit;
-      for(unsigned int j = 0; j < subdomain.size(); j++){
-	if(cell->getGEntity()->tag() == subdomain.at(j)->tag()){
-	  cell->setInSubdomain(true);
-	}
-      }
-    }
-  }
-}*/
-
-void CellComplex::deImmuneCells(bool subdomain)
-{
-  for(int i = 0; i < 4; i++){
-    for(citer cit = firstCell(i); cit != lastCell(i); ++cit){
-      Cell *cell = *cit;
-      if(cell->getImmune() && subdomain) cell->setInSubdomain(true);
-      cell->setImmune(false);
-    }
-  }
-}
 
 int CellComplex::coreduceComplex()
 {
diff --git a/Geo/CellComplex.h b/Geo/CellComplex.h
index daef3684dcc7cc5077e57215de03666c5752b93d..8a77c8cc38622217ee1b35139cbd1ce0e0bf8a18 100644
--- a/Geo/CellComplex.h
+++ b/Geo/CellComplex.h
@@ -20,6 +20,8 @@
 #include "Cell.h"
 #include "MElement.h"
 #include "ChainComplex.h"
+#include "OS.h"
+#include "GModel.h"
 
 class Cell;
 
@@ -177,6 +179,7 @@ class CellComplex
   
   // store cells of dimension dim to the GModel as a 
   // physical group of MElements 
+  // for debugging purposes
   void storeCells(int dim);
 };
 
diff --git a/Geo/ChainComplex.cpp b/Geo/ChainComplex.cpp
index 6960108497b6d906e0fa980c4cb1821a622269fd..1dd04bb090ac6cf978e76af155d740b37c86fc5e 100644
--- a/Geo/ChainComplex.cpp
+++ b/Geo/ChainComplex.cpp
@@ -7,9 +7,6 @@
 // Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
 
 #include "ChainComplex.h"
-#include "OS.h"
-#include "PView.h"
-#include "Options.h"
 
 #if defined(HAVE_KBIPACK)
 
@@ -42,6 +39,7 @@ ChainComplex::ChainComplex(CellComplex* cellComplex, int domain)
         index--;
         cols--;
       }
+      else _cellIndices[dim].insert( std::make_pair(index, cell));
     }
     index = 1;
     if(dim > 0){
@@ -55,6 +53,7 @@ ChainComplex::ChainComplex(CellComplex* cellComplex, int domain)
           index--;
           rows--;
         }
+	else _cellIndices[dim-1].insert( std::make_pair(index, cell));
       }
     }
     
@@ -434,351 +433,39 @@ std::vector<int> ChainComplex::getCoeffVector(int dim, int chainNumber)
   return coeffVector;  
 }
 
-int ChainComplex::getTorsion(int dim, int chainNumber)
-{
-  if(dim < 0 || dim > 4) return 0;
-  if(_Hbasis[dim] == NULL 
-     || (int)gmp_matrix_cols(_Hbasis[dim]) < chainNumber) return 0;
-  if(_torsion[dim].empty() 
-     || (int)_torsion[dim].size() < chainNumber) return 1;
-  else return _torsion[dim].at(chainNumber-1);
-}
-
-Chain::Chain(std::set<Cell*, Less_Cell> cells, std::vector<int> coeffs, 
-	     CellComplex* cellComplex, GModel* model,
-	     std::string name, int torsion)
-{  
-  int i = 0;
-  for(std::set<Cell*, Less_Cell>::iterator cit = cells.begin();
-      cit != cells.end(); cit++){
-    Cell* cell = *cit;
-    _dim = cell->getDim();
-    if((int)coeffs.size() > i){
-      if(coeffs.at(i) != 0){
-        std::list< std::pair<int, Cell*> > subCells;
-	cell->getCells(subCells);
-        for(std::list< std::pair<int, Cell*> >::iterator it = 
-	      subCells.begin(); it != subCells.end(); it++){
-          Cell* subCell = (*it).second;
-          int coeff = (*it).first;
-          _cells.insert( std::make_pair(subCell, coeffs.at(i)*coeff));
-	  subCell->setDeleteWithCellComplex(false);
-        }
-      }
-      i++;
-    }
-    
-  }
-  _name = name;
-  _cellComplex = cellComplex;
-  _torsion = torsion;
-  _model = model;
-  
-}
-
-bool Chain::deform(std::map<Cell*, int, Less_Cell>& cellsInChain, 
-		   std::map<Cell*, int, Less_Cell>& cellsNotInChain)
-{
-  std::vector<int> cc;
-  std::vector<int> bc;
-  
-  for(citer cit = cellsInChain.begin(); cit != cellsInChain.end(); cit++){
-    Cell* c = (*cit).first;
-    c->setImmune(false);
-    if(!c->inSubdomain()) {
-      cc.push_back(getCoeff(c));
-      bc.push_back((*cit).second);
-    }
-  }
-  
-  if(cc.empty() || (getDim() == 2 && cc.size() < 2) ) return false;
-  int inout = cc[0]*bc[0];
-  for(unsigned int i = 0; i < cc.size(); i++){
-    if(cc[i]*bc[i] != inout) return false;  
-  }
-  
-  for(citer cit = cellsInChain.begin(); cit != cellsInChain.end(); cit++){
-    removeCell((*cit).first);
-  }
-  
-  int n = 1;
-  for(citer cit = cellsNotInChain.begin(); cit != cellsNotInChain.end();
-      cit++){
-    Cell* c = (*cit).first;
-    if(n == 2) c->setImmune(true);
-    else c->setImmune(false);
-    int coeff = -1*inout*(*cit).second;
-    addCell(c, coeff);
-    n++;
-  }
-  
-  return true;
-}
-
-bool Chain::deformChain(std::pair<Cell*, int> cell, bool bend)
-{  
-  Cell* c1 = cell.first;
-  for(citer cit = c1->firstCoboundary(true); cit != c1->lastCoboundary(true);
-      cit++){
-    
-    std::map<Cell*, int, Less_Cell> cellsInChain;
-    std::map<Cell*, int, Less_Cell> cellsNotInChain;
-    Cell* c1CbdCell = (*cit).first;
-
-    for(citer cit2 = c1CbdCell->firstBoundary(true);
-	cit2 != c1CbdCell->lastBoundary(true); cit2++){
-      Cell* c1CbdBdCell = (*cit2).first;
-      int coeff = (*cit2).second;
-      if( (hasCell(c1CbdBdCell) && getCoeff(c1CbdBdCell) != 0) 
-	  || c1CbdBdCell->inSubdomain()){
-	cellsInChain.insert(std::make_pair(c1CbdBdCell, coeff));
-      }
-      else cellsNotInChain.insert(std::make_pair(c1CbdBdCell, coeff));
-    }
-    
-    bool next = false;
-    
-    for(citer cit2 = cellsInChain.begin(); cit2 != cellsInChain.end(); cit2++){
-      Cell* c = (*cit2).first;
-      int coeff = getCoeff(c);
-      if(c->getImmune()) next = true;
-      if(c->inSubdomain()) bend = false;
-      if(coeff > 1 || coeff < -1) next = true; 
-    }
-    
-    for(citer cit2 = cellsNotInChain.begin(); cit2 != cellsNotInChain.end();
-	cit2++){
-      Cell* c = (*cit2).first;
-      if(c->inSubdomain()) next = true;
-    }    
-    if(next) continue;
-    
-    if( (getDim() == 1 && cellsInChain.size() == 2 
-	 && cellsNotInChain.size() == 1) || 
-	(getDim() == 2 && cellsInChain.size() == 3 
-	 && cellsNotInChain.size() == 1)){
-      //printf("straighten \n");
-      return deform(cellsInChain, cellsNotInChain);
-    }
-    else if ( (getDim() == 1 && cellsInChain.size() == 1 
-	       && cellsNotInChain.size() == 2 && bend) ||
-              (getDim() == 2 && cellsInChain.size() == 2 
-	       && cellsNotInChain.size() == 2 && bend)){
-      //printf("bend \n");
-      return deform(cellsInChain, cellsNotInChain);
-    }
-    else if ((getDim() == 1 && cellsInChain.size() == 3 
-	      && cellsNotInChain.size() == 0) ||
-             (getDim() == 2 && cellsInChain.size() == 4 
-	      && cellsNotInChain.size() == 0)){
-      //printf("remove boundary \n");
-      return deform(cellsInChain, cellsNotInChain);
-    }
-  }
-  
-  return false;
-}
-
-void Chain::smoothenChain()
+void ChainComplex::getChain(std::map<Cell*, int, Less_Cell>& chain, int dim, int chainNumber)
 {
-  if(!_cellComplex->simplicial()) return;
-  
-  int start = getSize();
-  double t1 = Cpu();
-  
-  int useless = 0;
-  for(int i = 0; i < 20; i++){
-    int size = getSize();
-    for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
-      //if(!deformChain(*cit, false) && getDim() == 2) deformChain(*cit, true);
-      if(getDim() == 2) deformChain(*cit, true);
-      deformChain(*cit, false);      
-    }
-    deImmuneCells();
-    eraseNullCells();
-    if (size >= getSize()) useless++;
-    else useless = 0;
-    if (useless > 5) break;
-  }
-  
-  deImmuneCells();
-  for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
-    deformChain(*cit, false);
-  }
-  
-  eraseNullCells();
-  double t2 = Cpu();
-  Msg::Debug("Smoothened a %d-chain from %d cells to %d cells (%g s).\n",
-	     getDim(), start, getSize(), t2-t1);
-  return;
-}
-
-
-int Chain::writeChainMSH(const std::string &name)
-{  
-  if(getSize() == 0) return 1;
-  
-  FILE *fp = fopen(name.c_str(), "a");
-  if(!fp){
-    Msg::Error("Unable to open file '%s'", name.c_str());
-    Msg::Debug("Unable to open file.");
-      return 0;
-  }
- 
-  fprintf(fp, "\n$ElementData\n");
-  
-  fprintf(fp, "1 \n");
-  fprintf(fp, "\"%s\" \n", getName().c_str());
-  fprintf(fp, "1 \n");
-  fprintf(fp, "0.0 \n");
-  fprintf(fp, "4 \n");
-  fprintf(fp, "0 \n");
-  fprintf(fp, "1 \n");
-  fprintf(fp, "%d \n", getSize());
-  fprintf(fp, "0 \n");
-  
-  for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
-    Cell* cell = (*cit).first;
-    int coeff = (*cit).second;
-    fprintf(fp, "%d %d \n", cell->getNum(), coeff );
-  }
-  
-  fprintf(fp, "$EndElementData\n");
-  fclose(fp);
-  
-  return 1;
-}
-
-int Chain::createPGroup()
-{  
-  std::vector<MElement*> elements;
-  std::map<int, std::vector<double> > data;
-  MElementFactory factory;
-
-  for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
-    Cell* cell = (*cit).first;
-    int coeff = (*cit).second;
-
-    MElement* e = cell->getImageMElement();
-    std::vector<MVertex*> v;
-    for(int i = 0; i < e->getNumVertices(); i++){
-      v.push_back(e->getVertex(i));
-    }
-    MElement* ne = factory.create(e->getTypeForMSH(), v, 0, e->getPartition());
-    
-    if(cell->getDim() > 0 && coeff < 0) ne->revert(); // flip orientation
-    for(int i = 0; i < abs(coeff); i++) elements.push_back(ne);    
-
-    std::vector<double> coeffs (1,abs(coeff));
-    data[ne->getNum()] = coeffs;
-  }
-  
-  int max[4];
-  for(int i = 0; i < 4; i++) max[i] = _model->getMaxElementaryNumber(i);
-  int entityNum = *std::max_element(max,max+4) + 1;
-  for(int i = 0; i < 4; i++) max[i] = _model->getMaxPhysicalNumber(i);
-  int physicalNum = *std::max_element(max,max+4) + 1;
-  setNum(physicalNum);
-  
-  std::map<int, std::vector<MElement*> > entityMap;
-  entityMap[entityNum] = elements;
-  std::map<int, std::map<int, std::string> > physicalMap;
-  std::map<int, std::string> physicalInfo;
-  physicalInfo[physicalNum]=getName();
-  physicalMap[entityNum] = physicalInfo;
-  
-  // hide mesh
-  opt_mesh_points(0, GMSH_SET, 0);
-  opt_mesh_lines(0, GMSH_SET, 0);
-  opt_mesh_triangles(0, GMSH_SET, 0);
-  opt_mesh_quadrangles(0, GMSH_SET, 0);
-  opt_mesh_tetrahedra(0, GMSH_SET, 0);
-  opt_mesh_hexahedra(0, GMSH_SET, 0);
-  opt_mesh_prisms(0, GMSH_SET, 0);
-  opt_mesh_pyramids(0, GMSH_SET, 0);
-
-  // show post-processing normals, tangents and element boundaries
-  //opt_view_normals(0, GMSH_SET, 20);
-  //opt_view_tangents(0, GMSH_SET, 20);
-  opt_view_show_element(0, GMSH_SET, 1);
-  
-  if(!data.empty()){
-    _model->storeChain(getDim(), entityMap, physicalMap);
-    _model->setPhysicalName(getName(), getDim(), physicalNum);
-    
-    // create PView for visualization
-    PView* chain = new PView(getName(), "ElementData", getGModel(), 
-			     data, 0, 1);
-  }
-   
-  return physicalNum;
-}
+  chain.clear();
+  if(dim < 0 || dim > 4) return;
+  if(_Hbasis[dim] == NULL
+     || (int)gmp_matrix_cols(_Hbasis[dim]) < chainNumber) return;
 
+  int rows = gmp_matrix_rows(_Hbasis[dim]);
 
-void Chain::removeCell(Cell* cell) 
-{
-  citer it = _cells.find(cell);
-  if(it != _cells.end()){
-    (*it).second = 0;
-  }
-  return;
-}
+  int elemi;
+  long int elemli;
+  mpz_t elem;
+  mpz_init(elem);
 
-void Chain::addCell(Cell* cell, int coeff) 
-{
-  std::pair<citer,bool> insert = _cells.insert( std::make_pair( cell, coeff));
-  if(!insert.second && (*insert.first).second == 0){
-    (*insert.first).second = coeff; 
-    cell->setDeleteWithCellComplex(false);
-  }
-  else if (!insert.second && (*insert.first).second != 0){
-    Msg::Debug("Error: invalid chain smoothening add! \n");
+  for(int i = 1; i <= rows; i++){
+    gmp_matrix_get_elem(elem, i, chainNumber, _Hbasis[dim]);
+    elemli = mpz_get_si(elem);
+    elemi = elemli;
+    Cell* cell = _cellIndices[dim][i];
+    chain[cell] = elemi;
   }
-  return;
-}
-
-bool Chain::hasCell(Cell* c)
-{
-  citer it = _cells.find(c);
-  if(it != _cells.end() && (*it).second != 0) return true;
-  return false;
-}
-   
-Cell* Chain::findCell(Cell* c)
-{
-  citer it = _cells.find(c);
-  if(it != _cells.end() && (*it).second != 0) return (*it).first;
-  return NULL;
-}
-
-int Chain::getCoeff(Cell* c)
-{
-  citer it = _cells.find(c);
-  if(it != _cells.end()) return (*it).second;
-  return 0;
-}
 
-void Chain::eraseNullCells()
-{
-  std::vector<Cell*> toRemove;
-  for(int i = 0; i < 4; i++){
-    for(citer cit = _cells.begin(); cit != _cells.end(); ++cit){
-      if((*cit).second == 0) toRemove.push_back((*cit).first);
-    }
-  }
-  for(unsigned int i = 0; i < toRemove.size(); i++){
-    _cells.erase(toRemove[i]);
-    toRemove[i]->setDeleteWithCellComplex(true);
-  }
-  return;
+  mpz_clear(elem);
 }
 
-void Chain::deImmuneCells()
+int ChainComplex::getTorsion(int dim, int chainNumber)
 {
-  for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
-    Cell* cell = (*cit).first;
-    cell->setImmune(false);
-  }
+  if(dim < 0 || dim > 4) return 0;
+  if(_Hbasis[dim] == NULL 
+     || (int)gmp_matrix_cols(_Hbasis[dim]) < chainNumber) return 0;
+  if(_torsion[dim].empty() 
+     || (int)_torsion[dim].size() < chainNumber) return 1;
+  else return _torsion[dim].at(chainNumber-1);
 }
 
 #endif
diff --git a/Geo/ChainComplex.h b/Geo/ChainComplex.h
index 38f6197a3461cc3ffe406b39572dde260c2a9434..fce3e0a9502cef9f506bad4509547d6552dbb518 100644
--- a/Geo/ChainComplex.h
+++ b/Geo/ChainComplex.h
@@ -17,14 +17,8 @@
 #include <algorithm>
 #include <set>
 #include <queue>
-#include "MElement.h"
-#include "GModel.h"
-#include "GEntity.h"
-#include "GRegion.h"
-#include "GFace.h"
-#include "GVertex.h"
 #include "CellComplex.h"
-
+#include "OS.h"
 
 #if defined(HAVE_GMP) 
   #include "gmp.h"
@@ -60,6 +54,8 @@ class ChainComplex{
   
   int _dim;
   CellComplex* _cellComplex;
+
+  std::map<int, Cell*> _cellIndices[4];
   
   // set the matrices
   void setHMatrix(int dim, gmp_matrix* matrix) { 
@@ -141,6 +137,7 @@ class ChainComplex{
   // get coefficient vector for dim-dimensional chain chainNumber 
   // (columns of _Hbasis[dim]) 
   std::vector<int> getCoeffVector(int dim, int chainNumber);
+  void getChain(std::map<Cell*, int, Less_Cell>& chain, int dim, int chainNumber);
   // torsion coefficient for dim-dimensional chain chainNumber 
   int getTorsion(int dim, int chainNumber);
   // get rank of homology group of dimension dim
@@ -157,97 +154,6 @@ class ChainComplex{
   void matrixTest();
 };
 
-// A class representing a chain.
-// Used to visualize generators of the homology groups.
-class Chain{
-  
- private:
-  // cells and their coefficients in this chain
-  std::map< Cell*, int, Less_Cell > _cells;
-  // name of the chain (optional)
-  std::string _name;
-  // physical group number of the chain
-  int _num;
-  // cell complex this chain belongs to
-  CellComplex* _cellComplex;
-  GModel* _model;
-   
-  // torsion coefficient
-  int _torsion;
-  
-  int _dim;
-  
-  bool deform(std::map<Cell*, int, Less_Cell> &cellsInChain, 
-	      std::map<Cell*, int, Less_Cell> &cellsNotInChain);
-  bool deformChain(std::pair<Cell*, int> cell, bool bend);
-  
-  
- public:
-  Chain() {}
-  Chain(std::set<Cell*, Less_Cell> cells, std::vector<int> coeffs, 
-	CellComplex* cellComplex, GModel* model,
-	std::string name="Chain", int torsion=0);
-  Chain(Chain* chain){ 
-    _cells = chain->getCells();
-    _torsion = chain->getTorsion();
-    _name = chain->getName();
-    _cellComplex = chain->getCellComplex();
-    _dim = chain->getDim();
-    _model = chain->getGModel();
-    _num = chain->getNum();
-  }  
-  typedef std::map<Cell*, int, Less_Cell>::iterator citer;
-  citer firstCell() {return _cells.begin(); }
-  citer lastCell() {return _cells.end(); }
-
-  ~Chain() {} 
-
-  // remove a cell from this chain
-  void removeCell(Cell* cell);
-   
-  // add a cell to this chain
-  void addCell(Cell* cell, int coeff);
-  
-  bool hasCell(Cell* c);
-  Cell* findCell(Cell* c);
-  int getCoeff(Cell* c);
-  
-  
-  int getTorsion() { return _torsion; }
-  int getDim() { return _dim; }
-  CellComplex* getCellComplex() { return _cellComplex; }
-  GModel* getGModel() { return _model; }
-  std::map<Cell*, int, Less_Cell>  getCells() { return _cells; }
-  
-  // erase cells from the chain with zero coefficient
-  void eraseNullCells();
-   
-  void deImmuneCells();
-  
-  // number of cells in this chain 
-  int getSize() { return _cells.size();}
-  
-  // get/set chain name
-  std::string getName() { return _name; }
-  void setName(std::string name) { _name=name; }
-  // get/set physical group number
-  int getNum() { return _num; }
-  void setNum(int num) { _num=num; }
-  
-  // make local deformations to the chain to make it smoother and smaller
-  // (for primary complex chains only, not for dual chains represented 
-  // by primary cells (yet).)
-  void smoothenChain();
-  
-  // append this chain to a MSH ASCII file as $ElementData
-  // for debugging only
-  int writeChainMSH(const std::string &name);
-
-  // create a physical group of this chain.
-  int createPGroup();
-  
-};
-
 #endif
    
 #endif
diff --git a/Geo/Homology.cpp b/Geo/Homology.cpp
index ee17d26ba84bade56e8069f4f94cddf2f13d17c7..85f3a9d58c69800e9cefe1e544c696b6252fd77b 100644
--- a/Geo/Homology.cpp
+++ b/Geo/Homology.cpp
@@ -7,8 +7,6 @@
  
 
 #include "Homology.h"
-#include "ChainComplex.h"
-#include "OS.h"
 
 #if defined(HAVE_KBIPACK)
 
@@ -94,17 +92,10 @@ Homology::~Homology()
   
 }
 
-void Homology::findGenerators(CellComplex* cellComplex, bool omit, 
-			      std::string domainString)
+void Homology::findGenerators()
 {
-  bool newComplex = false;
-  if(cellComplex == NULL){
-    cellComplex = createCellComplex(_domainEntities, _subdomainEntities);
-    newComplex = true;
-  }
-  if(domainString == ""){
-    domainString = getDomainString(_domain, _subdomain);
-  }
+  CellComplex* cellComplex = createCellComplex(_domainEntities, _subdomainEntities);
+  std::string domainString = getDomainString(_domain, _subdomain);
 
   Msg::Info("Reducing the Cell Complex...");
   Msg::StatusBar(1, false, "Reducing...");
@@ -114,7 +105,7 @@ void Homology::findGenerators(CellComplex* cellComplex, bool omit,
 	 cellComplex->getSize(3), cellComplex->getSize(2),
 	 cellComplex->getSize(1), cellComplex->getSize(0));
 
-  int omitted = cellComplex->reduceComplex(omit);
+  int omitted = cellComplex->reduceComplex();
 
   printf(" %d volumes, %d faces, %d edges and %d vertices. \n",
          cellComplex->getSize(3), cellComplex->getSize(2),
@@ -168,7 +159,7 @@ void Homology::findGenerators(CellComplex* cellComplex, bool omit,
 			       chains->getTorsion(j,i));
       t1 = Cpu();
       int start = chain->getSize();
-      //chain->smoothenChain();
+      chain->smoothenChain();
       t2 = Cpu();
       Msg::Info("Smoothened H%d %d from %d cells to %d cells (%g s).", 
 		j, i, start, chain->getSize(), t2 - t1);
@@ -197,7 +188,7 @@ void Homology::findGenerators(CellComplex* cellComplex, bool omit,
   
   if(_fileName != "") writeGeneratorsMSH();
   
-  if(newComplex) delete cellComplex;
+  delete cellComplex;
   delete chains;
   
   Msg::Info("Ranks of homology spaces for primal cell complex:");
@@ -499,5 +490,355 @@ bool Homology::writeGeneratorsMSH(bool binary)
   Msg::Info("Wrote homology computation results to %s.", _fileName.c_str());
   return true;
 }
+Chain::Chain(std::set<Cell*, Less_Cell> cells, std::vector<int> coeffs, 
+	     CellComplex* cellComplex, GModel* model,
+	     std::string name, int torsion)
+{  
+  int i = 0;
+  for(std::set<Cell*, Less_Cell>::iterator cit = cells.begin();
+      cit != cells.end(); cit++){
+    Cell* cell = *cit;
+    _dim = cell->getDim();
+    if((int)coeffs.size() > i){
+      if(coeffs.at(i) != 0){
+        std::list< std::pair<int, Cell*> > subCells;
+	cell->getCells(subCells);
+        for(std::list< std::pair<int, Cell*> >::iterator it = 
+	      subCells.begin(); it != subCells.end(); it++){
+          Cell* subCell = (*it).second;
+          int coeff = (*it).first;
+          _cells.insert( std::make_pair(subCell, coeffs.at(i)*coeff));
+	  subCell->setDeleteWithCellComplex(false);
+        }
+      }
+      i++;
+    }
+    
+  }
+  _name = name;
+  _cellComplex = cellComplex;
+  _torsion = torsion;
+  _model = model;
+  
+}
+
+Chain::Chain(std::map<Cell*, int, Less_Cell>& chain, 
+	     CellComplex* cellComplex, GModel* model,
+	     std::string name, int torsion)
+{  
+
+  _cells = chain;
+
+  _name = name;
+  _cellComplex = cellComplex;
+  _torsion = torsion;
+  _model = model; 
+}
+
+bool Chain::deform(std::map<Cell*, int, Less_Cell>& cellsInChain, 
+		   std::map<Cell*, int, Less_Cell>& cellsNotInChain)
+{
+  std::vector<int> cc;
+  std::vector<int> bc;
+  
+  for(citer cit = cellsInChain.begin(); cit != cellsInChain.end(); cit++){
+    Cell* c = (*cit).first;
+    c->setImmune(false);
+    if(!c->inSubdomain()) {
+      cc.push_back(getCoeff(c));
+      bc.push_back((*cit).second);
+    }
+  }
+  
+  if(cc.empty() || (getDim() == 2 && cc.size() < 2) ) return false;
+  int inout = cc[0]*bc[0];
+  for(unsigned int i = 0; i < cc.size(); i++){
+    if(cc[i]*bc[i] != inout) return false;  
+  }
+  
+  for(citer cit = cellsInChain.begin(); cit != cellsInChain.end(); cit++){
+    removeCell((*cit).first);
+  }
+  
+  int n = 1;
+  for(citer cit = cellsNotInChain.begin(); cit != cellsNotInChain.end();
+      cit++){
+    Cell* c = (*cit).first;
+    if(n == 2) c->setImmune(true);
+    else c->setImmune(false);
+    int coeff = -1*inout*(*cit).second;
+    addCell(c, coeff);
+    n++;
+  }
+  
+  return true;
+}
+
+bool Chain::deformChain(std::pair<Cell*, int> cell, bool bend)
+{  
+  Cell* c1 = cell.first;
+  for(citer cit = c1->firstCoboundary(true); cit != c1->lastCoboundary(true);
+      cit++){
+    
+    std::map<Cell*, int, Less_Cell> cellsInChain;
+    std::map<Cell*, int, Less_Cell> cellsNotInChain;
+    Cell* c1CbdCell = (*cit).first;
+
+    for(citer cit2 = c1CbdCell->firstBoundary(true);
+	cit2 != c1CbdCell->lastBoundary(true); cit2++){
+      Cell* c1CbdBdCell = (*cit2).first;
+      int coeff = (*cit2).second;
+      if( (hasCell(c1CbdBdCell) && getCoeff(c1CbdBdCell) != 0) 
+	  || c1CbdBdCell->inSubdomain()){
+	cellsInChain.insert(std::make_pair(c1CbdBdCell, coeff));
+      }
+      else cellsNotInChain.insert(std::make_pair(c1CbdBdCell, coeff));
+    }
+    
+    bool next = false;
+    
+    for(citer cit2 = cellsInChain.begin(); cit2 != cellsInChain.end(); cit2++){
+      Cell* c = (*cit2).first;
+      int coeff = getCoeff(c);
+      if(c->getImmune()) next = true;
+      if(c->inSubdomain()) bend = false;
+      if(coeff > 1 || coeff < -1) next = true; 
+    }
+    
+    for(citer cit2 = cellsNotInChain.begin(); cit2 != cellsNotInChain.end();
+	cit2++){
+      Cell* c = (*cit2).first;
+      if(c->inSubdomain()) next = true;
+    }    
+    if(next) continue;
+    
+    if( (getDim() == 1 && cellsInChain.size() == 2 
+	 && cellsNotInChain.size() == 1) || 
+	(getDim() == 2 && cellsInChain.size() == 3 
+	 && cellsNotInChain.size() == 1)){
+      //printf("straighten \n");
+      return deform(cellsInChain, cellsNotInChain);
+    }
+    else if ( (getDim() == 1 && cellsInChain.size() == 1 
+	       && cellsNotInChain.size() == 2 && bend) ||
+              (getDim() == 2 && cellsInChain.size() == 2 
+	       && cellsNotInChain.size() == 2 && bend)){
+      //printf("bend \n");
+      return deform(cellsInChain, cellsNotInChain);
+    }
+    else if ((getDim() == 1 && cellsInChain.size() == 3 
+	      && cellsNotInChain.size() == 0) ||
+             (getDim() == 2 && cellsInChain.size() == 4 
+	      && cellsNotInChain.size() == 0)){
+      //printf("remove boundary \n");
+      return deform(cellsInChain, cellsNotInChain);
+    }
+  }
+  
+  return false;
+}
+
+void Chain::smoothenChain()
+{
+  if(!_cellComplex->simplicial()) return;
+  
+  int start = getSize();
+  double t1 = Cpu();
+  
+  int useless = 0;
+  for(int i = 0; i < 20; i++){
+    int size = getSize();
+    for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
+      //if(!deformChain(*cit, false) && getDim() == 2) deformChain(*cit, true);
+      if(getDim() == 2) deformChain(*cit, true);
+      deformChain(*cit, false);      
+    }
+    deImmuneCells();
+    eraseNullCells();
+    if (size >= getSize()) useless++;
+    else useless = 0;
+    if (useless > 5) break;
+  }
+  
+  deImmuneCells();
+  for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
+    deformChain(*cit, false);
+  }
+  
+  eraseNullCells();
+  double t2 = Cpu();
+  Msg::Debug("Smoothened a %d-chain from %d cells to %d cells (%g s).\n",
+	     getDim(), start, getSize(), t2-t1);
+  return;
+}
+
+
+int Chain::writeChainMSH(const std::string &name)
+{  
+  if(getSize() == 0) return 1;
+  
+  FILE *fp = fopen(name.c_str(), "a");
+  if(!fp){
+    Msg::Error("Unable to open file '%s'", name.c_str());
+    Msg::Debug("Unable to open file.");
+      return 0;
+  }
+ 
+  fprintf(fp, "\n$ElementData\n");
+  
+  fprintf(fp, "1 \n");
+  fprintf(fp, "\"%s\" \n", getName().c_str());
+  fprintf(fp, "1 \n");
+  fprintf(fp, "0.0 \n");
+  fprintf(fp, "4 \n");
+  fprintf(fp, "0 \n");
+  fprintf(fp, "1 \n");
+  fprintf(fp, "%d \n", getSize());
+  fprintf(fp, "0 \n");
+  
+  for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
+    Cell* cell = (*cit).first;
+    int coeff = (*cit).second;
+    fprintf(fp, "%d %d \n", cell->getNum(), coeff );
+  }
+  
+  fprintf(fp, "$EndElementData\n");
+  fclose(fp);
+  
+  return 1;
+}
+
+int Chain::createPGroup()
+{  
+  std::vector<MElement*> elements;
+  std::map<int, std::vector<double> > data;
+  MElementFactory factory;
+
+  for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
+    Cell* cell = (*cit).first;
+    int coeff = (*cit).second;
+
+    MElement* e = cell->getImageMElement();
+    std::vector<MVertex*> v;
+    for(int i = 0; i < e->getNumVertices(); i++){
+      v.push_back(e->getVertex(i));
+    }
+    MElement* ne = factory.create(e->getTypeForMSH(), v, 0, e->getPartition());
+    
+    if(cell->getDim() > 0 && coeff < 0) ne->revert(); // flip orientation
+    for(int i = 0; i < abs(coeff); i++) elements.push_back(ne);    
+
+    std::vector<double> coeffs (1,abs(coeff));
+    data[ne->getNum()] = coeffs;
+  }
+  
+  int max[4];
+  for(int i = 0; i < 4; i++) max[i] = _model->getMaxElementaryNumber(i);
+  int entityNum = *std::max_element(max,max+4) + 1;
+  for(int i = 0; i < 4; i++) max[i] = _model->getMaxPhysicalNumber(i);
+  int physicalNum = *std::max_element(max,max+4) + 1;
+  setNum(physicalNum);
+  
+  std::map<int, std::vector<MElement*> > entityMap;
+  entityMap[entityNum] = elements;
+  std::map<int, std::map<int, std::string> > physicalMap;
+  std::map<int, std::string> physicalInfo;
+  physicalInfo[physicalNum]=getName();
+  physicalMap[entityNum] = physicalInfo;
+  
+  // hide mesh
+  opt_mesh_points(0, GMSH_SET, 0);
+  opt_mesh_lines(0, GMSH_SET, 0);
+  opt_mesh_triangles(0, GMSH_SET, 0);
+  opt_mesh_quadrangles(0, GMSH_SET, 0);
+  opt_mesh_tetrahedra(0, GMSH_SET, 0);
+  opt_mesh_hexahedra(0, GMSH_SET, 0);
+  opt_mesh_prisms(0, GMSH_SET, 0);
+  opt_mesh_pyramids(0, GMSH_SET, 0);
+
+  // show post-processing normals, tangents and element boundaries
+  //opt_view_normals(0, GMSH_SET, 20);
+  //opt_view_tangents(0, GMSH_SET, 20);
+  opt_view_show_element(0, GMSH_SET, 1);
+  
+  if(!data.empty()){
+    _model->storeChain(getDim(), entityMap, physicalMap);
+    _model->setPhysicalName(getName(), getDim(), physicalNum);
+    
+    // create PView for visualization
+    PView* chain = new PView(getName(), "ElementData", getGModel(), 
+			     data, 0, 1);
+  }
+   
+  return physicalNum;
+}
+
+
+void Chain::removeCell(Cell* cell) 
+{
+  citer it = _cells.find(cell);
+  if(it != _cells.end()){
+    (*it).second = 0;
+  }
+  return;
+}
+
+void Chain::addCell(Cell* cell, int coeff) 
+{
+  std::pair<citer,bool> insert = _cells.insert( std::make_pair( cell, coeff));
+  if(!insert.second && (*insert.first).second == 0){
+    (*insert.first).second = coeff; 
+    cell->setDeleteWithCellComplex(false);
+  }
+  else if (!insert.second && (*insert.first).second != 0){
+    Msg::Debug("Error: invalid chain smoothening add! \n");
+  }
+  return;
+}
+
+bool Chain::hasCell(Cell* c)
+{
+  citer it = _cells.find(c);
+  if(it != _cells.end() && (*it).second != 0) return true;
+  return false;
+}
+   
+Cell* Chain::findCell(Cell* c)
+{
+  citer it = _cells.find(c);
+  if(it != _cells.end() && (*it).second != 0) return (*it).first;
+  return NULL;
+}
+
+int Chain::getCoeff(Cell* c)
+{
+  citer it = _cells.find(c);
+  if(it != _cells.end()) return (*it).second;
+  return 0;
+}
+
+void Chain::eraseNullCells()
+{
+  std::vector<Cell*> toRemove;
+  for(int i = 0; i < 4; i++){
+    for(citer cit = _cells.begin(); cit != _cells.end(); ++cit){
+      if((*cit).second == 0) toRemove.push_back((*cit).first);
+    }
+  }
+  for(unsigned int i = 0; i < toRemove.size(); i++){
+    _cells.erase(toRemove[i]);
+    toRemove[i]->setDeleteWithCellComplex(true);
+  }
+  return;
+}
+
+void Chain::deImmuneCells()
+{
+  for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
+    Cell* cell = (*cit).first;
+    cell->setImmune(false);
+  }
+}
 
 #endif
+
diff --git a/Geo/Homology.h b/Geo/Homology.h
index 62d1fd224171664d0293380bb020d3bb6a2b3445..49f80aa0aa993769c617f815dc3df86112b76121 100644
--- a/Geo/Homology.h
+++ b/Geo/Homology.h
@@ -11,6 +11,9 @@
 #include <sstream>
 #include "CellComplex.h"
 #include "ChainComplex.h"
+#include "OS.h"
+#include "PView.h"
+#include "Options.h"
 
 #if defined(HAVE_KBIPACK)
 
@@ -22,7 +25,9 @@ template <class TTypeA, class TTypeB>
   return stream.good();
 }
 
+class Chain;
 
+// Interface class for homology computation in Gmsh
 class Homology
 {
  private:
@@ -57,8 +62,7 @@ class Homology
 
   // Find the generators/duals of homology spaces,
   // or just compute the ranks of homology spaces
-  void findGenerators(CellComplex* cellComplex=NULL, 
-		      bool omit=true, std::string domainString="");
+  void findGenerators();
   void findDualGenerators();
   void computeBettiNumbers();
   
@@ -77,6 +81,100 @@ class Homology
   bool writeGeneratorsMSH(bool binary=false);
 };
 
+// A class representing a chain.
+// Used to visualize generators of the homology groups.
+class Chain{
+  
+ private:
+  // cells and their coefficients in this chain
+  std::map< Cell*, int, Less_Cell > _cells;
+  // name of the chain (optional)
+  std::string _name;
+  // physical group number of the chain
+  int _num;
+  // cell complex this chain belongs to
+  CellComplex* _cellComplex;
+  GModel* _model;
+   
+  // torsion coefficient
+  int _torsion;
+  
+  int _dim;
+  
+  bool deform(std::map<Cell*, int, Less_Cell> &cellsInChain, 
+	      std::map<Cell*, int, Less_Cell> &cellsNotInChain);
+  bool deformChain(std::pair<Cell*, int> cell, bool bend);
+  
+  
+ public:
+  Chain() {}
+  Chain(std::set<Cell*, Less_Cell> cells, std::vector<int> coeffs, 
+	CellComplex* cellComplex, GModel* model,
+	std::string name="Chain", int torsion=0);
+  Chain(std::map<Cell*, int, Less_Cell>& chain,
+        CellComplex* cellComplex, GModel* model,
+        std::string name="Chain", int torsion=0);
+  Chain(Chain* chain){ 
+    _cells = chain->getCells();
+    _torsion = chain->getTorsion();
+    _name = chain->getName();
+    _cellComplex = chain->getCellComplex();
+    _dim = chain->getDim();
+    _model = chain->getGModel();
+    _num = chain->getNum();
+  }  
+  typedef std::map<Cell*, int, Less_Cell>::iterator citer;
+  citer firstCell() {return _cells.begin(); }
+  citer lastCell() {return _cells.end(); }
+
+  ~Chain() {} 
+
+  // remove a cell from this chain
+  void removeCell(Cell* cell);
+   
+  // add a cell to this chain
+  void addCell(Cell* cell, int coeff);
+  
+  bool hasCell(Cell* c);
+  Cell* findCell(Cell* c);
+  int getCoeff(Cell* c);
+  
+  
+  int getTorsion() { return _torsion; }
+  int getDim() { return _dim; }
+  CellComplex* getCellComplex() { return _cellComplex; }
+  GModel* getGModel() { return _model; }
+  std::map<Cell*, int, Less_Cell>  getCells() { return _cells; }
+  
+  // erase cells from the chain with zero coefficient
+  void eraseNullCells();
+   
+  void deImmuneCells();
+  
+  // number of cells in this chain 
+  int getSize() { return _cells.size();}
+  
+  // get/set chain name
+  std::string getName() { return _name; }
+  void setName(std::string name) { _name=name; }
+  // get/set physical group number
+  int getNum() { return _num; }
+  void setNum(int num) { _num=num; }
+  
+  // make local deformations to the chain to make it smoother and smaller
+  // (for primary complex chains only, not for dual chains represented 
+  // by primary cells (yet).)
+  void smoothenChain();
+  
+  // append this chain to a MSH ASCII file as $ElementData
+  // for debugging only
+  int writeChainMSH(const std::string &name);
+
+  // create a physical group of this chain.
+  int createPGroup();
+  
+};
+
 #endif
 
 #endif
diff --git a/Solver/dgRungeKuttaMultirate.cpp b/Solver/dgRungeKuttaMultirate.cpp
index ac99bd9d2777daf808ea6ae546d2b90ec969e508..ed4c6fc4a9812e7621250324dd142d6d6159599f 100644
--- a/Solver/dgRungeKuttaMultirate.cpp
+++ b/Solver/dgRungeKuttaMultirate.cpp
@@ -5,6 +5,7 @@
 #include "dgDofContainer.h"
 #include "dgGroupOfElements.h"
 #include <algorithm>
+#include <limits.h>
 
 dgRungeKuttaMultirate::dgRungeKuttaMultirate(dgGroupCollection* gc,dgConservationLaw *law, int nStages){
   _law=law;
diff --git a/tutorial/t10.geo b/tutorial/t10.geo
index 5c32ee9b3692fae7b19c59e9447b5503b3b863de..cc9ccfa31c163d06fb4907ff85b581fbad6e5185 100644
--- a/tutorial/t10.geo
+++ b/tutorial/t10.geo
@@ -144,10 +144,6 @@ HomGen("t10_hom.msh") = {{69}, {75}};
 // Save the cut chains to t10_hom.msh.
 HomCut("t10_hom.msh") = {{69}, {70, 71, 72, 73}};
 
-// Only find and save the ranks of the relative homology spaces 
-// (Betti numbers) to t10_homrank.txt. Does not find generators.
-HomRank("t10_hom.txt") = {{69},{70, 71, 72, 73}};
-
 // More examples (uncomment):
 //  HomGen("t10_hom.msh") = {{69}, {}}; 
 //  HomGen("t10_hom.msh") = {{}, {}};
diff --git a/utils/api_demos/mainHomology.cpp b/utils/api_demos/mainHomology.cpp
index cc1fcbe01b0289638a3c292a0a4229dab7d3d7d4..6b6aecc25229581eee025548bdbd4faf0ccbfa3c 100644
--- a/utils/api_demos/mainHomology.cpp
+++ b/utils/api_demos/mainHomology.cpp
@@ -31,18 +31,15 @@ int main(int argc, char **argv)
   
   Homology* homology1 = new Homology(m, domain, subdomain);
   std::string fileName = "homology.msh";
-  homology->findGenerators(fileName);
+  homology->findGenerators();
+  homology->setFileName(fileName);
   delete homology1;
   
   Homology* homology2 = new Homology(m, domain, subdomain);
-  fileName = "homology.msh";
-  homology->findDualGenerators(fileName);
+  homology->findDualGenerators();
+  homology->setFileName(fileName);
   delete homology2;
   
-  Homology* homology3 = new Homology(m, domain, subdomain);
-  homology->computeBettiNumbers();
-  delete homology3;
-  
   delete m;
   GmshFinalize();