From 09fb813fa506fdba4d88b58703ef1fb3d25a101a Mon Sep 17 00:00:00 2001 From: Matti Pellika <matti.pellikka@tut.fi> Date: Wed, 5 Dec 2012 15:34:36 +0000 Subject: [PATCH] Fix inefficient memory management in cell complex reduction. --- Geo/CellComplex.cpp | 289 ++++++++++++++++++++++++-------- Geo/CellComplex.h | 32 +++- benchmarks/homology/torsion.geo | 2 + 3 files changed, 245 insertions(+), 78 deletions(-) diff --git a/Geo/CellComplex.cpp b/Geo/CellComplex.cpp index fe38baf4dd..74abf563ac 100644 --- a/Geo/CellComplex.cpp +++ b/Geo/CellComplex.cpp @@ -19,10 +19,14 @@ CellComplex::CellComplex(GModel* model, _relative(false) { _deleteCount = 0; + _createCount = 0; _insertCells(subdomainElements, 1); if(getSize(0) > 0) _relative = true; + for(int i = 0; i < 4; i++) _numSubdomainCells[i] = getSize(i); _insertCells(domainElements, 0); + for(int i = 0; i < 4; i++) + _numRelativeCells[i] = getSize(i) - _numSubdomainCells[i]; _removeCells(nonsubdomainElements, 1); _removeCells(nondomainElements, 0); @@ -38,7 +42,21 @@ CellComplex::CellComplex(GModel* model, cell->saveOriginalBd(); } } + _reduced = false; + + Msg::Debug("Cells in domain:"); + Msg::Debug(" %d volumes, %d faces %d edges, and %d vertices", + getNumCells(3, 1), getNumCells(2, 1), + getNumCells(1, 1), getNumCells(0, 1)); + Msg::Debug("Cells in subdomain:"); + Msg::Debug(" %d volumes, %d faces %d edges, and %d vertices", + getNumCells(3, 2), getNumCells(2, 2), + getNumCells(1, 2), getNumCells(0, 2)); + Msg::Debug("Cells in relative domain:"); + Msg::Debug(" %d volumes, %d faces %d edges, and %d vertices", + getNumCells(3, 0), getNumCells(2, 0), + getNumCells(1, 0), getNumCells(0, 0)); } bool CellComplex::_insertCells(std::vector<MElement*>& elements, @@ -67,6 +85,7 @@ bool CellComplex::_insertCells(std::vector<MElement*>& elements, cell = *(insert.first); if(domain) cell->setDomain(domain); } + else _createCount++; } for (int dim = 3; dim > 0; dim--){ @@ -86,6 +105,7 @@ bool CellComplex::_insertCells(std::vector<MElement*>& elements, newCell = *(insert.first); if(domain) newCell->setDomain(domain); } + else _createCount++; if(domain == 0) { int ori = cell->findBdCellOrientation(newCell, i); cell->addBoundaryCell( ori, newCell, true); @@ -170,6 +190,13 @@ CellComplex::~CellComplex() delete cell; _deleteCount++; } + for(citer cit = _cells[i].begin(); cit != _cells[i].end(); cit++){ + Cell* cell = *cit; + if(cell->isCombined()) { + delete cell; + _deleteCount++; + } + } } else { for(citer cit = _cells[i].begin(); cit != _cells[i].end(); cit++){ @@ -179,20 +206,18 @@ CellComplex::~CellComplex() } } } - for(unsigned int i = 0; i < _newcells.size(); i++) { - delete _newcells.at(i); - _deleteCount++; - } + for(unsigned int i = 0; i < _removedcells.size(); i++) { delete _removedcells.at(i); _deleteCount++; } - Msg::Debug("Total number of cells created: %d", _deleteCount); + + Msg::Debug("Total number of cells created: %d", _createCount); + Msg::Debug("Total number of cells deleted: %d", _deleteCount); } void CellComplex::insertCell(Cell* cell) { - if(_saveorig) _newcells.push_back(cell); std::pair<citer, bool> insertInfo = _cells[cell->getDim()].insert(cell); if(!insertInfo.second){ Msg::Debug("Cell not inserted"); @@ -202,7 +227,7 @@ void CellComplex::insertCell(Cell* cell) } } -void CellComplex::removeCell(Cell* cell, bool other) +void CellComplex::removeCell(Cell* cell, bool other, bool del) { std::map<Cell*, short int, Less_Cell > coboundary; cell->getCoboundary(coboundary); @@ -221,9 +246,17 @@ void CellComplex::removeCell(Cell* cell, bool other) bdCell->removeCoboundaryCell(cell, other); } - int erased = _cells[cell->getDim()].erase(cell); + int dim = cell->getDim(); + int erased = _cells[dim].erase(cell); + if(relative()) { + if(cell->inSubdomain()) _numSubdomainCells[dim] -= 1; + else _numRelativeCells[dim] -= 1; + } if(!erased) Msg::Debug("Tried to remove a cell from the cell complex \n"); - if(!_saveorig) _removedcells.push_back(cell); + if(!_saveorig && (!del || !cell->isCombined())) + _removedcells.push_back(cell); + else if (!del && cell->isCombined()) + _removedcells.push_back(cell); } void CellComplex::enqueueCells(std::map<Cell*, short int, Less_Cell>& cells, @@ -241,7 +274,7 @@ void CellComplex::enqueueCells(std::map<Cell*, short int, Less_Cell>& cells, } } -int CellComplex::coreduction(Cell* startCell, bool omit, +int CellComplex::coreduction(Cell* startCell, int omit, std::vector<Cell*>& omittedCells) { int coreductions = 0; @@ -267,7 +300,7 @@ int CellComplex::coreduction(Cell* startCell, bool omit, bd_s.begin()->first->getCoboundary(cbd_c); enqueueCells(cbd_c, Q, Qset); removeCell(bd_s.begin()->first); - if(bd_s.begin()->first->getDim() == 0 && omit){ + if(bd_s.begin()->first->getDim() == omit){ omittedCells.push_back(bd_s.begin()->first); } coreductions++; @@ -281,7 +314,7 @@ int CellComplex::coreduction(Cell* startCell, bool omit, return coreductions; } -int CellComplex::reduction(int dim, bool omit, +int CellComplex::reduction(int dim, int omit, std::vector<Cell*>& omittedCells) { if(dim < 1 || dim > 3) return 0; @@ -300,7 +333,7 @@ int CellComplex::reduction(int dim, bool omit, !cell->getImmune() && !cell->firstCoboundary()->first->getImmune()){ cit++; - if(dim == getDim() && omit){ + if(dim == omit){ omittedCells.push_back(cell->firstCoboundary()->first); } removeCell(cell->firstCoboundary()->first); @@ -317,7 +350,7 @@ int CellComplex::reduction(int dim, bool omit, return count; } -int CellComplex::coreduction(int dim, bool omit, +int CellComplex::coreduction(int dim, int omit, std::vector<Cell*>& omittedCells) { if(dim < 1 || dim > 3) return 0; @@ -334,7 +367,7 @@ int CellComplex::coreduction(int dim, bool omit, if(cell->getBoundarySize() == 1 && inSameDomain(cell, cell->firstBoundary()->first)) { ++cit; - if(dim-1 == 0 && omit){ + if(dim-1 == omit){ omittedCells.push_back(cell->firstBoundary()->first); } removeCell(cell->firstBoundary()->first); @@ -351,7 +384,59 @@ int CellComplex::coreduction(int dim, bool omit, return count; } -int CellComplex::reduceComplex(int combine, bool omit) +int CellComplex::getDomain(Cell* cell, std::string& str) +{ + int domain = 0; + if(cell->inSubdomain()) { + str = "subdomain"; + domain = 2; + } + if(!cell->inSubdomain()) { + if(relative()) { + str = "relative domain"; + domain = 0; + } + else { + str = "domain"; + domain = 1; + } + } + return domain; +} + +Cell* CellComplex::_omitCell(Cell* cell, bool dual) +{ + removeCell(cell, false); + std::vector<Cell*> omittedCells; + omittedCells.push_back(cell); + int count = 0; + + if(!dual) { + for(int j = 3; j > 0; j--) + count += reduction(j, cell->getDim(), omittedCells); + } + else { + count += coreduction(cell, cell->getDim(), omittedCells); + for(int j = 1; j <= getDim(); j++) + count += coreduction(j, cell->getDim(), omittedCells); + } + + CombinedCell* newcell = new CombinedCell(omittedCells); + _createCount++; + + std::string domainstr = ""; + int domain = getDomain(cell, domainstr); + + Msg::Debug("Omitted %d-cell in %s that caused %d reductions", + cell->getDim(), domainstr.c_str(), count); + Msg::Debug(" - number of %d-cells left in %s: %d", + cell->getDim(), domainstr.c_str(), + getNumCells(cell->getDim(), domain)); + + return newcell; +} + +int CellComplex::reduceComplex(int combine, bool omit, bool homseq) { Msg::Debug("Cell Complex reduction:"); Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", @@ -359,11 +444,14 @@ int CellComplex::reduceComplex(int combine, bool omit) if(!getSize(0)) return 0; int count = 0; - if(relative()) removeSubdomain(); + if(relative() && !homseq) removeSubdomain(); std::vector<Cell*> empty; - for(int i = 3; i > 0; i--) count = count + reduction(i, false, empty); + for(int i = 3; i > 0; i--) count = count + reduction(i, -1, empty); - if(omit){ + Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", + getSize(3), getSize(2), getSize(1), getSize(0)); + + if(omit && !homseq){ std::vector<Cell*> newCells; @@ -372,14 +460,9 @@ int CellComplex::reduceComplex(int combine, bool omit) citer cit = firstCell(getDim()); Cell* cell = *cit; - removeCell(cell, false); - std::vector<Cell*> omittedCells; - omittedCells.push_back(cell); - - for(int j = 3; j > 0; j--) reduction(j, true, omittedCells); - CombinedCell* newcell = new CombinedCell(omittedCells); - newCells.push_back(newcell); + newCells.push_back(_omitCell(cell, false)); } + for(unsigned int i = 0; i < newCells.size(); i++){ insertCell(newCells.at(i)); } @@ -389,16 +472,16 @@ int CellComplex::reduceComplex(int combine, bool omit) getSize(3), getSize(2), getSize(1), getSize(0)); if(combine > 0) this->combine(3); - reduction(2, false, empty); + reduction(2, -1, empty); if(combine > 0) this->combine(2); - reduction(1, false, empty); + reduction(1, -1, empty); if(combine > 0) this->combine(1); Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", - getSize(3), getSize(2), getSize(1), getSize(0)); + getSize(3), getSize(2), getSize(1), getSize(0)); _reduced = true; - return 0; + return count; } void CellComplex::removeSubdomain() @@ -439,11 +522,16 @@ int CellComplex::coreduceComplex(int combine, bool omit) citer cit = firstCell(dim); while(cit != lastCell(dim)){ Cell* cell = *cit; - count = count + coreduction(cell, false, empty); + int count =+ coreduction(cell, -1, empty); if(count != 0) break; cit++; } } + for(int j = 1; j <= getDim(); j++) + count += coreduction(j, -1, empty); + + Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", + getSize(3), getSize(2), getSize(1), getSize(0)); if(omit){ @@ -452,13 +540,7 @@ int CellComplex::coreduceComplex(int combine, bool omit) citer cit = firstCell(0); Cell* cell = *cit; - removeCell(cell, false); - std::vector<Cell*> omittedCells; - omittedCells.push_back(cell); - - coreduction(cell, true, omittedCells); - CombinedCell* newcell = new CombinedCell(omittedCells); - newCells.push_back(newcell); + newCells.push_back(_omitCell(cell, true)); } for(unsigned int i = 0; i < newCells.size(); i++){ insertCell(newCells.at(i)); @@ -470,25 +552,25 @@ int CellComplex::coreduceComplex(int combine, bool omit) getSize(3), getSize(2), getSize(1), getSize(0)); if(combine > 0) this->cocombine(0); - coreduction(1, false, empty); + coreduction(1, -1, empty); if(combine > 0) this->cocombine(1); - coreduction(2, false, empty); + coreduction(2, -1, empty); if(combine > 0) this->cocombine(2); - coreduction(3, false, empty); + coreduction(3, -1, empty); coherent(); Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", getSize(3), getSize(2), getSize(1), getSize(0)); _reduced = true; - return 0; + return count; } int CellComplex::combine(int dim) { - Msg::Debug("Cell complex before combining:"); - Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", - getSize(3), getSize(2), getSize(1), getSize(0)); + //Msg::Debug("Cell complex before combining:"); + //Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", + // getSize(3), getSize(2), getSize(1), getSize(0)); if(dim < 1 || dim > 3) return 0; std::queue<Cell*> Q; @@ -517,39 +599,53 @@ int CellComplex::combine(int dim) inSameDomain(s, c1) && inSameDomain(s, c2) && c1->getImmune() == c2->getImmune() ) { - removeCell(s); + removeCell(s, true, true); c1->getBoundary(bd_c); enqueueCells(bd_c, Q, Qset); c2->getBoundary(bd_c); enqueueCells(bd_c, Q, Qset); - CombinedCell* newCell = new CombinedCell(c1, c2, (or1 != or2)); - removeCell(c1); - removeCell(c2); + CombinedCell* newCell = new CombinedCell(c1, c2, (or1 != or2)); + _createCount++; + removeCell(c1, true, true); + removeCell(c2, true, true); insertCell(newCell); cit = firstCell(dim); count++; + + if(s->isCombined()) { + delete s; + _deleteCount++; + } + if(c1->isCombined()) { + delete c1; + _deleteCount++; + } + if(c2->isCombined()) { + delete c2; + _deleteCount++; + } + } } Qset.erase(s); } } - Msg::Debug("Cell complex after combining:"); - Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", - getSize(3), getSize(2), getSize(1), getSize(0)); + //Msg::Debug("Cell complex after combining:"); + //Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", + // getSize(3), getSize(2), getSize(1), getSize(0)); _reduced = true; return count; } - int CellComplex::cocombine(int dim) { - Msg::Debug("Cell complex before cocombining:"); - Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", - getSize(3), getSize(2), getSize(1), getSize(0)); + //Msg::Debug("Cell complex before cocombining:"); + //Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", + //getSize(3), getSize(2), getSize(1), getSize(0)); if(dim < 0 || dim > 2) return 0; @@ -578,7 +674,7 @@ int CellComplex::cocombine(int dim) if(!(*c1 == *c2) && abs(or1) == abs(or2) && inSameDomain(s, c1) && inSameDomain(s, c2)){ - removeCell(s); + removeCell(s, true, true); c1->getCoboundary(cbd_c); enqueueCells(cbd_c, Q, Qset); @@ -587,21 +683,36 @@ int CellComplex::cocombine(int dim) CombinedCell* newCell = new CombinedCell(c1, c2, (or1 != or2), true ); - removeCell(c1); - removeCell(c2); + _createCount++; + removeCell(c1, true, true); + removeCell(c2, true, true); insertCell(newCell); cit = firstCell(dim); count++; + + if(s->isCombined()) { + delete s; + _deleteCount++; + } + if(c1->isCombined()) { + delete c1; + _deleteCount++; + } + if(c2->isCombined()) { + delete c2; + _deleteCount++; + } + } } Qset.erase(s); } } - Msg::Debug("Cell complex after cocombining:"); - Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", - getSize(3), getSize(2), getSize(1), getSize(0)); + //Msg::Debug("Cell complex after cocombining:"); + //Msg::Debug(" %d volumes, %d faces, %d edges, and %d vertices", + // getSize(3), getSize(2), getSize(1), getSize(0)); _reduced = true; return count; } @@ -665,8 +776,8 @@ bool CellComplex::hasCell(Cell* cell, bool orig) else return true; } -void CellComplex::getCells(std::set<Cell*, Less_Cell>& cells, - int dim, int domain){ +void CellComplex::getCells(std::set<Cell*, Less_Cell>& cells, + int dim, int domain){ cells.clear(); for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){ Cell* cell = *cit; @@ -677,22 +788,60 @@ void CellComplex::getCells(std::set<Cell*, Less_Cell>& cells, } } +int CellComplex::getNumCells(int dim, int domain) +{ + if(domain == 0) return _numRelativeCells[dim]; + else if(domain == 1) return getSize(dim); + else if(domain == 2) return _numSubdomainCells[dim]; + return 0; +} + +Cell* CellComplex::getACell(int dim, int domain) +{ + int num = getNumCells(dim, domain); + if(num < 0) Msg::Debug("Domain cell counts not in sync."); + + if(num <= 0) { + if(domain == 0) Msg::Warning("%d cells in relative domain", num); + else if(domain == 1) Msg::Warning("%d cells in domain", num); + else if(domain == 2) Msg::Warning("%d cells in subdomain", num); + return NULL; + } + + for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){ + Cell* cell = *cit; + if( (domain == 1) || + (domain == 0 && !cell->inSubdomain()) || + (domain == 2 && cell->inSubdomain()) ) return cell; + } + Msg::Debug("Domain cell counts not in sync."); + return NULL; +} + bool CellComplex::restoreComplex() { if(_saveorig){ 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; + _deleteCount++; + } + } + _cells[i] = _ocells[i]; for(citer cit = firstCell(i); cit != lastCell(i); cit++){ Cell* cell = *cit; cell->restoreCell(); + if(relative()) { + if(cell->inSubdomain()) _numSubdomainCells[i] += 1; + else _numRelativeCells[i] += 1; + } } } - for(unsigned int i = 0; i < _newcells.size(); i++){ - Cell* cell = _newcells.at(i); - delete cell; - _deleteCount++; - } - _newcells.clear(); + Msg::Info("Restored Cell Complex:"); Msg::Info("%d volumes, %d faces, %d edges, and %d vertices", getSize(3), getSize(2), getSize(1), getSize(0)); diff --git a/Geo/CellComplex.h b/Geo/CellComplex.h index f3d8c0ac9f..d8b97eb8b3 100644 --- a/Geo/CellComplex.h +++ b/Geo/CellComplex.h @@ -34,8 +34,7 @@ class CellComplex // original cells of this cell complex std::set<Cell*, Less_Cell> _ocells[4]; - // new cells created during reductions - std::vector<Cell*> _newcells; + // original cells removed during reductions std::vector<Cell*> _removedcells; // cell complex dimension @@ -51,26 +50,33 @@ class CellComplex bool _relative; int _deleteCount; + int _createCount; // is the cell complex at reduced state bool _reduced; + int _numRelativeCells[4]; + int _numSubdomainCells[4]; + + // for constructor bool _insertCells(std::vector<MElement*>& elements, int domain); bool _removeCells(std::vector<MElement*>& elements, int domain); bool _immunizeCells(std::vector<MElement*>& elements); + Cell* _omitCell(Cell* cell, bool dual); + // enqueue cells in queue if they are not there already void enqueueCells(std::map<Cell*, short int, Less_Cell>& cells, std::queue<Cell*>& Q, std::set<Cell*, Less_Cell>& Qset); // insert/remove a cell from this cell complex - void removeCell(Cell* cell, bool other=true); + void removeCell(Cell* cell, bool other=true, bool del=false); void insertCell(Cell* cell); // queued coreduction - int coreduction(Cell* startCell, bool omit, + int coreduction(Cell* startCell, int omit, std::vector<Cell*>& omittedCells); public: @@ -89,16 +95,26 @@ class CellComplex bool simplicial() const { return _simplicial; } bool relative() const { return _relative; } + + // get the number of certain dimensional cells int getSize(int dim, bool orig=false){ if(!orig) return _cells[dim].size(); else return _ocells[dim].size(); } + // get domain of a cell + // cell in domain relative to subdomain -> domain = 0 + // cell in domain -> domain = 1 + // cell in subdomain -> domain = 2 + int getDomain(Cell* cell, std::string& str); + // get dim-dimensional cells // domain = 0: cells in domain relative to subdomain // domain = 1: cells in domain // domain = 2: cells in subdomain void getCells(std::set<Cell*, Less_Cell>& cells, int dim, int domain=0); + int getNumCells(int dim, int domain=0); + Cell* getACell(int dim, int domain=0); //std::set<Cell*, Less_Cell> getOrigCells(int dim){ return _ocells[dim]; } // iterator for the cells of same dimension @@ -125,8 +141,8 @@ class CellComplex // (co)reduction of this cell complex // removes (co)reduction pairs of cell of dimension dim and dim-1 - int reduction(int dim, bool omit, std::vector<Cell*>& omittedCells); - int coreduction(int dim, bool omit, std::vector<Cell*>& omittedCells); + int reduction(int dim, int omit, std::vector<Cell*>& omittedCells); + int coreduction(int dim, int omit, std::vector<Cell*>& omittedCells); // Cell combining for reduction and coreduction int combine(int dim); @@ -140,9 +156,9 @@ class CellComplex // full (co)reduction of this cell complex (all dimensions) // (combine = 1 -> with combining) - // (combine = 2 -> with combining and dual combining) // (omit = true -> with highest dimensional cell omitting?) - int reduceComplex(int combine=1, bool omit=true); + // (homseq = true -> homology sequence splitting possible after reduction) + int reduceComplex(int combine=1, bool omit=true, bool homseq=false); int coreduceComplex(int combine=1, bool omit=true); bool isReduced() const { return _reduced; } diff --git a/benchmarks/homology/torsion.geo b/benchmarks/homology/torsion.geo index 47d0bf48de..04d76847c9 100644 --- a/benchmarks/homology/torsion.geo +++ b/benchmarks/homology/torsion.geo @@ -130,5 +130,7 @@ Surface Loop(85) = {76, 78, 74, 80, 46, 48, 84, 64, 62, 60, 58, 82, 56, 54, 52, Volume(86) = {85}; Physical Volume(87) = {86}; Physical Surface(88) = {46, 48, 64, 62, 60, 58, 56, 54, 52, 50}; +Physical Surface(89) = {78, 80, 76, 74, 84, 82}; Homology {{87},{88}}; +Homology {{87},{89}}; -- GitLab