Skip to content
Snippets Groups Projects
Homology.cpp 11.4 KiB
Newer Older
Christophe Geuzaine's avatar
Christophe Geuzaine committed
// Gmsh - Copyright (C) 1997-2010 C. Geuzaine, J.-F. Remacle
Matti Pellika's avatar
Matti Pellika committed
//
// 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>.
Matti Pellika's avatar
Matti Pellika committed
 

#include "Homology.h"
#include "ChainComplex.h"
Matti Pellika's avatar
 
Matti Pellika committed
#include "OS.h"
Matti Pellika's avatar
Matti Pellika committed

Matti Pellika's avatar
 
Matti Pellika committed
#if defined(HAVE_KBIPACK)
Matti Pellika's avatar
Matti Pellika committed
Homology::Homology(GModel* model, std::vector<int> physicalDomain, 
		   std::vector<int> physicalSubdomain)
{ 
  _model = model; 
  _domain = physicalDomain;
  _subdomain = physicalSubdomain;
  
Matti Pellika's avatar
Matti Pellika committed
  Msg::Info("Creating a Cell Complex...");
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::StatusBar(1, false, "Cell Complex...");
  Msg::StatusBar(2, false, "");
Matti Pellika's avatar
 
Matti Pellika committed
  double t1 = Cpu();
Matti Pellika's avatar
Matti Pellika committed
  
  std::map<int, std::vector<GEntity*> > groups[4];
  model->getPhysicalGroups(groups);
  
  std::map<int, std::vector<GEntity*> >::iterator it;
  std::vector<GEntity*> domainEntities;
  std::vector<GEntity*> subdomainEntities;
    
  for(unsigned int i = 0; i < physicalDomain.size(); i++){
Matti Pellika's avatar
Matti Pellika committed
    for(int j = 0; j < 4; j++){
      it = groups[j].find(physicalDomain.at(i));
      if(it != groups[j].end()){
        std::vector<GEntity*> physicalGroup = (*it).second;
        for(unsigned int k = 0; k < physicalGroup.size(); k++){
Matti Pellika's avatar
Matti Pellika committed
          domainEntities.push_back(physicalGroup.at(k));
        }
      }
    }
  }
  for(unsigned int i = 0; i < physicalSubdomain.size(); i++){           
Matti Pellika's avatar
Matti Pellika committed
    for(int j = 0; j < 4; j++){
      it = groups[j].find(physicalSubdomain.at(i));
      if(it != groups[j].end()){
        std::vector<GEntity*> physicalGroup = (*it).second;
        for(unsigned int k = 0; k < physicalGroup.size(); k++){
Matti Pellika's avatar
Matti Pellika committed
          subdomainEntities.push_back(physicalGroup.at(k));
        }
        
      }
    }
  }
  
  if(domainEntities.empty()) Msg::Warning("Domain is empty.");
  if(subdomainEntities.empty()) Msg::Info("Subdomain is empty.");
  
  
  _cellComplex =  new CellComplex(domainEntities, subdomainEntities);
  
  if(_cellComplex->getSize(0) == 0){ 
    Msg::Error("Cell Complex is empty!");
    Msg::Error("Check the domain & the mesh.");
    return;
  }
Matti Pellika's avatar
 
Matti Pellika committed
  double t2 = Cpu();
  Msg::Info("Cell Complex complete (%g s).", t2 - t1);
Matti Pellika's avatar
Matti Pellika committed
  Msg::Info("%d volumes, %d faces, %d edges and %d vertices.",
Matti Pellika's avatar
Matti Pellika committed
            _cellComplex->getSize(3), _cellComplex->getSize(2), 
	    _cellComplex->getSize(1), _cellComplex->getSize(0));
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::StatusBar(2, false, "%d V, %d F, %d E, %d V.",
Matti Pellika's avatar
Matti Pellika committed
		 _cellComplex->getSize(3), _cellComplex->getSize(2), 
		 _cellComplex->getSize(1), _cellComplex->getSize(0));          
Matti Pellika's avatar
Matti Pellika committed
  
}
Homology::~Homology(){ 
  delete _cellComplex; 
    for(int i = 0; i < 4; i++) {
      for(int j = 0; j < _generators[i].size(); j++){
        Chain* chain = _generators[i].at(j);
        //_model->deletePhysicalGroup(chain->getDim(), chain->getNum());
        delete chain;
    }
  }
}
Matti Pellika's avatar
Matti Pellika committed

void Homology::findGenerators(std::string fileName)
{
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::Info("Reducing the Cell Complex...");
  Msg::StatusBar(1, false, "Reducing...");
Matti Pellika's avatar
 
Matti Pellika committed
  double t1 = Cpu();
Matti Pellika's avatar
Matti Pellika committed

  int omitted = _cellComplex->reduceComplex();
Matti Pellika's avatar
 
Matti Pellika committed
  
  _cellComplex->combine(3);
  _cellComplex->reduction(2);
  _cellComplex->combine(2);
  _cellComplex->reduction(1);
  _cellComplex->combine(1);
  
Matti Pellika's avatar
Matti Pellika committed
  _cellComplex->checkCoherence();
Matti Pellika's avatar
 
Matti Pellika committed
  
Matti Pellika's avatar
 
Matti Pellika committed
  double t2 = Cpu();
  Msg::Info("Cell Complex reduction complete (%g s).", t2 - t1);
Matti Pellika's avatar
Matti Pellika committed
  Msg::Info("%d volumes, %d faces, %d edges and %d vertices.",
Matti Pellika's avatar
Matti Pellika committed
            _cellComplex->getSize(3), _cellComplex->getSize(2), 
	    _cellComplex->getSize(1), _cellComplex->getSize(0));
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::StatusBar(2, false, "%d V, %d F, %d E, %d N.",
Matti Pellika's avatar
Matti Pellika committed
		 _cellComplex->getSize(3), _cellComplex->getSize(2), 
		 _cellComplex->getSize(1), _cellComplex->getSize(0));
Matti Pellika's avatar
 
Matti Pellika committed
  
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::Info("Computing homology spaces...");
  Msg::StatusBar(1, false, "Computing...");
Matti Pellika's avatar
 
Matti Pellika committed
  t1 = Cpu();
Matti Pellika's avatar
Matti Pellika committed
  ChainComplex* chains = new ChainComplex(_cellComplex);
  chains->computeHomology();
Matti Pellika's avatar
 
Matti Pellika committed
  t2 = Cpu();
  Msg::Info("Homology Computation complete (%g s).", t2 - t1);
Matti Pellika's avatar
 
Matti Pellika committed
  int HRank[4];
Matti Pellika's avatar
Matti Pellika committed
  for(int j = 0; j < 4; j++){
Matti Pellika's avatar
 
Matti Pellika committed
    HRank[j] = 0;
Matti Pellika's avatar
Matti Pellika committed
    std::string dimension = "";
Matti Pellika's avatar
 
Matti Pellika committed
    convert(j, dimension);
Matti Pellika's avatar
Matti Pellika committed
    for(int i = 1; i <= chains->getBasisSize(j); i++){
      
Matti Pellika's avatar
Matti Pellika committed
      std::string generator = "";
Matti Pellika's avatar
Matti Pellika committed
      convert(i, generator);
      
      std::string name = "H" + dimension + getDomainString()  + generator;
Matti Pellika's avatar
Matti Pellika committed
      Chain* chain = new Chain(_cellComplex->getCells(j), 
			       chains->getCoeffVector(j,i), 
			       _cellComplex, _model, name, 
			       chains->getTorsion(j,i));
Matti Pellika's avatar
Matti Pellika committed
      /*t1 = Cpu();
Matti Pellika's avatar
Matti Pellika committed
      chain->smoothenChain();
Matti Pellika's avatar
Matti Pellika committed
      Msg::Info("Smoothened H%d %d from %d cells to %d cells (%g s).", 
Matti Pellika's avatar
Matti Pellika committed
      j, i, start, chain->getSize(), t2 - t1);*/
Matti Pellika's avatar
 
Matti Pellika committed
      if(chain->getSize() != 0) {
        HRank[j] = HRank[j] + 1;
Matti Pellika's avatar
Matti Pellika committed
        if(chain->getTorsion() != 1){
	  Msg::Warning("H%d %d has torsion coefficient %d!", 
		       j, i, chain->getTorsion());
	}
Matti Pellika's avatar
 
Matti Pellika committed
      }
      _generators[j].push_back(chain);
Matti Pellika's avatar
Matti Pellika committed
    }
Matti Pellika's avatar
 
Matti Pellika committed
    if(j == _cellComplex->getDim() && _cellComplex->getNumOmitted() > 0){
      for(int i = 0; i < _cellComplex->getNumOmitted(); i++){
        std::string generator;
        convert(i+1, generator);
        std::string name = "H" + dimension + getDomainString() + generator;
Matti Pellika's avatar
 
Matti Pellika committed
        std::vector<int> coeffs (_cellComplex->getOmitted(i).size(),1);
Matti Pellika's avatar
Matti Pellika committed
        Chain* chain = new Chain(_cellComplex->getOmitted(i), coeffs, 
				 _cellComplex, _model, name, 1);
Matti Pellika's avatar
 
Matti Pellika committed
        if(chain->getSize() != 0) HRank[j] = HRank[j] + 1;
        _generators[j].push_back(chain);
Matti Pellika's avatar
 
Matti Pellika committed
      }
    }
Matti Pellika's avatar
Matti Pellika committed
  }
Matti Pellika's avatar
 
Matti Pellika committed
  
  createPViews();
  if(fileName != "") writeGeneratorsMSH(fileName);
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::Info("Ranks of homology spaces for primal cell complex:");
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::Info("H0 = %d", HRank[0]);
  Msg::Info("H1 = %d", HRank[1]);
  Msg::Info("H2 = %d", HRank[2]);
  Msg::Info("H3 = %d", HRank[3]);
Matti Pellika's avatar
 
Matti Pellika committed
  if(omitted != 0) Msg::Info("The computation of generators in the highest dimension was omitted.");
Matti Pellika's avatar
 
Matti Pellika committed
  
Matti Pellika's avatar
Matti Pellika committed
  delete chains;
  
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::Debug("H0 = %d \n", HRank[0]);
  Msg::Debug("H1 = %d \n", HRank[1]);
  Msg::Debug("H2 = %d \n", HRank[2]);
  Msg::Debug("H3 = %d \n", HRank[3]);

  Msg::StatusBar(1, false, "Homology");
Matti Pellika's avatar
Matti Pellika committed
  Msg::StatusBar(2, false, "H0: %d, H1: %d, H2: %d, H3: %d.", 
		 HRank[0], HRank[1], HRank[2], HRank[3]);
Matti Pellika's avatar
 
Matti Pellika committed

Matti Pellika's avatar
Matti Pellika committed
  return;
}

void Homology::findDualGenerators(std::string fileName)
{ 
Matti Pellika's avatar
Matti Pellika committed
  Msg::Info("Reducing Cell Complex...");
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::StatusBar(1, false, "Reducing...");
Matti Pellika's avatar
 
Matti Pellika committed
  double t1 = Cpu();
  int omitted = _cellComplex->coreduceComplex();
Matti Pellika's avatar
 
Matti Pellika committed
  
  _cellComplex->coreduction(1);
  _cellComplex->coreduction(2);
  _cellComplex->coreduction(3);
Matti Pellika's avatar
 
Matti Pellika committed
  _cellComplex->checkCoherence();
Matti Pellika's avatar
 
Matti Pellika committed
  double t2 = Cpu();
  Msg::Info("Cell Complex reduction complete (%g s).", t2 - t1);
Matti Pellika's avatar
Matti Pellika committed
  Msg::Info("%d volumes, %d faces, %d edges and %d vertices.",
Matti Pellika's avatar
Matti Pellika committed
            _cellComplex->getSize(3), _cellComplex->getSize(2), 
	    _cellComplex->getSize(1), _cellComplex->getSize(0));
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::StatusBar(2, false, "%d V, %d F, %d E, %d N.",
Matti Pellika's avatar
Matti Pellika committed
		 _cellComplex->getSize(3), _cellComplex->getSize(2), 
		 _cellComplex->getSize(1), _cellComplex->getSize(0));
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::Info("Computing homology spaces...");
  Msg::StatusBar(1, false, "Computing...");
Matti Pellika's avatar
 
Matti Pellika committed
  t1 = Cpu();
Matti Pellika's avatar
Matti Pellika committed
  ChainComplex* chains = new ChainComplex(_cellComplex);
  chains->transposeHMatrices();
  chains->computeHomology(true);
Matti Pellika's avatar
 
Matti Pellika committed
  t2 = Cpu();
  Msg::Info("Homology Computation complete (%g s).", t2- t1);
Matti Pellika's avatar
Matti Pellika committed
  
Matti Pellika's avatar
 
Matti Pellika committed
  int dim = _cellComplex->getDim();
Matti Pellika's avatar
 
Matti Pellika committed
  int HRank[4];
Matti Pellika's avatar
 
Matti Pellika committed
  for(int i = 0; i < 4; i++) HRank[i] = 0;
Matti Pellika's avatar
Matti Pellika committed
  for(int j = 3; j > -1; j--){
Matti Pellika's avatar
Matti Pellika committed
    std::string dimension = "";
Matti Pellika's avatar
 
Matti Pellika committed
    convert(dim-j, dimension);

Matti Pellika's avatar
Matti Pellika committed
    for(int i = 1; i <= chains->getBasisSize(j); i++){
      
Matti Pellika's avatar
Matti Pellika committed
      std::string generator = "";
Matti Pellika's avatar
Matti Pellika committed
      convert(i, generator);
      
      std::string name = "H" + dimension + "*" + getDomainString() + generator;
Matti Pellika's avatar
Matti Pellika committed
      Chain* chain = new Chain(_cellComplex->getCells(j), 
			       chains->getCoeffVector(j,i), _cellComplex, 
			       _model, name, chains->getTorsion(j,i));
      _generators[dim-j].push_back(chain);
Matti Pellika's avatar
 
Matti Pellika committed
      if(chain->getSize() != 0){
        HRank[dim-j] = HRank[dim-j] + 1;
Matti Pellika's avatar
Matti Pellika committed
        if(chain->getTorsion() != 1){ 
	  Msg::Warning("H%d* %d has torsion coefficient %d!", 
		       dim-j, i, chain->getTorsion());
	}
Matti Pellika's avatar
Matti Pellika committed
    }
Matti Pellika's avatar
 
Matti Pellika committed
    
    
    if(j == 0 && _cellComplex->getNumOmitted() > 0){
      for(int i = 0; i < _cellComplex->getNumOmitted(); i++){
        std::string generator;
        convert(i+1, generator);
Matti Pellika's avatar
Matti Pellika committed
        std::string name 
	  = "H" + dimension + "*" + getDomainString() + generator;
Matti Pellika's avatar
 
Matti Pellika committed
        std::vector<int> coeffs (_cellComplex->getOmitted(i).size(),1);
Matti Pellika's avatar
Matti Pellika committed
        Chain* chain = new Chain(_cellComplex->getOmitted(i), coeffs, 
				 _cellComplex, _model, name, 1);
        _generators[dim-j].push_back(chain);
Matti Pellika's avatar
 
Matti Pellika committed
        if(chain->getSize() != 0) HRank[dim-j] = HRank[dim-j] + 1;
      }
    }
    
    
Matti Pellika's avatar
Matti Pellika committed
  }
  createPViews();
  if(fileName != "") writeGeneratorsMSH(fileName);
  Msg::Info("Ranks of homology spaces for the dual cell complex:");
  Msg::Info("H0* = %d", HRank[0]);
  Msg::Info("H1* = %d", HRank[1]);
  Msg::Info("H2* = %d", HRank[2]);
  Msg::Info("H3* = %d", HRank[3]);
  if(omitted != 0) Msg::Info("The computation of %d highest dimension dual generators was omitted.", omitted);
Matti Pellika's avatar
 
Matti Pellika committed
  
Matti Pellika's avatar
Matti Pellika committed
  delete chains;
  
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::Debug("H0* = %d \n", HRank[0]);
  Msg::Debug("H1* = %d \n", HRank[1]);
  Msg::Debug("H2* = %d \n", HRank[2]);
  Msg::Debug("H3* = %d \n", HRank[3]);

  Msg::StatusBar(1, false, "Homology");
Matti Pellika's avatar
Matti Pellika committed
  Msg::StatusBar(2, false, "H0*: %d, H1*: %d, H2*: %d, H3*: %d.", 
		 HRank[0], HRank[1], HRank[2], HRank[3]);
Matti Pellika's avatar
 
Matti Pellika committed

Matti Pellika's avatar
Matti Pellika committed
}
Matti Pellika's avatar
 
Matti Pellika committed

void Homology::computeBettiNumbers()
{  
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::Info("Running coreduction...");
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::StatusBar(1, false, "Computing...");
Matti Pellika's avatar
 
Matti Pellika committed
  double t1 = Cpu();
  _cellComplex->computeBettiNumbers();
  double t2 = Cpu();
  Msg::Info("Betti number computation complete (%g s).", t2- t1);

  Msg::Info("H0 = %d", _cellComplex->getBettiNumber(0));
  Msg::Info("H1 = %d", _cellComplex->getBettiNumber(1));
  Msg::Info("H2 = %d", _cellComplex->getBettiNumber(2));
  Msg::Info("H3 = %d", _cellComplex->getBettiNumber(3));
Matti Pellika's avatar
 
Matti Pellika committed
  Msg::StatusBar(1, false, "Homology");
Matti Pellika's avatar
Matti Pellika committed
  Msg::StatusBar(2, false, "H0: %d, H1: %d, H2: %d, H3: %d.", 
		 _cellComplex->getBettiNumber(0), 
		 _cellComplex->getBettiNumber(1), 
		 _cellComplex->getBettiNumber(2), 
		 _cellComplex->getBettiNumber(3));
Matti Pellika's avatar
 
Matti Pellika committed
  return;
}
Matti Pellika's avatar
 
Matti Pellika committed

Matti Pellika's avatar
Matti Pellika committed
  _cellComplex->restoreComplex();
  for(int i = 0; i < 4; i++) _generators[i].clear();
}

std::string Homology::getDomainString() 
{
Matti Pellika's avatar
Matti Pellika committed
  std::string domainString = "({";
  for(unsigned int i = 0; i < _domain.size(); i++){
    std::string temp = "";
    convert(_domain.at(i),temp);
    domainString += temp;
    if (_domain.size()-1 > i){ 
      domainString += ", ";
    }
  }
  domainString += "}";
  
  if(!_subdomain.empty()){
    domainString += ", {";
Matti Pellika's avatar
 
Matti Pellika committed
       
Matti Pellika's avatar
Matti Pellika committed
    for(unsigned int i = 0; i < _subdomain.size(); i++){
      std::string temp = "";
      convert(_subdomain.at(i),temp);
      domainString += temp;
      if (_subdomain.size()-1 > i){
        domainString += ", ";
      }
    } 
    domainString += "}";
    
  }
  domainString += ") ";
  return domainString;
}

Matti Pellika's avatar
Matti Pellika committed
  for(int i = 0; i < 4; i++){
    for(int j = 0; j < _generators[i].size(); j++){
      Chain* chain = _generators[i].at(j);
      chain->createPView();
    }
  }
}

bool Homology::writeGeneratorsMSH(std::string fileName, bool binary)
{
Matti Pellika's avatar
Matti Pellika committed
  if(!_model->writeMSH(fileName, 2.0, binary)) return false;
  Msg::Info("Wrote homology computation results to %s.", fileName.c_str());
Matti Pellika's avatar
Matti Pellika committed
  Msg::Debug("Wrote homology computation results to %s. \n", 
	     fileName.c_str());  
Matti Pellika's avatar
Matti Pellika committed
  return true;
}

Matti Pellika's avatar
 
Matti Pellika committed
#endif