68 template <
typename triangulationType>
70 const size_t scalarsMTime,
72 const triangulationType &triangulation,
73 const std::vector<bool> *updateMask =
nullptr) {
93 this->
dg_ = std::move(dg);
98 return std::move(this->
dg_);
101 template <
typename triangulationType>
104 const triangulationType &triangulation) {
108 inline const std::vector<std::vector<SimplexId>> &
127 template <
typename triangulationType>
130 const triangulationType &triangulation,
131 const bool ignoreBoundary,
132 const bool compute2SaddlesChildren =
false);
160 template <
typename triangulationType>
161 std::vector<std::vector<SimplexId>>
163 const triangulationType &triangulation)
const;
180 template <
typename triangulationType,
184 std::vector<std::vector<SimplexId>>
186 const GFS &getFaceStar,
187 const GFSN &getFaceStarNumber,
188 const OB &isOnBoundary,
189 const triangulationType &triangulation)
const;
202 template <
typename triangulationType>
204 std::vector<bool> &pairedMinima,
205 std::vector<bool> &paired1Saddles,
206 const std::vector<SimplexId> &criticalEdges,
207 const std::vector<SimplexId> &critEdgesOrder,
209 const triangulationType &triangulation)
const;
222 template <
typename triangulationType>
224 std::vector<bool> &pairedMaxima,
225 std::vector<bool> &pairedSaddles,
226 const std::vector<SimplexId> &criticalSaddles,
227 const std::vector<SimplexId> &critSaddlesOrder,
228 const std::vector<SimplexId> &critMaxsOrder,
229 const triangulationType &triangulation)
const;
244 template <
typename triangulationType>
246 std::vector<bool> &paired1Saddles,
247 std::vector<bool> &paired2Saddles,
248 const bool exportBoundaries,
249 std::vector<GeneratorType> &boundaries,
250 const std::vector<SimplexId> &critical1Saddles,
251 const std::vector<SimplexId> &critical2Saddles,
252 const std::vector<SimplexId> &crit1SaddlesOrder,
253 const triangulationType &triangulation)
const;
264 template <
typename triangulationType>
266 std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
267 std::array<std::vector<SimplexId>, 4> &critCellsOrder,
269 const triangulationType &triangulation,
270 const bool sortEdges)
const;
284 const std::vector<PersistencePair> &pairs,
285 const std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
286 const std::vector<bool> &pairedMinima,
287 const std::vector<bool> &paired1Saddles,
288 const std::vector<bool> &paired2Saddles,
289 const std::vector<bool> &pairedMaxima)
const;
313 std::vector<bool> &pairedExtrema,
314 std::vector<bool> &pairedSaddles,
315 std::vector<SimplexId> &reps,
316 std::vector<tripletType> &triplets,
339 template <
typename triangulationType,
typename Container>
342 std::vector<bool> &onBoundary,
343 std::vector<Container> &s2Boundaries,
344 const std::vector<SimplexId> &s2Mapping,
345 const std::vector<SimplexId> &s1Mapping,
346 std::vector<SimplexId> &partners,
347 std::vector<Lock> &s1Locks,
348 std::vector<Lock> &s2Locks,
349 const triangulationType &triangulation)
const;
374 template <
typename triangulationType>
377 const triangulationType &triangulation) {
379 triangulation.getEdgeVertex(
id, 0, this->
vertsOrder_[0]);
380 triangulation.getEdgeVertex(
id, 1, this->
vertsOrder_[1]);
382 this->vertsOrder_[1] = offsets[this->vertsOrder_[1]];
384 std::sort(this->vertsOrder_.rbegin(), this->vertsOrder_.rend());
392 template <
typename triangulationType>
395 const triangulationType &triangulation) {
397 triangulation.getTriangleVertex(
id, 0, this->
vertsOrder_[0]);
398 triangulation.getTriangleVertex(
id, 1, this->
vertsOrder_[1]);
399 triangulation.getTriangleVertex(
id, 2, this->
vertsOrder_[2]);
401 this->vertsOrder_[1] = offsets[this->vertsOrder_[1]];
402 this->vertsOrder_[2] = offsets[this->vertsOrder_[2]];
404 std::sort(this->vertsOrder_.rbegin(), this->vertsOrder_.rend());
412 template <
typename triangulationType>
415 const triangulationType &triangulation) {
417 triangulation.getCellVertex(
id, 0, this->
vertsOrder_[0]);
418 triangulation.getCellVertex(
id, 1, this->
vertsOrder_[1]);
419 triangulation.getCellVertex(
id, 2, this->
vertsOrder_[2]);
420 triangulation.getCellVertex(
id, 3, this->
vertsOrder_[3]);
422 this->vertsOrder_[1] = offsets[this->vertsOrder_[1]];
423 this->vertsOrder_[2] = offsets[this->vertsOrder_[2]];
424 this->vertsOrder_[3] = offsets[this->vertsOrder_[3]];
426 std::sort(this->vertsOrder_.rbegin(), this->vertsOrder_.rend());
430 template <
typename triangulationType>
431 void alloc(
const triangulationType &triangulation) {
434 if(dim > 3 || dim < 1) {
437#ifdef TTK_ENABLE_OPENMP
438#pragma omp parallel master num_threads(threadNumber_)
441#ifdef TTK_ENABLE_OPENMP
444 this->
firstRepMin_.resize(triangulation.getNumberOfVertices());
446#ifdef TTK_ENABLE_OPENMP
449 this->
firstRepMax_.resize(triangulation.getNumberOfCells());
452#ifdef TTK_ENABLE_OPENMP
455 this->
critEdges_.resize(triangulation.getNumberOfEdges());
456#ifdef TTK_ENABLE_OPENMP
460 triangulation.getNumberOfEdges(), -1);
461#ifdef TTK_ENABLE_OPENMP
464 this->
onBoundary_.resize(triangulation.getNumberOfEdges(),
false);
465#ifdef TTK_ENABLE_OPENMP
468 this->
s2Mapping_.resize(triangulation.getNumberOfTriangles(), -1);
469#ifdef TTK_ENABLE_OPENMP
472 this->
s1Mapping_.resize(triangulation.getNumberOfEdges(), -1);
474 for(
int i = 0; i < dim + 1; ++i) {
475#ifdef TTK_ENABLE_OPENMP
484#ifdef TTK_ENABLE_OPENMP
491#ifdef TTK_ENABLE_OPENMP
498#ifdef TTK_ENABLE_OPENMP
505 this->
printMsg(
"Memory allocations", 1.0, tm.getElapsedTime(), 1,
520 this->
printMsg(
"Memory cleanup", 1.0, tm.getElapsedTime(), 1,
542template <
typename triangulationType>
543std::vector<std::vector<SimplexId>>
545 const std::vector<SimplexId> &criticalEdges,
546 const triangulationType &triangulation)
const {
550 std::vector<std::vector<SimplexId>> res(criticalEdges.size());
553#ifdef TTK_ENABLE_OPENMP
554#pragma omp parallel for num_threads(threadNumber_)
556 for(
size_t i = 0; i < criticalEdges.size(); ++i) {
559 const auto followVPath = [
this, &mins, &triangulation](
const SimplexId v) {
560 std::vector<Cell> vpath{};
562 const Cell &lastCell = vpath.back();
563 if(lastCell.
dim_ == 0 && this->dg_.isCellCritical(lastCell)) {
564 mins.emplace_back(lastCell.
id_);
570 triangulation.getEdgeVertex(criticalEdges[i], 0, v0);
571 triangulation.getEdgeVertex(criticalEdges[i], 1, v1);
578 this->
printMsg(
"Computed the descending 1-separatrices", 1.0,
585template <
typename triangulationType,
typename GFS,
typename GFSN,
typename OB>
586std::vector<std::vector<SimplexId>>
588 const std::vector<SimplexId> &criticalCells,
589 const GFS &getFaceStar,
590 const GFSN &getFaceStarNumber,
591 const OB &isOnBoundary,
592 const triangulationType &triangulation)
const {
596 const auto dim = this->dg_.getDimensionality();
597 std::vector<std::vector<SimplexId>> res(criticalCells.size());
600#ifdef TTK_ENABLE_OPENMP
601#pragma omp parallel for num_threads(threadNumber_)
603 for(
size_t i = 0; i < criticalCells.size(); ++i) {
604 const auto sid = criticalCells[i];
607 const auto followVPath
608 = [
this, dim, &maxs, &triangulation](
const SimplexId v) {
609 std::vector<Cell> vpath{};
610 this->dg_.getAscendingPath(
Cell{dim, v}, vpath, triangulation);
611 const Cell &lastCell = vpath.back();
612 if(lastCell.
dim_ == dim && this->dg_.isCellCritical(lastCell)) {
613 maxs.emplace_back(lastCell.
id_);
614 }
else if(lastCell.
dim_ == dim - 1) {
615 maxs.emplace_back(-1);
619 const auto starNumber = getFaceStarNumber(sid);
621 for(
SimplexId j = 0; j < starNumber; ++j) {
623 getFaceStar(sid, j, cellId);
627 if(isOnBoundary(sid)) {
629 maxs.emplace_back(-1);
633 this->
printMsg(
"Computed the ascending 1-separatrices", 1.0,
640template <
typename triangulationType>
642 std::vector<PersistencePair> &pairs,
643 std::vector<bool> &pairedMinima,
644 std::vector<bool> &paired1Saddles,
645 const std::vector<SimplexId> &criticalEdges,
646 const std::vector<SimplexId> &critEdgesOrder,
648 const triangulationType &triangulation)
const {
652 auto saddle1ToMinima = getSaddle1ToMinima(criticalEdges, triangulation);
656 auto &firstRep{this->firstRepMin_};
657 std::iota(firstRep.begin(), firstRep.end(), 0);
658 std::vector<tripletType> sadMinTriplets{};
660 for(
size_t i = 0; i < saddle1ToMinima.size(); ++i) {
661 auto &mins = saddle1ToMinima[i];
662 const auto s1 = criticalEdges[i];
664 TTK_PSORT(this->threadNumber_, mins.begin(), mins.end());
665 const auto last = std::unique(mins.begin(), mins.end());
666 mins.erase(last, mins.end());
667 if(mins.size() != 2) {
670 sadMinTriplets.emplace_back(
tripletType{s1, mins[0], mins[1]});
673 tripletsToPersistencePairs(pairs, pairedMinima, paired1Saddles, firstRep,
674 sadMinTriplets, critEdgesOrder.data(), offsets, 0);
676 const auto nMinSadPairs = pairs.size();
679 "Computed " + std::to_string(nMinSadPairs) +
" min-saddle pairs", 1.0,
680 tm.getElapsedTime(), this->threadNumber_);
682 this->
printMsg(
"min-saddle pairs sequential part", 1.0,
687template <
typename triangulationType>
689 std::vector<PersistencePair> &pairs,
690 std::vector<bool> &pairedMaxima,
691 std::vector<bool> &pairedSaddles,
692 const std::vector<SimplexId> &criticalSaddles,
693 const std::vector<SimplexId> &critSaddlesOrder,
694 const std::vector<SimplexId> &critMaxsOrder,
695 const triangulationType &triangulation)
const {
699 const auto dim = this->dg_.getDimensionality();
703 ? getSaddle2ToMaxima(
706 return triangulation.getTriangleStar(a, i, r);
709 return triangulation.getTriangleStarNumber(a);
712 return triangulation.isTriangleOnBoundary(a);
715 : getSaddle2ToMaxima(
718 return triangulation.getEdgeStar(a, i, r);
721 return triangulation.getEdgeStarNumber(a);
724 return triangulation.isEdgeOnBoundary(a);
730 auto &firstRep{this->firstRepMax_};
731 std::iota(firstRep.begin(), firstRep.end(), 0);
732 std::vector<tripletType> sadMaxTriplets{};
734 for(
size_t i = 0; i < saddle2ToMaxima.size(); ++i) {
735 auto &maxs = saddle2ToMaxima[i];
737 TTK_PSORT(this->threadNumber_, maxs.begin(), maxs.end(),
747 const auto last = std::unique(maxs.begin(), maxs.end());
748 maxs.erase(last, maxs.end());
752 if(maxs.size() != 2) {
756 const auto s2 = criticalSaddles[i];
757 if(!pairedSaddles[s2]) {
758 sadMaxTriplets.emplace_back(
tripletType{s2, maxs[0], maxs[1]});
762 const auto nMinSadPairs = pairs.size();
764 tripletsToPersistencePairs(pairs, pairedMaxima, pairedSaddles, firstRep,
765 sadMaxTriplets, critSaddlesOrder.data(),
766 critMaxsOrder.data(), dim - 1);
768 const auto nSadMaxPairs = pairs.size() - nMinSadPairs;
771 "Computed " + std::to_string(nSadMaxPairs) +
" saddle-max pairs", 1.0,
772 tm.getElapsedTime(), this->threadNumber_);
774 this->
printMsg(
"saddle-max pairs sequential part", 1.0,
779template <
typename triangulationType,
typename Container>
782 std::vector<bool> &onBoundary,
783 std::vector<Container> &s2Boundaries,
784 const std::vector<SimplexId> &s2Mapping,
785 const std::vector<SimplexId> &s1Mapping,
786 std::vector<SimplexId> &partners,
787 std::vector<Lock> &s1Locks,
788 std::vector<Lock> &s2Locks,
789 const triangulationType &triangulation)
const {
791 auto &boundaryIds{s2Boundaries[s2Mapping[s2]]};
793 const auto addBoundary = [&boundaryIds, &onBoundary](
const SimplexId e) {
796 boundaryIds.emplace(e);
797 onBoundary[e] =
true;
799 const auto it = boundaryIds.find(e);
800 boundaryIds.erase(it);
801 onBoundary[e] =
false;
805 const auto clearOnBoundary = [&boundaryIds, &onBoundary]() {
807 for(
const auto e : boundaryIds) {
808 onBoundary[e] =
false;
812 if(!boundaryIds.empty()) {
814 for(
const auto e : boundaryIds) {
815 onBoundary[e] =
true;
821 triangulation.getTriangleEdge(s2, i, e);
828 s2Locks[s2Mapping[s2]].lock();
830 while(!boundaryIds.empty()) {
832 const auto tau{*boundaryIds.begin()};
834 auto pTau{this->dg_.getPairedCell(
Cell{1, tau}, triangulation)};
835 bool critical{
false};
839#ifdef TTK_ENABLE_OPENMP
840#pragma omp atomic read
842 pTau = partners[tau];
843 if(pTau == -1 || s2Boundaries[s2Mapping[pTau]].empty()) {
846 }
while(*s2Boundaries[s2Mapping[pTau]].
begin() != tau);
855 s1Locks[s1Mapping[tau]].lock();
856 const auto cap = partners[tau];
857 if(partners[tau] == -1) {
860 s1Locks[s1Mapping[tau]].unlock();
864 s2Locks[s2Mapping[s2]].unlock();
868 return this->eliminateBoundariesSandwich(
869 s2, onBoundary, s2Boundaries, s2Mapping, s1Mapping, partners, s1Locks,
870 s2Locks, triangulation);
875 if(critical && s2Mapping[pTau] != -1) {
876 if(s2Mapping[pTau] < s2Mapping[s2]) {
882 s2Locks[s2Mapping[pTau]].lock();
883 for(
const auto e : s2Boundaries[s2Mapping[pTau]]) {
886 s2Locks[s2Mapping[pTau]].unlock();
887 if(this->Compute2SaddlesChildren) {
888 this->s2Children_[s2Mapping[s2]].emplace_back(s2Mapping[pTau]);
891 }
else if(s2Mapping[pTau] > s2Mapping[s2]) {
895 s1Locks[s1Mapping[tau]].lock();
896 const auto cap = partners[tau];
897 if(partners[tau] == pTau) {
900 s1Locks[s1Mapping[tau]].unlock();
905 s2Locks[s2Mapping[s2]].unlock();
906 return this->eliminateBoundariesSandwich(
907 pTau, onBoundary, s2Boundaries, s2Mapping, s1Mapping, partners,
908 s1Locks, s2Locks, triangulation);
915 triangulation.getTriangleEdge(pTau, i, e);
924 s2Locks[s2Mapping[s2]].unlock();
928template <
typename triangulationType>
930 std::vector<PersistencePair> &pairs,
931 std::vector<bool> &paired1Saddles,
932 std::vector<bool> &paired2Saddles,
933 const bool exportBoundaries,
934 std::vector<GeneratorType> &boundaries,
935 const std::vector<SimplexId> &critical1Saddles,
936 const std::vector<SimplexId> &critical2Saddles,
937 const std::vector<SimplexId> &crit1SaddlesOrder,
938 const triangulationType &triangulation)
const {
941 const auto nSadExtrPairs = pairs.size();
944 std::vector<SimplexId> saddles1{}, saddles2{};
946 for(
const auto s1 : critical1Saddles) {
947 if(!paired1Saddles[s1]) {
948 saddles1.emplace_back(s1);
952 for(
const auto s2 : critical2Saddles) {
953 if(!paired2Saddles[s2]) {
954 saddles2.emplace_back(s2);
958 if(this->Compute2SaddlesChildren) {
959 this->s2Children_.resize(saddles2.size());
963 const auto &edgesFiltrOrder{crit1SaddlesOrder};
965 auto &onBoundary{this->onBoundary_};
966 auto &edgeTrianglePartner{this->edgeTrianglePartner_};
970 return edgesFiltrOrder[a] > edgesFiltrOrder[b];
972 using Container = std::set<
SimplexId,
decltype(cmpEdges)>;
973 std::vector<Container> s2Boundaries(saddles2.size(), Container(cmpEdges));
976 auto &s2Mapping{this->s2Mapping_};
977#ifdef TTK_ENABLE_OPENMP
978#pragma omp parallel for num_threads(threadNumber_)
980 for(
size_t i = 0; i < saddles2.size(); ++i) {
981 s2Mapping[saddles2[i]] = i;
985 auto &s1Mapping{this->s1Mapping_};
986#ifdef TTK_ENABLE_OPENMP
987#pragma omp parallel for num_threads(threadNumber_)
989 for(
size_t i = 0; i < saddles1.size(); ++i) {
990 s1Mapping[saddles1[i]] = i;
994 std::vector<Lock> s1Locks(saddles1.size());
996 std::vector<Lock> s2Locks(saddles2.size());
1000#ifdef TTK_ENABLE_OPENMP4
1001#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) \
1002 firstprivate(onBoundary)
1004 for(
size_t i = 0; i < saddles2.size(); ++i) {
1006 const auto s2 = saddles2[i];
1007 this->eliminateBoundariesSandwich(s2, onBoundary, s2Boundaries, s2Mapping,
1008 s1Mapping, edgeTrianglePartner, s1Locks,
1009 s2Locks, triangulation);
1016 for(
size_t i = 0; i < saddles2.size(); ++i) {
1017 if(!s2Boundaries[i].empty()) {
1018 const auto s2 = saddles2[i];
1019 const auto s1 = *s2Boundaries[i].begin();
1021 pairs.emplace_back(s1, s2, 1);
1022 paired1Saddles[s1] =
true;
1023 paired2Saddles[s2] =
true;
1027 if(exportBoundaries) {
1028 boundaries.resize(s2Boundaries.size());
1029 for(
size_t i = 0; i < boundaries.size(); ++i) {
1030 const auto &boundSet{s2Boundaries[i]};
1031 if(boundSet.empty()) {
1035 {boundSet.begin(), boundSet.end()},
1037 std::array<SimplexId, 2>{
1038 this->dg_.getCellGreaterVertex(
Cell{2, saddles2[i]}, triangulation),
1039 this->dg_.getCellGreaterVertex(
1040 Cell{1, *boundSet.begin()}, triangulation),
1045 const auto nSadSadPairs = pairs.size() - nSadExtrPairs;
1048 "Computed " + std::to_string(nSadSadPairs) +
" saddle-saddle pairs", 1.0,
1049 tm2.getElapsedTime(), this->threadNumber_);
1051 this->
printMsg(
"saddle-saddle pairs sequential part", 1.0,
1056template <
typename triangulationType>
1058 std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
1059 std::array<std::vector<SimplexId>, 4> &critCellsOrder,
1061 const triangulationType &triangulation,
1062 const bool sortEdges)
const {
1066 this->dg_.getCriticalPoints(criticalCellsByDim, triangulation);
1068 this->
printMsg(
"Extracted critical cells", 1.0, tm.getElapsedTime(),
1073 auto &critEdges{this->critEdges_};
1075 critEdges.resize(criticalCellsByDim[1].size());
1077 std::vector<TriangleSimplex> critTriangles(criticalCellsByDim[2].size());
1078 std::vector<TetraSimplex> critTetras(criticalCellsByDim[3].size());
1080#ifdef TTK_ENABLE_OPENMP
1081#pragma omp parallel num_threads(threadNumber_)
1085#ifdef TTK_ENABLE_OPENMP
1086#pragma omp for nowait
1088 for(
size_t i = 0; i < critEdges.size(); ++i) {
1089 critEdges[i].fillEdge(i, offsets, triangulation);
1092#ifdef TTK_ENABLE_OPENMP
1093#pragma omp for nowait
1095 for(
size_t i = 0; i < critEdges.size(); ++i) {
1096 critEdges[i].fillEdge(criticalCellsByDim[1][i], offsets, triangulation);
1100#ifdef TTK_ENABLE_OPENMP
1101#pragma omp for nowait
1103 for(
size_t i = 0; i < critTriangles.size(); ++i) {
1104 critTriangles[i].fillTriangle(
1105 criticalCellsByDim[2][i], offsets, triangulation);
1108#ifdef TTK_ENABLE_OPENMP
1111 for(
size_t i = 0; i < critTetras.size(); ++i) {
1112 critTetras[i].fillTetra(criticalCellsByDim[3][i], offsets, triangulation);
1116 TTK_PSORT(this->threadNumber_, critEdges.begin(), critEdges.end());
1117 TTK_PSORT(this->threadNumber_, critTriangles.begin(), critTriangles.end());
1118 TTK_PSORT(this->threadNumber_, critTetras.begin(), critTetras.end());
1120#ifdef TTK_ENABLE_OPENMP
1121#pragma omp parallel num_threads(threadNumber_)
1124#ifdef TTK_ENABLE_OPENMP
1125#pragma omp for nowait
1127 for(
size_t i = 0; i < critEdges.size(); ++i) {
1128 critCellsOrder[1][critEdges[i].id_] = i;
1131#ifdef TTK_ENABLE_OPENMP
1132#pragma omp for nowait
1134 for(
size_t i = 0; i < critTriangles.size(); ++i) {
1135 criticalCellsByDim[2][i] = critTriangles[i].id_;
1136 critCellsOrder[2][critTriangles[i].id_] = i;
1139#ifdef TTK_ENABLE_OPENMP
1142 for(
size_t i = 0; i < critTetras.size(); ++i) {
1143 criticalCellsByDim[3][i] = critTetras[i].id_;
1144 critCellsOrder[3][critTetras[i].id_] = i;
1150 criticalCellsByDim[1].
end(),
1152 return critCellsOrder[1][a] < critCellsOrder[1][b];
1155#ifdef TTK_ENABLE_OPENMP
1156#pragma omp parallel for num_threads(threadNumber_)
1158 for(
size_t i = 0; i < critEdges.size(); ++i) {
1159 criticalCellsByDim[1][i] = critEdges[i].id_;
1163 this->
printMsg(
"Extracted & sorted critical cells", 1.0, tm.getElapsedTime(),
1168template <
typename triangulationType>
1170 std::vector<PersistencePair> &pairs,
1172 const triangulationType &triangulation,
1173 const bool ignoreBoundary,
1174 const bool compute2SaddlesChildren) {
1177 this->alloc(triangulation);
1181 const auto dim = this->dg_.getDimensionality();
1182 this->Compute2SaddlesChildren = compute2SaddlesChildren;
1185 std::array<std::vector<SimplexId>, 4> criticalCellsByDim{};
1187 auto &critCellsOrder{this->critCellsOrder_};
1189 this->extractCriticalCells(
1190 criticalCellsByDim, critCellsOrder, offsets, triangulation, dim == 3);
1193 auto &pairedMinima{this->pairedCritCells_[0]};
1195 auto &paired1Saddles{this->pairedCritCells_[1]};
1197 auto &paired2Saddles{this->pairedCritCells_[dim - 1]};
1199 auto &pairedMaxima{this->pairedCritCells_[dim]};
1204 if(this->ComputeMinSad) {
1206 this->getMinSaddlePairs(pairs, pairedMinima, paired1Saddles,
1207 criticalCellsByDim[1], critCellsOrder[1], offsets,
1211 for(
const auto min : criticalCellsByDim[0]) {
1212 if(!pairedMinima[min]) {
1213 pairs.emplace_back(min, -1, 0);
1214 pairedMinima[min] =
true;
1220 const auto globMin{*std::min_element(
1221 criticalCellsByDim[0].
begin(), criticalCellsByDim[0].
end(),
1223 return offsets[a] < offsets[b];
1225 pairs.emplace_back(globMin, -1, 0);
1226 pairedMinima[globMin] =
true;
1230 if(dim > 1 && this->ComputeSadMax) {
1232 this->getMaxSaddlePairs(
1233 pairs, pairedMaxima, paired2Saddles, criticalCellsByDim[dim - 1],
1234 critCellsOrder[dim - 1], critCellsOrder[dim], triangulation);
1237 if(ignoreBoundary) {
1241 = std::find_if(pairs.begin(), pairs.end(), [&](
const PersistencePair &p) {
1242 if(p.type < dim - 1) {
1245 const Cell cmax{dim, p.death};
1246 const auto vmax{this->getCellGreaterVertex(cmax, triangulation)};
1247 return offsets[vmax] == triangulation.getNumberOfVertices() - 1;
1250 if(it != pairs.end()) {
1252 paired2Saddles[it->birth] =
false;
1253 pairedMaxima[it->death] =
false;
1259 if(dim == 3 && !criticalCellsByDim[1].empty()
1260 && !criticalCellsByDim[2].empty() && this->ComputeSadSad) {
1261 std::vector<GeneratorType> tmp{};
1262 this->getSaddleSaddlePairs(
1263 pairs, paired1Saddles, paired2Saddles,
false, tmp, criticalCellsByDim[1],
1264 criticalCellsByDim[2], critCellsOrder[1], triangulation);
1267 if(std::is_same<triangulationType, ttk::ExplicitTriangulation>::value) {
1269 size_t nHandles{}, nCavities{}, nNonPairedMax{};
1270 if((dim == 2 && !ignoreBoundary && this->ComputeMinSad
1271 && this->ComputeSadMax)
1272 || (dim == 3 && this->ComputeMinSad && this->ComputeSadSad)) {
1274 for(
const auto s1 : criticalCellsByDim[1]) {
1275 if(!paired1Saddles[s1]) {
1276 paired1Saddles[s1] =
true;
1278 pairs.emplace_back(s1, -1, 1);
1283 if(dim == 3 && !ignoreBoundary && this->ComputeSadMax
1284 && this->ComputeSadSad) {
1286 for(
const auto s2 : criticalCellsByDim[2]) {
1287 if(!paired2Saddles[s2]) {
1288 paired2Saddles[s2] =
true;
1290 pairs.emplace_back(s2, -1, 2);
1295 if(dim == 2 && !ignoreBoundary && this->ComputeSadMax) {
1297 for(
const auto max : criticalCellsByDim[dim]) {
1298 if(!pairedMaxima[max]) {
1299 pairs.emplace_back(max, -1, 2);
1306 = (dim == 3 ? nCavities : nHandles) + nConnComp - nNonPairedMax;
1307 nBoundComp = std::max(nBoundComp, 0);
1310 const std::vector<std::vector<std::string>> rows{
1311 {
" #Connected components", std::to_string(nConnComp)},
1312 {
" #Topological handles", std::to_string(nHandles)},
1313 {
" #Cavities", std::to_string(nCavities)},
1314 {
" #Boundary components", std::to_string(nBoundComp)},
1321 "Computed " + std::to_string(pairs.size()) +
" persistence pairs", 1.0,
1322 tm.getElapsedTime(), this->threadNumber_);
1324 this->displayStats(pairs, criticalCellsByDim, pairedMinima, paired1Saddles,
1325 paired2Saddles, pairedMaxima);
#define TTK_PSORT(NTHREADS,...)
Parallel sort macro.
AbstractTriangulation is an interface class that defines an interface for efficient traversal methods...
virtual int setThreadNumber(const int threadNumber)
Minimalist debugging class.
virtual int setDebugLevel(const int &debugLevel)
TTK DiscreteMorseSandwich processing package.
void setComputeSadMax(const bool data)
std::array< SimplexId, 3 > tripletType
Triplet type for persistence pairs.
std::vector< SimplexId > s1Mapping_
ttk::dcg::DiscreteGradient && getGradient()
dcg::DiscreteGradient dg_
std::vector< SimplexId > firstRepMin_
std::vector< std::vector< SimplexId > > s2Children_
const std::vector< std::vector< SimplexId > > & get2SaddlesChildren() const
std::array< std::vector< SimplexId >, 4 > critCellsOrder_
SimplexId getCellGreaterVertex(const dcg::Cell &c, const triangulationType &triangulation)
std::vector< bool > onBoundary_
void alloc(const triangulationType &triangulation)
std::vector< EdgeSimplex > critEdges_
std::vector< SimplexId > edgeTrianglePartner_
void setGradient(ttk::dcg::DiscreteGradient &&dg)
Ugly hack to avoid a call to buildGradient()
void setComputeMinSad(const bool data)
void setInputOffsets(const SimplexId *const offsets)
bool Compute2SaddlesChildren
void preconditionTriangulation(AbstractTriangulation *const data)
std::vector< SimplexId > firstRepMax_
int buildGradient(const void *const scalars, const size_t scalarsMTime, const SimplexId *const offsets, const triangulationType &triangulation, const std::vector< bool > *updateMask=nullptr)
void setComputeSadSad(const bool data)
void getMinSaddlePairs(std::vector< PersistencePair > &pairs, std::vector< bool > &pairedMinima, std::vector< bool > &paired1Saddles, const std::vector< SimplexId > &criticalEdges, const std::vector< SimplexId > &critEdgesOrder, const SimplexId *const offsets, const triangulationType &triangulation) const
Compute the pairs of dimension 0.
void extractCriticalCells(std::array< std::vector< SimplexId >, 4 > &criticalCellsByDim, std::array< std::vector< SimplexId >, 4 > &critCellsOrder, const SimplexId *const offsets, const triangulationType &triangulation, const bool sortEdges) const
Extract & sort critical cell from the DiscreteGradient.
void displayStats(const std::vector< PersistencePair > &pairs, const std::array< std::vector< SimplexId >, 4 > &criticalCellsByDim, const std::vector< bool > &pairedMinima, const std::vector< bool > &paired1Saddles, const std::vector< bool > &paired2Saddles, const std::vector< bool > &pairedMaxima) const
Print number of pairs, critical cells per dimension & unpaired cells.
std::vector< SimplexId > s2Mapping_
void getSaddleSaddlePairs(std::vector< PersistencePair > &pairs, std::vector< bool > &paired1Saddles, std::vector< bool > &paired2Saddles, const bool exportBoundaries, std::vector< GeneratorType > &boundaries, const std::vector< SimplexId > &critical1Saddles, const std::vector< SimplexId > &critical2Saddles, const std::vector< SimplexId > &crit1SaddlesOrder, const triangulationType &triangulation) const
Compute the saddle-saddle pairs (in 3D)
int computePersistencePairs(std::vector< PersistencePair > &pairs, const SimplexId *const offsets, const triangulationType &triangulation, const bool ignoreBoundary, const bool compute2SaddlesChildren=false)
Compute the persistence pairs from the discrete gradient.
std::vector< std::vector< SimplexId > > getSaddle2ToMaxima(const std::vector< SimplexId > &criticalCells, const GFS &getFaceStar, const GFSN &getFaceStarNumber, const OB &isOnBoundary, const triangulationType &triangulation) const
Follow the ascending 1-separatrices to compute the saddles -> maxima association.
std::array< std::vector< bool >, 4 > pairedCritCells_
SimplexId eliminateBoundariesSandwich(const SimplexId s2, std::vector< bool > &onBoundary, std::vector< Container > &s2Boundaries, const std::vector< SimplexId > &s2Mapping, const std::vector< SimplexId > &s1Mapping, std::vector< SimplexId > &partners, std::vector< Lock > &s1Locks, std::vector< Lock > &s2Locks, const triangulationType &triangulation) const
Detect 1-saddles paired to a given 2-saddle.
void getMaxSaddlePairs(std::vector< PersistencePair > &pairs, std::vector< bool > &pairedMaxima, std::vector< bool > &pairedSaddles, const std::vector< SimplexId > &criticalSaddles, const std::vector< SimplexId > &critSaddlesOrder, const std::vector< SimplexId > &critMaxsOrder, const triangulationType &triangulation) const
Compute the pairs of dimension dim - 1.
void tripletsToPersistencePairs(std::vector< PersistencePair > &pairs, std::vector< bool > &pairedExtrema, std::vector< bool > &pairedSaddles, std::vector< SimplexId > &reps, std::vector< tripletType > &triplets, const SimplexId *const saddlesOrder, const SimplexId *const extremaOrder, const SimplexId pairDim) const
Compute persistence pairs from triplets.
std::vector< std::vector< SimplexId > > getSaddle1ToMinima(const std::vector< SimplexId > &criticalEdges, const triangulationType &triangulation) const
Follow the descending 1-separatrices to compute the saddles -> minima association.
TTK discreteGradient processing package.
void setInputOffsets(const SimplexId *const data)
void setInputScalarField(const void *const data, const size_t mTime)
SimplexId getNumberOfCells(const int dimension, const triangulationType &triangulation) const
void setLocalGradient()
Use local storage instead of cache.
SimplexId getCellGreaterVertex(const Cell c, const triangulationType &triangulation) const
int buildGradient(const triangulationType &triangulation, bool bypassCache=false, const std::vector< bool > *updateMask=nullptr)
void preconditionTriangulation(AbstractTriangulation *const data)
int getDimensionality() const
int getDescendingPath(const Cell &cell, std::vector< Cell > &vpath, const triangulationType &triangulation) const
int SimplexId
Identifier type for simplices of any dimension.
T end(std::pair< T, T > &p)
T begin(std::pair< T, T > &p)
Simplex adaptation for edges
void fillEdge(const SimplexId id, const SimplexId *const offsets, const triangulationType &triangulation)
Type for exporting persistent generators.
std::array< SimplexId, 2 > critVertsIds
std::vector< SimplexId > boundary
Persistence pair struct as exported by DiscreteGradient.
PersistencePair(SimplexId b, SimplexId d, int t)
Ad-hoc struct for sorting simplices.
friend bool operator<(const Simplex< n > &lhs, const Simplex< n > &rhs)
std::array< SimplexId, n > vertsOrder_
Simplex adaptation for tetrahedra
void fillTetra(const SimplexId id, const SimplexId *const offsets, const triangulationType &triangulation)
Simplex adaptation for triangles
void fillTriangle(const SimplexId id, const SimplexId *const offsets, const triangulationType &triangulation)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)