diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp index 46eb4b36c28e16b615a6940133aeaeb5dc6f627d..2eb31a86ac99368be821596280cc6da95fd2b598 100644 --- a/Geo/CellComplex.cpp +++ b/Geo/CellComplex.cpp @@ -103,10 +103,10 @@ CellComplex::CellComplex( std::vector<GEntity*> domain, std::vector<GEntity*> su for(int i = 0; i < 4; i++){ for(citer cit = firstCell(i); cit != lastCell(i); cit++){ Cell* cell = *cit; - cell->setTag(tag); + //cell->setTag(tag); tag++; } - _cells2[i] = _cells[i]; + //_cells2[i] = _cells[i]; _betti[i] = 0; if(getSize(i) > _dim) _dim = i; } @@ -127,7 +127,7 @@ void CellComplex::insert_cells(bool subdomain, bool boundary){ std::vector<MVertex*> vertices; std::pair<citer, bool> insertInfo; - + int tag = 1; // add highest dimensional cells for(unsigned int j=0; j < domain.size(); j++) { @@ -140,11 +140,34 @@ void CellComplex::insert_cells(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, 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, 0, subdomain, boundary); + // simplex types + if(type == MSH_LIN_2 || type == MSH_TRI_3 || type == MSH_TET_4 || type == MSH_LIN_3 || type == MSH_TRI_6 || + type == MSH_TET_10 || type == MSH_PNT || type == MSH_TRI_9 || type == MSH_TRI_10 || type == MSH_TRI_12 || + type == MSH_TRI_15 || type == MSH_TRI_15I || type == MSH_TRI_21 || type == MSH_LIN_4 || + type == MSH_LIN_5 || type == MSH_LIN_6 || type == MSH_TET_20 || type == MSH_TET_35 || type == MSH_TET_56 + || type == MSH_TET_34 || type == MSH_TET_52 ){ + if(dim == 3) cell = new ThreeSimplex(vertices, tag, subdomain, boundary); + else if(dim == 2) cell = new TwoSimplex(vertices, tag, subdomain, boundary); + else if(dim == 1) cell = new OneSimplex(vertices, tag, subdomain, boundary); + else cell = new ZeroSimplex(vertices, tag, subdomain, boundary); + } + else if(type == MSH_QUA_4 || type == MSH_QUA_8 || type == MSH_QUA_9){ + cell = new CQuadrangle(vertices, tag, subdomain, boundary); + } + /* + else if(type == MSH_HEX_8 || type == MSH_HEX_27 || type == MSH_HEX_20){ + cell = new CHexahedron(vertices, tag, subdomain, boundary); + } + else if(type == MSH_PRI_6 || type == MSH_PRI_18 || type == MSH_PRI_15){ + cell = new CPrism(vertices, tag, subdomain, boundary); + } + else if(type == MSH_PYR_5 || type == MSH_PYR_14 || type == MSH_PYR_13){ + cell = new CPyramid(vertices, tag, subdomain, boundary); + }*/ + else printf("Error: mesh element %d not implemented yet! \n", type); + tag++; insertInfo = _cells[dim].insert(cell); if(!insertInfo.second) delete cell; } @@ -158,9 +181,14 @@ void CellComplex::insert_cells(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, 0, subdomain, boundary); - else if(dim == 2) newCell = new OneSimplex(vertices, 0, subdomain, boundary); - else if(dim == 1) newCell = new ZeroSimplex(vertices, 0, subdomain, boundary); + if(dim == 3){ + if(vertices.size() == 3) newCell = new TwoSimplex(vertices, tag, subdomain, boundary); + else if(vertices.size() == 4) newCell = new CQuadrangle(vertices, tag, subdomain, boundary); + else printf("Error: invalid face! \n"); + } + else if(dim == 2) newCell = new OneSimplex(vertices, tag, subdomain, boundary); + else if(dim == 1) newCell = new ZeroSimplex(vertices, tag, subdomain, boundary); + tag++; insertInfo = _cells[dim-1].insert(newCell); if(!insertInfo.second){ delete newCell; @@ -186,7 +214,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)->getNum())) ) return 0; @@ -202,11 +230,11 @@ int Simplex::kappa(Cell* tau) const{ return value; } +*/ -/* -int Simplex::kappa(Cell* tau) const{ +int Cell::kappa(Cell* tau) const{ for(int i=0; i < tau->getNumVertices(); i++){ - if( !(this->hasVertex(tau->getVertex(i))) ) return 0; + if( !(this->hasVertex(tau->getVertex(i)->getNum())) ) return 0; } if(this->getDim() - tau->getDim() != 1) return 0; @@ -219,6 +247,8 @@ int Simplex::kappa(Cell* tau) const{ this->getFacetVertices(i, v); value = -1; + if(v.size() != vTau.size()) printf("Error: invalid facet!"); + do { value = value*-1; if(v == vTau) return value; @@ -238,11 +268,12 @@ int Simplex::kappa(Cell* tau) const{ 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( !(this->hasVertex(tau->getVertex(i)->getNum())) ) return 0; } if(tau->getDim() != 0) return 0; @@ -251,9 +282,9 @@ int OneSimplex::kappa(Cell* tau) const{ else return 1; } -*/ -void CellComplex::removeCell(Cell* cell){ + +void CellComplex::removeCell(Cell* cell, bool other){ std::list< std::pair< int, Cell*> > coboundary = cell->getOrientedCoboundary(); std::list< std::pair< int, Cell*> > boundary = cell->getOrientedBoundary(); @@ -264,7 +295,7 @@ void CellComplex::removeCell(Cell* cell){ //for(std::list<Cell*>::iterator it = coboundary.begin(); it != coboundary.end(); it++){ Cell* cbdCell = (*it).second; //Cell* cbdCell = *it; - cbdCell->removeBoundaryCell(cell); + cbdCell->removeBoundaryCell(cell, other); } @@ -272,7 +303,7 @@ void CellComplex::removeCell(Cell* cell){ //for(std::list<Cell*>::iterator it = boundary.begin(); it != boundary.end(); it++){ Cell* bdCell = (*it).second; //Cell* bdCell = *it; - bdCell->removeCoboundaryCell(cell); + bdCell->removeCoboundaryCell(cell, other); } _cells[cell->getDim()].erase(cell); @@ -317,14 +348,18 @@ int CellComplex::coreduction(Cell* generator){ s = Q.front(); Q.pop(); removeCellQset(s, Qset); - 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, Qset); removeCell(bd_s.front()); coreductions++; + + _trash.push_back(s); + _trash.push_back(bd_s.front()); + } else if(bd_s.empty()){ cbd_c = s->getCoboundary(); @@ -344,24 +379,32 @@ int CellComplex::reduction(int dim){ bool reduced = true; while (reduced){ + reduced = false; - for(citer cit = firstCell(dim-1); cit != lastCell(dim-1); cit++){ + citer cit = firstCell(dim-1); + while(cit != lastCell(dim-1)){ + Cell* cell = *cit; cbd_c = cell->getCoboundary(); if( cbd_c.size() == 1 && inSameDomain(cell, cbd_c.front()) ){ - + ++cit; removeCell(cbd_c.front()); removeCell(cell); + _trash.push_back(cell); + _trash.push_back(cbd_c.front()); + count++; reduced = true; } + if(getSize(dim) == 0 || getSize(dim-1) == 0) break; + cit++; } - + } - + return count; } /* @@ -455,16 +498,14 @@ int CellComplex::reduceComplex(int omit){ printf("Cell complex before reduction: %d volumes, %d faces, %d edges and %d vertices.\n", getSize(3), getSize(2), getSize(1), getSize(0)); - + int count = 0; for(int i = 3; i > 0; i--) count = count + reduction(i); - - int omitted = 0; if(omit > getDim()) omit = getDim(); - if(count == 0 && omit > 0){ + //if(count == 0 && omit > 0){ CellComplex::removeSubdomain(); @@ -472,7 +513,7 @@ int CellComplex::reduceComplex(int omit){ std::set<Cell*, Less_Cell> generatorCells; while (getSize(getDim()) != 0){ - + citer cit = firstCell(getDim()); Cell* cell = *cit; @@ -494,14 +535,13 @@ int CellComplex::reduceComplex(int omit){ cell->clearCoboundary(); _cells[cell->getDim()].insert(cell); } - - } + //} double t2 = Cpu(); printf("Cell complex after reduction: %d volumes, %d faces, %d edges and %d vertices (%g s).\n", getSize(3), getSize(2), getSize(1), getSize(0), t2 - t1); - + return 0; } @@ -512,6 +552,7 @@ void CellComplex::removeSubdomain(){ for(citer cit = firstCell(i); cit != lastCell(i); cit++){ Cell* cell = *cit; if(cell->inSubdomain()) { + //++cit; removeCell(cell); cit = firstCell(i); } @@ -543,7 +584,7 @@ int CellComplex::coreduceComplex(int omit){ } int omitted = 0; - if(count == 0 && omit > 0){ + //if(count == 0 && omit > 0){ //if(omit > getDim()) omit = getDim(); //for(int i = 0; i < omit; i++){ std::set<Cell*, Less_Cell> generatorCells; @@ -551,9 +592,8 @@ int CellComplex::coreduceComplex(int omit){ citer cit = firstCell(0); Cell* cell = *cit; generatorCells.insert(cell); - removeCell(cell); - coreduceComplex(0); - //coreduction(cell); + removeCell(cell, false); + coreduction(cell); omitted++; } @@ -564,7 +604,7 @@ int CellComplex::coreduceComplex(int omit){ _cells[0].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)); @@ -575,11 +615,10 @@ int CellComplex::coreduceComplex(int omit){ void CellComplex::computeBettiNumbers(){ for(int i = 0; i < 4; i++){ + _betti[i] = 0; printf("Betti number computation process: step %d of 4 \n", i+1); - - + while (getSize(i) != 0){ - citer cit = firstCell(i); Cell* cell = *cit; while(!cell->inSubdomain() && cit != lastCell(i)){ @@ -587,11 +626,9 @@ void CellComplex::computeBettiNumbers(){ cit++; } if(!cell->inSubdomain()) _betti[i] = _betti[i] + 1; - removeCell(cell); - + removeCell(cell, false); coreduction(cell); } - } printf("Cell complex Betti numbers: \n b0 = %d \n b1 = %d \n b2 = %d \n b3 = %d \n", getBettiNumber(0), getBettiNumber(1), getBettiNumber(2), getBettiNumber(3)); @@ -636,6 +673,7 @@ int CellComplex::cocombine(int dim){ Cell* c2 = bd_c.back().second; removeCell(s); + _trash.push_back(s); cbd_c = c1->getCoboundary(); enqueueCells(cbd_c, Q, Qset); @@ -697,7 +735,8 @@ int CellComplex::combine(int dim){ Cell* c2 = cbd_c.back().second; removeCell(s); - + _trash.push_back(s); + bd_c = c1->getBoundary(); enqueueCells(bd_c, Q, Qset); bd_c = c2->getBoundary(); @@ -840,49 +879,53 @@ int CellComplex::writeComplexMSH(const std::string &name){ fprintf(fp, "%d\n", count); - int physical = 0; + int partition = 0; for(citer cit = firstCell(0); cit != lastCell(0); cit++) { Cell* vertex = *cit; - if(vertex->inSubdomain()) physical = 3; - else if(vertex->onDomainBoundary()) physical = 2; - else physical = 1; - fprintf(fp, "%d %d %d %d %d %d %d\n", vertex->getNum(), 15, 3, 0, 0, physical, vertex->getVertex(0)->getNum()); + if(vertex->inSubdomain()) partition = 3; + else if(vertex->onDomainBoundary()) partition = 2; + else partition = 1; + fprintf(fp, "%d %d %d %d %d %d %d\n", vertex->getNum(), 15, 3, 0, 0, partition, vertex->getVertex(0)->getNum()); } 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; + if(edge->inSubdomain()) partition = 3; + else if(edge->onDomainBoundary()) partition = 2; + else partition = 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->getNum(), 1, 3, 0, 0, physical, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum()); + fprintf(fp, "%d %d %d %d %d %d %d %d\n", cell->getNum(), 1, 3, 0, 0, partition, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum()); } } for(citer cit = firstCell(2); cit != lastCell(2); cit++) { Cell* face = *cit; - if(face->inSubdomain()) physical = 3; - else if(face->onDomainBoundary()) physical = 2; - else physical = 1; + if(face->inSubdomain()) partition = 3; + else if(face->onDomainBoundary()) partition = 2; + else partition = 1; 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->getNum(), 2, 3, 0, 0, physical, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum(), cell->getVertex(2)->getNum()); + if(cell->getNumVertices() == 3) fprintf(fp, "%d %d %d %d %d %d %d %d %d\n", cell->getNum(), 2, 3, 0, 0, partition, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum(), cell->getVertex(2)->getNum()); + else if (cell->getNumVertices() == 4) fprintf(fp, "%d %d %d %d %d %d %d %d %d %d\n", cell->getNum(), 3, 3, 0, 0, partition, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum(), cell->getVertex(2)->getNum(), cell->getVertex(3)->getNum()); } } 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; + if(volume->inSubdomain()) partition = 3; + else if(volume->onDomainBoundary()) partition = 2; + else partition = 1; 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->getNum(), 4, 3, 0, 0, physical, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum(), cell->getVertex(2)->getNum(), cell->getVertex(3)->getNum()); + if(cell->getNumVertices() == 4) fprintf(fp, "%d %d %d %d %d %d %d %d %d %d\n", cell->getNum(), 4, 3, 0, 0, partition, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum(), cell->getVertex(2)->getNum(), cell->getVertex(3)->getNum()); + if(cell->getNumVertices() == 8) fprintf(fp, "%d %d %d %d %d %d %d %d %d %d %d %d %d %d\n", cell->getNum(), 12, 3, 0, 0, partition, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum(), cell->getVertex(2)->getNum(), cell->getVertex(3)->getNum(), cell->getVertex(4)->getNum(), cell->getVertex(5)->getNum(), cell->getVertex(6)->getNum(), cell->getVertex(7)->getNum() ); + if(cell->getNumVertices() == 6) fprintf(fp, "%d %d %d %d %d %d %d %d %d %d %d %d\n", cell->getNum(), 13, 3, 0, 0, partition, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum(), cell->getVertex(2)->getNum(), cell->getVertex(3)->getNum(),cell->getVertex(4)->getNum(), cell->getVertex(5)->getNum()); + if(cell->getNumVertices() == 5) fprintf(fp, "%d %d %d %d %d %d %d %d %d %d %d\n", cell->getNum(), 14, 3, 0, 0, partition, cell->getVertex(0)->getNum(), cell->getVertex(1)->getNum(), cell->getVertex(2)->getNum(), cell->getVertex(3)->getNum(), cell->getVertex(4)->getNum()); } } diff --git a/Geo/CellComplex.h b/Geo/CellComplex.h index ad55b013c9efe8050472a722058712f4a88dbff1..3f6bdd09830136854a19ee3c742f534840b018eb 100644 --- a/Geo/CellComplex.h +++ b/Geo/CellComplex.h @@ -18,6 +18,10 @@ #include "MPoint.h" #include "MLine.h" #include "MTriangle.h" +#include "MQuadrangle.h" +#include "MHexahedron.h" +#include "MPrism.h" +#include "MPyramid.h" #include "MTetrahedron.h" #include "GModel.h" #include "GEntity.h" @@ -58,9 +62,10 @@ class Cell public: Cell(){ - _bdSize = 0; _cbdSize = 0; + _combined = false; + _index = 0; } virtual ~Cell(){} @@ -80,7 +85,7 @@ class Cell // returns 1 or -1 if lower dimensional cell tau is on the boundary of this cell // otherwise returns 0 // implementation will vary depending on cell type - virtual int kappa(Cell* tau) const = 0; + //virtual int kappa(Cell* tau) const = 0; // true if this cell has given vertex virtual bool hasVertex(int vertex) const = 0; @@ -233,7 +238,7 @@ class Cell virtual int getNumCells() {return 1;} bool operator==(const Cell& c2){ - + if(this->getNumVertices() != c2.getNumVertices()){ return false; } @@ -243,12 +248,14 @@ class Cell } } return true; - + + //return (this->getTag() == c2.getTag()); } bool operator<(const Cell& c2) const { + if(this->getNumVertices() != c2.getNumVertices()){ return (this->getNumVertices() < c2.getNumVertices()); } @@ -257,8 +264,11 @@ class Cell else if (this->getSortedVertex(i) > c2.getSortedVertex(i)) return false; } return false; + + //return (this->getTag() < c2.getTag()); } + virtual int kappa(Cell* tau) const; }; @@ -268,15 +278,12 @@ class Simplex : public Cell { public: - Simplex() : Cell() { - _combined = false; - _index = 0; - } + Simplex() : Cell() {} ~Simplex(){} // kappa for simplices // checks whether lower dimensional simplex tau is on the boundary of this cell - virtual int kappa(Cell* tau) const; + //virtual int kappa(Cell* tau) const; }; @@ -348,7 +355,7 @@ class OneSimplex : public Simplex, public MLine v[0] = _v[num]; } - //int kappa(Cell* tau) const; + int kappa(Cell* tau) const; void printCell() const { printf("Cell dimension: %d, Vertices: %d %d, in subdomain: %d \n", getDim(), _v[0]->getNum(), _v[1]->getNum(), _inSubdomain); } }; @@ -397,7 +404,53 @@ class TwoSimplex : public Simplex, public MTriangle void printCell() const { printf("Cell dimension: %d, Vertices: %d %d %d, in subdomain: %d\n", getDim(), _v[0]->getNum(), _v[1]->getNum(), _v[2]->getNum(), _inSubdomain); } }; -// Three simplex cell type. +// Quadrangle cell type. +class CQuadrangle : public Cell, public MQuadrangle +{ + private: + + int _vs[4]; + + public: + + CQuadrangle(std::vector<MVertex*> v, int tag=0, bool subdomain=false, bool boundary=false, int num=0, int part=0) + : MQuadrangle(v, num, part){ + _tag = tag; + _inSubdomain = subdomain; + _onDomainBoundary = boundary; + _vs[0] = v.at(0)->getNum(); + _vs[1] = v.at(1)->getNum(); + _vs[2] = v.at(2)->getNum(); + _vs[3] = v.at(3)->getNum(); + std::sort(_vs, _vs+3); + } + + ~CQuadrangle(){} + + int getDim() const { return 2; } + int getNum() { return MQuadrangle::getNum(); } + int getNumVertices() const { return 4; } + int getNumFacets() const { return 4; } + MVertex* getVertex(int vertex) const {return _v[vertex]; } + int getSortedVertex(int vertex) const {return _vs[vertex]; } + bool hasVertex(int vertex) const {return + (_v[0]->getNum() == vertex || _v[1]->getNum() == vertex || _v[2]->getNum() == vertex || _v[3]->getNum() == vertex); } + + std::vector<MVertex*> getVertexVector() const { + return std::vector<MVertex*>(_v, _v + sizeof(_v)/sizeof(MVertex*) ); } + std::vector<int> getSortedVertexVector() const { + return std::vector<int>(_vs, _vs + sizeof(_vs)/sizeof(int) ); + } + + void getFacetVertices(const int num, std::vector<MVertex*> &v) const { + MQuadrangle::getEdgeVertices(num, v); + } + + void printCell() const { printf("Cell dimension: %d, Vertices: %d %d %d, in subdomain: %d\n", getDim(), _v[0]->getNum(), _v[1]->getNum(), _v[2]->getNum(), _v[3]->getNum(), _inSubdomain); } +}; + + +// ThreeSimplex cell type. class ThreeSimplex : public Simplex, public MTetrahedron { private: @@ -438,6 +491,142 @@ class ThreeSimplex : public Simplex, public MTetrahedron virtual void printCell() const { printf("Cell dimension: %d, Vertices: %d %d %d %d, in subdomain: %d \n", getDim(), _v[0]->getNum(), _v[1]->getNum(), _v[2]->getNum(), _v[3]->getNum(), _inSubdomain); } }; +// Hexahedron cell type. +class CHexahedron : public Cell, public MHexahedron +{ + private: + int _vs[8]; + + public: + CHexahedron(std::vector<MVertex*> v, int tag=0, bool subdomain=false, bool boundary=false, int num=0, int part=0) + : MHexahedron(v, num, part){ + _tag = tag; + _inSubdomain = subdomain; + _onDomainBoundary = boundary; + _vs[0] = v.at(0)->getNum(); + _vs[1] = v.at(1)->getNum(); + _vs[2] = v.at(2)->getNum(); + _vs[3] = v.at(3)->getNum(); + _vs[4] = v.at(4)->getNum(); + _vs[5] = v.at(5)->getNum(); + _vs[6] = v.at(6)->getNum(); + _vs[7] = v.at(7)->getNum(); + std::sort(_vs, _vs+8); + } + + ~CHexahedron(){} + + int getDim() const { return 3; } + int getNum() { return MHexahedron::getNum(); } + int getNumVertices() const { return 8; } + int getNumFacets() const { return 6; } + MVertex* getVertex(int vertex) const {return _v[vertex]; } + int getSortedVertex(int vertex) const {return _vs[vertex]; } + bool hasVertex(int vertex) const {return + (_v[0]->getNum() == vertex || _v[1]->getNum() == vertex || _v[2]->getNum() == vertex || _v[3]->getNum() == vertex || + _v[4]->getNum() == vertex || _v[5]->getNum() == vertex || _v[6]->getNum() == vertex || _v[7]->getNum() == vertex ); } + std::vector<MVertex*> getVertexVector() const { + return std::vector<MVertex*>(_v, _v + sizeof(_v)/sizeof(MVertex*) ); } + std::vector<int> getSortedVertexVector() const { + return std::vector<int>(_vs, _vs + sizeof(_vs)/sizeof(int) ); } + + void getFacetVertices(const int num, std::vector<MVertex*> &v) const { + MHexahedron::getFaceVertices(num, v); + } + + virtual void printCell() const { printf("Cell dimension: %d, Vertices: %d %d %d %d %d %d %d %d, in subdomain: %d \n", getDim(), _v[0]->getNum(), _v[1]->getNum(), _v[2]->getNum(), _v[3]->getNum(), _v[4]->getNum(), _v[5]->getNum(), _v[6]->getNum(), _v[7]->getNum(), _inSubdomain); } +}; + + +// Prism cell type. +class CPrism : public Cell, public MPrism +{ + private: + int _vs[6]; + + public: + CPrism(std::vector<MVertex*> v, int tag=0, bool subdomain=false, bool boundary=false, int num=0, int part=0) + : MPrism(v, num, part){ + _tag = tag; + _inSubdomain = subdomain; + _onDomainBoundary = boundary; + _vs[0] = v.at(0)->getNum(); + _vs[1] = v.at(1)->getNum(); + _vs[2] = v.at(2)->getNum(); + _vs[3] = v.at(3)->getNum(); + _vs[4] = v.at(4)->getNum(); + _vs[5] = v.at(5)->getNum(); + std::sort(_vs, _vs+6); + } + + ~CPrism(){} + + int getDim() const { return 3; } + int getNum() { return MPrism::getNum(); } + int getNumVertices() const { return 6; } + int getNumFacets() const { return 5; } + MVertex* getVertex(int vertex) const {return _v[vertex]; } + int getSortedVertex(int vertex) const {return _vs[vertex]; } + bool hasVertex(int vertex) const {return + (_v[0]->getNum() == vertex || _v[1]->getNum() == vertex || _v[2]->getNum() == vertex || _v[3]->getNum() == vertex || + _v[4]->getNum() == vertex || _v[5]->getNum() == vertex); } + std::vector<MVertex*> getVertexVector() const { + return std::vector<MVertex*>(_v, _v + sizeof(_v)/sizeof(MVertex*) ); } + std::vector<int> getSortedVertexVector() const { + return std::vector<int>(_vs, _vs + sizeof(_vs)/sizeof(int) ); } + + void getFacetVertices(const int num, std::vector<MVertex*> &v) const { + MPrism::getFaceVertices(num, v); + } + + virtual void printCell() const { printf("Cell dimension: %d, Vertices: %d %d %d %d %d %d, in subdomain: %d \n", getDim(), _v[0]->getNum(), _v[1]->getNum(), _v[2]->getNum(), _v[3]->getNum(), _v[4]->getNum(), _v[5]->getNum(), _inSubdomain); } +}; + + +// Pyramid cell type. +class CPyramid : public Cell, public MPyramid +{ + private: + int _vs[5]; + + public: + CPyramid(std::vector<MVertex*> v, int tag=0, bool subdomain=false, bool boundary=false, int num=0, int part=0) + : MPyramid(v, num, part){ + _tag = tag; + _inSubdomain = subdomain; + _onDomainBoundary = boundary; + _vs[0] = v.at(0)->getNum(); + _vs[1] = v.at(1)->getNum(); + _vs[2] = v.at(2)->getNum(); + _vs[3] = v.at(3)->getNum(); + _vs[4] = v.at(4)->getNum(); + std::sort(_vs, _vs+5); + } + + ~CPyramid(){} + + int getDim() const { return 3; } + int getNum() { return MPyramid::getNum(); } + int getNumVertices() const { return 5; } + int getNumFacets() const { return 5; } + MVertex* getVertex(int vertex) const {return _v[vertex]; } + int getSortedVertex(int vertex) const {return _vs[vertex]; } + bool hasVertex(int vertex) const {return + (_v[0]->getNum() == vertex || _v[1]->getNum() == vertex || _v[2]->getNum() == vertex || _v[3]->getNum() == vertex || + _v[4]->getNum() == vertex); } + std::vector<MVertex*> getVertexVector() const { + return std::vector<MVertex*>(_v, _v + sizeof(_v)/sizeof(MVertex*) ); } + std::vector<int> getSortedVertexVector() const { + return std::vector<int>(_vs, _vs + sizeof(_vs)/sizeof(int) ); } + + void getFacetVertices(const int num, std::vector<MVertex*> &v) const { + MPyramid::getFaceVertices(num, v); + } + + virtual void printCell() const { printf("Cell dimension: %d, Vertices: %d %d %d %d %d, in subdomain: %d \n", getDim(), _v[0]->getNum(), _v[1]->getNum(), _v[2]->getNum(), _v[3]->getNum(), _v[4]->getNum(), _inSubdomain); } +}; + + // Ordering for the cells. class Less_Cell{ public: @@ -459,6 +648,10 @@ class Less_Cell{ } return false; + + + //return (c1->getTag() < c2->getTag()); + } }; @@ -466,6 +659,8 @@ class Less_Cell{ class Equal_Cell{ public: bool operator ()(const Cell* c1, const Cell* c2){ + + if(c1->getNumVertices() != c2->getNumVertices()){ return false; } @@ -475,6 +670,9 @@ class Equal_Cell{ } } return true; + + //return (c1->getTag() == c2->getTag()); + } }; @@ -595,7 +793,13 @@ class CombinedCell : public Cell{ } - ~CombinedCell(){} + ~CombinedCell(){ + std::list< std::pair<int, Cell*> > cells = getCells(); + for(std::list< std::pair<int, Cell*> >::iterator it = cells.begin(); it != cells.end(); it++){ + Cell* cell2 = (*it).second; + delete cell2; + } + } int getNum() { return _num; } int getNumVertices() const { return _v.size(); } @@ -650,7 +854,9 @@ class CellComplex std::set<Cell*, Less_Cell> _cells[4]; // storage for cell pointers to delete them - std::set<Cell*, Less_Cell> _cells2[4]; + //std::set<Cell*, Less_Cell> _cells2[4]; + std::list<Cell*> _trash; + //std::set<Cell*, Less_Cell> _originalCells[4]; @@ -675,7 +881,7 @@ class CellComplex void insert_cells(bool subdomain, bool boundary); // remove a cell from this cell complex - void removeCell(Cell* cell); + void removeCell(Cell* cell, bool other=true); void insertCell(Cell* cell); public: @@ -722,23 +928,33 @@ class CellComplex CellComplex( std::vector<GEntity*> domain, std::vector<GEntity*> subdomain ); CellComplex(){} - ~CellComplex(){ + ~CellComplex(){ for(int i = 0; i < 4; i++){ for(citer cit = _cells[i].begin(); cit != _cells[i].end(); cit++){ Cell* cell = *cit; - if(cell->isCombined()) delete cell; + delete cell; + //if(cell->isCombined()) delete cell; } _cells[i].clear(); + /* for(citer cit = _cells2[i].begin(); cit != _cells2[i].end(); cit++){ Cell* cell = *cit; delete cell; } _cells2[i].clear(); + */ } - + emptyTrash(); } + void emptyTrash(){ + for(std::list<Cell*>::iterator cit = _trash.begin(); cit != _trash.end(); cit++){ + Cell* cell = *cit; + delete cell; + } + _trash.clear(); + } // get the number of certain dimensional cells int getSize(int dim){ return _cells[dim].size(); } @@ -768,7 +984,7 @@ class CellComplex bool inSameDomain(Cell* c1, Cell* c2) const { return ( (!c1->inSubdomain() && !c2->inSubdomain()) || (c1->inSubdomain() && c2->inSubdomain()) ); } - + // useful functions for (co)reduction of cell complex int reduceComplex(int omit = 0); int coreduceComplex(int omit = 0); @@ -799,6 +1015,11 @@ class CellComplex // also check whether all (co)boundary cells of a cell belong to this cell complex bool checkCoherence(); + int eulerCharacteristic(){ + return getSize(0) - getSize(1) + getSize(2) - getSize(3); + } + void printEuler(){ printf("Euler characteristic: %d. \n", eulerCharacteristic()); } + // change roles of boundaries and coboundaries of the cells in this cell complex // equivalent to transposing boundary operator matrices void makeDualComplex(){ diff --git a/Geo/Homology.cpp b/Geo/Homology.cpp index 650ac8a1dcbb8bebf5955dd932f4049e00f9c38d..c3ff48d10313e2972d636b8e01a64c53bee2eee4 100644 --- a/Geo/Homology.cpp +++ b/Geo/Homology.cpp @@ -77,7 +77,11 @@ void Homology::findGenerators(std::string fileName){ Msg::Info("Reducing Cell Complex..."); double t1 = Cpu(); + //_cellComplex->printEuler(); int omitted = _cellComplex->reduceComplex(_omit); + //_cellComplex->printEuler(); + + _cellComplex->emptyTrash(); if(getCombine()){ _cellComplex->combine(3); @@ -87,6 +91,9 @@ void Homology::findGenerators(std::string fileName){ _cellComplex->combine(1); } _cellComplex->checkCoherence(); + //_cellComplex->printEuler(); + + _cellComplex->emptyTrash(); double t2 = Cpu(); Msg::Info("Cell Complex reduction complete (%g s).", t2 - t1); @@ -130,7 +137,7 @@ void Homology::findGenerators(std::string fileName){ Msg::Info("H1 = %d", HRank[1]); Msg::Info("H2 = %d", HRank[2]); Msg::Info("H3 = %d", HRank[3]); - if(omitted != 0) Msg::Info("Computation of generators in %d highest dimensions was omitted.", _omit); + if(omitted != 0) Msg::Info("The computation of generators in %d highest dimensions was omitted.", _omit); Msg::Info("Wrote results to %s.", fileName.c_str()); @@ -144,13 +151,15 @@ void Homology::findGenerators(std::string fileName){ return; } -void Homology::findThickCuts(std::string fileName){ +void Homology::findDualGenerators(std::string fileName){ //for(int i = 0; i < 4; i++) { printf("Dim %d: \n", i); _cellComplex->printComplex(i); } Msg::Info("Reducing Cell Complex..."); double t1 = Cpu(); int omitted = _cellComplex->coreduceComplex(_omit); + _cellComplex->emptyTrash(); + /* _cellComplex->makeDualComplex(); int omitted = _cellComplex->reduceComplex(_omit); @@ -168,6 +177,8 @@ void Homology::findThickCuts(std::string fileName){ _cellComplex->cocombine(2); } + _cellComplex->emptyTrash(); + _cellComplex->checkCoherence(); double t2 = Cpu(); Msg::Info("Cell Complex reduction complete (%g s).", t2 - t1); @@ -200,12 +211,12 @@ void Homology::findThickCuts(std::string fileName){ convert(i, generator); convert(dim-j, dimension); - std::string name = dimension + "D Thick cut " + generator; + std::string name = dimension + "D Dual generator " + generator; Chain* chain = new Chain(_cellComplex->getCells(j), chains->getCoeffVector(j,i), _cellComplex, name, chains->getTorsion(j,i)); chain->writeChainMSH(fileName); if(chain->getSize() != 0){ HRank[dim-j] = HRank[dim-j] + 1; - if(chain->getTorsion() != 1) Msg::Warning("%dD Thick cut %d has torsion coefficient %d!", j, i, chain->getTorsion()); + if(chain->getTorsion() != 1) Msg::Warning("%dD Dual generator %d has torsion coefficient %d!", j, i, chain->getTorsion()); } delete chain; @@ -217,7 +228,7 @@ void Homology::findThickCuts(std::string fileName){ Msg::Info("H1 = %d", HRank[1]); Msg::Info("H2 = %d", HRank[2]); Msg::Info("H3 = %d", HRank[3]); - if(omitted != 0) Msg::Info("Computation of %d highest dimension thick cuts was omitted.", _omit); + if(omitted != 0) Msg::Info("The computation of %d highest dimension dual generators was omitted.", _omit); Msg::Info("Wrote results to %s.", fileName.c_str()); @@ -230,4 +241,21 @@ void Homology::findThickCuts(std::string fileName){ return; } + +void Homology::computeBettiNumbers(){ + + Msg::Info("Running coreduction..."); + double t1 = Cpu(); + _cellComplex->computeBettiNumbers(); + double t2 = Cpu(); + Msg::Info("Betti number computation complete (%g s).", t2- t1); + + Msg::Info("b0 = %d \n", _cellComplex->getBettiNumber(0)); + Msg::Info("b1 = %d \n", _cellComplex->getBettiNumber(1)); + Msg::Info("b2 = %d \n", _cellComplex->getBettiNumber(2)); + Msg::Info("b3 = %d \n", _cellComplex->getBettiNumber(3)); + + return; +} + #endif diff --git a/Geo/Homology.h b/Geo/Homology.h index c5dad2dbe24d8c203f4b8529e2981c07be5ba32b..8be0e76cb5ea9ff5803a371c526ad00e51b85ed7 100644 --- a/Geo/Homology.h +++ b/Geo/Homology.h @@ -40,8 +40,9 @@ class Homology bool setCombine(bool combine) { _combine = combine; return _combine; } void findGenerators(std::string fileName); - void findThickCuts(std::string fileName); - + void findDualGenerators(std::string fileName); + void computeBettiNumbers(); + void swapSubdomain() { _cellComplex->swapSubdomain(); } int getOmit() {return _omit; } diff --git a/Plugin/HomologyComputation.cpp b/Plugin/HomologyComputation.cpp index 0f0fa194c1c144c2b7885ffb3bde9aa538ec0239..337b2a79c83a3782e2ca36c4712bcf66988d0329 100644 --- a/Plugin/HomologyComputation.cpp +++ b/Plugin/HomologyComputation.cpp @@ -21,8 +21,9 @@ StringXNumber HomologyComputationOptions_Number[] = { {GMSH_FULLRC, "PhysicalGroupForSubdomain1", NULL, 0.}, {GMSH_FULLRC, "PhysicalGroupForSubdomain2", NULL, 0.}, {GMSH_FULLRC, "ComputeGenerators", NULL, 1.}, - {GMSH_FULLRC, "ComputeThickCuts", NULL, 0.}, - {GMSH_FULLRC, "OmitDimensions", NULL, 1.}, + {GMSH_FULLRC, "ComputeDualGenerators", NULL, 0.}, + {GMSH_FULLRC, "ComputeBettiNumbers", NULL, 0.}, + //{GMSH_FULLRC, "OmitDimensions", NULL, 1.}, //{GMSH_FULLRC, "CombineCells", NULL, 1.}, }; @@ -84,7 +85,8 @@ PView *GMSH_HomologyComputationPlugin::execute(PView *v) int gens = (int)HomologyComputationOptions_Number[4].def; int cuts = (int)HomologyComputationOptions_Number[5].def; - int omit = (int)HomologyComputationOptions_Number[6].def; + int betti = (int)HomologyComputationOptions_Number[6].def; + //int omit = (int)HomologyComputationOptions_Number[6].def; //int combine = (int)HomologyComputationOptions_Number[7].def; @@ -92,19 +94,22 @@ PView *GMSH_HomologyComputationPlugin::execute(PView *v) Homology* homology = new Homology(m, domain, subdomain); //if(combine == 0) homology->setCombine(false); - homology->setOmit(omit); + homology->setOmit(1); //if(swap == 1) homology->swapSubdomain(); - if(gens == 1 && cuts != 1) { + if(gens == 1 && cuts != 1 && betti != 1) { homology->findGenerators(fileName); GmshMergeFile(fileName); } - else if(cuts == 1 && gens != 1) { - homology->findThickCuts(fileName); + else if(cuts == 1 && gens != 1 && betti != 1) { + homology->findDualGenerators(fileName); GmshMergeFile(fileName); } - else Msg::Error("Choose either generators or thick cuts to compute."); + else if(cuts != 1 && gens != 1 && betti == 1) { + homology->computeBettiNumbers(); + } + else Msg::Error("Choose either generators, dual generators or Betti numbers to compute."); delete homology;