25template <
typename dataType,
typename triangulationType>
29 const dataType *
const scalars,
30 const triangulationType &triangulation)
const {
36template <
typename triangulationType>
39 const std::vector<bool> *updateMask) {
42 triangulation, bypassCache, updateMask);
45template <
typename dataType,
typename triangulationType>
48 const std::vector<bool> *updateMask) {
50#ifdef TTK_ENABLE_MPI_TIME
55 auto &cacheHandler = *triangulation.getGradientCacheHandler();
56 const auto findGradient
64#ifdef TTK_ENABLE_OPENMP
65 if(!bypassCache && omp_in_parallel()) {
67 "buildGradient() called inside a parallel region, disabling cache...");
79 if(this->
gradient_ ==
nullptr && !bypassCache) {
86 this->initMemory(triangulation);
89 this->processLowerStarsWithMask(
91 this->
printMsg(
"Update cached discrete gradient", 1.0,
92 tm.getElapsedTime(), this->threadNumber_);
94 this->processLowerStarsStochastic<dataType, triangulationType>(
96 this->
printMsg(
"Built gradient (stochastic algorithm)", 1.0,
97 tm.getElapsedTime(), this->threadNumber_);
101 this->
printMsg(
"Built gradient (homotopic expansion)", 1.0,
102 tm.getElapsedTime(), this->threadNumber_);
103#ifdef TTK_ENABLE_MPI_TIME
108 +
" MPI processes lasted: " + std::to_string(elapsedTime));
113 this->
printMsg(
"Fetched cached discrete gradient");
116 this->processLowerStarsWithMask(
118 this->
printMsg(
"Update cached discrete gradient", 1.0,
119 tm.getElapsedTime(), this->threadNumber_);
125template <
typename triangulationType>
127 const std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
128 std::vector<std::array<float, 3>> &points,
129 std::vector<char> &cellDimensions,
130 std::vector<SimplexId> &cellIds,
131 std::vector<char> &isOnBoundary,
132 std::vector<SimplexId> &PLVertexIdentifiers,
133 const triangulationType &triangulation)
const {
135 std::array<size_t, 5> partSums{};
136 for(
size_t i = 0; i < criticalCellsByDim.size(); ++i) {
137 partSums[i + 1] = partSums[i] + criticalCellsByDim[i].size();
140 const auto nCritPoints = partSums.back();
142 points.resize(nCritPoints);
143 cellDimensions.resize(nCritPoints);
144 cellIds.resize(nCritPoints);
145 isOnBoundary.resize(nCritPoints);
146 PLVertexIdentifiers.resize(nCritPoints);
148 for(
size_t i = 0; i < criticalCellsByDim.size(); ++i) {
149#ifdef TTK_ENABLE_OPENMP
150#pragma omp parallel for num_threads(threadNumber_)
152 for(
size_t j = 0; j < criticalCellsByDim[i].size(); ++j) {
153 const SimplexId cellId = criticalCellsByDim[i][j];
154 const int cellDim = i;
155 const auto o{partSums[i] + j};
157 triangulation.getCellIncenter(cellId, i, points[o].data());
158 cellDimensions[o] = cellDim;
161 triangulation.getDistributedGlobalCellId(cellId, cellDim, globalId);
162 cellIds[o] = globalId;
166 const Cell cell{
static_cast<int>(i), cellId};
167 isOnBoundary[o] = this->
isBoundary(cell, triangulation);
175 = std::vector<std::string>{
"#" + std::to_string(i) +
"-cell(s)",
176 std::to_string(criticalCellsByDim[i].size())};
183template <
typename triangulationType>
185 std::vector<std::array<float, 3>> &points,
186 std::vector<char> &cellDimensions,
187 std::vector<SimplexId> &cellIds,
188 std::vector<char> &isOnBoundary,
189 std::vector<SimplexId> &PLVertexIdentifiers,
190 const triangulationType &triangulation)
const {
192 std::array<std::vector<SimplexId>, 4> criticalCellsByDim;
195 isOnBoundary, PLVertexIdentifiers, triangulation);
200template <
typename triangulationType>
202 std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
203 const triangulationType &triangulation)
const {
206 for(
int i = 0; i < dims; ++i) {
209 std::vector<std::vector<SimplexId>> critCellsPerThread(this->
threadNumber_);
215#ifdef TTK_ENABLE_OPENMP
216#pragma omp parallel for num_threads(this->threadNumber_) schedule(static)
218 for(
SimplexId j = 0; j < numberOfCells; ++j) {
219#ifdef TTK_ENABLE_OPENMP
220 const auto tid = omp_get_thread_num();
229 critCellsPerThread[tid].emplace_back(j);
234 criticalCellsByDim[i] = std::move(critCellsPerThread[0]);
235 for(
size_t j = 1; j < critCellsPerThread.size(); ++j) {
236 const auto &vec{critCellsPerThread[j]};
237 criticalCellsByDim[i].insert(
238 criticalCellsByDim[i].
end(), vec.begin(), vec.end());
245template <
typename triangulationType>
247 std::vector<Cell> &criticalPoints,
248 const triangulationType &triangulation)
const {
252 for(
int i = 0; i < numberOfDimensions; ++i) {
256 for(
SimplexId j = 0; j < numberOfCells; ++j) {
257 const Cell cell(i, j);
260 criticalPoints.push_back(cell);
268template <
typename triangulationType>
270 const int dimension,
const triangulationType &triangulation)
const {
278 return triangulation.getNumberOfVertices();
282 return triangulation.getNumberOfEdges();
286 return triangulation.getNumberOfTriangles();
290 return triangulation.getNumberOfCells();
297template <
typename triangulationType>
298inline void DiscreteGradient::lowerStarWithMask(
302 const triangulationType &triangulation,
303 const std::vector<bool> *updateMask)
const {
306 for(
auto &vec : ls) {
311 ls[0].emplace_back(
CellExt{0, a});
313 if(updateMask !=
nullptr) {
314 for(
auto &vec : ls[0]) {
315 int vertexId = vec.id_;
316 int edgeId = (*gradient_)[0][vertexId];
318 (*gradient_)[0][vertexId] = -1;
320 (*gradient_)[1][edgeId] = -1;
326 const auto nedges = triangulation.getVertexEdgeNumber(a);
327 ls[1].reserve(nedges);
330 triangulation.getVertexEdge(a, i, edgeId);
332 triangulation.getEdgeVertex(edgeId, 0, vertexId);
334 triangulation.getEdgeVertex(edgeId, 1, vertexId);
336 if(offsets[vertexId] < offsets[a]) {
337 ls[1].emplace_back(CellExt{1, edgeId, {offsets[vertexId], -1, -1}, {}});
341 if(updateMask !=
nullptr) {
342 for(
auto &vec : ls[1]) {
343 int edgeId = vec.id_;
344 int vertexId = (*gradient_)[1][edgeId];
345 int triangleId = (*gradient_)[2][edgeId];
347 (*gradient_)[1][edgeId] = -1;
349 (*gradient_)[0][vertexId] = -1;
352 (*gradient_)[2][edgeId] = -1;
353 if(triangleId != -1) {
354 (*gradient_)[3][triangleId] = -1;
359 if(ls[1].size() < 2) {
364 const auto processTriangle
367 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
369 lowVerts[0] = offsets[v1];
370 lowVerts[1] = offsets[v2];
372 lowVerts[0] = offsets[v0];
373 lowVerts[1] = offsets[v2];
375 lowVerts[0] = offsets[v0];
376 lowVerts[1] = offsets[v1];
379 if(lowVerts[0] < lowVerts[1]) {
380 std::swap(lowVerts[0], lowVerts[1]);
382 if(offsets[a] > lowVerts[0]) {
385 std::array<uint8_t, 3> faces{};
386 for(
const auto &e : ls[1]) {
387 if(e.lowVerts_[0] == lowVerts[0] || e.lowVerts_[0] == lowVerts[1]) {
392 ls[2].emplace_back(CellExt{2, triangleId, lowVerts, faces});
402 const auto ncells = triangulation.getVertexStarNumber(a);
403 ls[2].reserve(ncells);
406 triangulation.getVertexStar(a, i, cellId);
408 triangulation.getCellVertex(cellId, 0, v0);
409 triangulation.getCellVertex(cellId, 1, v1);
410 triangulation.getCellVertex(cellId, 2, v2);
411 processTriangle(cellId, v0, v1, v2);
414 if(updateMask !=
nullptr) {
415 for(
auto &vec : ls[2]) {
416 int triangleId = vec.id_;
417 int edgeId = (*gradient_)[3][triangleId];
419 (*gradient_)[3][triangleId] = -1;
421 (*gradient_)[2][edgeId] = -1;
428 const auto ntri = triangulation.getVertexTriangleNumber(a);
432 triangulation.getVertexTriangle(a, i, triangleId);
434 triangulation.getTriangleVertex(triangleId, 0, v0);
435 triangulation.getTriangleVertex(triangleId, 1, v1);
436 triangulation.getTriangleVertex(triangleId, 2, v2);
437 processTriangle(triangleId, v0, v1, v2);
440 if(updateMask !=
nullptr) {
441 for(
auto &vec : ls[2]) {
442 int triangleId = vec.id_;
443 int edgeId = (*gradient_)[3][triangleId];
444 int tetraId = (*gradient_)[4][triangleId];
446 (*gradient_)[3][triangleId] = -1;
448 (*gradient_)[2][edgeId] = -1;
451 (*gradient_)[4][triangleId] = -1;
453 (*gradient_)[5][tetraId] = -1;
459 if(ls[2].size() >= 3) {
461 const auto ncells = triangulation.getVertexStarNumber(a);
462 ls[3].reserve(ncells);
465 triangulation.getVertexStar(a, i, cellId);
466 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
468 triangulation.getCellVertex(cellId, 0, v0);
469 triangulation.getCellVertex(cellId, 1, v1);
470 triangulation.getCellVertex(cellId, 2, v2);
471 triangulation.getCellVertex(cellId, 3, v3);
473 lowVerts[0] = offsets[v1];
474 lowVerts[1] = offsets[v2];
475 lowVerts[2] = offsets[v3];
477 lowVerts[0] = offsets[v0];
478 lowVerts[1] = offsets[v2];
479 lowVerts[2] = offsets[v3];
481 lowVerts[0] = offsets[v0];
482 lowVerts[1] = offsets[v1];
483 lowVerts[2] = offsets[v3];
485 lowVerts[0] = offsets[v0];
486 lowVerts[1] = offsets[v1];
487 lowVerts[2] = offsets[v2];
489 if(offsets[a] > *std::max_element(
490 lowVerts.begin(), lowVerts.end())) {
493 std::sort(lowVerts.rbegin(), lowVerts.rend());
497 std::array<uint8_t, 3> faces{};
498 for(
const auto &t : ls[2]) {
501 if((t.lowVerts_[0] == lowVerts[0]
502 && (t.lowVerts_[1] == lowVerts[1]
503 || t.lowVerts_[1] == lowVerts[2]))
504 || (t.lowVerts_[0] == lowVerts[1]
505 && t.lowVerts_[1] == lowVerts[2])) {
511 ls[3].emplace_back(CellExt{3, cellId, lowVerts, faces});
515 if(updateMask !=
nullptr) {
516 for(
auto &vec : ls[3]) {
517 int tetraId = vec.id_;
518 int triangleId = (*gradient_)[5][tetraId];
519 (*gradient_)[5][tetraId] = -1;
520 if(triangleId != -1) {
521 (*gradient_)[4][triangleId] = -1;
529template <
typename triangulationType>
531 DiscreteGradient::lowerStar(lowerStarType &ls,
534 const triangulationType &triangulation)
const {
541 for(
auto &vec : ls) {
546 CellExt
const localCellExt{0, a};
547 ls[0].emplace_back(localCellExt);
550 const auto nedges = triangulation.getVertexEdgeNumber(a);
551 ls[1].reserve(nedges);
554 triangulation.getVertexEdge(a, i, edgeId);
556 triangulation.getEdgeVertex(edgeId, 0, vertexId);
558 triangulation.getEdgeVertex(edgeId, 1, vertexId);
560 if(offsets[vertexId] < offsets[a]) {
561 ls[1].emplace_back(CellExt{1, edgeId, {offsets[vertexId], -1, -1}, {}});
565 if(ls[1].size() < 2) {
570 const auto processTriangle
573 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
575 lowVerts[0] = offsets[v1];
576 lowVerts[1] = offsets[v2];
578 lowVerts[0] = offsets[v0];
579 lowVerts[1] = offsets[v2];
581 lowVerts[0] = offsets[v0];
582 lowVerts[1] = offsets[v1];
585 if(lowVerts[0] < lowVerts[1]) {
586 std::swap(lowVerts[0], lowVerts[1]);
588 if(offsets[a] > lowVerts[0]) {
591 std::array<uint8_t, 3> faces{};
592 for(
const auto &e : ls[1]) {
593 if(e.lowVerts_[0] == lowVerts[0] || e.lowVerts_[0] == lowVerts[1]) {
598 CellExt
const localCellExt2{2, triangleId, lowVerts, faces};
599 ls[2].emplace_back(localCellExt2);
609 const auto ncells = triangulation.getVertexStarNumber(a);
610 ls[2].reserve(ncells);
613 triangulation.getVertexStar(a, i, cellId);
615 triangulation.getCellVertex(cellId, 0, v0);
616 triangulation.getCellVertex(cellId, 1, v1);
617 triangulation.getCellVertex(cellId, 2, v2);
618 processTriangle(cellId, v0, v1, v2);
622 const auto ntri = triangulation.getVertexTriangleNumber(a);
626 triangulation.getVertexTriangle(a, i, triangleId);
628 triangulation.getTriangleVertex(triangleId, 0, v0);
629 triangulation.getTriangleVertex(triangleId, 1, v1);
630 triangulation.getTriangleVertex(triangleId, 2, v2);
631 processTriangle(triangleId, v0, v1, v2);
635 if(ls[2].size() >= 3) {
637 const auto ncells = triangulation.getVertexStarNumber(a);
638 ls[3].reserve(ncells);
641 triangulation.getVertexStar(a, i, cellId);
642 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
644 triangulation.getCellVertex(cellId, 0, v0);
645 triangulation.getCellVertex(cellId, 1, v1);
646 triangulation.getCellVertex(cellId, 2, v2);
647 triangulation.getCellVertex(cellId, 3, v3);
649 lowVerts[0] = offsets[v1];
650 lowVerts[1] = offsets[v2];
651 lowVerts[2] = offsets[v3];
653 lowVerts[0] = offsets[v0];
654 lowVerts[1] = offsets[v2];
655 lowVerts[2] = offsets[v3];
657 lowVerts[0] = offsets[v0];
658 lowVerts[1] = offsets[v1];
659 lowVerts[2] = offsets[v3];
661 lowVerts[0] = offsets[v0];
662 lowVerts[1] = offsets[v1];
663 lowVerts[2] = offsets[v2];
665 if(offsets[a] > *std::max_element(
666 lowVerts.begin(), lowVerts.end())) {
669 std::sort(lowVerts.rbegin(), lowVerts.rend());
673 std::array<uint8_t, 3> faces{};
674 for(
const auto &t : ls[2]) {
677 if((t.lowVerts_[0] == lowVerts[0]
678 && (t.lowVerts_[1] == lowVerts[1]
679 || t.lowVerts_[1] == lowVerts[2]))
680 || (t.lowVerts_[0] == lowVerts[1]
681 && t.lowVerts_[1] == lowVerts[2])) {
687 CellExt
const localCellExt3{3, cellId, lowVerts, faces};
688 ls[3].emplace_back(localCellExt3);
695template <
typename triangulationType>
696inline void DiscreteGradient::pairCells(
697 CellExt &alpha,
CellExt &beta,
const triangulationType &triangulation) {
698#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
699 char localBId{0}, localAId{0};
705 triangulation.getEdgeVertex(beta.
id_, i, a);
711 const auto nedges = triangulation.getVertexEdgeNumber(alpha.
id_);
713 triangulation.getVertexEdge(alpha.
id_, i, b);
719 }
else if(beta.
dim_ == 2) {
721 triangulation.getTriangleEdge(beta.
id_, i, a);
727 const auto ntri = triangulation.getEdgeTriangleNumber(alpha.
id_);
729 triangulation.getEdgeTriangle(alpha.
id_, i, b);
737 triangulation.getCellTriangle(beta.
id_, i, a);
743 const auto ntetra = triangulation.getTriangleStarNumber(alpha.
id_);
745 triangulation.getTriangleStar(alpha.
id_, i, b);
752 (*gradient_)[2 * alpha.
dim_][alpha.
id_] = localBId;
753 (*gradient_)[2 * alpha.
dim_ + 1][beta.
id_] = localAId;
756 (*gradient_)[2 * alpha.
dim_][alpha.
id_] = beta.
id_;
757 (*gradient_)[2 * alpha.
dim_ + 1][beta.
id_] = alpha.
id_;
763template <
typename triangulationType>
764int DiscreteGradient::processLowerStars(
765 const SimplexId *
const offsets,
const triangulationType &triangulation) {
773 auto nverts = triangulation.getNumberOfVertices();
776 const auto orderCells = [&](
const CellExt &a,
const CellExt &b) ->
bool {
782 = std::priority_queue<std::reference_wrapper<CellExt>,
783 std::vector<std::reference_wrapper<CellExt>>,
784 decltype(orderCells)>;
792 pqType pqZero{orderCells}, pqOne{orderCells};
803#ifdef TTK_ENABLE_OPENMP
804#pragma omp parallel for num_threads(threadNumber_) \
805 firstprivate(Lx, pqZero, pqOne)
811 while(!pqZero.empty()) {
814 while(!pqOne.empty()) {
819 const auto insertCofacets = [&](
const CellExt &ca, lowerStarType &ls) {
821 for(
auto &beta : ls[2]) {
823 || ls[1][beta.
faces_[1]].id_ == ca.
id_) {
825 if(numUnpairedFacesTriangle(beta, ls).first == 1) {
831 }
else if(ca.
dim_ == 2) {
832 for(
auto &beta : ls[3]) {
835 || ls[2][beta.
faces_[2]].id_ == ca.
id_) {
837 if(numUnpairedFacesTetra(beta, ls).first == 1) {
845 lowerStar(Lx, x, offsets, triangulation);
851 for(
size_t i = 1; i < Lx[1].size(); ++i) {
852 const auto &a = Lx[1][minId].
lowVerts_[0];
853 const auto &b = Lx[1][i].lowVerts_[0];
860 auto &c_delta = Lx[1][minId];
863 pairCells(Lx[0][0], c_delta, triangulation);
866 for(
auto &alpha : Lx[1]) {
867 if(alpha.
id_ != c_delta.id_) {
875 insertCofacets(c_delta, Lx);
877 while(!pqOne.empty() || !pqZero.empty()) {
878 while(!pqOne.empty()) {
879 auto &c_alpha = pqOne.top().get();
881 auto unpairedFaces = numUnpairedFaces(c_alpha, Lx);
882 if(unpairedFaces.first == 0) {
883 pqZero.push(c_alpha);
885 auto &c_pair_alpha = Lx[c_alpha.dim_ - 1][unpairedFaces.second];
888 pairCells(c_pair_alpha, c_alpha, triangulation);
891 insertCofacets(c_alpha, Lx);
892 insertCofacets(c_pair_alpha, Lx);
898 while(!pqZero.empty() && pqZero.top().get().paired_) {
902 if(!pqZero.empty()) {
903 auto &c_gamma = pqZero.top().get();
908 c_gamma.paired_ =
true;
911 insertCofacets(c_gamma, Lx);
920template <
typename triangulationType>
921int DiscreteGradient::processLowerStarsWithMask(
923 const triangulationType &triangulation,
924 const std::vector<bool> *updateMask) {
926 auto nverts = triangulation.getNumberOfVertices();
931 const auto orderCells = [&](
const CellExt &a,
const CellExt &b) ->
bool {
937 = std::priority_queue<std::reference_wrapper<CellExt>,
938 std::vector<std::reference_wrapper<CellExt>>,
939 decltype(orderCells)>;
947 pqType pqZero{orderCells}, pqOne{orderCells};
952#ifdef TTK_ENABLE_OPENMP
953#pragma omp parallel for num_threads(threadNumber_) \
954 firstprivate(Lx, pqZero, pqOne)
958 if((updateMask !=
nullptr) && ((*updateMask)[x] ==
false)) {
964 while(!pqZero.empty()) {
967 while(!pqOne.empty()) {
972 const auto insertCofacets = [&](
const CellExt &ca, lowerStarType &ls) {
974 for(
auto &beta : ls[2]) {
976 || ls[1][beta.
faces_[1]].id_ == ca.
id_) {
978 if(numUnpairedFacesTriangle(beta, ls).first == 1) {
984 }
else if(ca.
dim_ == 2) {
985 for(
auto &beta : ls[3]) {
988 || ls[2][beta.
faces_[2]].id_ == ca.
id_) {
990 if(numUnpairedFacesTetra(beta, ls).first == 1) {
998 lowerStarWithMask(Lx, x, offsets, triangulation, updateMask);
1001#ifdef TTK_ENABLE_MPI
1002 if(ttk::isRunningWithMPI()
1004 int sizeDim = Lx.size();
1005 for(
int i = 0; i < sizeDim; i++) {
1006 int nCells = Lx[i].size();
1007 for(
int j = 0; j < nCells; j++) {
1008 setCellToGhost(Lx[i][j].dim_, Lx[i][j].id_);
1016 if(!Lx[1].empty()) {
1019 for(
size_t i = 1; i < Lx[1].size(); ++i) {
1020 const auto &a = Lx[1][minId].
lowVerts_[0];
1021 const auto &b = Lx[1][i].lowVerts_[0];
1028 auto &c_delta = Lx[1][minId];
1031 pairCells(Lx[0][0], c_delta, triangulation);
1034 for(
auto &alpha : Lx[1]) {
1035 if(alpha.
id_ != c_delta.id_) {
1043 insertCofacets(c_delta, Lx);
1045 while(!pqOne.empty() || !pqZero.empty()) {
1046 while(!pqOne.empty()) {
1047 auto &c_alpha = pqOne.top().get();
1049 auto unpairedFaces = numUnpairedFaces(c_alpha, Lx);
1050 if(unpairedFaces.first == 0) {
1051 pqZero.push(c_alpha);
1053 auto &c_pair_alpha = Lx[c_alpha.dim_ - 1][unpairedFaces.second];
1056 pairCells(c_pair_alpha, c_alpha, triangulation);
1059 insertCofacets(c_alpha, Lx);
1060 insertCofacets(c_pair_alpha, Lx);
1066 while(!pqZero.empty() && pqZero.top().get().paired_) {
1070 if(!pqZero.empty()) {
1071 auto &c_gamma = pqZero.top().get();
1076 c_gamma.paired_ =
true;
1079 insertCofacets(c_gamma, Lx);
1089template <
typename dataType,
typename triangulationType>
1090int DiscreteGradient::processLowerStarsStochastic(
1091 const SimplexId *
const offsets,
const triangulationType &triangulation) {
1099 auto nverts = triangulation.getNumberOfVertices();
1102 const auto orderCells = [&](
const CellExt &a,
const CellExt &b) ->
bool {
1108 = std::priority_queue<std::reference_wrapper<CellExt>,
1109 std::vector<std::reference_wrapper<CellExt>>,
1110 decltype(orderCells)>;
1118 pqType pqZero{orderCells}, pqOne{orderCells};
1124 float threshold = 10e-12;
1125 const auto nedges = triangulation.getVertexEdgeNumber(0);
1128 triangulation.getVertexPoint(0, x1, x2, x3);
1129 std::vector<float> edgeLengths(3);
1132 triangulation.getVertexEdge(0, i, edgeId);
1134 triangulation.getEdgeVertex(edgeId, 0, vertexId);
1136 triangulation.getEdgeVertex(edgeId, 1, vertexId);
1137 triangulation.getVertexPoint(vertexId, y1, y2, y3);
1138 if(std::abs(y1 - x1) < threshold && std::abs(y2 - x2) < threshold) {
1139 edgeLengths[2] = std::abs(x3 - y3);
1141 if(std::abs(y2 - x2) < threshold && std::abs(y3 - x3) < threshold) {
1142 edgeLengths[0] = std::abs(x1 - y1);
1144 if(std::abs(y1 - x1) < threshold && std::abs(y3 - x3) < threshold) {
1145 edgeLengths[1] = std::abs(x2 - y2);
1149#ifdef TTK_ENABLE_OPENMP
1150#pragma omp parallel for num_threads(threadNumber_) \
1151 firstprivate(Lx, pqZero, pqOne)
1157 while(!pqZero.empty()) {
1160 while(!pqOne.empty()) {
1165 const auto insertCofacets = [&](
const CellExt &ca, lowerStarType &ls) {
1167 for(
auto &beta : ls[2]) {
1169 || ls[1][beta.
faces_[1]].id_ == ca.
id_) {
1171 if(numUnpairedFacesTriangle(beta, ls).first == 1) {
1177 }
else if(ca.
dim_ == 2) {
1178 for(
auto &beta : ls[3]) {
1181 || ls[2][beta.
faces_[2]].id_ == ca.
id_) {
1183 if(numUnpairedFacesTetra(beta, ls).first == 1) {
1191 lowerStar(Lx, x, offsets, triangulation);
1194#ifdef TTK_ENABLE_MPI
1195 if(ttk::isRunningWithMPI()
1197 int sizeDim = Lx.size();
1198 for(
int i = 0; i < sizeDim; i++) {
1199 int nCells = Lx[i].size();
1200 for(
int j = 0; j < nCells; j++) {
1201 setCellToGhost(Lx[i][j].dim_, Lx[i][j].id_);
1209 if(!Lx[1].empty()) {
1212 std::array<float, 3> xCoords;
1213 triangulation.getVertexPoint(x, xCoords[0], xCoords[1], xCoords[2]);
1215 std::vector<SimplexId>
1217 std::vector<float> stencilLengths = edgeLengths;
1219 buildStencil(x, xCoords, triangulation, stencilIds, stencilLengths);
1222 = std::conditional_t<std::is_same_v<dataType, double>, double,
float>;
1224 const dataType *scalars
1227 grad[0] = (scalars[stencilIds[0]] - scalars[stencilIds[1]])
1228 / stencilLengths[0];
1229 grad[1] = (scalars[stencilIds[2]] - scalars[stencilIds[3]])
1230 / stencilLengths[1];
1231 grad[2] = triangulation.getDimensionality() == 3
1232 ? (scalars[stencilIds[4]] - scalars[stencilIds[5]])
1236 std::vector<double> repartitionBounds;
1237 repartitionBounds.push_back(0);
1238 std::vector<int> indexInLowerStar;
1239 indexInLowerStar.push_back(0);
1240 double totalWeight = 0;
1241 for(
size_t i = 0; i < Lx[1].size(); ++i) {
1243 triangulation.getEdgeVertex(Lx[1][i].id_, 0, vertexId);
1245 triangulation.getEdgeVertex(Lx[1][i].id_, 1, vertexId);
1246 if(std::find(stencilIds.begin(), stencilIds.end(), vertexId)
1247 == stencilIds.end())
1249 std::array<float, 3> newCoords;
1250 triangulation.getVertexPoint(
1251 vertexId, newCoords[0], newCoords[1], newCoords[2]);
1253 float scalarProduct = -(newCoords[0] - xCoords[0]) * grad[0]
1254 - (newCoords[1] - xCoords[1]) * grad[1]
1255 - (newCoords[2] - xCoords[2]) * grad[2];
1256 if(scalarProduct > 0) {
1257 double previousBound
1258 = repartitionBounds[repartitionBounds.size() - 1];
1259 repartitionBounds.push_back(scalarProduct + previousBound);
1260 totalWeight += scalarProduct;
1261 indexInLowerStar.push_back(i);
1265 for(
size_t i = 1; i < repartitionBounds.size(); ++i) {
1266 repartitionBounds[i] /= totalWeight;
1271 std::uniform_real_distribution<float> dis(0.0, 1.0);
1272 float random_number = dis(gen);
1275 while(repartitionBounds[it] < random_number
1276 && repartitionBounds.size() > 1) {
1280 minId = indexInLowerStar[it];
1281 auto &c_delta = Lx[1][minId];
1284 pairCells(Lx[0][0], c_delta, triangulation);
1287 for(
auto &alpha : Lx[1]) {
1288 if(alpha.
id_ != c_delta.id_) {
1296 insertCofacets(c_delta, Lx);
1298 while(!pqOne.empty() || !pqZero.empty()) {
1299 while(!pqOne.empty()) {
1300 auto &c_alpha = pqOne.top().get();
1302 auto unpairedFaces = numUnpairedFaces(c_alpha, Lx);
1303 if(unpairedFaces.first == 0) {
1304 pqZero.push(c_alpha);
1306 auto &c_pair_alpha = Lx[c_alpha.dim_ - 1][unpairedFaces.second];
1309 pairCells(c_pair_alpha, c_alpha, triangulation);
1312 insertCofacets(c_alpha, Lx);
1313 insertCofacets(c_pair_alpha, Lx);
1319 while(!pqZero.empty() && pqZero.top().get().paired_) {
1323 if(!pqZero.empty()) {
1324 auto &c_gamma = pqZero.top().get();
1329 c_gamma.paired_ =
true;
1332 insertCofacets(c_gamma, Lx);
1341template <
typename triangulationType>
1342void DiscreteGradient::buildStencil(
const SimplexId &x,
1343 const std::array<float, 3> xCoords,
1344 const triangulationType &triangulation,
1345 std::vector<SimplexId> &stencilIds,
1346 std::vector<float> &stencilLength) {
1347 float threshold = 10e-12;
1348 const auto nedges = triangulation.getVertexEdgeNumber(x);
1349 int dimension = triangulation.getDimensionality();
1350 stencilIds.resize(dimension * 2, -1);
1353 triangulation.getVertexEdge(x, i, edgeId);
1355 triangulation.getEdgeVertex(edgeId, 0, vertexId);
1357 triangulation.getEdgeVertex(edgeId, 1, vertexId);
1359 std::array<float, 3> currentCoords;
1360 triangulation.getVertexPoint(
1361 vertexId, currentCoords[0], currentCoords[1], currentCoords[2]);
1362 if(std::abs(currentCoords[0] - xCoords[0]) < threshold
1363 && std::abs(currentCoords[1] - xCoords[1]) < threshold
1364 && dimension == 3) {
1365 if(currentCoords[2] - xCoords[2] > threshold) {
1366 stencilIds[4] = vertexId;
1367 }
else if(currentCoords[2] - xCoords[2] < -threshold) {
1368 stencilIds[5] = vertexId;
1370 }
else if(std::abs(currentCoords[0] - xCoords[0]) < threshold
1371 && std::abs(currentCoords[2] - xCoords[2]) < threshold) {
1372 if(currentCoords[1] - xCoords[1] > threshold) {
1373 stencilIds[2] = vertexId;
1374 }
else if(currentCoords[1] - xCoords[1] < -threshold) {
1375 stencilIds[3] = vertexId;
1377 }
else if(std::abs(currentCoords[1] - xCoords[1]) < threshold
1378 && std::abs(currentCoords[2] - xCoords[2]) < threshold) {
1379 if(currentCoords[0] - xCoords[0] > threshold) {
1380 stencilIds[0] = vertexId;
1381 }
else if(currentCoords[0] - xCoords[0] < -threshold) {
1382 stencilIds[1] = vertexId;
1386 for(
int i = 0; i < dimension; i++) {
1387 if(stencilIds[2 * i] != -1 && stencilIds[2 * i + 1] != -1) {
1388 stencilLength[i] *= 2;
1391 for(
size_t i = 0; i < stencilIds.size(); i++) {
1392 if(stencilIds[i] == -1)
1397template <
typename triangulationType>
1399 const Cell &cell,
const triangulationType &triangulation)
const {
1401 if(cell.
dim_ > this->dimensionality_ || cell.
dim_ < 0) {
1406 return triangulation.isVertexOnBoundary(vert);
1409template <
typename triangulationType>
1412 const triangulationType &triangulation,
1413 bool isReverse)
const {
1417 std::is_base_of<AbstractTriangulation, triangulationType>(),
1418 "triangulationType should be an AbstractTriangulation derivative");
1420#ifndef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1424 if((cell.
dim_ > this->dimensionality_ - 1 && !isReverse)
1425 || (cell.
dim_ > this->dimensionality_ && isReverse) || cell.
dim_ < 0) {
1431 if(cell.
dim_ == 0) {
1433#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1434 const auto locId{(*gradient_)[0][cell.
id_]};
1436 triangulation.getVertexEdge(cell.
id_, locId,
id);
1439 id = (*gradient_)[0][cell.
id_];
1444 else if(cell.
dim_ == 1) {
1446#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1447 const auto locId{(*gradient_)[1][cell.
id_]};
1449 triangulation.getEdgeVertex(cell.
id_, locId,
id);
1452 id = (*gradient_)[1][cell.
id_];
1455#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1456 const auto locId{(*gradient_)[2][cell.
id_]};
1458 triangulation.getEdgeTriangle(cell.
id_, locId,
id);
1461 id = (*gradient_)[2][cell.
id_];
1466 else if(cell.
dim_ == 2) {
1468#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1469 const auto locId{(*gradient_)[3][cell.
id_]};
1471 triangulation.getTriangleEdge(cell.
id_, locId,
id);
1474 id = (*gradient_)[3][cell.
id_];
1477#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1478 const auto locId{(*gradient_)[4][cell.
id_]};
1480 triangulation.getTriangleStar(cell.
id_, locId,
id);
1483 id = (*gradient_)[4][cell.
id_];
1488 else if(cell.
dim_ == 3) {
1490#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1491 const auto locId{(*gradient_)[5][cell.
id_]};
1493 triangulation.getCellTriangle(cell.
id_, locId,
id);
1496 id = (*gradient_)[5][cell.
id_];
1504template <
typename triangulationType>
1507 std::vector<Cell> &vpath,
1508 const triangulationType &triangulation)
const {
1510 if(cell.
dim_ == 0) {
1516 const Cell vertex(0, currentId);
1517 vpath.push_back(vertex);
1520#ifdef TTK_ENABLE_MPI
1528 if(connectedEdgeId == -1) {
1533 const Cell edge(1, connectedEdgeId);
1534 vpath.push_back(edge);
1540 for(
int i = 0; i < 2; ++i) {
1542 triangulation.getEdgeVertex(connectedEdgeId, i, vertexId);
1544 if(vertexId != currentId) {
1545 currentId = vertexId;
1550 }
while(connectedEdgeId != -1);
1556template <
typename triangulationType>
1558 const Cell &saddle2,
1559 const Cell &saddle1,
1560 const std::vector<bool> &isVisited,
1561 std::vector<Cell> *
const vpath,
1562 const triangulationType &triangulation,
1563 const bool stopIfMultiConnected,
1564 const bool enableCycleDetector)
const {
1567 const SimplexId numberOfEdges = triangulation.getNumberOfEdges();
1568 std::vector<bool> isCycle;
1569 if(enableCycleDetector) {
1570 isCycle.resize(numberOfEdges,
false);
1575 if(vpath !=
nullptr) {
1576 vpath->push_back(saddle2);
1581 int nconnections = 0;
1582 for(
int i = 0; i < 3; ++i) {
1584 triangulation.getTriangleEdge(saddle2.
id_, i, edgeId);
1585 if(isVisited[edgeId]) {
1588 if(vpath !=
nullptr) {
1589 vpath->push_back(
Cell(1, edgeId));
1598 if(stopIfMultiConnected && nconnections > 1) {
1607 if(enableCycleDetector) {
1608 if(not isCycle[currentId]) {
1609 isCycle[currentId] =
true;
1611 this->
printErr(
"Cycle detected on the wall of 1-saddle "
1612 + std::to_string(saddle1.
id_));
1620 const Cell edge(1, currentId);
1621 if(vpath !=
nullptr) {
1622 vpath->push_back(edge);
1632 const Cell triangle(2, connectedTriangleId);
1633 if(vpath !=
nullptr) {
1634 vpath->push_back(triangle);
1641 int nconnections = 0;
1642 for(
int i = 0; i < 3; ++i) {
1644 triangulation.getTriangleEdge(connectedTriangleId, i, edgeId);
1646 if(isVisited[edgeId] and edgeId != oldId) {
1651 if(stopIfMultiConnected && nconnections > 1) {
1656 }
while(currentId != oldId);
1662template <
typename triangulationType>
1664 std::vector<Cell> &vpath,
1665 const triangulationType &triangulation,
1666 const bool enableCycleDetector)
const {
1668 const SimplexId numberOfCells = triangulation.getNumberOfCells();
1669 std::vector<bool> isCycle;
1670 if(enableCycleDetector) {
1671 isCycle.resize(numberOfCells,
false);
1675 if(cell.
dim_ == 2) {
1683 const Cell triangle(2, currentId);
1684 vpath.push_back(triangle);
1687#ifdef TTK_ENABLE_MPI
1688 || triangulation.getTriangleRank(currentId) !=
ttk::MPIrank_
1696 if(connectedEdgeId == -1) {
1701 const Cell edge(1, connectedEdgeId);
1702 vpath.push_back(edge);
1709 = triangulation.getEdgeStarNumber(connectedEdgeId);
1710 for(
SimplexId i = 0; i < starNumber; ++i) {
1712 triangulation.getEdgeStar(connectedEdgeId, i, starId);
1714 if(starId != currentId) {
1721 }
while(currentId != oldId);
1724 if(cell.
dim_ == 3) {
1731 if(enableCycleDetector) {
1732 if(not isCycle[currentId]) {
1733 isCycle[currentId] =
true;
1735 this->
printErr(
"cycle detected in the path from tetra "
1736 + std::to_string(cell.
id_));
1744 const Cell tetra(3, currentId);
1745 vpath.push_back(tetra);
1748#ifdef TTK_ENABLE_MPI
1757 if(connectedTriangleId == -1) {
1762 const Cell triangle(2, connectedTriangleId);
1763 vpath.push_back(triangle);
1770 = triangulation.getTriangleStarNumber(connectedTriangleId);
1771 for(
SimplexId i = 0; i < starNumber; ++i) {
1773 triangulation.getTriangleStar(connectedTriangleId, i, starId);
1775 if(starId != currentId) {
1782 }
while(currentId != oldId);
1789template <
typename triangulationType>
1791 const Cell &saddle1,
1792 const Cell &saddle2,
1793 const std::vector<bool> &isVisited,
1794 std::vector<Cell> *
const vpath,
1795 const triangulationType &triangulation,
1796 const bool stopIfMultiConnected,
1797 const bool enableCycleDetector,
1798 bool *
const cycleFound)
const {
1801 const SimplexId numberOfTriangles = triangulation.getNumberOfTriangles();
1802 std::vector<bool> isCycle;
1803 if(enableCycleDetector) {
1804 isCycle.resize(numberOfTriangles,
false);
1809 if(vpath !=
nullptr) {
1810 vpath->push_back(saddle1);
1815 int nconnections = 0;
1817 = triangulation.getEdgeTriangleNumber(saddle1.
id_);
1818 for(
SimplexId i = 0; i < triangleNumber; ++i) {
1820 triangulation.getEdgeTriangle(saddle1.
id_, i, triangleId);
1821 if(isVisited[triangleId]) {
1824 if(vpath !=
nullptr) {
1825 vpath->push_back(
Cell(2, triangleId));
1830 currentId = triangleId;
1834 if(stopIfMultiConnected && nconnections > 1) {
1839 if(currentId == -1) {
1847 if(enableCycleDetector) {
1848 if(not isCycle[currentId]) {
1849 isCycle[currentId] =
true;
1854 this->
printErr(
"Cycle detected on the wall of 2-saddle "
1855 + std::to_string(saddle2.
id_));
1863 const Cell triangle(2, currentId);
1864 if(vpath !=
nullptr) {
1865 vpath->push_back(triangle);
1876 const Cell edge(1, connectedEdgeId);
1877 if(vpath !=
nullptr) {
1878 vpath->push_back(edge);
1885 int nconnections = 0;
1887 = triangulation.getEdgeTriangleNumber(connectedEdgeId);
1888 for(
SimplexId i = 0; i < triangleNumber; ++i) {
1890 triangulation.getEdgeTriangle(connectedEdgeId, i, triangleId);
1892 if(isVisited[triangleId] and triangleId != oldId) {
1893 currentId = triangleId;
1897 if(stopIfMultiConnected && nconnections > 1) {
1902 }
while(currentId != oldId);
1907template <
typename triangulationType>
1909 const Cell &cell,
const triangulationType &triangulation)
const {
1911 if(cell.
dim_ == 1) {
1916 std::queue<SimplexId> bfs;
1918 std::vector<bool> isVisited(triangulation.getNumberOfTriangles(),
false);
1921 while(!bfs.empty()) {
1922 const SimplexId triangleId = bfs.front();
1925 isVisited[triangleId] =
true;
1927 for(
int j = 0; j < 3; ++j) {
1929 triangulation.getTriangleEdge(triangleId, j, edgeId);
1934 if(triangleId == pairedCellId or pairedCellId == -1)
1937 if(isVisited[pairedCellId])
1940 bfs.push(pairedCellId);
1948template <
typename triangulationType>
1952 const triangulationType &triangulation,
1953 std::vector<Cell> *
const wall,
1954 std::vector<SimplexId> *
const saddles)
const {
1956 if(saddles !=
nullptr) {
1961 if(cell.
dim_ == 2) {
1965 std::queue<SimplexId> bfs;
1969 while(!bfs.empty()) {
1970 const SimplexId triangleId = bfs.front();
1978 if(wall !=
nullptr) {
1979 wall->push_back(
Cell(2, triangleId));
1982 for(
int j = 0; j < 3; ++j) {
1984 triangulation.getTriangleEdge(triangleId, j, edgeId);
1987 saddles->emplace_back(edgeId);
1993 if(pairedCellId != -1 and pairedCellId != triangleId) {
1994 bfs.push(pairedCellId);
2000 if(saddles !=
nullptr && saddles->size() > 1) {
2001 std::sort(saddles->begin(), saddles->end());
2002 const auto last = std::unique(saddles->begin(), saddles->end());
2003 saddles->erase(last, saddles->end());
2011template <
typename triangulationType>
2015 const triangulationType &triangulation,
2016 std::vector<Cell> *
const wall,
2017 std::vector<SimplexId> *
const saddles)
const {
2019 if(saddles !=
nullptr) {
2024 if(cell.
dim_ == 1) {
2028 std::queue<SimplexId> bfs;
2032 while(!bfs.empty()) {
2041 if(wall !=
nullptr) {
2042 wall->push_back(
Cell(1, edgeId));
2046 = triangulation.getEdgeTriangleNumber(edgeId);
2047 for(
SimplexId j = 0; j < triangleNumber; ++j) {
2049 triangulation.getEdgeTriangle(edgeId, j, triangleId);
2051 if((saddles !=
nullptr) and
isSaddle2(
Cell(2, triangleId))) {
2052 saddles->emplace_back(triangleId);
2058 if(pairedCellId != -1 and pairedCellId != edgeId) {
2059 bfs.push(pairedCellId);
2065 if(saddles !=
nullptr && saddles->size() > 1) {
2066 std::sort(saddles->begin(), saddles->end());
2067 const auto last = std::unique(saddles->begin(), saddles->end());
2068 saddles->erase(last, saddles->end());
2076template <
typename triangulationType>
2078 const std::vector<Cell> &vpath,
2079 const triangulationType &triangulation)
const {
2083 const SimplexId numberOfCellsInPath = vpath.size();
2084 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
2086 const SimplexId triangleId = vpath[i + 1].id_;
2088#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
2089 for(
int k = 0; k < 3; ++k) {
2091 triangulation.getCellEdge(triangleId, k, tmp);
2093 (*gradient_)[3][triangleId] = k;
2097 for(
int k = 0; k < triangulation.getEdgeStarNumber(edgeId); ++k) {
2099 triangulation.getEdgeStar(edgeId, k, tmp);
2100 if(tmp == triangleId) {
2101 (*gradient_)[2][edgeId] = k;
2107 (*gradient_)[3][triangleId] = edgeId;
2108 (*gradient_)[2][edgeId] = triangleId;
2113 const SimplexId numberOfCellsInPath = vpath.size();
2114 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
2115 const SimplexId triangleId = vpath[i].id_;
2116 const SimplexId tetraId = vpath[i + 1].id_;
2118#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
2119 for(
int k = 0; k < 4; ++k) {
2121 triangulation.getCellTriangle(tetraId, k, tmp);
2122 if(tmp == triangleId) {
2123 (*gradient_)[5][tetraId] = k;
2127 for(
int k = 0; k < triangulation.getTriangleStarNumber(triangleId); ++k) {
2129 triangulation.getTriangleStar(triangleId, k, tmp);
2130 if(tmp == tetraId) {
2131 (*gradient_)[4][triangleId] = k;
2136 (*gradient_)[5][tetraId] = triangleId;
2137 (*gradient_)[4][triangleId] = tetraId;
2145template <
typename triangulationType>
2147 const std::vector<Cell> &vpath,
2148 const triangulationType &triangulation)
const {
2151 for(
size_t i = 0; i < vpath.size(); i += 2) {
2153 const SimplexId vertId = vpath[i + 1].id_;
2155#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
2156 const auto nneighs = triangulation.getVertexEdgeNumber();
2157 for(
int k = 0; k < nneighs; ++k) {
2159 triangulation.getVertexEdge(vertId, k, tmp);
2161 (*gradient_)[0][vertId] = k;
2165 const auto nverts = triangulation.getEdgeStarNumber(edgeId);
2166 for(
int k = 0; k < nverts; ++k) {
2168 triangulation.getEdgeVertex(edgeId, k, tmp);
2170 (*gradient_)[1][edgeId] = k;
2176 (*gradient_)[0][vertId] = edgeId;
2177 (*gradient_)[1][edgeId] = vertId;
2184template <
typename triangulationType>
2186 const std::vector<Cell> &vpath,
2187 const triangulationType &triangulation,
2188 bool cancelReversal)
const {
2192 if(cancelReversal) {
2197 if(vpath.size() <= 1)
2199 (*gradient_)[3][vpath[vpath.size() - 1].id_] =
NULL_GRADIENT;
2201 const SimplexId numberOfCellsInPath = vpath.size();
2202 const SimplexId startIndex = (cancelReversal ? 2 : 0);
2203 for(
SimplexId i = startIndex; i < numberOfCellsInPath; i += 2) {
2205 const SimplexId vpathTriangleIndex = (cancelReversal ? i - 1 : i + 1);
2206 const SimplexId edgeId = vpath[vpathEdgeIndex].id_;
2207 const SimplexId triangleId = vpath[vpathTriangleIndex].id_;
2209#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
2210 for(
int k = 0; k < 3; ++k) {
2212 triangulation.getTriangleEdge(triangleId, k, tmp);
2214 (*gradient_)[3][triangleId] = k;
2218 for(
int k = 0; k < triangulation.getEdgeTriangleNumber(edgeId); ++k) {
2220 triangulation.getEdgeTriangle(edgeId, k, tmp);
2221 if(tmp == triangleId) {
2222 (*gradient_)[2][edgeId] = k;
2228 (*gradient_)[3][triangleId] = edgeId;
2229 (*gradient_)[2][edgeId] = triangleId;
2237template <
typename triangulationType>
2239 const std::vector<Cell> &vpath,
2240 const triangulationType &triangulation)
const {
2244 const SimplexId numberOfCellsInPath = vpath.size();
2245 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
2246 const SimplexId triangleId = vpath[i].id_;
2247 const SimplexId edgeId = vpath[i + 1].id_;
2249#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
2250 for(
int k = 0; k < 3; ++k) {
2252 triangulation.getTriangleEdge(triangleId, k, tmp);
2254 (*gradient_)[3][triangleId] = k;
2258 for(
int k = 0; k < triangulation.getEdgeTriangleNumber(edgeId); ++k) {
2260 triangulation.getEdgeTriangle(edgeId, k, tmp);
2261 if(tmp == triangleId) {
2262 (*gradient_)[2][edgeId] = k;
2268 (*gradient_)[2][edgeId] = triangleId;
2269 (*gradient_)[3][triangleId] = edgeId;
2277template <
typename triangulationType>
2279 const Cell c,
const triangulationType &triangulation)
const {
2283 auto cellDim = c.
dim_;
2284 auto cellId = c.
id_;
2291 else if(cellDim == 1) {
2294 triangulation.getEdgeVertex(cellId, 0, v0);
2295 triangulation.getEdgeVertex(cellId, 1, v1);
2297 if(offsets[v0] > offsets[v1]) {
2304 else if(cellDim == 2) {
2306 triangulation.getTriangleVertex(cellId, 0, v0);
2307 triangulation.getTriangleVertex(cellId, 1, v1);
2308 triangulation.getTriangleVertex(cellId, 2, v2);
2309 if(offsets[v0] > offsets[v1] && offsets[v0] > offsets[v2]) {
2311 }
else if(offsets[v1] > offsets[v0] && offsets[v1] > offsets[v2]) {
2318 else if(cellDim == 3) {
2320 triangulation.getCellVertex(cellId, 0, v0);
2321 triangulation.getCellVertex(cellId, 1, v1);
2322 triangulation.getCellVertex(cellId, 2, v2);
2323 triangulation.getCellVertex(cellId, 3, v3);
2324 if(offsets[v0] > offsets[v1] && offsets[v0] > offsets[v2]
2325 && offsets[v0] > offsets[v3]) {
2327 }
else if(offsets[v1] > offsets[v0] && offsets[v1] > offsets[v2]
2328 && offsets[v1] > offsets[v3]) {
2330 }
else if(offsets[v2] > offsets[v0] && offsets[v2] > offsets[v1]
2331 && offsets[v2] > offsets[v3]) {
2340template <
typename triangulationType>
2342 const Cell c,
const triangulationType &triangulation)
const {
2346 auto cellDim = c.
dim_;
2347 auto cellId = c.
id_;
2354 else if(cellDim == 1) {
2357 triangulation.getEdgeVertex(cellId, 0, v0);
2358 triangulation.getEdgeVertex(cellId, 1, v1);
2360 if(offsets[v0] < offsets[v1]) {
2367 else if(cellDim == 2) {
2369 triangulation.getTriangleVertex(cellId, 0, v0);
2370 triangulation.getTriangleVertex(cellId, 1, v1);
2371 triangulation.getTriangleVertex(cellId, 2, v2);
2372 if(offsets[v0] < offsets[v1] && offsets[v0] < offsets[v2]) {
2374 }
else if(offsets[v1] < offsets[v0] && offsets[v1] < offsets[v2]) {
2381 else if(cellDim == 3) {
2383 triangulation.getCellVertex(cellId, 0, v0);
2384 triangulation.getCellVertex(cellId, 1, v1);
2385 triangulation.getCellVertex(cellId, 2, v2);
2386 triangulation.getCellVertex(cellId, 3, v3);
2387 if(offsets[v0] < offsets[v1] && offsets[v0] < offsets[v2]
2388 && offsets[v0] < offsets[v3]) {
2390 }
else if(offsets[v1] < offsets[v0] && offsets[v1] < offsets[v2]
2391 && offsets[v1] < offsets[v3]) {
2393 }
else if(offsets[v2] < offsets[v0] && offsets[v2] < offsets[v1]
2394 && offsets[v2] < offsets[v3]) {
2403template <
typename triangulationType>
2405 std::vector<std::array<float, 3>> &points,
2406 std::vector<char> &points_pairOrigins,
2407 std::vector<char> &cells_pairTypes,
2408 std::vector<SimplexId> &cellIds,
2409 std::vector<char> &cellDimensions,
2410 const triangulationType &triangulation)
const {
2415 std::vector<size_t> nGlyphsPerDim(nDims);
2417#ifdef TTK_ENABLE_OPENMP
2418#pragma omp parallel for num_threads(threadNumber_)
2420 for(
int i = 0; i < nDims - 1; ++i) {
2430 std::vector<size_t> offsets(nDims + 1);
2432 offsets[i + 1] = offsets[i] + nGlyphsPerDim[i];
2436 const auto nGlyphs = offsets.back();
2439 points.resize(2 * nGlyphs);
2440 points_pairOrigins.resize(2 * nGlyphs);
2441 cells_pairTypes.resize(nGlyphs);
2442 cellIds.resize(2 * nGlyphs);
2443 cellDimensions.resize(2 * nGlyphs);
2445#ifdef TTK_ENABLE_OPENMP
2446#pragma omp parallel for num_threads(threadNumber_)
2448 for(
int i = 0; i < nDims - 1; ++i) {
2450 size_t nProcessedGlyphs{offsets[i]};
2455 const Cell pc{i + 1, pcid};
2456 triangulation.getCellIncenter(
2457 c.id_, c.dim_, points[2 * nProcessedGlyphs].data());
2458 triangulation.getCellIncenter(
2459 pc.id_, pc.dim_, points[2 * nProcessedGlyphs + 1].data());
2460 points_pairOrigins[2 * nProcessedGlyphs] = 0;
2461 points_pairOrigins[2 * nProcessedGlyphs + 1] = 1;
2462 cells_pairTypes[nProcessedGlyphs] = i;
2463#ifdef TTK_ENABLE_MPI
2465 triangulation.getDistributedGlobalCellId(j, i, globalId);
2466 cellIds[2 * nProcessedGlyphs + 0] = globalId;
2467 triangulation.getDistributedGlobalCellId(pcid, i + 1, globalId);
2468 cellIds[2 * nProcessedGlyphs + 1] = globalId;
2470 cellIds[2 * nProcessedGlyphs + 0] = j;
2471 cellIds[2 * nProcessedGlyphs + 1] = pcid;
2473 cellDimensions[2 * nProcessedGlyphs + 0] = i;
2474 cellDimensions[2 * nProcessedGlyphs + 1] = i + 1;
2483template <
typename dataType,
typename triangulationType>
2485 const std::vector<std::pair<SimplexId, char>> &criticalPoints,
2486 const std::vector<char> &isPL,
2487 const int iterationThreshold,
2488 const bool allowBoundary,
2489 const bool allowBruteForce,
2490 const bool returnSaddleConnectors,
2491 const triangulationType &triangulation) {
2495 std::vector<char> isRemovableSaddle1;
2497 getRemovableSaddles1<dataType>(criticalPoints, allowBoundary,
2498 isRemovableSaddle1, pl2dmt_saddle1,
2501 std::vector<char> isRemovableSaddle2;
2503 getRemovableSaddles2<dataType>(criticalPoints, allowBoundary,
2504 isRemovableSaddle2, pl2dmt_saddle2,
2508 std::vector<VPath> vpaths;
2509 std::vector<CriticalPoint> dmt_criticalPoints;
2510 std::vector<SimplexId> saddle1Index;
2511 std::vector<SimplexId> saddle2Index;
2512 initializeSaddleSaddleConnections1<dataType>(
2513 isRemovableSaddle1, isRemovableSaddle2, allowBruteForce, vpaths,
2514 dmt_criticalPoints, saddle1Index, saddle2Index, triangulation);
2518 std::set<std::tuple<dataType, SimplexId, SimplexId>,
2521 orderSaddleSaddleConnections1<dataType>(vpaths, dmt_criticalPoints, S);
2524 processSaddleSaddleConnections1<dataType>(
2525 iterationThreshold, isPL, allowBoundary, allowBruteForce,
2526 returnSaddleConnectors, S, pl2dmt_saddle1, pl2dmt_saddle2,
2527 isRemovableSaddle1, isRemovableSaddle2, vpaths, dmt_criticalPoints,
2528 saddle1Index, saddle2Index, triangulation);
2531 this->threadNumber_);
2536template <
typename dataType,
typename triangulationType>
2538 const std::vector<std::pair<SimplexId, char>> &criticalPoints,
2539 const std::vector<char> &isPL,
2540 const int iterationThreshold,
2541 const bool allowBoundary,
2542 const bool allowBruteForce,
2543 const bool returnSaddleConnectors,
2544 const triangulationType &triangulation) {
2548 std::vector<char> isRemovableSaddle1;
2550 getRemovableSaddles1<dataType>(criticalPoints, allowBoundary,
2551 isRemovableSaddle1, pl2dmt_saddle1,
2554 std::vector<char> isRemovableSaddle2;
2556 getRemovableSaddles2<dataType>(criticalPoints, allowBoundary,
2557 isRemovableSaddle2, pl2dmt_saddle2,
2561 std::vector<VPath> vpaths;
2562 std::vector<CriticalPoint> dmt_criticalPoints;
2563 std::vector<SimplexId> saddle1Index;
2564 std::vector<SimplexId> saddle2Index;
2565 initializeSaddleSaddleConnections2<dataType>(
2566 isRemovableSaddle1, isRemovableSaddle2, allowBruteForce, vpaths,
2567 dmt_criticalPoints, saddle1Index, saddle2Index, triangulation);
2571 std::set<std::tuple<dataType, SimplexId, SimplexId>,
2574 orderSaddleSaddleConnections2<dataType>(vpaths, dmt_criticalPoints, S);
2577 processSaddleSaddleConnections2<dataType>(
2578 iterationThreshold, isPL, allowBoundary, allowBruteForce,
2579 returnSaddleConnectors, S, pl2dmt_saddle1, pl2dmt_saddle2,
2580 isRemovableSaddle1, isRemovableSaddle2, vpaths, dmt_criticalPoints,
2581 saddle1Index, saddle2Index, triangulation);
2584 this->threadNumber_);
2589template <
typename dataType,
typename triangulationType>
2591 const bool allowBoundary,
const triangulationType &triangulation) {
2593 const bool allowBruteForce =
false;
2594 const bool returnSaddleConnectors =
true;
2598 auto getNodeType = [&](
const ftm::Node *node) {
2599 const int upDegree = node->getNumberOfUpSuperArcs();
2600 const int downDegree = node->getNumberOfDownSuperArcs();
2601 const int degree = upDegree + downDegree;
2605 if(upDegree == 2 and downDegree == 1) {
2607 }
else if(upDegree == 1 and downDegree == 2) {
2623 std::vector<std::pair<SimplexId, char>> cpset;
2625 const auto *
const scalars
2631 contourTree_.setVertexScalars(scalars);
2633 contourTree_.setVertexSoSoffsets(offsets);
2635 contourTree_.setSegmentation(
false);
2636 contourTree_.build<dataType>(&triangulation);
2639 const SimplexId numberOfNodes = tree->getNumberOfNodes();
2640 for(
SimplexId nodeId = 0; nodeId < numberOfNodes; ++nodeId) {
2641 const ftm::Node *node = tree->getNode(nodeId);
2644 cpset.push_back(std::make_pair(vertexId, getNodeType(node)));
2647 std::vector<char> isPL;
2652 returnSaddleConnectors, triangulation);
2655 returnSaddleConnectors, triangulation);
2660template <
typename dataType,
typename triangulationType>
2661int DiscreteGradient::getRemovableSaddles1(
2662 const std::vector<std::pair<SimplexId, char>> &criticalPoints,
2663 const bool allowBoundary,
2664 std::vector<char> &isRemovableSaddle,
2665 std::vector<SimplexId> &pl2dmt_saddle,
2666 const triangulationType &triangulation) {
2668 const SimplexId numberOfEdges = triangulation.getNumberOfEdges();
2669 isRemovableSaddle.resize(numberOfEdges);
2671 std::vector<int> dmt1Saddle2PL_(numberOfEdges, -1);
2674#ifdef TTK_ENABLE_OPENMP
2675#pragma omp parallel for num_threads(threadNumber_)
2677 for(
SimplexId i = 0; i < numberOfEdges; ++i) {
2678 const Cell saddleCandidate(1, i);
2679 isRemovableSaddle[i] =
isSaddle1(saddleCandidate);
2683 for(
auto &criticalPoint : criticalPoints) {
2684 const SimplexId criticalPointId = criticalPoint.first;
2685 const char criticalPointType = criticalPoint.second;
2688 if(!allowBoundary and triangulation.isVertexOnBoundary(criticalPointId)) {
2695 = triangulation.getVertexEdgeNumber(criticalPointId);
2696 for(
SimplexId i = 0; i < edgeNumber; ++i) {
2698 triangulation.getVertexEdge(criticalPointId, i, edgeId);
2699 const Cell saddleCandidate(1, edgeId);
2701 if(
isSaddle1(saddleCandidate) and dmt1Saddle2PL_[edgeId] == -1) {
2708 if(numberOfSaddles == 1) {
2709 if(dmt1Saddle2PL_[saddleId] == -1
2710 and pl2dmt_saddle[criticalPointId] == -1) {
2711 dmt1Saddle2PL_[saddleId] = criticalPointId;
2712 pl2dmt_saddle[criticalPointId] = saddleId;
2713 isRemovableSaddle[saddleId] =
false;
2722template <
typename dataType,
typename triangulationType>
2723int DiscreteGradient::getRemovableSaddles2(
2724 const std::vector<std::pair<SimplexId, char>> &criticalPoints,
2725 const bool allowBoundary,
2726 std::vector<char> &isRemovableSaddle,
2727 std::vector<SimplexId> &pl2dmt_saddle,
2728 const triangulationType &triangulation) {
2730 const SimplexId numberOfTriangles = triangulation.getNumberOfTriangles();
2731 isRemovableSaddle.resize(numberOfTriangles);
2733 std::vector<int> dmt2Saddle2PL_(numberOfTriangles, -1);
2736#ifdef TTK_ENABLE_OPENMP
2737#pragma omp parallel for num_threads(threadNumber_)
2739 for(
SimplexId i = 0; i < numberOfTriangles; ++i) {
2740 const Cell saddleCandidate(2, i);
2741 isRemovableSaddle[i] =
isSaddle2(saddleCandidate);
2745 for(
auto &criticalPoint : criticalPoints) {
2746 const SimplexId criticalPointId = criticalPoint.first;
2747 const char criticalPointType = criticalPoint.second;
2750 if(!allowBoundary and triangulation.isVertexOnBoundary(criticalPointId)) {
2757 = triangulation.getVertexTriangleNumber(criticalPointId);
2758 for(
SimplexId i = 0; i < triangleNumber; ++i) {
2760 triangulation.getVertexTriangle(criticalPointId, i, triangleId);
2761 const Cell saddleCandidate(2, triangleId);
2763 if(
isSaddle2(saddleCandidate) and dmt2Saddle2PL_[triangleId] == -1) {
2764 saddleId = triangleId;
2770 if(numberOfSaddles == 1) {
2771 if(dmt2Saddle2PL_[saddleId] == -1
2772 and pl2dmt_saddle[criticalPointId] == -1) {
2773 dmt2Saddle2PL_[saddleId] = criticalPointId;
2774 pl2dmt_saddle[criticalPointId] = saddleId;
2775 isRemovableSaddle[saddleId] =
false;
2784template <
typename dataType,
typename triangulationType>
2785int DiscreteGradient::initializeSaddleSaddleConnections1(
2786 const std::vector<char> &isRemovableSaddle1,
2787 const std::vector<char> &isRemovableSaddle2,
2788 const bool allowBruteForce,
2789 std::vector<VPath> &vpaths,
2790 std::vector<CriticalPoint> &criticalPoints,
2791 std::vector<SimplexId> &saddle1Index,
2792 std::vector<SimplexId> &saddle2Index,
2793 const triangulationType &triangulation)
const {
2796 const auto *
const scalars
2800 const int saddle2Dim = maximumDim - 1;
2801 const int saddle1Dim = saddle2Dim - 1;
2805 const SimplexId numberOfSaddle2Candidates
2807 saddle2Index.resize(numberOfSaddle2Candidates, -1);
2808 for(
SimplexId i = 0; i < numberOfSaddle2Candidates; ++i) {
2809 if(allowBruteForce or isRemovableSaddle2[i]) {
2810 const Cell saddle2Candidate(saddle2Dim, i);
2813 const SimplexId index = criticalPoints.size();
2814 saddle2Index[i] = index;
2815 criticalPoints.emplace_back(saddle2Candidate);
2819 const SimplexId numberOf2Saddles = criticalPoints.size();
2822 const SimplexId numberOfSaddle1Candidates
2824 saddle1Index.resize(numberOfSaddle1Candidates, -1);
2825 for(
SimplexId i = 0; i < numberOfSaddle1Candidates; ++i) {
2826 if(isRemovableSaddle1[i]) {
2827 const Cell saddle1Candidate(saddle1Dim, i);
2829 const SimplexId index = criticalPoints.size();
2830 saddle1Index[i] = index;
2831 criticalPoints.emplace_back(saddle1Candidate);
2837 std::vector<bool> isVisited(numberOfSaddle2Candidates,
false);
2838 std::vector<SimplexId> visitedTriangles{};
2840 for(
SimplexId i = 0; i < numberOf2Saddles; ++i) {
2842 CriticalPoint &destination = criticalPoints[destinationIndex];
2843 const Cell &saddle2 = destination.cell_;
2844 VisitedMask mask{isVisited, visitedTriangles};
2846 std::vector<SimplexId> saddles1;
2849 for(
auto &saddle1Id : saddles1) {
2850 if(!isRemovableSaddle1[saddle1Id]) {
2854 const Cell &saddle1 = Cell(1, saddle1Id);
2856 std::vector<Cell> path;
2858 saddle1, saddle2, isVisited, &path, triangulation,
true);
2860 if(!isMultiConnected) {
2861 const SimplexId sourceIndex = saddle1Index[saddle1Id];
2862 CriticalPoint &source = criticalPoints[sourceIndex];
2865 const SimplexId sourceSlot = source.addSlot();
2866 const SimplexId destinationSlot = destination.addSlot();
2872 vpaths.push_back(VPath(
true, -1, sourceIndex, destinationIndex,
2873 sourceSlot, destinationSlot, persistence));
2879 const SimplexId numberOfCriticalPoints = criticalPoints.size();
2880 for(
SimplexId i = 0; i < numberOfCriticalPoints; ++i) {
2881 CriticalPoint &cp = criticalPoints[i];
2883 const SimplexId numberOfSlots = cp.numberOfSlots_;
2884 cp.vpaths_.resize(numberOfSlots);
2885 cp.numberOfSlots_ = 0;
2888 const SimplexId numberOfVPaths = vpaths.size();
2889#ifdef TTK_ENABLE_OPENMP
2890#pragma omp parallel for num_threads(threadNumber_)
2892 for(
SimplexId i = 0; i < numberOfVPaths; ++i) {
2893 const VPath &vpath = vpaths[i];
2895 if(vpath.isValid_) {
2896 const SimplexId sourceIndex = vpath.source_;
2897 const SimplexId destinationIndex = vpath.destination_;
2899 const SimplexId sourceSlot = vpath.sourceSlot_;
2900 const SimplexId destinationSlot = vpath.destinationSlot_;
2902 CriticalPoint &source = criticalPoints[sourceIndex];
2903 CriticalPoint &destination = criticalPoints[destinationIndex];
2905 source.vpaths_[sourceSlot] = i;
2906 destination.vpaths_[destinationSlot] = i;
2911 " Initialization step #1", 1.0, t.getElapsedTime(), this->threadNumber_);
2916template <
typename dataType,
typename triangulationType>
2917int DiscreteGradient::initializeSaddleSaddleConnections2(
2918 const std::vector<char> &isRemovableSaddle1,
2919 const std::vector<char> &isRemovableSaddle2,
2920 const bool allowBruteForce,
2921 std::vector<VPath> &vpaths,
2922 std::vector<CriticalPoint> &criticalPoints,
2923 std::vector<SimplexId> &saddle1Index,
2924 std::vector<SimplexId> &saddle2Index,
2925 const triangulationType &triangulation)
const {
2928 const auto *
const scalars
2932 const int saddle2Dim = maximumDim - 1;
2933 const int saddle1Dim = saddle2Dim - 1;
2937 const SimplexId numberOfSaddle1Candidates
2939 saddle1Index.resize(numberOfSaddle1Candidates, -1);
2940 for(
SimplexId i = 0; i < numberOfSaddle1Candidates; ++i) {
2941 if(isRemovableSaddle1[i]) {
2942 const Cell saddle1Candidate(saddle1Dim, i);
2944 const SimplexId index = criticalPoints.size();
2945 saddle1Index[i] = index;
2946 criticalPoints.emplace_back(saddle1Candidate);
2949 const SimplexId numberOf1Saddles = criticalPoints.size();
2952 const SimplexId numberOfSaddle2Candidates
2954 saddle2Index.resize(numberOfSaddle2Candidates, -1);
2955 for(
SimplexId i = 0; i < numberOfSaddle2Candidates; ++i) {
2956 if(allowBruteForce or isRemovableSaddle2[i]) {
2957 const Cell saddle2Candidate(saddle2Dim, i);
2960 const SimplexId index = criticalPoints.size();
2961 saddle2Index[i] = index;
2962 criticalPoints.emplace_back(saddle2Candidate);
2969 std::vector<bool> isVisited(numberOfSaddle1Candidates,
false);
2970 std::vector<SimplexId> visitedEdges{};
2971 for(
SimplexId i = 0; i < numberOf1Saddles; ++i) {
2973 CriticalPoint &source = criticalPoints[sourceIndex];
2974 const Cell &saddle1 = source.cell_;
2976 std::vector<SimplexId> saddles2;
2977 VisitedMask mask{isVisited, visitedEdges};
2980 for(
auto &saddle2Id : saddles2) {
2981 if(!isRemovableSaddle2[saddle2Id]) {
2985 const Cell &saddle2 = Cell(2, saddle2Id);
2987 std::vector<Cell> path;
2989 saddle2, saddle1, isVisited, &path, triangulation,
true);
2991 if(!isMultiConnected) {
2992 const SimplexId destinationIndex = saddle2Index[saddle2Id];
2993 CriticalPoint &destination = criticalPoints[destinationIndex];
2996 const SimplexId sourceSlot = source.addSlot();
2997 const SimplexId destinationSlot = destination.addSlot();
3003 vpaths.push_back(VPath(
true, -1, sourceIndex, destinationIndex,
3004 sourceSlot, destinationSlot, persistence));
3010 const SimplexId numberOfCriticalPoints = criticalPoints.size();
3011 for(
SimplexId i = 0; i < numberOfCriticalPoints; ++i) {
3012 CriticalPoint &cp = criticalPoints[i];
3014 const SimplexId numberOfSlots = cp.numberOfSlots_;
3015 cp.vpaths_.resize(numberOfSlots);
3016 cp.numberOfSlots_ = 0;
3019 const SimplexId numberOfVPaths = vpaths.size();
3020#ifdef TTK_ENABLE_OPENMP
3021#pragma omp parallel for num_threads(threadNumber_)
3023 for(
SimplexId i = 0; i < numberOfVPaths; ++i) {
3024 const VPath &vpath = vpaths[i];
3026 if(vpath.isValid_) {
3027 const SimplexId sourceIndex = vpath.source_;
3028 const SimplexId destinationIndex = vpath.destination_;
3030 const SimplexId sourceSlot = vpath.sourceSlot_;
3031 const SimplexId destinationSlot = vpath.destinationSlot_;
3033 CriticalPoint &source = criticalPoints[sourceIndex];
3034 CriticalPoint &destination = criticalPoints[destinationIndex];
3036 source.vpaths_[sourceSlot] = i;
3037 destination.vpaths_[destinationSlot] = i;
3042 " Initialization step #2", 1.0, t.getElapsedTime(), this->threadNumber_);
3047template <
typename dataType>
3048int DiscreteGradient::orderSaddleSaddleConnections1(
3049 const std::vector<VPath> &vpaths,
3050 std::vector<CriticalPoint> &criticalPoints,
3051 std::set<std::tuple<dataType, SimplexId, SimplexId>,
3055 const SimplexId numberOfVPaths = vpaths.size();
3056 for(
SimplexId i = 0; i < numberOfVPaths; ++i) {
3057 const VPath &vpath = vpaths[i];
3059 if(vpath.isValid_) {
3060 const SimplexId saddleId = criticalPoints[vpath.destination_].cell_.id_;
3061 S.insert(std::make_tuple(vpath.persistence_, i, saddleId));
3066 " Ordering of the vpaths #1", 1.0, t.getElapsedTime(), this->threadNumber_);
3071template <
typename dataType>
3072int DiscreteGradient::orderSaddleSaddleConnections2(
3073 const std::vector<VPath> &vpaths,
3074 std::vector<CriticalPoint> &criticalPoints,
3075 std::set<std::tuple<dataType, SimplexId, SimplexId>,
3079 const SimplexId numberOfVPaths = vpaths.size();
3080 for(
SimplexId i = 0; i < numberOfVPaths; ++i) {
3081 const VPath &vpath = vpaths[i];
3083 if(vpath.isValid_) {
3084 const SimplexId saddleId = criticalPoints[vpath.source_].cell_.id_;
3085 S.insert(std::make_tuple(vpath.persistence_, i, saddleId));
3090 " Ordering of the vpaths #2", 1.0, t.getElapsedTime(), this->threadNumber_);
3095template <
typename dataType,
typename triangulationType>
3096int DiscreteGradient::processSaddleSaddleConnections1(
3097 const int iterationThreshold,
3098 const std::vector<char> &isPL,
3099 const bool allowBoundary,
3100 const bool allowBruteForce,
3101 const bool returnSaddleConnectors,
3102 std::set<std::tuple<dataType, SimplexId, SimplexId>,
3104 std::vector<SimplexId> &pl2dmt_saddle1,
3105 std::vector<SimplexId> &pl2dmt_saddle2,
3106 std::vector<char> &isRemovableSaddle1,
3107 std::vector<char> &isRemovableSaddle2,
3108 std::vector<VPath> &vpaths,
3109 std::vector<CriticalPoint> &criticalPoints,
3110 std::vector<SimplexId> &saddle1Index,
3111 std::vector<SimplexId> &saddle2Index,
3112 const triangulationType &triangulation) {
3115 const auto *
const scalars
3118 const SimplexId numberOfEdges = triangulation.getNumberOfEdges();
3119 const SimplexId numberOfTriangles = triangulation.getNumberOfTriangles();
3120 const SimplexId optimizedSize = std::max(numberOfEdges, numberOfTriangles);
3121 std::vector<bool> isVisited(optimizedSize,
false);
3122 std::vector<SimplexId> visitedCells{};
3124 int numberOfIterations{};
3126 if(iterationThreshold >= 0 and numberOfIterations >= iterationThreshold) {
3130 auto ptr = S.begin();
3131 const SimplexId vpathId = std::get<1>(*ptr);
3133 VPath &vpath = vpaths[vpathId];
3135 if(vpath.isValid_) {
3136 if(returnSaddleConnectors) {
3143 const Cell &minSaddle1 = criticalPoints[vpath.source_].cell_;
3144 const Cell &minSaddle2 = criticalPoints[vpath.destination_].cell_;
3146 std::vector<SimplexId> saddles1;
3147 VisitedMask mask{isVisited, visitedCells};
3152 = std::find_if(saddles1.begin(), saddles1.end(),
3153 [&](
const auto &s) { return s == minSaddle1.id_; });
3154 if(isFound == saddles1.end()) {
3155 ++numberOfIterations;
3160 std::vector<Cell> path;
3162 minSaddle1, minSaddle2, isVisited, &path, triangulation,
true);
3164 if(isMultiConnected) {
3165 ++numberOfIterations;
3170 if(vpath.isValid_) {
3171 const Cell &dmt_saddle1 = criticalPoints[vpath.source_].cell_;
3175 for(
int i = 0; i < 2; ++i) {
3177 triangulation.getEdgeVertex(dmt_saddle1Id, i, vertexId);
3183 if(!allowBoundary and triangulation.isVertexOnBoundary(vertexId)) {
3187 if(pl2dmt_saddle1[vertexId] == -1) {
3188 const SimplexId pl_saddle1Id = vertexId;
3190 SimplexId numberOfRemainingSaddles1 = 0;
3194 = triangulation.getVertexEdgeNumber(pl_saddle1Id);
3195 for(
SimplexId j = 0; j < edgeNumber; ++j) {
3197 triangulation.getVertexEdge(pl_saddle1Id, j, edgeId);
3199 if(edgeId != dmt_saddle1Id and
isSaddle1(Cell(1, edgeId))
3200 and isRemovableSaddle1[edgeId]) {
3201 ++numberOfRemainingSaddles1;
3206 if(numberOfRemainingSaddles1 == 0) {
3207 isRemovableSaddle1[dmt_saddle1Id] =
false;
3208 pl2dmt_saddle1[vertexId] = dmt_saddle1Id;
3213 if(numberOfRemainingSaddles1 == 1) {
3214 isRemovableSaddle1[dmt_saddle1Id] =
false;
3215 isRemovableSaddle1[savedId] =
false;
3216 pl2dmt_saddle1[vertexId] = savedId;
3220 }
else if(pl2dmt_saddle1[vertexId] == dmt_saddle1Id) {
3231 if(!allowBruteForce and vpath.isValid_) {
3232 const Cell &dmt_saddle2 = criticalPoints[vpath.destination_].cell_;
3236 for(
int i = 0; i < 3; ++i) {
3238 triangulation.getTriangleVertex(dmt_saddle2Id, i, vertexId);
3244 if(!allowBoundary and triangulation.isVertexOnBoundary(vertexId)) {
3248 if(pl2dmt_saddle2[vertexId] == -1) {
3249 const SimplexId pl_saddle2Id = vertexId;
3251 SimplexId numberOfRemainingSaddles2 = 0;
3255 = triangulation.getVertexTriangleNumber(pl_saddle2Id);
3256 for(
SimplexId j = 0; j < triangleNumber; ++j) {
3258 triangulation.getVertexTriangle(pl_saddle2Id, j, triangleId);
3260 if(triangleId != dmt_saddle2Id
3262 and isRemovableSaddle2[triangleId]) {
3263 ++numberOfRemainingSaddles2;
3264 savedId = triangleId;
3268 if(numberOfRemainingSaddles2 == 0) {
3269 isRemovableSaddle2[dmt_saddle2Id] =
false;
3270 pl2dmt_saddle2[vertexId] = dmt_saddle2Id;
3275 if(numberOfRemainingSaddles2 == 1) {
3276 isRemovableSaddle2[dmt_saddle2Id] =
false;
3277 isRemovableSaddle2[savedId] =
false;
3278 pl2dmt_saddle2[vertexId] = savedId;
3282 }
else if(pl2dmt_saddle2[vertexId] == dmt_saddle2Id) {
3292 if(vpath.isValid_) {
3297 if(vpath.isValid_) {
3299 const SimplexId sourceId = vpath.source_;
3300 const SimplexId destinationId = vpath.destination_;
3303 std::vector<SimplexId> newSourceIds;
3304 CriticalPoint &destination = criticalPoints[destinationId];
3305 for(
auto &destinationVPathId : destination.vpaths_) {
3306 VPath &destinationVPath = vpaths[destinationVPathId];
3308 if(destinationVPath.isValid_ and destinationVPath.source_ != sourceId) {
3310 const SimplexId newSourceId = destinationVPath.source_;
3311 newSourceIds.push_back(newSourceId);
3314 destinationVPath.invalidate();
3320 std::vector<SimplexId> newDestinationIds;
3321 CriticalPoint &source = criticalPoints[sourceId];
3322 for(
auto &sourceVPathId : source.vpaths_) {
3323 VPath &sourceVPath = vpaths[sourceVPathId];
3325 if(sourceVPath.isValid_ and sourceVPath.destination_ != destinationId) {
3327 const SimplexId newDestinationId = sourceVPath.destination_;
3328 newDestinationIds.push_back(newDestinationId);
3330 CriticalPoint &newDestination = criticalPoints[newDestinationId];
3331 for(
auto &newDestinationVPathId : newDestination.vpaths_) {
3332 VPath &newDestinationVPath = vpaths[newDestinationVPathId];
3333 if(newDestinationVPath.isValid_
3334 and newDestinationVPath.source_ != sourceId) {
3337 newDestinationVPath.invalidate();
3342 sourceVPath.invalidate();
3349 destination.clear();
3352 for(
auto &newDestinationId : newDestinationIds) {
3353 CriticalPoint &newDestination = criticalPoints[newDestinationId];
3354 const Cell &saddle2 = newDestination.cell_;
3356 std::vector<SimplexId> saddles1;
3357 VisitedMask mask{isVisited, visitedCells};
3360 for(
auto &saddle1Id : saddles1) {
3361 const Cell saddle1(1, saddle1Id);
3363 std::vector<Cell> path;
3365 saddle1, saddle2, isVisited, &path, triangulation,
true);
3367 if(isMultiConnected) {
3371 SimplexId newSourceId = saddle1Index[saddle1Id];
3374 if(newSourceId == -1) {
3375 if(!isRemovableSaddle1[saddle1Id]) {
3379 const SimplexId newCriticalPointId = criticalPoints.size();
3380 saddle1Index[saddle1Id] = newCriticalPointId;
3381 criticalPoints.emplace_back(saddle1);
3383 newSourceId = newCriticalPointId;
3385 CriticalPoint &newSource = criticalPoints[newSourceId];
3388 const SimplexId newVPathId = vpaths.size();
3392 vpaths.push_back(VPath(
3393 true, -1, newSourceId, newDestinationId, -1, -1, persistence));
3396 newDestination.vpaths_.push_back(newVPathId);
3397 newSource.vpaths_.push_back(newVPathId);
3401 std::make_tuple(persistence, newVPathId, newDestination.cell_.id_));
3406 for(
auto &newSourceId : newSourceIds) {
3407 CriticalPoint &newSource = criticalPoints[newSourceId];
3408 const Cell &saddle1 = newSource.cell_;
3410 std::vector<SimplexId> saddles2;
3411 VisitedMask mask{isVisited, visitedCells};
3414 for(
auto &saddle2Id : saddles2) {
3415 const Cell saddle2(2, saddle2Id);
3417 std::vector<Cell> path;
3419 saddle2, saddle1, isVisited, &path, triangulation,
true);
3421 if(isMultiConnected) {
3425 const SimplexId newDestinationId = saddle2Index[saddle2Id];
3428 if(newDestinationId == -1) {
3432 CriticalPoint &newDestination = criticalPoints[newDestinationId];
3435 bool alreadyExists =
false;
3436 for(
auto &newDestinationVPathId : newDestination.vpaths_) {
3437 const VPath &newDestinationVPath = vpaths[newDestinationVPathId];
3439 if(newDestinationVPath.isValid_
3440 and newDestinationVPath.source_ == newSourceId) {
3441 alreadyExists =
true;
3451 const SimplexId newVPathId = vpaths.size();
3455 vpaths.push_back(VPath(
3456 true, -1, newSourceId, newDestinationId, -1, -1, persistence));
3459 newDestination.vpaths_.push_back(newVPathId);
3460 newSource.vpaths_.push_back(newVPathId);
3464 std::make_tuple(persistence, newVPathId, newDestination.cell_.id_));
3469 ++numberOfIterations;
3472 this->
printMsg(
" Processing of the vpaths #1", 1.0, t.getElapsedTime(),
3473 this->threadNumber_);
3478template <
typename dataType,
typename triangulationType>
3479int DiscreteGradient::processSaddleSaddleConnections2(
3480 const int iterationThreshold,
3481 const std::vector<char> &isPL,
3482 const bool allowBoundary,
3483 const bool allowBruteForce,
3484 const bool returnSaddleConnectors,
3485 std::set<std::tuple<dataType, SimplexId, SimplexId>,
3487 std::vector<SimplexId> &pl2dmt_saddle1,
3488 std::vector<SimplexId> &pl2dmt_saddle2,
3489 std::vector<char> &isRemovableSaddle1,
3490 std::vector<char> &isRemovableSaddle2,
3491 std::vector<VPath> &vpaths,
3492 std::vector<CriticalPoint> &criticalPoints,
3493 std::vector<SimplexId> &saddle1Index,
3494 std::vector<SimplexId> &saddle2Index,
3495 const triangulationType &triangulation) {
3498 this->
printMsg(
"Saddle connector persistence threshold: "
3501 const auto *
const scalars
3504 const SimplexId numberOfEdges = triangulation.getNumberOfEdges();
3505 const SimplexId numberOfTriangles = triangulation.getNumberOfTriangles();
3506 const SimplexId optimizedSize = std::max(numberOfEdges, numberOfTriangles);
3507 std::vector<bool> isVisited(optimizedSize,
false);
3508 std::vector<SimplexId> visitedIds{};
3510 int numberOfIterations{};
3512 if(iterationThreshold >= 0 and numberOfIterations >= iterationThreshold) {
3516 auto ptr = S.begin();
3517 const SimplexId vpathId = std::get<1>(*ptr);
3519 VPath &vpath = vpaths[vpathId];
3521 if(vpath.isValid_) {
3522 if(returnSaddleConnectors) {
3529 const Cell &minSaddle1 = criticalPoints[vpath.source_].cell_;
3530 const Cell &minSaddle2 = criticalPoints[vpath.destination_].cell_;
3532 std::vector<SimplexId> saddles2;
3533 VisitedMask mask{isVisited, visitedIds};
3538 = std::find_if(saddles2.begin(), saddles2.end(),
3539 [&](
const auto &s) { return s == minSaddle2.id_; });
3541 if(isFound == saddles2.end()) {
3542 ++numberOfIterations;
3547 std::vector<Cell> path;
3549 minSaddle2, minSaddle1, isVisited, &path, triangulation,
true);
3551 if(isMultiConnected) {
3552 ++numberOfIterations;
3557 if(vpath.isValid_) {
3558 const Cell &dmt_saddle1 = criticalPoints[vpath.source_].cell_;
3562 for(
int i = 0; i < 2; ++i) {
3564 triangulation.getEdgeVertex(dmt_saddle1Id, i, vertexId);
3570 if(!allowBoundary and triangulation.isVertexOnBoundary(vertexId)) {
3574 if(pl2dmt_saddle1[vertexId] == -1) {
3575 const SimplexId pl_saddle1Id = vertexId;
3577 SimplexId numberOfRemainingSaddles1 = 0;
3581 = triangulation.getVertexEdgeNumber(pl_saddle1Id);
3582 for(
SimplexId j = 0; j < edgeNumber; ++j) {
3584 triangulation.getVertexEdge(pl_saddle1Id, j, edgeId);
3586 if(edgeId != dmt_saddle1Id and
isSaddle1(Cell(1, edgeId))
3587 and isRemovableSaddle1[edgeId]) {
3588 ++numberOfRemainingSaddles1;
3593 if(numberOfRemainingSaddles1 == 0) {
3594 isRemovableSaddle1[dmt_saddle1Id] =
false;
3595 pl2dmt_saddle1[vertexId] = dmt_saddle1Id;
3600 if(numberOfRemainingSaddles1 == 1) {
3601 isRemovableSaddle1[dmt_saddle1Id] =
false;
3602 isRemovableSaddle1[savedId] =
false;
3603 pl2dmt_saddle1[vertexId] = savedId;
3607 }
else if(pl2dmt_saddle1[vertexId] == dmt_saddle1Id) {
3618 if(!allowBruteForce and vpath.isValid_) {
3619 const Cell &dmt_saddle2 = criticalPoints[vpath.destination_].cell_;
3623 for(
int i = 0; i < 3; ++i) {
3625 triangulation.getTriangleVertex(dmt_saddle2Id, i, vertexId);
3631 if(!allowBoundary and triangulation.isVertexOnBoundary(vertexId)) {
3635 if(pl2dmt_saddle2[vertexId] == -1) {
3636 const SimplexId pl_saddle2Id = vertexId;
3638 SimplexId numberOfRemainingSaddles2 = 0;
3642 = triangulation.getVertexTriangleNumber(pl_saddle2Id);
3643 for(
SimplexId j = 0; j < triangleNumber; ++j) {
3645 triangulation.getVertexTriangle(pl_saddle2Id, j, triangleId);
3647 if(triangleId != dmt_saddle2Id
3649 and isRemovableSaddle2[triangleId]) {
3650 ++numberOfRemainingSaddles2;
3651 savedId = triangleId;
3655 if(!numberOfRemainingSaddles2) {
3656 isRemovableSaddle2[dmt_saddle2Id] =
false;
3657 pl2dmt_saddle2[vertexId] = dmt_saddle2Id;
3661 if(numberOfRemainingSaddles2 == 1) {
3662 isRemovableSaddle2[dmt_saddle2Id] =
false;
3663 isRemovableSaddle2[savedId] =
false;
3664 pl2dmt_saddle2[vertexId] = savedId;
3667 }
else if(pl2dmt_saddle2[vertexId] == dmt_saddle2Id) {
3677 if(vpath.isValid_) {
3682 if(vpath.isValid_) {
3690 const SimplexId sourceId = vpath.source_;
3691 const SimplexId destinationId = vpath.destination_;
3694 std::vector<SimplexId> newDestinationIds;
3695 CriticalPoint &source = criticalPoints[sourceId];
3696 for(
auto &sourceVPathId : source.vpaths_) {
3697 VPath &sourceVPath = vpaths[sourceVPathId];
3699 if(sourceVPath.isValid_ and sourceVPath.destination_ != destinationId) {
3701 const SimplexId newDestinationId = sourceVPath.destination_;
3702 newDestinationIds.push_back(newDestinationId);
3705 sourceVPath.invalidate();
3711 std::vector<SimplexId> newSourceIds;
3712 CriticalPoint &destination = criticalPoints[destinationId];
3713 for(
auto &destinationVPathId : destination.vpaths_) {
3714 VPath &destinationVPath = vpaths[destinationVPathId];
3716 if(destinationVPath.isValid_ and destinationVPath.source_ != sourceId) {
3718 const SimplexId newSourceId = destinationVPath.source_;
3719 newSourceIds.push_back(newSourceId);
3721 CriticalPoint &newSource = criticalPoints[newSourceId];
3722 for(
auto &newSourceVPathId : newSource.vpaths_) {
3723 VPath &newSourceVPath = vpaths[newSourceVPathId];
3724 if(newSourceVPath.isValid_
3725 and newSourceVPath.destination_ != destinationId) {
3728 newSourceVPath.invalidate();
3733 destinationVPath.invalidate();
3740 destination.clear();
3743 for(
auto &newSourceId : newSourceIds) {
3744 CriticalPoint &newSource = criticalPoints[newSourceId];
3745 const Cell &saddle1 = newSource.cell_;
3747 std::vector<SimplexId> saddles2;
3748 VisitedMask mask{isVisited, visitedIds};
3751 for(
auto &saddle2Id : saddles2) {
3752 const Cell saddle2(2, saddle2Id);
3755 saddle2, saddle1, isVisited,
nullptr, triangulation,
true);
3757 if(isMultiConnected) {
3761 SimplexId newDestinationId = saddle2Index[saddle2Id];
3764 if(newDestinationId == -1) {
3765 if(!isRemovableSaddle2[saddle2Id]) {
3769 const SimplexId newCriticalPointId = criticalPoints.size();
3770 saddle2Index[saddle2Id] = newCriticalPointId;
3771 criticalPoints.emplace_back(saddle2);
3773 newDestinationId = newCriticalPointId;
3776 CriticalPoint &newDestination = criticalPoints[newDestinationId];
3779 const SimplexId newVPathId = vpaths.size();
3783 vpaths.push_back(VPath(
3784 true, -1, newSourceId, newDestinationId, -1, -1, persistence));
3787 newDestination.vpaths_.push_back(newVPathId);
3788 newSource.vpaths_.push_back(newVPathId);
3792 std::make_tuple(persistence, newVPathId, newSource.cell_.id_));
3797 for(
auto &newDestinationId : newDestinationIds) {
3798 CriticalPoint &newDestination = criticalPoints[newDestinationId];
3799 const Cell &saddle2 = newDestination.cell_;
3801 std::vector<SimplexId> saddles1;
3802 VisitedMask mask{isVisited, visitedIds};
3805 for(
auto &saddle1Id : saddles1) {
3806 const Cell saddle1(1, saddle1Id);
3808 std::vector<Cell> path;
3810 saddle1, saddle2, isVisited, &path, triangulation,
true);
3812 if(isMultiConnected) {
3816 const SimplexId newSourceId = saddle1Index[saddle1Id];
3818 if(newSourceId == -1) {
3822 CriticalPoint &newSource = criticalPoints[newSourceId];
3825 bool alreadyExists =
false;
3826 for(
auto &newSourceVPathId : newSource.vpaths_) {
3827 const VPath &newSourceVPath = vpaths[newSourceVPathId];
3829 if(newSourceVPath.isValid_
3830 and newSourceVPath.destination_ == newDestinationId) {
3831 alreadyExists =
true;
3841 const SimplexId newVPathId = vpaths.size();
3845 vpaths.push_back(VPath(
3846 true, -1, newSourceId, newDestinationId, -1, -1, persistence));
3849 newDestination.vpaths_.push_back(newVPathId);
3850 newSource.vpaths_.push_back(newVPathId);
3854 std::make_tuple(persistence, newVPathId, newSource.cell_.id_));
3859 ++numberOfIterations;
3862 this->
printMsg(
" Processing of the vpaths #2", 1.0, t.getElapsedTime(),
3863 this->threadNumber_);
#define TTK_FORCE_USE(x)
Force the compiler to use the function/method parameter.
dataType getPersistence(const Cell &up, const Cell &down, const dataType *const scalars, const triangulationType &triangulation) const
std::array< std::vector< gradIdType >, 6 > gradientType
Discrete gradient internal struct.
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
TTK discreteGradient processing package.
int getCriticalPointMap(const std::vector< std::pair< SimplexId, char > > &criticalPoints, std::vector< char > &isPL)
SimplexId getCellLowerVertex(const Cell c, const triangulationType &triangulation) const
int reverseAscendingPath(const std::vector< Cell > &vpath, const triangulationType &triangulation) const
int reverseDescendingPath(const std::vector< Cell > &vpath, const triangulationType &triangulation) const
int setGradientGlyphs(std::vector< std::array< float, 3 > > &points, std::vector< char > &points_pairOrigins, std::vector< char > &cells_pairTypes, std::vector< SimplexId > &cellsIds, std::vector< char > &cellsDimensions, const triangulationType &triangulation) const
int reverseAscendingPathOnWall(const std::vector< Cell > &vpath, const triangulationType &triangulation, bool cancelReversal=false) const
bool getDescendingPathThroughWall(const Cell &saddle2, const Cell &saddle1, const std::vector< bool > &isVisited, std::vector< Cell > *const vpath, const triangulationType &triangulation, const bool stopIfMultiConnected=false, const bool enableCycleDetector=false) const
bool isSaddle1(const Cell &cell) const
bool isSaddle2(const Cell &cell) const
AbstractTriangulation::gradientKeyType inputScalarField_
int simplifySaddleSaddleConnections1(const std::vector< std::pair< SimplexId, char > > &criticalPoints, const std::vector< char > &isPL, const int iterationThreshold, const bool allowBoundary, const bool allowBruteForce, const bool returnSaddleConnectors, const triangulationType &triangulation)
SimplexId getNumberOfCells(const int dimension, const triangulationType &triangulation) const
SimplexId numberOfVertices_
bool isBoundary(const Cell &cell, const triangulationType &triangulation) const
bool isCellCritical(const int cellDim, const SimplexId cellId) const
SimplexId getPairedCell(const Cell &cell, const triangulationType &triangulation, bool isReverse=false) const
int getAscendingWall(const Cell &cell, VisitedMask &mask, const triangulationType &triangulation, std::vector< Cell > *const wall=nullptr, std::vector< SimplexId > *const saddles=nullptr) const
int reverseDescendingPathOnWall(const std::vector< Cell > &vpath, const triangulationType &triangulation) const
int filterSaddleConnectors(const bool allowBoundary, const triangulationType &triangulation)
SimplexId getCellGreaterVertex(const Cell c, const triangulationType &triangulation) const
int getCriticalPoints(std::array< std::vector< SimplexId >, 4 > &criticalCellsByDim, const triangulationType &triangulation) const
bool getAscendingPathThroughWall(const Cell &saddle1, const Cell &saddle2, const std::vector< bool > &isVisited, std::vector< Cell > *const vpath, const triangulationType &triangulation, const bool stopIfMultiConnected=false, const bool enableCycleDetector=false, bool *const cycleFound=nullptr) const
dataType getPersistence(const Cell &up, const Cell &down, const dataType *const scalars, const triangulationType &triangulation) const
double SaddleConnectorsPersistenceThreshold
int setCriticalPoints(const std::array< std::vector< SimplexId >, 4 > &criticalCellsByDim, std::vector< std::array< float, 3 > > &points, std::vector< char > &cellDimensions, std::vector< SimplexId > &cellIds, std::vector< char > &isOnBoundary, std::vector< SimplexId > &PLVertexIdentifiers, const triangulationType &triangulation) const
int getDescendingPath(const Cell &cell, std::vector< Cell > &vpath, const triangulationType &triangulation) const
int simplifySaddleSaddleConnections2(const std::vector< std::pair< SimplexId, char > > &criticalPoints, const std::vector< char > &isPL, const int iterationThreshold, const bool allowBoundary, const bool allowBruteForce, const bool returnSaddleConnectors, const triangulationType &triangulation)
int buildGradient(const triangulationType &triangulation, bool bypassCache=false, const std::vector< bool > *updateMask=nullptr)
bool detectGradientCycle(const Cell &cell, const triangulationType &triangulation) const
int getAscendingPath(const Cell &cell, std::vector< Cell > &vpath, const triangulationType &triangulation, const bool enableCycleDetector=false) const
AbstractTriangulation::gradientType localGradient_
int getNumberOfDimensions() const
int getDescendingWall(const Cell &cell, VisitedMask &mask, const triangulationType &triangulation, std::vector< Cell > *const wall=nullptr, std::vector< SimplexId > *const saddles=nullptr) const
AbstractTriangulation::gradientType * gradient_
const SimplexId * inputOffsets_
void setReturnSaddleConnectors(const bool &returnSaddleConnectors)
int setDebugLevel(const int &d) override
SimplexId getVertexId() const
COMMON_EXPORTS int MPIsize_
int SimplexId
Identifier type for simplices of any dimension.
COMMON_EXPORTS int MPIrank_
T end(std::pair< T, T > &p)
Auto-cleaning re-usable graph propagations data structure.
std::vector< bool > & isVisited_
std::vector< SimplexId > & visitedIds_
Extended Cell structure for processLowerStars.
const std::array< SimplexId, 3 > lowVerts_
const std::array< uint8_t, 3 > faces_
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)