Forked from
gmsh / gmsh
7640 commits behind the upstream repository.
-
Christophe Geuzaine authoredChristophe Geuzaine authored
CellComplex.cpp 29.84 KiB
// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle
//
// See the LICENSE.txt file for license information. Please report all
// bugs and problems to the public mailing list <gmsh@onelab.info>.
//
// Contributed by Matti Pellikka <matti.pellikka@gmail.com>.
#include "CellComplex.h"
#include "MElement.h"
#include "OS.h"
double CellComplex::_patience = 10;
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),
_relative(false)
{
_smallestCell.second = -1.;
_biggestCell.second = -1.;
_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);
_immunizeCells(immuneElements);
int num = 0;
for(int dim = 0; dim < 4; dim++){
if(getSize(dim) != 0) _dim = dim;
if(_saveorig) _ocells[dim] = _cells[dim];
for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
Cell* cell = *cit;
cell->setNum(++num);
cell->increaseGlobalNum();
cell->saveCellBoundary();
}
}
_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,
int domain)
{
std::pair<Cell*, double> smallestElement[4];
std::pair<Cell*, double> biggestElement[4];
for(int i = 0; i < 4; i++) {
smallestElement[i].second = -1.;
biggestElement[i].second = -1.;
}
_dim = 0;
double t1 = Cpu();
for(unsigned int i=0; i < elements.size(); i++){
MElement* element = elements.at(i);
int dim = element->getDim();
int type = element->getType();
if(type == TYPE_POLYG || type == TYPE_POLYH) {
Msg::Error("Mesh element type %d not implemented in homology solver", type);
}
if(type == TYPE_QUA || type == TYPE_HEX ||
type == TYPE_PYR || type == TYPE_PRI)
_simplicial = false;
std::pair<Cell*, bool> maybeCell = Cell::createCell(element, domain);
if(!maybeCell.second) {
delete maybeCell.first;
continue;
}
if(_dim < dim) _dim = dim;
Cell* cell = maybeCell.first;
std::pair<citer, bool> insert =
_cells[cell->getDim()].insert(cell);
if(!insert.second) {
delete cell;
cell = *(insert.first);
if(domain) cell->setDomain(domain);
}
else _createCount++;
if(domain == 0) {
double size = fabs(element->getVolume());
if(smallestElement[dim].second < 0. || smallestElement[dim].second > size)
smallestElement[dim] = std::make_pair(cell, size);
if(biggestElement[dim].second < 0. || biggestElement[dim].second < size)
biggestElement[dim] = std::make_pair(cell, size);
}
}
_smallestCell = smallestElement[_dim];
_biggestCell = biggestElement[_dim];
for (int dim = 3; dim > 0; dim--){
double t2 = Cpu();
if(t2-t1 > CellComplex::_patience && dim > 1) {
if(domain == 0)
Msg::Info(" ... creating domain %d-cells", dim);
else if(domain == 1)
Msg::Info(" ... creating subdomain %d-cells", dim);
}
for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
Cell* cell = *cit;
for(int i = 0; i < cell->getNumBdElements(); i++){
std::pair<Cell*, bool> maybeCell = Cell::createCell(cell, i);
if(!maybeCell.second) {
delete maybeCell.first;
continue;
}
Cell* newCell = maybeCell.first;
std::pair<citer, bool> insert =
_cells[newCell->getDim()].insert(newCell);
if(!insert.second) {
delete newCell;
newCell = *(insert.first);
if(domain) newCell->setDomain(domain);
}
else _createCount++;
if(domain == 0) {
int ori = cell->findBdCellOrientation(newCell, i);
cell->addBoundaryCell( ori, newCell, true);
if(_smallestCell.first == cell)
_smallestCell = std::make_pair(newCell, _smallestCell.second);
if(_biggestCell.first == cell)
_biggestCell = std::make_pair(newCell, _biggestCell.second);
}
}
}
}
return true;
}
bool CellComplex::_removeCells(std::vector<MElement*>& elements,
int domain)
{
if(elements.empty()) return true;
Msg::Debug("Removing %d elements and their subcells from the cell complex.",
(int)elements.size());
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;
}
}
Msg::Debug("Removed %d volumes, %d faces, %d edges, and %d vertices from the cell complex.",
(int)removed[3].size(), (int)removed[2].size(),
(int)removed[1].size(), (int)removed[0].size());
return true;
}
bool CellComplex::_immunizeCells(std::vector<MElement*>& elements)
{
for(unsigned int i=0; i < elements.size(); i++){
MElement* element = elements.at(i);
Cell* cell = new Cell(element, 0);
int dim = cell->getDim();
citer cit = _cells[dim].find(cell);
if(cit != lastCell(dim)) (*cit)->setImmune(true);
delete cell;
}
return true;
}
CellComplex::~CellComplex()
{
for(int i = 0; i < 4; i++){
for(citer cit = _cells[i].begin(); cit != _cells[i].end(); cit++){
Cell* cell = *cit;
delete cell;
_deleteCount++;
}
}
for(unsigned int i = 0; i < _removedcells.size(); i++) {
delete _removedcells.at(i);
_deleteCount++;
}
Msg::Debug("Total number of cells created: %d", _createCount);
Msg::Debug("Total number of cells deleted: %d", _deleteCount);
}
void CellComplex::insertCell(Cell* cell)
{
std::pair<citer, bool> insertInfo = _cells[cell->getDim()].insert(cell);
if(!insertInfo.second){
Msg::Debug("Cell not inserted");
Cell* oldCell = (*insertInfo.first);
cell->printCell();
oldCell->printCell();
}
}
void CellComplex::removeCell(Cell* cell, bool other, bool del)
{
std::map<Cell*, short int, Less_Cell > coboundary;
cell->getCoboundary(coboundary);
std::map<Cell*, short int, Less_Cell > boundary;
cell->getBoundary(boundary);
for(std::map<Cell*, short int, Less_Cell>::iterator it =
coboundary.begin(); it != coboundary.end(); it++){
Cell* cbdCell = (*it).first;
cbdCell->removeBoundaryCell(cell, other);
}
for(std::map<Cell*, short int, Less_Cell>::iterator it =
boundary.begin(); it != boundary.end(); it++){
Cell* bdCell = (*it).first;
bdCell->removeCoboundaryCell(cell, other);
}
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");
else if(!del) _removedcells.push_back(cell);
}
void CellComplex::enqueueCells(std::map<Cell*, short int, Less_Cell>& cells,
std::queue<Cell*>& Q,
std::set<Cell*, Less_Cell>& Qset)
{
for(std::map<Cell*, short int, Less_Cell>::iterator cit = cells.begin();
cit != cells.end(); cit++){
Cell* cell = (*cit).first;
citer it = Qset.find(cell);
if(it == Qset.end()){
Qset.insert(cell);
Q.push(cell);
}
}
}
int CellComplex::coreduction(Cell* startCell, int omit,
std::vector<Cell*>& omittedCells)
{
int coreductions = 0;
std::queue<Cell*> Q;
std::set<Cell*, Less_Cell> Qset;
Q.push(startCell);
Qset.insert(startCell);
std::map<Cell*, short int, Less_Cell > bd_s;
std::map<Cell*, short int, Less_Cell > cbd_c;
Cell* s;
while( !Q.empty() ){
s = Q.front();
Q.pop();
Qset.erase(s);
if(s->getBoundarySize() == 1 &&
inSameDomain(s, s->firstBoundary()->first) &&
!s->getImmune() && !s->firstBoundary()->first->getImmune() &&
abs(s->firstBoundary()->second.get()) < 2){
s->getBoundary(bd_s);
removeCell(s);
bd_s.begin()->first->getCoboundary(cbd_c);
enqueueCells(cbd_c, Q, Qset);
removeCell(bd_s.begin()->first);
if(bd_s.begin()->first->getDim() == omit){
omittedCells.push_back(bd_s.begin()->first);
}
coreductions++;
}
else if(s->getBoundarySize() == 0){
s->getCoboundary(cbd_c);
enqueueCells(cbd_c, Q, Qset);
}
}
_reduced = true;
return coreductions;
}
int CellComplex::reduction(int dim, int omit,
std::vector<Cell*>& omittedCells)
{
if(dim < 1 || dim > 3) return 0;
int numCells[4];
for(int i = 0; i < 4; i++) numCells[i] = getSize(i);
int count = 0;
bool reduced = true;
while (reduced){
reduced = false;
citer cit = firstCell(dim-1);
while(cit != lastCell(dim-1)){
Cell* cell = *cit;
if(cell->getCoboundarySize() == 1 &&
inSameDomain(cell, cell->firstCoboundary()->first) &&
!cell->getImmune() && !cell->firstCoboundary()->first->getImmune() &&
!cell->firstCoboundary()->first->getImmune() &&
abs(cell->firstCoboundary()->second.get()) < 2){
cit++;
if(dim == omit){
omittedCells.push_back(cell->firstCoboundary()->first);
}
removeCell(cell->firstCoboundary()->first);
removeCell(cell);
count++;
reduced = true;
}
if(getSize(dim) == 0 || getSize(dim-1) == 0) break;
if(cit != lastCell(dim-1)) cit++;
}
}
_reduced = true;
Msg::Debug("Cell complex %d-reduction removed %dv, %df, %de, %dn", dim,
numCells[3]-getSize(3), numCells[2]-getSize(2),
numCells[1]-getSize(1), numCells[0]-getSize(0));
return count;
}
int CellComplex::coreduction(int dim, int omit,
std::vector<Cell*>& omittedCells)
{
if(dim < 1 || dim > 3) return 0;
int numCells[4];
for(int i = 0; i < 4; i++) numCells[i] = getSize(i);
int count = 0;
bool reduced = true;
while (reduced){
reduced = false;
citer cit = firstCell(dim);
while(cit != lastCell(dim)){
Cell* cell = *cit;
if(cell->getBoundarySize() == 1 &&
inSameDomain(cell, cell->firstBoundary()->first) &&
!cell->getImmune() && !cell->firstBoundary()->first->getImmune() &&
abs(cell->firstBoundary()->second.get()) < 2) {
++cit;
if(dim-1 == omit){
omittedCells.push_back(cell->firstBoundary()->first);
}
removeCell(cell->firstBoundary()->first);
removeCell(cell);
count++;
reduced = true;
}
if(getSize(dim) == 0 || getSize(dim-1) == 0) break;
if(cit != lastCell(dim)) cit++;
}
}
_reduced = true;
Msg::Debug("Cell complex %d-coreduction removed %dv, %df, %de, %dn", dim,
numCells[3]-getSize(3), numCells[2]-getSize(2),
numCells[1]-getSize(1), numCells[0]-getSize(0));
return count;
}
int CellComplex::getSize(int dim, bool orig) {
if(dim == -1) {
unsigned int size = 0;
if(!orig) for(int i = 0; i < 4; i++) size += _cells[i].size();
else for(int i = 0; i < 4; i++) size += _ocells[i].size();
return size;
}
if(!orig) return _cells[dim].size();
else return _ocells[dim].size();
}
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)
{
Msg::Debug("Omitting %d-cell from the cell complex", cell->getDim());
removeCell(cell, false);
std::vector<Cell*> omittedCells;
omittedCells.push_back(cell);
int count = 0;
int numCells[4];
for(int i = 0; i < 4; i++) numCells[i] = getSize(i);
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("Cell complex %d-omit removed %dv, %df, %de, %dn",
cell->getDim(),
numCells[3]-getSize(3), numCells[2]-getSize(2),
numCells[1]-getSize(1), numCells[0]-getSize(0));
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)
{
if(!getSize(0)) return 0;
double t1 = Cpu();
int count = 0;
if(relative() && !homseq) removeSubdomain();
std::vector<Cell*> empty;
for(int i = 3; i > 0; i--) count = count + reduction(i, -1, empty);
if(omit && !homseq){
std::vector<Cell*> newCells;
while (getSize(getDim()) != 0){
citer cit = firstCell(getDim());
Cell* cell = *cit;
newCells.push_back(_omitCell(cell, false));
}
for(unsigned int i = 0; i < newCells.size(); i++){
insertCell(newCells.at(i));
}
}
double t2 = Cpu();
if(t2-t1 > CellComplex::_patience) {
Msg::Info(" .. %d volumes, %d faces, %d edges, and %d vertices",
getSize(3), getSize(2), getSize(1), getSize(0));
}
if(combine > 0) this->combine(3);
if(combine > 2) for(int i = 3; i > 0; i--) reduction(i, -1, empty);
else if(combine > 1) reduction(2, -1, empty);
if(combine > 0) this->combine(2);
if(combine > 2) for(int i = 3; i > 0; i--) reduction(i, -1, empty);
else if(combine > 1) reduction(1, -1, empty);
if(combine > 0) this->combine(1);
if(combine > 2) for(int i = 3; i > 0; i--) reduction(i, -1, empty);
else if(combine > 1) reduction(0, -1, empty);
_reduced = true;
return count;
}
void CellComplex::removeSubdomain()
{
std::vector<Cell*> toRemove;
for(int i = 0; i < 4; i++){
for(citer cit = firstCell(i); cit != lastCell(i); ++cit){
Cell *cell = *cit;
if(cell->inSubdomain()) toRemove.push_back(cell);
}
}
for(unsigned int i = 0; i < toRemove.size(); i++) removeCell(toRemove[i]);
_reduced = true;
}
void CellComplex::removeCells(int dim)
{
if(dim < 0 || dim > 3) return;
std::vector<Cell*> toRemove;
for(citer cit = firstCell(dim); cit != lastCell(dim); ++cit){
toRemove.push_back(*cit);
}
for(unsigned int i = 0; i < toRemove.size(); i++) removeCell(toRemove[i]);
_reduced = true;
}
int CellComplex::coreduceComplex(int combine, bool omit, int heuristic)
{
if(!getSize(0)) return 0;
double t1 = Cpu();
int count = 0;
if(relative()) removeSubdomain();
std::vector<Cell*> empty;
for(int dim = 0; dim < 4; dim++){
citer cit = firstCell(dim);
while(cit != lastCell(dim)){
Cell* cell = *cit;
int count =+ coreduction(cell, -1, empty);
if(count != 0) break;
cit++;
}
}
for(int j = 1; j <= getDim(); j++)
count += coreduction(j, -1, empty);
if(omit){
std::vector<Cell*> newCells;
while (getSize(0) != 0){
citer cit = firstCell(0);
Cell* cell = *cit;
if(heuristic == -1 && _smallestCell.second != 0. &&
hasCell(_smallestCell.first)) {
Msg::Debug("Omitted a cell in the smallest mesh element with volume %g",
_smallestCell.second);
cell = _smallestCell.first;
}
else if(heuristic == 1 && _biggestCell.second != 0. &&
hasCell(_biggestCell.first)) {
Msg::Debug("Omitted a cell in the biggest mesh element with volume %g",
_biggestCell.second);
cell = _biggestCell.first;
}
newCells.push_back(_omitCell(cell, true));
}
for(unsigned int i = 0; i < newCells.size(); i++){
insertCell(newCells.at(i));
}
}
double t2 = Cpu();
if(t2-t1 > CellComplex::_patience) {
Msg::Info(" .. %d volumes, %d faces, %d edges, and %d vertices",
getSize(3), getSize(2), getSize(1), getSize(0));
}
if(combine > 0) this->cocombine(0);
if(combine > 2) for(int i = 1; i < 4; i++) coreduction(i, -1, empty);
else if(combine > 1) coreduction(1, -1, empty);
if(combine > 0) this->cocombine(1);
if(combine > 2) for(int i = 1; i < 4; i++) coreduction(i, -1, empty);
else if(combine > 1) coreduction(2, -1, empty);
if(combine > 0) this->cocombine(2);
if(combine > 2) for(int i = 1; i < 4; i++) coreduction(i, -1, empty);
else if(combine > 1) coreduction(3, -1, empty);
coherent();
_reduced = true;
return count;
}
void CellComplex::bettiReduceComplex()
{
reduceComplex(3, true);
for(int i = 1; i <= 3; i++) cocombine(i-1);
return;
}
int CellComplex::combine(int dim)
{
if(dim < 1 || dim > 3) return 0;
int numCells[4];
for(int i = 0; i < 4; i++) numCells[i] = getSize(i);
double t1 = Cpu();
std::queue<Cell*> Q;
std::set<Cell*, Less_Cell> Qset;
std::map<Cell*, short int, Less_Cell> bd_c;
int count = 0;
for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
double t2 = Cpu();
if(t2-t1 > CellComplex::_patience) {
t1 = Cpu();
Msg::Info(" ... %d volumes, %d faces, %d edges, and %d vertices",
getSize(3), getSize(2), getSize(1), getSize(0));
}
Cell* cell = *cit;
cell->getBoundary(bd_c);
enqueueCells(bd_c, Q, Qset);
while(Q.size() != 0){
Cell* s = Q.front();
Q.pop();
if(s->getCoboundarySize() == 2 && !s->getImmune()){
Cell::biter it = s->firstCoboundary();
int or1 = it->second.get();
Cell* c1 = it->first;
it++;
while (it->second.get() == 0) it++;
int or2 = it->second.get();
Cell* c2 = it->first;
if(!(*c1 == *c2) && abs(or1) == abs(or2) &&
inSameDomain(s, c1) && inSameDomain(s, c2) &&
c1->getImmune() == c2->getImmune() ) {
removeCell(s, true, false);
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));
_createCount++;
removeCell(c1, true, c1->isCombined());
removeCell(c2, true, c2->isCombined());
insertCell(newCell);
cit = firstCell(dim);
count++;
if(c1->isCombined()) {
delete c1;
_deleteCount++;
}
if(c2->isCombined()) {
delete c2;
_deleteCount++;
}
}
}
Qset.erase(s);
}
}
Msg::Debug("Cell complex %d-combine removed %dv, %df, %de, %dn", dim,
numCells[3]-getSize(3), numCells[2]-getSize(2),
numCells[1]-getSize(1), numCells[0]-getSize(0));
_reduced = true;
return count;
}
int CellComplex::cocombine(int dim)
{
if(dim < 0 || dim > 2) return 0;
int numCells[4];
for(int i = 0; i < 4; i++) numCells[i] = getSize(i);
double t1 = Cpu();
std::queue<Cell*> Q;
std::set<Cell*, Less_Cell> Qset;
std::map<Cell*, short int, Less_Cell> cbd_c;
int count = 0;
for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
double t2 = Cpu();
if(t2-t1 > CellComplex::_patience) {
t1 = Cpu();
Msg::Info(" ... %d volumes, %d faces, %d edges, and %d vertices",
getSize(3), getSize(2), getSize(1), getSize(0));
}
Cell* cell = *cit;
cell->getCoboundary(cbd_c);
enqueueCells(cbd_c, Q, Qset);
while(Q.size() != 0){
Cell* s = Q.front();
Q.pop();
if(s->getBoundarySize() == 2){
Cell::biter it = s->firstBoundary();
int or1 = it->second.get();
Cell* c1 = it->first;
it++;
while (it->second.get() == 0) it++;
int or2 = it->second.get();
Cell* c2 = it->first;
if(!(*c1 == *c2) && abs(or1) == abs(or2)
&& inSameDomain(s, c1) && inSameDomain(s, c2)
&& c1->getImmune() == c2->getImmune()){
removeCell(s, true, false);
c1->getCoboundary(cbd_c);
enqueueCells(cbd_c, Q, Qset);
c2->getCoboundary(cbd_c);
enqueueCells(cbd_c, Q, Qset);
CombinedCell* newCell = new CombinedCell(c1, c2,
(or1 != or2), true );
_createCount++;
removeCell(c1, true, c1->isCombined());
removeCell(c2, true, c2->isCombined());
insertCell(newCell);
cit = firstCell(dim);
count++;
if(c1->isCombined()) {
delete c1;
_deleteCount++;
}
if(c2->isCombined()) {
delete c2;
_deleteCount++;
}
}
}
Qset.erase(s);
}
}
Msg::Debug("Cell complex %d-cocombine removed %dv, %df, %de, %dn", dim,
numCells[3]-getSize(3), numCells[2]-getSize(2),
numCells[1]-getSize(1), numCells[0]-getSize(0));
_reduced = true;
return count;
}
bool CellComplex::coherent()
{
bool coherent = true;
for(int i = 0; i < 4; i++){
for(citer cit = firstCell(i); cit != lastCell(i); cit++){
Cell* cell = *cit;
std::map<Cell*, short int, Less_Cell> boundary;
cell->getBoundary(boundary);
for(std::map<Cell*, short int, Less_Cell>::iterator it = boundary.begin();
it != boundary.end(); it++){
Cell* bdCell = (*it).first;
int ori = (*it).second;
citer cit = _cells[bdCell->getDim()].find(bdCell);
if(cit == lastCell(bdCell->getDim())){
Msg::Debug("Boundary cell not in cell complex! Boundary removed");
cell->removeBoundaryCell(bdCell, false);
coherent = false;
}
if(!bdCell->hasCoboundary(cell)){
Msg::Debug("Incoherent boundary/coboundary pair! Fixed");
bdCell->addCoboundaryCell(ori, cell, false);
coherent = false;
}
}
std::map<Cell*, short int, Less_Cell> coboundary;
cell->getCoboundary(coboundary);
for(std::map<Cell*, short int, Less_Cell>::iterator it = coboundary.begin();
it != coboundary.end(); it++){
Cell* cbdCell = (*it).first;
int ori = (*it).second;
citer cit = _cells[cbdCell->getDim()].find(cbdCell);
if(cit == lastCell(cbdCell->getDim())){
Msg::Debug("Coboundary cell not in cell complex! Coboundary removed");
cell->removeCoboundaryCell(cbdCell, false);
coherent = false;
}
if(!cbdCell->hasBoundary(cell)){
Msg::Debug("Incoherent coboundary/boundary pair! Fixed");
cbdCell->addBoundaryCell(ori, cell, false);
coherent = false;
}
}
}
}
return coherent;
}
bool CellComplex::hasCell(Cell* cell, bool orig)
{
citer cit;
if(!orig) cit = _cells[cell->getDim()].find(cell);
else cit = _ocells[cell->getDim()].find(cell);
if( cit == lastCell(cell->getDim(), orig) ) return false;
else return true;
}
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;
if( (domain == 0 && !cell->inSubdomain()) || domain == 1
|| (domain == 2 && cell->inSubdomain()) ){
cells.insert(cell);
}
}
}
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(unsigned int i = 0; i < _removedcells.size(); i++) {
Cell* cell = _removedcells.at(i);
if(cell->isCombined()) {
delete cell;
_deleteCount++;
}
}
_removedcells.clear();
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->restoreCellBoundary();
if(relative()) {
if(cell->inSubdomain()) _numSubdomainCells[i] += 1;
else _numRelativeCells[i] += 1;
}
}
}
Msg::Info("Restored Cell Complex:");
Msg::Info("%d volumes, %d faces, %d edges, and %d vertices",
getSize(3), getSize(2), getSize(1), getSize(0));
_reduced = false;
return true;
}
else {
Msg::Error("Cannot restore cell complex");
return false;
}
}
void CellComplex::printComplex(int dim)
{
if(getSize(dim) == 0)
Msg::Info("Cell complex dimension %d is empty", dim);
for (citer cit = firstCell(dim); cit != lastCell(dim); cit++){
Cell* cell = *cit;
cell->printCell();
cell->printBoundary();
cell->printCoboundary();
printf("--- \n");
}
}
int CellComplex::saveComplex(std::string filename)
{
/*FILE *fp = Fopen (filename.c_str(), "w");
if(!fp){
printf("\nUnable to open file '%s' \n", filename.c_str());
return 0;
}
printf("\nWriting file '%s' ... \n", filename.c_str());
fprintf(fp, "$Cells\n");
fprintf(fp, "%d\n", getSize(0)+getSize(1)+getSize(2)+getSize(3));
for(int dim = 0; dim < 4; dim++){
for(citer cit = firstCell(dim); cit != lastCell(dim); cit++){
Cell* cell = *cit;
fprintf(fp, "%d %d %d %d %d", cell->getNum(), cell->getType(),
1, cell->getDomain(), cell->getNumVertices());
for(int i = 0; i < cell->getNumVertices(); i++){
fprintf(fp, " %d", cell->getVertex(i));
}
fprintf(fp, " %d", cell->getBoundarySize());
for(Cell::biter bit = cell->firstBoundary();
bit != cell->lastBoundary(); bit++){
fprintf(fp, " %d %d", bit->first->getNum(), bit->second);
}
fprintf(fp, " %d", cell->getCoboundarySize());
for(Cell::biter bit = cell->firstCoboundary();
bit != cell->lastCoboundary(); bit++){
fprintf(fp, " %d %d", bit->first->getNum(), bit->second);
}
fprintf(fp, "\n");
}
}
fclose(fp);
printf("Wrote %d cells to '%s' \n",
getSize(0)+getSize(1)+getSize(2)+getSize(3), filename.c_str());
*/
return 1;
}
int CellComplex::loadComplex(std::string filename)
{
/* FILE *fp = Fopen (filename.c_str(), "r");
if(!fp){
printf("\nUnable to open file '%s' \n", filename.c_str());
return 0;
}
std::map<int, Cell*> numToCell;
char str[256] = "XXX";
while(1) {
while(str[0] != '$'){
if(!fgets(str, sizeof(str), fp) || feof(fp))
break;
}
if(feof(fp))
break;
if(!strncmp(&str[1], "Cells", 5)) {
if(!fgets(str, sizeof(str), fp)) return 0;
int numCells;
sscanf(str, "%d", &numCells);
for(int i = 0; i < numCells; i++) {
int num, type, numTags;
std::vector<int> domain;
int tag;
if(fscanf(fp, "%d %d %d", &num, &type, &numTags) != 3) return 0;
for(int j = 0; j < numTags; j++){
if(fscanf(fp, "%d", &tag) != 1) return 0;
domain.push_back(tag);
}
std::vector<int> vertices;
if(fscanf(fp, "%d", &numTags) != 1) return 0;
for(int j = 0; j < numTags; j++){
if(fscanf(fp, "%d", &tag) != 1) return 0;
vertices.push_back(tag);
}
int dim = 0;
if(type == 1){
if(vertices.size() == 2) dim = 1;
else if(vertices.size() == 3) dim = 2;
else if(vertices.size() == 4) dim = 3;
}
Cell* cell = new Cell(num, dim, type, domain, vertices);
numToCell[num] = cell;
int numCell;
if(fscanf(fp, "%d", &numTags) != 1) return 0;
for(int j = 0; j < numTags; j++){
if(fscanf(fp, "%d %d", &numCell, &tag) != 1) return 0;
}
if(fscanf(fp, "%d", &numTags) != 1) return 0;
for(int j = 0; j < numTags; j++){
if(fscanf(fp, "%d %d", &numCell, &tag) != 1) return 0;
}
}
}
}
fclose(fp);
*/
return 1;
}