diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp
index 3d59c7fac1631144aec101d897d60767d7cb5149..7ea6d4a226e8254f76003e76d4e79ce2a702764b 100644
--- a/Geo/CellComplex.cpp
+++ b/Geo/CellComplex.cpp
@@ -11,6 +11,8 @@
 CellComplex::CellComplex(GModel* model,
 			 std::vector<MElement*>& domainElements,
 			 std::vector<MElement*>& subdomainElements,
+                         std::vector<MElement*>& nondomainElements,
+                         std::vector<MElement*>& nonsubdomainElements,
                          std::vector<MElement*>& immuneElements,
                          bool saveOriginalComplex) :
   _model(model), _dim(0), _simplicial(true), _saveorig(saveOriginalComplex)
@@ -18,6 +20,8 @@ CellComplex::CellComplex(GModel* model,
   _deleteCount = 0;
   _insertCells(subdomainElements, 1);
   _insertCells(domainElements, 0);
+  _removeCells(nonsubdomainElements, 1);
+  _removeCells(nondomainElements, 0);
   _immunizeCells(immuneElements);
   int num = 0;
   for(int dim = 0; dim < 4; dim++){
@@ -78,6 +82,53 @@ bool CellComplex::_insertCells(std::vector<MElement*>& elements,
   return true;
 }
 
+bool CellComplex::_removeCells(std::vector<MElement*>& elements,
+			       int domain)
+{
+
+  std::set<Cell*, Less_Cell> removed[4];
+
+  for(unsigned int i=0; i < elements.size(); i++){
+    MElement* element = elements.at(i);
+    int type = element->getType();
+    if(type == TYPE_PYR || type == TYPE_PRI ||
+       type == TYPE_POLYG || type == TYPE_POLYH) {
+      Msg::Error("Mesh element type %d not implemented in homology solver", type);
+      return false;
+    }
+    Cell* cell = new Cell(element, domain);
+    int dim = cell->getDim();
+    citer cit = _cells[dim].find(cell);
+    if(cit != lastCell(dim)) {
+      removeCell(*cit);
+      removed[dim].insert(cell);
+    }
+    else delete cell;
+  }
+
+  for (int dim = 3; dim > 0; dim--){
+    for(citer cit = removed[dim].begin(); cit != removed[dim].end(); cit++){
+      Cell* cell = *cit;
+      for(int i = 0; i < cell->getNumBdElements(); i++){
+	Cell* newCell = new Cell(cell, i);
+
+        citer cit2 = _cells[dim-1].find(newCell);
+        if(cit2 != lastCell(dim-1)) {
+          removeCell(*cit2);
+          removed[dim-1].insert(newCell);
+        }
+        else delete newCell;
+      }
+    }
+  }
+  for (int dim = 3; dim > 0; dim--){
+    for(citer cit = removed[dim].begin(); cit != removed[dim].end(); cit++){
+      delete *cit;
+    }
+  }
+  return true;
+}
+
 bool CellComplex::_immunizeCells(std::vector<MElement*>& elements)
 {
   for(unsigned int i=0; i < elements.size(); i++){
@@ -291,7 +342,7 @@ int CellComplex::reduceComplex(bool docombine, bool omit)
   std::vector<Cell*> empty;
   for(int i = 3; i > 0; i--) count = count + reduction(i, false, empty);
 
-  if(omit && !count){
+  if(omit){
 
     removeSubdomain();
     std::vector<Cell*> newCells;
@@ -362,7 +413,8 @@ int CellComplex::coreduceComplex(bool docombine, bool omit)
     }
   }
 
-  if(omit && !count){
+  if(omit){
+
     std::vector<Cell*> newCells;
     while (getSize(0) != 0){
       citer cit = firstCell(0);
diff --git a/Geo/CellComplex.h b/Geo/CellComplex.h
index c6d4a76bf48d3ba516e8e55a18526ee636634458..326521e7bf47241528b9e1ac9cdcf3b3534c26bd 100644
--- a/Geo/CellComplex.h
+++ b/Geo/CellComplex.h
@@ -48,6 +48,7 @@ class CellComplex
 
   // for constructor
   bool _insertCells(std::vector<MElement*>& elements, int domain);
+  bool _removeCells(std::vector<MElement*>& elements, int domain);
 
   bool _immunizeCells(std::vector<MElement*>& elements);
 
@@ -67,6 +68,8 @@ class CellComplex
   CellComplex(GModel* model,
 	      std::vector<MElement*>& domainElements,
 	      std::vector<MElement*>& subdomainElements,
+              std::vector<MElement*>& nondomainElements,
+              std::vector<MElement*>& nonsubdomainElements,
               std::vector<MElement*>& immuneElements,
               bool saveOriginalComplex=true);
   ~CellComplex();
diff --git a/Geo/Homology.cpp b/Geo/Homology.cpp
index 9f9b8ccfd8f063959ebc283943de3bbd1cc4774b..e163d8aad3c5d31835b1ea624aad04faf7f502a6 100644
--- a/Geo/Homology.cpp
+++ b/Geo/Homology.cpp
@@ -36,41 +36,43 @@ Homology::Homology(GModel* model, std::vector<int> physicalDomain,
     }
   }
 
+  _getEntities(_domain, _domainEntities);
+  _getEntities(_subdomain, _subdomainEntities);
+  _getEntities(_nondomain, _nondomainEntities);
+  _getEntities(_nonsubdomain, _nonsubdomainEntities);
+  _getEntities(_imdomain, _immuneEntities);
+
+}
+
+void Homology::_getEntities(const std::vector<int>& physicalGroups,
+                            std::vector<GEntity*>& entities)
+{
+  entities.clear();
   std::map<int, std::vector<GEntity*> > groups[4];
-  model->getPhysicalGroups(groups);
+  _model->getPhysicalGroups(groups);
   std::map<int, std::vector<GEntity*> >::iterator it;
 
-  for(unsigned int i = 0; i < _domain.size(); i++){
-    for(int j = 0; j < 4; j++){
-      it = groups[j].find(_domain.at(i));
-      if(it != groups[j].end()){
-	std::vector<GEntity*> physicalGroup = (*it).second;
-	for(unsigned int k = 0; k < physicalGroup.size(); k++){
-	  _domainEntities.push_back(physicalGroup.at(k));
-	}
-      }
-    }
-  }
-  for(unsigned int i = 0; i < _subdomain.size(); i++){
+  for(unsigned int i = 0; i < physicalGroups.size(); i++){
     for(int j = 0; j < 4; j++){
-      it = groups[j].find(_subdomain.at(i));
+      it = groups[j].find(physicalGroups.at(i));
       if(it != groups[j].end()){
 	std::vector<GEntity*> physicalGroup = (*it).second;
 	for(unsigned int k = 0; k < physicalGroup.size(); k++){
-	  _subdomainEntities.push_back(physicalGroup.at(k));
+	  entities.push_back(physicalGroup.at(k));
 	}
       }
     }
   }
-  for(unsigned int i = 0; i < _imdomain.size(); i++){
-    for(int j = 0; j < 4; j++){
-      it = groups[j].find(_imdomain.at(i));
-      if(it != groups[j].end()){
-	std::vector<GEntity*> physicalGroup = (*it).second;
-	for(unsigned int k = 0; k < physicalGroup.size(); k++){
-	  _immuneEntities.push_back(physicalGroup.at(k));
-	}
-      }
+}
+
+void Homology::_getElements(const std::vector<GEntity*>& entities,
+                            std::vector<MElement*>& elements)
+{
+  elements.clear();
+  for(unsigned int j=0; j < entities.size(); j++) {
+    for(unsigned int i=0; i < entities.at(j)->getNumMeshElements(); i++){
+      MElement* element = entities.at(j)->getMeshElement(i);
+      elements.push_back(element);
     }
   }
 }
@@ -85,32 +87,22 @@ void Homology::_createCellComplex()
 
   std::vector<MElement*> domainElements;
   std::vector<MElement*> subdomainElements;
+  std::vector<MElement*> nondomainElements;
+  std::vector<MElement*> nonsubdomainElements;
   std::vector<MElement*> immuneElements;
-  for(unsigned int j=0; j < _domainEntities.size(); j++) {
-    for(unsigned int i=0; i < _domainEntities.at(j)->getNumMeshElements(); i++){
-      MElement* element = _domainEntities.at(j)->getMeshElement(i);
-      domainElements.push_back(element);
-    }
-  }
-  for(unsigned int j=0; j < _subdomainEntities.size(); j++) {
-    for(unsigned int i=0; i < _subdomainEntities.at(j)->getNumMeshElements();
-	i++){
-      MElement* element = _subdomainEntities.at(j)->getMeshElement(i);
-      subdomainElements.push_back(element);
-    }
-  }
-  for(unsigned int j=0; j < _immuneEntities.size(); j++) {
-    for(unsigned int i=0; i < _immuneEntities.at(j)->getNumMeshElements();
-	i++){
-      MElement* element = _immuneEntities.at(j)->getMeshElement(i);
-      immuneElements.push_back(element);
-    }
-  }
+
+  _getElements(_domainEntities, domainElements);
+  _getElements(_subdomainEntities, subdomainElements);
+  _getElements(_nondomainEntities, nondomainElements);
+  _getElements(_nonsubdomainEntities, nonsubdomainElements);
+  _getElements(_immuneEntities, immuneElements);
 
   if(_cellComplex != NULL) delete _cellComplex;
   _cellComplex =  new CellComplex(_model,
                                   domainElements,
                                   subdomainElements,
+                                  nondomainElements,
+                                  nonsubdomainElements,
                                   immuneElements,
                                   _saveOrig);
 
diff --git a/Geo/Homology.h b/Geo/Homology.h
index 16bf78964604f9368c937f8d5174cfd1c8142da3..a84124a951b49cc9a565d9c8e7b8965c4b61da02 100644
--- a/Geo/Homology.h
+++ b/Geo/Homology.h
@@ -30,10 +30,14 @@ class Homology
   // physical group IDs
   std::vector<int> _domain;
   std::vector<int> _subdomain;
+  std::vector<int> _nondomain;
+  std::vector<int> _nonsubdomain;
   std::vector<int> _imdomain;
   // corresponding geometrical entities
   std::vector<GEntity*> _domainEntities;
   std::vector<GEntity*> _subdomainEntities;
+  std::vector<GEntity*> _nondomainEntities;
+  std::vector<GEntity*> _nonsubdomainEntities;
   std::vector<GEntity*> _immuneEntities;
 
   // save original cell complex
@@ -61,6 +65,11 @@ class Homology
 
   typedef std::map<Cell*, int, Less_Cell>::iterator citer;
 
+  void _getEntities(const std::vector<int>& physicalGroups,
+                    std::vector<GEntity*>& entities);
+  void _getElements(const std::vector<GEntity*>& entities,
+                    std::vector<MElement*>& elements);
+
   // create a string describing the generator
   std::string _getDomainString(const std::vector<int>& domain,
                                const std::vector<int>& subdomain);
diff --git a/doc/texinfo/gmsh.texi b/doc/texinfo/gmsh.texi
index d938c021a78d6a50831091e1516556ca1f8b799e..86018f0c08c13e2fd69167d5ad68665137356a56 100644
--- a/doc/texinfo/gmsh.texi
+++ b/doc/texinfo/gmsh.texi
@@ -2525,6 +2525,7 @@ Show the entities listed in @var{expression-list}, if
 Show the entity @var{char-expression}, if @code{General.VisibilityMode} is
 set to @code{0} or @code{1} (@var{char-expression} can for example be
 @code{"*"}).
+
 @end ftable
 
 @c -------------------------------------------------------------------------
@@ -3023,6 +3024,20 @@ Shows the mesh of the entity @var{char-expression}, if
 Sets number of elliptic smoothing steps for the surfaces listed in
 @var{expression-list} (smoothing only applies to transfinite meshes at
 the moment).
+
+@item Homology @{ @{ @var{expression-list} @}, @{ @var{expression-list} @} @};
+Compute a basis representation for homology spaces after a mesh has
+been generated. The first @var{expression-list} is a list of physical
+groups that constitute the computation domain. The second
+@var{expression-list} is a list of physical groups that constitute the
+relative subdomain of relative homology computation; if empty,
+absolute homology is computed. Resulting basis representation chains
+are stored as physical groups in the mesh.
+
+@item Cohomology @{ @{ @var{expression-list} @}, @{ @var{expression-list} @} @};
+Similar to command @code{Homology}, but computes a basis representation
+for cohomology spaces instead.
+
 @end ftable
 
 @c -------------------------------------------------------------------------
diff --git a/tutorial/t14.geo b/tutorial/t14.geo
index c945f69ae5f1d5a0b40c1226956174ba4b784fe8..8af18545f5cbf1d7352bed0c487d035dfc82f378 100644
--- a/tutorial/t14.geo
+++ b/tutorial/t14.geo
@@ -1,19 +1,15 @@
-/*********************************************************************
+/********************************************************************* 
  *
  *  Gmsh tutorial 14
  *
- *  Homology computation
+ *  Homology and cohomology computation
  *
  *********************************************************************/
-
+ 
 // Homology computation in Gmsh finds representative chains of
-// (relative) homology spaces using a mesh of a model. Those
-// representatives generate the (relative) homology spaces of the
-// model.
-
-// The generator chains are stored in a given .msh-file as physical
-// groups, whose mesh elements are oriented such that their
-// coefficients are 1 in the generator chain.
+// (relative) (co)homology space bases using a mesh of a model. 
+// The representative basis chains are stored in the mesh as 
+// physical groups of Gmsh, one for each chain. 
 
 // Create an example geometry
 
@@ -40,7 +36,7 @@ Plane Surface(15) = {13, 14};
 Extrude {0, 0, h}{ Surface{15}; }
 
 // Create physical groups, which are used to define the domain of the
-// homology computation and the subdomain of the relative homology
+// (co)homology computation and the subdomain of the relative (co)homology
 // computation.
 
 // Whole domain
@@ -60,17 +56,20 @@ Physical Surface(80) = bnd[];
 bnd[] -= {36, 44, 52, 60};
 Physical Surface(75) = bnd[];
 
-// Find generators of relative homology spaces of the domain modulo
-// the four terminals.
+// Find bases for relative homology spaces of 
+// the domain modulo the four terminals.
 Homology {{1}, {70, 71, 72, 73}};
 
-// Find the corresponding thick cuts
-Cohomology {{1}, {70, 71, 72, 73}};
-
-// Find the corresponding thin cuts, generators of relative homology
-// spaces modulo the non-terminal domain surface.
+// Find homology space bases isomorphic to the previous bases: 
+// homology spaces modulo the non-terminal domain surface,
+// a.k.a the thin cuts.
 Homology {{1}, {75}};
 
+// Find cohomology space bases isomorphic to the previous bases: 
+// cohomology spaces of the domain modulo the four terminals,
+// a.k.a the thick cuts.
+Cohomology {{1}, {70, 71, 72, 73}};
+
 // More examples:
 //  Homology {1};
 //  Homology;