diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp
index 09876bbe70a13170881d0abd81f58b7c7bcb82c4..01164cc1e492994adadc26f1f2da3c02e1351982 100644
--- a/Geo/CellComplex.cpp
+++ b/Geo/CellComplex.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to <gmsh@geuz.org>.
 //
-// Contributed by Matti Pellikka.
+// Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
 
 #include "CellComplex.h"
 #include "OS.h"
diff --git a/Geo/ChainComplex.cpp b/Geo/ChainComplex.cpp
index ed1fa49b202e77ea9eea04137c437ea255c54443..f25ec4c13d076a19e3292d6e30230fc5380b6663 100644
--- a/Geo/ChainComplex.cpp
+++ b/Geo/ChainComplex.cpp
@@ -783,8 +783,24 @@ void Chain::smoothenChain(){
   
   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(!straightenChain(*cit) && getDim() == 2) bendChain(*cit);
+      removeBoundary(*cit);
+    }
+    deImmuneCells();
+    eraseNullCells();
+    if (size >= getSize()) useless++;
+    else useless = 0;
+    if (useless > 5) break;
+  }
+  
+  
+  /*
   const int MAXROUNDS = 2;
-
   bool smoothened = true;
   int round = 0;
   while(smoothened){
@@ -798,67 +814,70 @@ void Chain::smoothenChain(){
   }
   eraseNullCells(); 
   
-  if(getDim() == 2){
-  Chain* bestChain = new Chain(this);
-  int before = getSize();
-  deImmuneCells();
-  srand ( time(NULL) );
-  int n = 0;
-  while( n < 10){
-    double t = 1;
-    while(t>0){
-      double tt = 1;
-
-      for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
-        int random = rand() % 100 + 1;
-        double r = random*t; 
-        //printf("random: %d, t: %d \n", random, t);
-        if(r > 80) { 
-          bendChain(*cit);
-          //printf("random: %d, t: %g, random*t: %g.\n", random, t, r);
-          //cit = _cells.begin(); 
-          //tt = tt - 0.1;
-          //if(tt <= 0) tt = 0;
-        }
-      }
-      eraseNullCells();
-
-      smoothened = true;
-      round = 0;
-      while(smoothened){
-        round++;
-        smoothened = false;
+   if(getDim() == 2){
+    Chain* bestChain = new Chain(this);
+    int before = getSize();
+    deImmuneCells();
+    srand ( time(NULL) );
+    int n = 0;
+    while( n < 10){
+      double t = 1;
+      while(t>0){
+        double tt = 1;
+        
         for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
-          if(straightenChain(*cit)){smoothened = true;}
-          if(removeBoundary(*cit)) { smoothened = true; }
+          int random = rand() % 100 + 1;
+          double r = random*t; 
+          //printf("random: %d, t: %d \n", random, t);
+          if(r > 80) { 
+            bendChain(*cit);
+            //printf("random: %d, t: %g, random*t: %g.\n", random, t, r);
+            //cit = _cells.begin(); 
+            //tt = tt - 0.1;
+            //if(tt <= 0) tt = 0;
+          }
         }
-        if(round > MAXROUNDS) smoothened = false;
+        eraseNullCells();
+        
+        smoothened = true;
+        round = 0;
+        while(smoothened){
+          round++;
+          smoothened = false;
+          for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
+            if(straightenChain(*cit)){smoothened = true;}
+            if(removeBoundary(*cit)) { smoothened = true; }
+          }
+          if(round > MAXROUNDS) smoothened = false;
+        }
+        eraseNullCells();
+        if(this->getSize() < bestChain->getSize()) bestChain = this;
+        t = t - 0.1;
       }
-      eraseNullCells();
-      if(this->getSize() < bestChain->getSize()) bestChain = this;
-      t = t - 0.1;
+      deImmuneCells();
+      n=n+1;
     }
+    
+    
     deImmuneCells();
-    n=n+1;
-  }
-
-  
-  deImmuneCells();
-  smoothened = true;
-  round = 0;
-  while(smoothened){
-    round++;
-    smoothened = false;
-    for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
-      if(straightenChain(*cit)){smoothened = true;}
-      if(removeBoundary(*cit)) { smoothened = true; }
+    smoothened = true;
+    round = 0;
+    while(smoothened){
+      round++;
+      smoothened = false;
+      for(citer cit = _cells.begin(); cit != _cells.end(); cit++){
+        if(straightenChain(*cit)){smoothened = true;}
+        if(removeBoundary(*cit)) { smoothened = true; }
+      }
+      if(round > MAXROUNDS) smoothened = false;
     }
-    if(round > MAXROUNDS) smoothened = false;
-  }
-  eraseNullCells();
-  if(this->getSize() < bestChain->getSize()) bestChain = this;
-  printf("%d-chain simulated annealing removed %d cells. \n", getDim(), before - getSize());  
+    
+    
+    eraseNullCells();
+    if(this->getSize() < bestChain->getSize()) bestChain = this;
+    printf("%d-chain simulated annealing removed %d cells. \n", getDim(), before - getSize());  
   }
+  */
   double t2 = Cpu();
   printf("Smoothened a %d-chain from %d cells to %d cells (%g s).\n", getDim(), start, getSize(), t2-t1);
   return;
diff --git a/Geo/ChainComplex.h b/Geo/ChainComplex.h
index e18aec776e8604d7081956ad43c7923079f7dcdd..6a7dc870913e89718a69027f4c02138cd73686c2 100644
--- a/Geo/ChainComplex.h
+++ b/Geo/ChainComplex.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to <gmsh@geuz.org>.
 //
-// Contributed by Matti Pellikka.
+// Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
 
 #ifndef _CHAINCOMPLEX_H_
 #define _CHAINCOMPLEX_H_
diff --git a/Geo/Homology.cpp b/Geo/Homology.cpp
index f2ca589ee6f1b898864b565b0af44a8de66fa985..198f0566d23b94210d97df44f1927ee09fef0b9d 100644
--- a/Geo/Homology.cpp
+++ b/Geo/Homology.cpp
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to <gmsh@geuz.org>.
 //
-// Contributed by Matti Pellikka.
+// Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
  
 
 #include "Homology.h"
diff --git a/Geo/Homology.h b/Geo/Homology.h
index 5308ce105ad5492da59950b21402db645ddf8dc3..2c8e69a5bc2831d85ba41522e82105c7335ad472 100644
--- a/Geo/Homology.h
+++ b/Geo/Homology.h
@@ -3,7 +3,7 @@
 // See the LICENSE.txt file for license information. Please report all
 // bugs and problems to <gmsh@geuz.org>.
 // 
-// Contributed by Matti Pellikka.
+// Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
 
 #ifndef _HOMOLOGY_H_
 #define _HOMOLOGY_H_
@@ -36,15 +36,19 @@ class Homology
    Homology(GModel* model, std::vector<int> physicalDomain, std::vector<int> physicalSubdomain);
    ~Homology(){ delete _cellComplex; }
    
+   // Find the generators/duals of homology spaces, or just compute the ranks of homology spaces
    void findGenerators(std::string fileName);
    void findDualGenerators(std::string fileName);
-
    void computeBettiNumbers();
    
+   
    void swapSubdomain() { _cellComplex->swapSubdomain(); }
-
+   
+   // Restore the cell complex to its original state before cell reductions
+   void restoreHomology() { _cellComplex->restoreComplex(); }
+   
+   // Create a string describing the generator
    std::string getDomainString() {
-     
      std::string domainString = "({";
      for(unsigned int i = 0; i < _domain.size(); i++){
        std::string temp = "";
diff --git a/utils/api_demos/mainHomology.cpp b/utils/api_demos/mainHomology.cpp
index 4fe82d739b793405b77af7a7f45865dcbde804a7..acf2812edc22ede0319feb38dbe26fd36df83e89 100644
--- a/utils/api_demos/mainHomology.cpp
+++ b/utils/api_demos/mainHomology.cpp
@@ -1,14 +1,10 @@
-// configure, compile and install Gmsh as a library with
-//
-//   ./configure --disable-gui --disable-netgen --disable-chaco --prefix=/usr/local/
-//   make install-lib
-//
-// Then compile this driver with "g++ celldriver.cpp -lGmsh -llapack -lblas -lgmp"
-//
-//
-// This program creates .msh file chains.msh which represents the generators and
-// the cuts of an two port transformer model's homology groups.
-
+// Gmsh - Copyright (C) 1997-2009 C. Geuzaine, J.-F. Remacle
+// 
+// See the LICENSE.txt file for license information. Please report all
+// bugs and problems to <gmsh@geuz.org>.
+// 
+// Contributed by Matti Pellikka <matti.pellikka@tut.fi>.
+// 
 
 #include <stdio.h>
 #include <sstream>
@@ -17,130 +13,36 @@
 #include <gmsh/MElement.h>
 #include <gmsh/CellComplex.h>
 #include <gmsh/ChainComplex.h>
-
-template <class TTypeA, class TTypeB>
-bool convert(const TTypeA& input, TTypeB& output ){
-  std::stringstream stream;
-  stream << input;
-  stream >> output;
-  return stream.good();
-}
-
+#include <gmsh/Homology.h>
 
 int main(int argc, char **argv)
 {
   GmshInitialize(argc, argv);
   GModel *m = new GModel();
-  m->readGEO("transformer.geo");
-  m->mesh(3);
-  
-  printf("This model has: %d GRegions, %d GFaces, %d GEdges and %d GVertices. \n" , m->getNumRegions(), m->getNumFaces(), m->getNumEdges(), m->getNumVertices());
-  
-  std::vector<GEntity*> domain;
-  std::vector<GEntity*> subdomain;
-  
-  // whole model the domain
-  for(GModel::riter rit = m->firstRegion(); rit != m->lastRegion(); rit++){
-    GEntity *r = *rit;
-    domain.push_back(r);
-  }
-
-  // the ports as subdomain
-  GModel::fiter sub = m->firstFace();
-  GEntity *s = *sub;
-  subdomain.push_back(s);
-  s = *(++sub);
-  subdomain.push_back(s);
-  s =*(++sub);
-  subdomain.push_back(s);
-  s= *(++sub);
-  subdomain.push_back(s);
-  
-  // create a cell complex
-  CellComplex* complex = new CellComplex(domain, subdomain);
-
-  // write the cell complex to a .msh file
-  complex->writeComplexMSH("chains.msh");
-
-  printf("Cell complex of this model has: %d volumes, %d faces, %d edges and %d vertices\n",
-         complex->getSize(3), complex->getSize(2), complex->getSize(1), complex->getSize(0));  
   
-  // reduce the complex in order to ease homology computation
-  complex->reduceComplex(true);
-  
-  // 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
-  chains->computeHomology();
-  
-  // Append the homology generators to the .msh file as post-processing views. 
-  // To visualize the result, open chains.msh with Gmsh GUI and deselect all mesh
-  // entities from Tools->Options->Mesh->Visibility.
-  for(int j = 0; j < 4; j++){
-    for(int i = 1; i <= chains->getBasisSize(j); i++){
-    
-      std::string generator;
-      std::string dimension;
-      convert(i, generator);
-      convert(j, dimension);
-      std::string name = dimension + "D Generator " + generator;
-      
-      Chain* chain = new Chain(complex->getCells(j), chains->getCoeffVector(j,i), complex, name);
-      chain->writeChainMSH("chains.msh");
-      delete chain;
-      
-    }
-  }
-  
-  delete chains;
-  delete complex;
-  
-  // create new complex to compute the cuts
-  CellComplex* complex2 = new CellComplex(domain, subdomain);
-  
-  // reduce the complex by coreduction, this removes all vertices, hence 0 as an argument 
-  complex2->coreduceComplex(true);
-  
-  // perform series of "dual complex" cell combinations in order to ease homology computation
-  complex2->cocombine(0);
-  complex2->cocombine(1);
-  complex2->cocombine(2);
+  m->readGEO("model.geo");
+  m->mesh(3);
+  // OR
+  // m->readMSH("model.msh");
   
-  // create a chain complex of a cell complex (construct boundary operator matrices)
-  ChainComplex* dualChains = new ChainComplex(complex2);
+  // List of physical regions as domain for homology computation (relative to subdomain).
+  std::vector<int> domain;
+  std::vector<int> subdomain;
   
-  // transpose the boundary operator matrices, 
-  // these are the boundary operator matrices for the dual chain complex
-  dualChains->transposeHMatrices();
+  Homology* homology = new Homology(m, domain, subdomain);
+  std::string fileName = "homology_generators.msh";
+  homology->findGenerators(fileName);
+  homology->restoreHomology();
   
-  // compute the homology of the dual complex
-  dualChains->computeHomology(true);  
+  Homology* homology = new Homology(m, domain, subdomain);
+  fileName = "homology_dualgenerators.msh";
+  homology->findDualGenerators(fileName);
+  homology->restoreHomology();
   
-  // Append the duals of the cuts of the homology generators to the .msh file.
-  for(int j = 3; j > -1; j--){
-    for(int i = 1; i <= dualChains->getBasisSize(j); i++){
-
-      std::string generator;
-      std::string dimension;
-      convert(i, generator);
-      convert(3-j, dimension);
-
-      std::string name = dimension + "D Dual cut " + generator;
-      Chain* chain = new Chain(complex2->getCells(j), dualChains->getCoeffVector(j,i), complex2, name);
-                chain->writeChainMSH("chains.msh");
-      delete chain;
-    }
-  }
-
-  delete dualChains;
-
+  Homology* homology = new Homology(m, domain, subdomain);
+  homology->computeBettiNumbers();
+  delete homology;
   
-  delete complex2;  
   delete m;
   GmshFinalize();