diff --git a/Geo/ChainComplex.cpp b/Geo/ChainComplex.cpp index 2d8fb36c989e8583c1c0a0452614ee542867e9bc..fabbf3b36f9a901345eb639c99ebdcf585c5b89f 100644 --- a/Geo/ChainComplex.cpp +++ b/Geo/ChainComplex.cpp @@ -668,7 +668,7 @@ void ChainComplex::smoothenChain(std::map<Cell*, int, Less_Cell>& cells) } eraseNullCells(cells); int size = cells.size(); - Msg::Info("Smoothened a %d-chain from %d cells to %d cells", + Msg::Info("Simplified a %d-chain from %d cells to %d cells", dim, start, size); } diff --git a/Geo/GModel.cpp b/Geo/GModel.cpp index ed620e77db2729e6701566bcd4bfd8ebb2f8ae54..28231946bfffca78d85056541b91d12982d953a2 100644 --- a/Geo/GModel.cpp +++ b/Geo/GModel.cpp @@ -3220,19 +3220,25 @@ void GModel::computeHomology() } std::string dims = ss.str(); - if(type == "Homology") { + if(type == "Homology" && !homology->isHomologyComputed(dim)) { + homology->findHomologyBasis(dim); + Msg::Info("Homology space basis chains to save: %s.", dims.c_str()); for(unsigned int i = 0; i < dim.size(); i++) if(dim.at(i) >= 0 && dim.at(i) <= getDim()) homology->addChainsToModel(dim.at(i)); + } - else if(type == "Cohomology") { + else if(type == "Cohomology" && !homology->isCohomologyComputed(dim)) { + homology->findCohomologyBasis(dim); + Msg::Info("Cohomology space basis cochains to save: %s.", dims.c_str()); for(unsigned int i = 0; i < dim.size(); i++) if(dim.at(i) >= 0 && dim.at(i) <= getDim()) homology->addCochainsToModel(dim.at(i)); + } else Msg::Error("Unknown type of homology computation: %s", type.c_str()); diff --git a/Geo/Homology.cpp b/Geo/Homology.cpp index a9db40d532232c597332285637a8e4d78e1435c9..69a14f6d1aa0ea7caae57fe3e07b46466df537f9 100644 --- a/Geo/Homology.cpp +++ b/Geo/Homology.cpp @@ -137,8 +137,8 @@ void Homology::_deleteChains(std::vector<int> dim) if(d < 0 || d > 3) continue; for(unsigned int i = 0; i < _chains[d].size(); i++) { delete _chains[d].at(i); - _chains[d].clear(); } + _chains[d].clear(); _homologyComputed[d] = false; } } @@ -157,8 +157,8 @@ void Homology::_deleteCochains(std::vector<int> dim) if(d < 0 || d > 3) continue; for(unsigned int i = 0; i < _cochains[d].size(); i++) { delete _cochains[d].at(i); - _cochains[d].clear(); } + _cochains[d].clear(); _cohomologyComputed[d] = false; } } @@ -179,7 +179,7 @@ void Homology::findHomologyBasis(std::vector<int> dim) double t1 = Cpu(); int omitted = _cellComplex->reduceComplex(_combine, _omit); - if(!dim.empty() && _combine > 1) { + if(!dim.empty() && _combine > 1 && !_smoothen) { for(int i = 1; i <= 3; i++) { if(!std::binary_search(dim.begin(), dim.end(), i)) { _cellComplex->cocombine(i-1); @@ -297,7 +297,7 @@ void Homology::findCohomologyBasis(std::vector<int> dim) std::string name = "H^" + dimension + domain + generator; std::map<Cell*, int, Less_Cell> chain; - chainComplex.getBasisChain(chain, i, j, 3, _smoothen); + chainComplex.getBasisChain(chain, i, j, 3, false); int torsion = chainComplex.getTorsion(j,i); if(!chain.empty()) { _createChain(chain, name, true); @@ -331,6 +331,102 @@ void Homology::findCohomologyBasis(std::vector<int> dim) } } +bool Homology::isHomologyComputed(std::vector<int> dim) +{ + if(dim.empty()) return (_homologyComputed[0] && + _homologyComputed[1] && + _homologyComputed[2] && + _homologyComputed[3]); + + bool computed = true; + for(unsigned int i = 0; i < dim.size(); i++) { + int d = dim.at(i); + if(d < 0 || d > 3) continue; + computed = computed && _homologyComputed[d]; + } + return computed; +} + +bool Homology::isCohomologyComputed(std::vector<int> dim) +{ + if(dim.empty()) return (_cohomologyComputed[0] && + _cohomologyComputed[1] && + _cohomologyComputed[2] && + _cohomologyComputed[3]); + + bool computed = true; + for(unsigned int i = 0; i < dim.size(); i++) { + int d = dim.at(i); + if(d < 0 || d > 3) continue; + computed = computed && _cohomologyComputed[d]; + } + return computed; +} + +void Homology::findCompatibleBasisPair(int master, std::vector<int> dim) +{ + if(!this->isHomologyComputed(dim)) this->findHomologyBasis(dim); + if(!this->isCohomologyComputed(dim)) this->findCohomologyBasis(dim); + for(unsigned int idim = 0 ; idim < dim.size(); idim++) { + int d = dim.at(idim); + if(d < 1 || d > 2) continue; + int n = this->betti(d); + if(n < 2) continue; + if((int)_chains[d].size() != n || (int)_cochains[d].size() != n) { + Msg::Warning("Cannot produce compatible %d-(co)homology bases.", d); + Msg::Debug("%d basis %d-chains and %d basis %d-cochains.", + (int)_chains[d].size(), d, (int)_cochains[d].size(), d); + continue; + } + fullMatrix<double> m(n,n); + for(int i = 0; i < n; i++) { + for(int j = 0; j < n; j++) { + if(master==0) m(i,j) = incidence(*_cochains[d].at(i), *_chains[d].at(j)); + else m(i,j) = incidence(*_chains[d].at(i), *_cochains[d].at(j)); + } + } + + int det = m.determinant(); + if(abs(det) != 1 || !m.invertInPlace()) { + Msg::Warning("Cannot produce compatible %d-(co)homology bases.", d); + Msg::Debug("Incidence matrix: "); + for(int i = 0; i < n; i++) + for(int j = 0; j < n; j++) + Msg::Debug("(%d, %d) = %d", i, j, m(i,j)); + continue; + } + + std::vector<Chain<int>*> newBasis(n, NULL); + + if(master==0) { + for(int i = 0; i < n; i++) { + newBasis.at(i) = new Chain<int>(); + for(int j = 0; j < n; j++) { + *newBasis.at(i) += (int)m(i,j)*(*_cochains[d].at(j)); + } + } + for(int i = 0; i < n; i++) { + newBasis.at(i)->setName(_cochains[d].at(i)->getName()); + delete _cochains[d].at(i); + _cochains[d].at(i) = newBasis.at(i); + } + } + else { + for(int i = 0; i < n; i++) { + newBasis.at(i) = new Chain<int>(); + for(int j = 0; j < n; j++) { + *newBasis.at(i) += (int)m(i,j)*(*_chains[d].at(j)); + } + } + for(int i = 0; i < n; i++) { + newBasis.at(i)->setName(_chains[d].at(i)->getName()); + delete _chains[d].at(i); + _chains[d].at(i) = newBasis.at(i); + } + } + } +} + void Homology::addChainsToModel(int dim, bool post, int physicalNumRequest) { int pgnum = -1; diff --git a/Geo/Homology.h b/Geo/Homology.h index 0af68cbd80ef5d7619a7f91230f6515d89a2dcee..386e6a7e7f122d448a4d6588b1b462079de87a62 100644 --- a/Geo/Homology.h +++ b/Geo/Homology.h @@ -99,12 +99,28 @@ class Homology GModel* getModel() const { return _model; } void setFileName(std::string fileName) { _fileName = fileName; } + void getDomain(std::vector<int>& domain) { domain = _domain; } + void getSubdomain(std::vector<int>& subdomain) { subdomain = _subdomain; } + // find the bases of (co)homology spaces // if dim is empty, find 0-,1-,2-,3-(co)homology spaces bases // otherwise only find those indicated in dim void findHomologyBasis(std::vector<int> dim=std::vector<int>()); void findCohomologyBasis(std::vector<int> dim=std::vector<int>()); + // find a homology and cohomology basis pair such that + // the incidence matrix of the bases is an identity matrix + // if master==0, homology basis determines the cohomology basis + // if dim is empty, find 0-,1-,2-,3-(co)homology spaces bases + // otherwise only find those indicated in dim + void findCompatibleBasisPair(int master=0, + std::vector<int> dim=std::vector<int>()); + + // is the (co)homology in given dimensions already compited + // if dim is empty, return true only if computed in all dimensions + bool isHomologyComputed(std::vector<int> dim=std::vector<int>()); + bool isCohomologyComputed(std::vector<int> dim=std::vector<int>()); + // add chains to Gmsh model // dim: only add dim-chains if dim != -1 // post: create a post-processing view diff --git a/Plugin/HomologyComputation.cpp b/Plugin/HomologyComputation.cpp index 9d52c8714a0800318f9ed08980208849a713dd47..e3794c78d4521336fdb3f6daf6368d0b306d2e27 100644 --- a/Plugin/HomologyComputation.cpp +++ b/Plugin/HomologyComputation.cpp @@ -25,7 +25,7 @@ StringXNumber HomologyComputationOptions_Number[] = { {GMSH_FULLRC, "CreatePostProcessingViews", NULL, 1.}, {GMSH_FULLRC, "ReductionOmit", NULL, 1.}, {GMSH_FULLRC, "ReductionCombine", NULL, 2.}, - {GMSH_FULLRC, "PostProcessSmoothen", NULL, 1.} + {GMSH_FULLRC, "PostProcessSimplify", NULL, 1.} }; StringXString HomologyComputationOptions_String[] = {