23#include <boost/math/special_functions/next.hpp>
33 inline std::string
toFixed(
const float &number,
const int precision = 2) {
34 std::stringstream vFraction;
35 vFraction << std::fixed << std::setprecision(precision) << number;
36 return vFraction.str();
39 template <
typename IT>
41 toFixed(
const IT &number0,
const IT &number1,
const int precision = 2) {
42 return toFixed(((
float)number0) / ((
float)number1), precision);
66 template <
typename IT>
68 std::vector<IT> &queueMask,
69 std::vector<IT> &localOrder,
71 std::vector<std::tuple<IT, IT, IT>> &sortedIndices,
73 const IT &nVertices)
const {
76 constexpr char msg[] =
"Allocating Memory";
80 segmentation.resize(nVertices);
81 queueMask.resize(nVertices);
82 localOrder.resize(nVertices);
83 propagationMask.resize(nVertices);
84 sortedIndices.resize(nVertices);
93 template <
typename IT>
99 const IT &nVertices)
const {
102 constexpr char msg[] =
"Initializing Memory";
106#ifdef TTK_ENABLE_OPENMP
107#pragma omp parallel for num_threads(this->threadNumber_)
109 for(IT i = 0; i < nVertices; i++) {
110 segmentation[i] = -1;
113 propagationMask[i] =
nullptr;
128 template <
typename IT,
class TT>
131 IT *authorizationMask,
134 const IT *authorizedExtremaIndices,
135 const IT &nAuthorizedExtremaIndices,
137 const TT *triangulation)
const {
143 const IT nVertices = triangulation->getNumberOfVertices();
144#ifdef TTK_ENABLE_OPENMP
145#pragma omp parallel for num_threads(this->threadNumber_)
147 for(IT i = 0; i < nAuthorizedExtremaIndices; i++)
148 authorizationMask[authorizedExtremaIndices[i]] = -2;
152#ifdef TTK_ENABLE_OPENMP
153#pragma omp parallel for num_threads(this->threadNumber_)
155 for(IT v = 0; v < nVertices; v++) {
158 if(authorizationMask[v] == -2)
162 bool hasLargerNeighbor =
false;
163 const IT &vOrder = order[v];
164 const IT nNeighbors = triangulation->getVertexNeighborNumber(v);
165 for(IT n = 0; n < nNeighbors; n++) {
167 triangulation->getVertexNeighbor(v, n, u);
168 if(vOrder < order[u]) {
169 hasLargerNeighbor =
true;
175 if(hasLargerNeighbor)
179 IT localWriteIndex = 0;
180#ifdef TTK_ENABLE_OPENMP
181#pragma omp atomic capture
183 localWriteIndex = writeIndex++;
186#ifdef TTK_ENABLE_OPENMP
187#pragma omp atomic write
189 maximaBuffer[localWriteIndex] = v;
193 std::sort(maximaBuffer, maximaBuffer + writeIndex,
194 [=](
const IT &a,
const IT &b) ->
bool {
195 return order[a] < order[b];
200 if(nAuthorizedExtremaIndices < 1)
204 propagations.resize(writeIndex);
205#ifdef TTK_ENABLE_OPENMP
206#pragma omp parallel for num_threads(this->threadNumber_)
208 for(IT p = 0; p < writeIndex; p++) {
209 propagations[p].criticalPoints.push_back(maximaBuffer[p]);
212 this->
printMsg(
"Initializing Propagations ("
213 + std::to_string(writeIndex) +
"|"
214 + std::to_string(nVertices) +
")",
225 template <
typename IT,
typename TT>
233 const TT *triangulation,
234 const IT *order)
const {
237 auto *currentPropagation = &propagation;
241 auto queue = ¤tPropagation->queue;
242 queue->emplace(order[segmentId], segmentId);
244 queueMask[segmentId] = segmentId;
249 while(!queue->empty()) {
250 v = std::get<1>(queue->top());
254 if(propagationMask[v] !=
nullptr)
257 const IT &orderV = order[v];
260 bool isSaddle =
false;
261 const IT nNeighbors = triangulation->getVertexNeighborNumber(v);
263 IT numberOfLargerNeighbors = 0;
264 IT numberOfLargerNeighborsThisThreadVisited = 0;
265 for(IT n = 0; n < nNeighbors; n++) {
267 triangulation->getVertexNeighbor(v, n, u);
269 const IT &orderU = order[u];
272 if(orderU > orderV) {
273 numberOfLargerNeighbors++;
275 auto uPropagation = propagationMask[u];
276 if(uPropagation ==
nullptr
277 || currentPropagation != uPropagation->find())
280 numberOfLargerNeighborsThisThreadVisited++;
281 }
else if(queueMask[u] != segmentId) {
282 queue->emplace(orderU, u);
283 queueMask[u] = segmentId;
290 currentPropagation->criticalPoints.push_back(v);
292 IT numberOfRegisteredLargerVertices = 0;
293#ifdef TTK_ENABLE_OPENMP
294#pragma omp atomic capture
297 segmentation[v] -= numberOfLargerNeighborsThisThreadVisited;
298 numberOfRegisteredLargerVertices = segmentation[v];
303 if(numberOfRegisteredLargerVertices != -numberOfLargerNeighbors - 1)
307 std::vector<Propagation<IT> *> neighborPropagations(
308 nNeighbors,
nullptr);
309 for(IT n = 0; n < nNeighbors; n++) {
311 triangulation->getVertexNeighbor(v, n, u);
312 if(propagationMask[u] !=
nullptr) {
313 auto &neighborPropagation = neighborPropagations[n];
314 neighborPropagation = propagationMask[u]->
find();
315 if(order[neighborPropagation->criticalPoints[0]]
316 > order[currentPropagation->criticalPoints[0]])
317 currentPropagation = neighborPropagation;
322 for(IT n = 0; n < nNeighbors; n++) {
324 currentPropagation, neighborPropagations[n]);
327 queue = ¤tPropagation->queue;
328 segmentId = currentPropagation->criticalPoints[0];
332 propagationMask[v] = currentPropagation;
333 segmentation[v] = segmentId;
338 "Simple propagations should never reach global minimum/maximum.");
347 template <
typename IT,
typename DT,
typename TT>
355 const TT *triangulation,
358 const DT persistenceThreshold)
const {
361 auto *currentPropagation = &propagation;
365 auto queue = ¤tPropagation->queue;
366 queue->emplace(order[segmentId], segmentId);
368 DT s0 = scalars[segmentId];
370 queueMask[segmentId] = segmentId;
375 while(!queue->empty()) {
376 v = std::get<1>(queue->top());
380 if(propagationMask[v] !=
nullptr)
384 const DT &s1 = scalars[v];
385 const DT &sd = s0 < s1 ? s1 - s0 : s0 - s1;
386 if(sd > persistenceThreshold) {
387 currentPropagation->aborted =
true;
391 const IT &orderV = order[v];
394 bool isSaddle =
false;
395 const IT nNeighbors = triangulation->getVertexNeighborNumber(v);
397 IT numberOfLargerNeighbors = 0;
398 IT numberOfLargerNeighborsThisThreadVisited = 0;
399 for(IT n = 0; n < nNeighbors; n++) {
401 triangulation->getVertexNeighbor(v, n, u);
403 const IT &orderU = order[u];
406 if(orderU > orderV) {
407 numberOfLargerNeighbors++;
409 auto uPropagation = propagationMask[u];
410 if(uPropagation ==
nullptr
411 || currentPropagation != uPropagation->find())
414 numberOfLargerNeighborsThisThreadVisited++;
415 }
else if(queueMask[u] != segmentId) {
416 queue->emplace(orderU, u);
417 queueMask[u] = segmentId;
424 currentPropagation->criticalPoints.push_back(v);
426 IT numberOfRegisteredLargerVertices = 0;
427#ifdef TTK_ENABLE_OPENMP
428#pragma omp atomic capture
431 segmentation[v] -= numberOfLargerNeighborsThisThreadVisited;
432 numberOfRegisteredLargerVertices = segmentation[v];
437 if(numberOfRegisteredLargerVertices != -numberOfLargerNeighbors - 1)
441 std::vector<Propagation<IT> *> neighborPropagations(
442 nNeighbors,
nullptr);
443 for(IT n = 0; n < nNeighbors; n++) {
445 triangulation->getVertexNeighbor(v, n, u);
446 if(propagationMask[u] !=
nullptr) {
447 auto &neighborPropagation = neighborPropagations[n];
448 neighborPropagation = propagationMask[u]->
find();
449 if(order[neighborPropagation->criticalPoints[0]]
450 > order[currentPropagation->criticalPoints[0]])
451 currentPropagation = neighborPropagation;
456 for(IT n = 0; n < nNeighbors; n++) {
458 currentPropagation, neighborPropagations[n]);
461 queue = ¤tPropagation->queue;
462 segmentId = currentPropagation->criticalPoints[0];
463 s0 = scalars[segmentId];
467 propagationMask[v] = currentPropagation;
468 segmentation[v] = segmentId;
477 template <
typename IT,
class TT>
483 const TT *triangulation,
484 const IT *inputOrder)
const {
486 const IT nPropagations = propagations.size();
487 const std::string msg
488 =
"Computing Propagations (" + std::to_string(nPropagations) +
")";
494#ifdef TTK_ENABLE_OPENMP
495#pragma omp parallel for schedule(dynamic, 1) num_threads(this->threadNumber_)
497 for(IT p = 0; p < nPropagations; p++) {
499 propagations[p], propagationMask, segmentation, queueMask,
501 triangulation, inputOrder);
517 template <
typename IT,
typename DT,
class TT>
524 const TT *triangulation,
527 const DT persistenceThreshold)
const {
529 const IT nPropagations = propagations.size();
530 const std::string msg =
"Computing Persistence-Sensitive Propagations ("
531 + std::to_string(nPropagations) +
")";
537#ifdef TTK_ENABLE_OPENMP
538#pragma omp parallel for schedule(dynamic, 1) num_threads(this->threadNumber_)
540 for(IT p = 0; p < nPropagations; p++) {
541 int const localStatus
543 propagations[p], propagationMask, segmentation, queueMask,
545 triangulation, order, scalars, persistenceThreshold);
564 template <
typename IT>
569 const IT nVertices)
const {
572 const IT nPropagations = propagations.size();
575 "Finalizing Propagations (" + std::to_string(nPropagations) +
")", 0,
579 IT nSegmentVertices = 0;
580 IT nParentPropagations = 0;
581 parentPropagations.resize(nPropagations);
582 for(IT p = 0; p < nPropagations; p++) {
583 auto *propagation = &propagations[p];
584 if(!propagation->aborted
585 && (propagation->parent == propagation
586 || propagation->parent->aborted)) {
587 nSegmentVertices = nSegmentVertices + propagation->segmentSize;
588 parentPropagations[nParentPropagations++] = propagation;
591 parentPropagations.resize(nParentPropagations);
593 this->
printMsg(
"Finalizing Propagations ("
594 + std::to_string(nParentPropagations) +
"|"
595 +
toFixed(nParentPropagations, nPropagations) +
"|"
596 +
toFixed(nSegmentVertices, nVertices) +
")",
605 template <
typename IT,
class TT>
610 const TT *triangulation)
const {
614 const IT &saddleOrder = order[saddleIndex];
617 auto &segment = propagation->
segment;
627 queue[queueIndex++] = extremumIndex;
628 segmentation[extremumIndex] = -1000;
632 while(queueIndex > 0) {
633 const IT v = queue[--queueIndex];
635 segment[segmentIndex++] = v;
637 IT nNeighbors = triangulation->getVertexNeighborNumber(v);
638 for(IT n = 0; n < nNeighbors; n++) {
640 triangulation->getVertexNeighbor(v, n, u);
641 auto &s = segmentation[u];
642 if(s >= 0 && order[u] > saddleOrder) {
644 queue[queueIndex++] = u;
651 this->
printErr(
"Segment size incorrect: "
652 + std::to_string(segmentIndex) +
" "
657 for(
auto idx : propagation->
segment)
658 segmentation[idx] = extremumIndex;
664 template <
typename IT,
class TT>
669 const TT *triangulation)
const {
671 const IT nPropagations = propagations.size();
672 const IT nVertices = triangulation->getNumberOfVertices();
675 const std::string msg
676 =
"Computing Segments (" + std::to_string(nPropagations) +
")";
683#ifdef TTK_ENABLE_OPENMP
684#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
686 for(IT p = 0; p < nPropagations; p++) {
687 int const localStatus
690 order, triangulation);
702 IT min = propagations[0]->segmentSize;
706 for(IT p = 0; p < nPropagations; p++) {
707 const auto propagation = propagations[p];
708 if(min > propagation->segmentSize)
709 min = propagation->segmentSize;
710 if(max < propagation->segmentSize)
711 max = propagation->segmentSize;
712 avg += propagation->segmentSize;
715 avg /= nPropagations;
717 this->
printMsg(
"Computing Segments (" + std::to_string(nPropagations)
718 +
"|" +
toFixed(min, nVertices) +
"|"
719 +
toFixed(avg, nVertices) +
"|"
720 +
toFixed(max, nVertices) +
")",
727 template <
typename IT,
class TT>
730 IT *localVertexSequence,
732 const bool &performSuperlevelSetPropagation,
733 const TT *triangulation,
734 const IT *segmentation,
736 const std::vector<IT> &boundary,
737 const std::vector<IT> &segment,
738 const IT &saddleIdx)
const {
740 std::priority_queue<std::pair<IT, IT>, std::vector<std::pair<IT, IT>>>
743 IT nSegmentVertices = segment.size();
745 if(performSuperlevelSetPropagation) {
747 queue.emplace(std::numeric_limits<IT>::max(), saddleIdx);
750 IT offset = -nSegmentVertices - 1;
751 for(IT i = 0; i < nSegmentVertices; i++)
752 localOrder[segment[i]] = offset - localOrder[segment[i]];
755 for(
const auto &v : boundary) {
756 queue.emplace(localOrder[v], v);
761 queue.emplace(std::numeric_limits<IT>::min(), saddleIdx);
765 while(!queue.empty()) {
766 IT v = std::get<1>(queue.top());
769 localVertexSequence[q++] = v;
771 IT nNeighbors = triangulation->getVertexNeighborNumber(v);
772 for(IT n = 0; n < nNeighbors; n++) {
774 triangulation->getVertexNeighbor(v, n, u);
777 if(segmentation[u] == segmentId && localOrder[u] < 0) {
778 queue.emplace(localOrder[u], u);
784 if(performSuperlevelSetPropagation) {
786 for(IT i = 1; i <= nSegmentVertices; i++)
787 localOrder[localVertexSequence[i]] = -i;
789 IT order = -nSegmentVertices;
791 for(IT i = 0; i < nSegmentVertices; i++)
792 localOrder[localVertexSequence[i]] = order++;
798 template <
typename IT,
class TT>
802 const TT *triangulation,
803 const IT *segmentation,
804 const IT *inputOrder)
const {
807 localOrder[propagation->
segment[0]] = -2;
814 IT nVertices = triangulation->getNumberOfVertices();
815 for(
const auto &v : propagation->
segment)
816 localOrder[v] = inputOrder[v] - nVertices;
822 std::vector<IT> boundary;
825 std::vector<IT> localVertexSequence(propagation->
segmentSize + 1);
828 bool containsResidualExtrema =
true;
829 bool performSuperlevelSetPropagation =
true;
830 while(containsResidualExtrema) {
834 this->
printWrn(
"Unable to converge with less than 20 iterations!");
838 localOrder, localVertexSequence.data(),
840 performSuperlevelSetPropagation, triangulation, segmentation,
841 extremumIndex, boundary, propagation->
segment, saddleIndex);
845 performSuperlevelSetPropagation = !performSuperlevelSetPropagation;
847 IT boundaryWriteIdx = 0;
848 IT nResidualMaxima = 0;
849 IT nResidualMinima = 0;
851 for(
const auto &v : propagation->
segment) {
852 bool isOnSegmentBoundary =
false;
853 bool hasSmallerNeighbor =
false;
854 bool hasLargerNeighbor =
false;
856 const auto &vOrder = localOrder[v];
858 IT nNeighbors = triangulation->getVertexNeighborNumber(v);
859 for(IT n = 0; n < nNeighbors; n++) {
861 triangulation->getVertexNeighbor(v, n, u);
863 if(u == saddleIndex) {
864 hasLargerNeighbor =
true;
869 if(segmentation[u] != extremumIndex) {
870 isOnSegmentBoundary =
true;
872 if(localOrder[u] > vOrder)
873 hasLargerNeighbor =
true;
875 hasSmallerNeighbor =
true;
879 if(!hasLargerNeighbor)
882 if(isOnSegmentBoundary) {
883 localVertexSequence[boundaryWriteIdx++] = v;
884 }
else if(!hasSmallerNeighbor) {
893 containsResidualExtrema
894 = nResidualMaxima > 0
895 || (nResidualMinima > 0 && boundaryWriteIdx > 0);
897 if(containsResidualExtrema && boundary.size() == 0) {
898 boundary.resize(boundaryWriteIdx);
899 for(IT i = 0; i < boundaryWriteIdx; i++) {
900 boundary[i] = localVertexSequence[i];
908 template <
typename IT,
class TT>
912 const TT *triangulation,
913 const IT *segmentation,
914 const IT *inputOrder,
918 const IT nPropagations = propagations.size();
919 this->
printMsg(
"Computing Local Order of Segments ("
920 + std::to_string(nPropagations) +
")",
924#ifdef TTK_ENABLE_OPENMP
925#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
927 for(IT p = 0; p < nPropagations; p++) {
931 propagations[p], triangulation, segmentation, inputOrder);
939#ifdef TTK_ENABLE_OPENMP
940#pragma omp parallel for num_threads(this->threadNumber_)
942 for(IT p = 0; p < nPropagations; p++) {
943 localOrder[propagations[p]->criticalPoints.back()]
944 = std::numeric_limits<IT>::max();
948 this->
printMsg(
"Computing Local Order of Segments ("
949 + std::to_string(nPropagations) +
")",
952 IT min = propagations[0]->nIterations;
956 for(IT p = 0; p < nPropagations; p++) {
957 const auto propagation = propagations[p];
958 if(min > propagation->nIterations)
959 min = propagation->nIterations;
960 if(max < propagation->nIterations)
961 max = propagation->nIterations;
962 avg += propagation->nIterations;
965 avg /= nPropagations;
967 this->
printMsg(
"Computing Local Order of Segments ("
968 + std::to_string(nPropagations) +
"|"
969 + std::to_string(min) +
"|" + std::to_string(avg)
970 +
"|" + std::to_string(max) +
")",
977 template <
typename IT>
986 const IT nParentPropagations = parentPropagations.size();
989#ifdef TTK_ENABLE_OPENMP
990#pragma omp parallel for num_threads(this->threadNumber_)
992 for(IT p = 0; p < nParentPropagations; p++) {
993 const auto *propagation = parentPropagations[p];
994 const auto &saddleOrder
995 = outputOrder[propagation->criticalPoints.back()];
996 for(
const auto &v : propagation->segment)
997 outputOrder[v] = saddleOrder;
1001 this->threadNumber_);
1006 template <
typename DT,
typename IT>
1016 std::vector<const std::vector<Propagation<IT>> *>
const propagationsPair
1017 = {&propagationsA, &propagationsB};
1019 for(
const auto propagations : propagationsPair) {
1020 const IT nPropagations = propagations->size();
1023#ifdef TTK_ENABLE_OPENMP
1024#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
1026 for(IT p = 0; p < nPropagations; p++) {
1027 const auto propagation = &((*propagations)[p]);
1029 if(!propagation->aborted
1030 && (propagation->parent == propagation
1031 || propagation->parent->aborted)) {
1032 const auto &saddleScalar
1033 = scalars[propagation->criticalPoints.back()];
1034 for(
const auto &v : propagation->segment)
1035 scalars[v] = saddleScalar;
1041 this->threadNumber_);
1046 template <
typename IT>
1049 const IT *localOrder,
1050 std::vector<std::tuple<IT, IT, IT>> &sortedIndices)
const {
1053 const IT nVertices = sortedIndices.size();
1056#ifdef TTK_ENABLE_OPENMP
1057#pragma omp parallel for num_threads(this->threadNumber_)
1059 for(IT i = 0; i < nVertices; i++) {
1060 auto &t = sortedIndices[i];
1061 std::get<0>(t) = order[i];
1062 std::get<1>(t) = localOrder[i];
1070 this->
threadNumber_, sortedIndices.begin(), sortedIndices.end());
1075#ifdef TTK_ENABLE_OPENMP
1076#pragma omp parallel for num_threads(this->threadNumber_)
1078 for(IT i = 0; i < nVertices; i++)
1079 order[std::get<2>(sortedIndices[i])] = i;
1082 this->threadNumber_);
1087 template <
typename DT,
typename IT>
1090 const std::vector<std::tuple<IT, IT, IT>> &sortedIndices,
1091 const bool descending =
false)
const {
1093 this->
printMsg(
"Applying numerical perturbation", 0, 0,
1096 const IT nVertices = sortedIndices.size();
1099 for(IT i = 1; i < nVertices; i++) {
1100 const IT &v0 = std::get<2>(sortedIndices[i - 1]);
1101 const IT &v1 = std::get<2>(sortedIndices[i]);
1102 if(scalars[v0] >= scalars[v1])
1103 scalars[v1] = boost::math::float_next(scalars[v0]);
1106 for(IT i = nVertices - 1; i > 0; i--) {
1107 const IT &v0 = std::get<2>(sortedIndices[i]);
1108 const IT &v1 = std::get<2>(sortedIndices[i - 1]);
1109 if(scalars[v0] >= scalars[v1])
1110 scalars[v1] = boost::math::float_next(scalars[v0]);
1113 this->
printMsg(
"Applying numerical perturbation", 1,
1119 template <
typename IT,
class TT>
1127 std::vector<std::tuple<IT, IT, IT>> &sortedIndices,
1129 const TT *triangulation,
1130 const IT *authorizedExtremaIndices,
1131 const IT &nAuthorizedExtremaIndices)
const {
1132 const IT nVertices = triangulation->getNumberOfVertices();
1152 authorizedExtremaIndices, nAuthorizedExtremaIndices, order,
1159 propagations, propagationMask, segmentation, queueMask,
1161 triangulation, order);
1166 std::vector<Propagation<IT> *> parentPropagations;
1177 order, triangulation);
1185 triangulation, segmentation, order, parentPropagations);
1202 template <
typename IT,
typename DT,
class TT>
1211 std::vector<std::tuple<IT, IT, IT>> &sortedIndices,
1213 const TT *triangulation,
1214 const DT persistenceThreshold)
const {
1216 const IT nVertices = triangulation->getNumberOfVertices();
1235 nullptr, 0, order, triangulation);
1241 propagations, propagationMask, segmentation, queueMask,
1243 triangulation, order, scalars, persistenceThreshold);
1248 std::vector<Propagation<IT> *> parentPropagations;
1259 order, triangulation);
1267 triangulation, segmentation, order, parentPropagations);
1288 template <
typename IT>
1294 const auto nVerticesM1 = nVertices - 1;
1296#ifdef TTK_ENABLE_OPENMP
1297#pragma omp parallel for num_threads(this->threadNumber_)
1299 for(IT v = 0; v < nVertices; v++)
1300 outputOrder[v] = nVerticesM1 - outputOrder[v];
1303 "Inverting Order", 1, timer.
getElapsedTime(), this->threadNumber_);
1308 template <
typename DT,
typename IT,
class TT>
1312 const TT *triangulation,
1313 const IT *authorizedExtremaIndices,
1314 const IT &nAuthorizedExtremaIndices,
1315 const bool &computePerturbation)
const {
1318 IT nVertices = triangulation->getNumberOfVertices();
1322 std::vector<IT> segmentation;
1323 std::vector<IT> queueMask;
1324 std::vector<IT> localOrder;
1325 std::vector<Propagation<IT> *> propagationMask;
1326 std::vector<Propagation<IT>> propagationsMax;
1327 std::vector<Propagation<IT>> propagationsMin;
1328 std::vector<std::tuple<IT, IT, IT>> sortedIndices;
1331 propagationMask, sortedIndices,
1335 bool hasMinima{
false};
1336 bool hasMaxima{
false};
1337 for(IT i = 0; i < nAuthorizedExtremaIndices; i++) {
1338 const auto &extremum{authorizedExtremaIndices[i]};
1339 const auto nNeigh{triangulation->getVertexNeighborNumber(extremum)};
1343 triangulation->getVertexNeighbor(extremum, 0, neigh);
1344 if(order[extremum] > order[neigh]) {
1351 if(hasMaxima && hasMinima) {
1358 this->
printMsg(
"----------- [Removing Unauthorized Maxima]",
1362 order, segmentation.data(), queueMask.data(), localOrder.data(),
1363 propagationMask.data(), propagationsMax, sortedIndices,
1365 triangulation, authorizedExtremaIndices, nAuthorizedExtremaIndices);
1372 this->
printMsg(
"----------- [Removing Unauthorized Minima]",
1380 order, segmentation.data(), queueMask.data(), localOrder.data(),
1381 propagationMask.data(), propagationsMin, sortedIndices,
1383 triangulation, authorizedExtremaIndices, nAuthorizedExtremaIndices);
1394 scalars, propagationsMax, propagationsMin);
1399 if(computePerturbation) {
1402 scalars, sortedIndices);
1409 "Complete", 1, globalTimer.
getElapsedTime(), this->threadNumber_);
1416 template <
typename DT,
typename IT,
class TT>
1420 const TT *triangulation,
1421 const DT persistenceThreshold,
1422 const bool &computePerturbation,
1427 IT nVertices = triangulation->getNumberOfVertices();
1431 std::vector<IT> segmentation;
1432 std::vector<IT> queueMask;
1433 std::vector<IT> localOrder;
1434 std::vector<Propagation<IT> *> propagationMask;
1435 std::vector<Propagation<IT>> propagationsMax;
1436 std::vector<Propagation<IT>> propagationsMin;
1437 std::vector<std::tuple<IT, IT, IT>> sortedIndices;
1440 propagationMask, sortedIndices,
1447 this->
printMsg(
"----------- [Removing Non-Persistent Maxima]",
1451 scalars, order, segmentation.data(), queueMask.data(),
1452 localOrder.data(), propagationMask.data(), propagationsMax,
1455 triangulation, persistenceThreshold);
1463 this->
printMsg(
"----------- [Removing Non-Persistent Minima]",
1470 scalars, order, segmentation.data(), queueMask.data(),
1471 localOrder.data(), propagationMask.data(), propagationsMin,
1474 triangulation, persistenceThreshold);
1483 if(computePerturbation) {
1493 "Complete", 1, globalTimer.
getElapsedTime(), this->threadNumber_);
#define TTK_PSORT(NTHREADS,...)
Parallel sort macro.
AbstractTriangulation is an interface class that defines an interface for efficient traversal methods...
virtual int preconditionVertexNeighbors()
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
void setDebugMsgPrefix(const std::string &prefix)
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
int flattenScalars(DT *scalars, const std::vector< Propagation< IT > > &propagationsA, const std::vector< Propagation< IT > > &propagationsB={}) const
int computeLocalOrderOfSegment(IT *localOrder, const Propagation< IT > *propagation, const TT *triangulation, const IT *segmentation, const IT *inputOrder) const
int computeSimplePropagations(std::vector< Propagation< IT > > &propagations, Propagation< IT > **propagationMask, IT *segmentation, IT *queueMask, const TT *triangulation, const IT *inputOrder) const
int computeSimplePropagation(Propagation< IT > &propagation, Propagation< IT > **propagationMask, IT *segmentation, IT *queueMask, const TT *triangulation, const IT *order) const
int computeSegments(IT *segmentation, std::vector< Propagation< IT > * > &propagations, const IT *order, const TT *triangulation) const
This method computes the segments of a given list of propagations.
int detectAndRemoveNonPersistentMaxima(DT *scalars, IT *order, IT *segmentation, IT *queueMask, IT *localOrder, Propagation< IT > **propagationMask, std::vector< Propagation< IT > > &propagations, std::vector< std::tuple< IT, IT, IT > > &sortedIndices, const TT *triangulation, const DT persistenceThreshold) const
int computeNumericalPerturbation(DT *scalars, const std::vector< std::tuple< IT, IT, IT > > &sortedIndices, const bool descending=false) const
int initializePropagations(std::vector< Propagation< IT > > &propagations, IT *authorizationMask, IT *maximaBuffer, const IT *authorizedExtremaIndices, const IT &nAuthorizedExtremaIndices, const IT *order, const TT *triangulation) const
int computeLocalOrderOfSegments(IT *localOrder, const TT *triangulation, const IT *segmentation, const IT *inputOrder, const std::vector< Propagation< IT > * > &propagations) const
LocalizedTopologicalSimplification()
int initializeMemory(IT *segmentation, IT *queueMask, IT *localOrder, Propagation< IT > **propagationMask, const IT &nVertices) const
int computePersistenceSensitivePropagations(std::vector< Propagation< IT > > &propagations, Propagation< IT > **propagationMask, IT *segmentation, IT *queueMask, const TT *triangulation, const IT *order, const DT *scalars, const DT persistenceThreshold) const
int finalizePropagations(std::vector< Propagation< IT > * > &parentPropagations, std::vector< Propagation< IT > > &propagations, const IT nVertices) const
int computeSegment(IT *segmentation, Propagation< IT > *propagation, const IT *order, const TT *triangulation) const
int allocateMemory(std::vector< IT > &segmentation, std::vector< IT > &queueMask, std::vector< IT > &localOrder, std::vector< Propagation< IT > * > &propagationMask, std::vector< std::tuple< IT, IT, IT > > &sortedIndices, const IT &nVertices) const
~LocalizedTopologicalSimplification() override=default
int computeGlobalOrder(IT *order, const IT *localOrder, std::vector< std::tuple< IT, IT, IT > > &sortedIndices) const
int flattenOrder(IT *outputOrder, const std::vector< Propagation< IT > * > &parentPropagations) const
int computePersistenceSensitivePropagation(Propagation< IT > &propagation, Propagation< IT > **propagationMask, IT *segmentation, IT *queueMask, const TT *triangulation, const IT *order, const DT *scalars, const DT persistenceThreshold) const
int preconditionTriangulation(ttk::AbstractTriangulation *triangulation) const
int detectAndRemoveUnauthorizedMaxima(IT *order, IT *segmentation, IT *queueMask, IT *localOrder, Propagation< IT > **propagationMask, std::vector< Propagation< IT > > &propagations, std::vector< std::tuple< IT, IT, IT > > &sortedIndices, const TT *triangulation, const IT *authorizedExtremaIndices, const IT &nAuthorizedExtremaIndices) const
int removeUnauthorizedExtrema(DT *scalars, IT *order, const TT *triangulation, const IT *authorizedExtremaIndices, const IT &nAuthorizedExtremaIndices, const bool &computePerturbation) const
int invertOrder(IT *outputOrder, const IT &nVertices) const
int computeLocalOrderOfSegmentIteration(IT *localOrder, IT *localVertexSequence, const bool &performSuperlevelSetPropagation, const TT *triangulation, const IT *segmentation, const IT &segmentId, const std::vector< IT > &boundary, const std::vector< IT > &segment, const IT &saddleIdx) const
int removeNonPersistentExtrema(DT *scalars, IT *order, const TT *triangulation, const DT persistenceThreshold, const bool &computePerturbation, const PAIR_TYPE &pairType=PAIR_TYPE::EXTREMUM_SADDLE) const
std::string toFixed(const float &number, const int precision=2)
TTK base package defining the standard types.
int SimplexId
Identifier type for simplices of any dimension.
Superlevel Set Component Propagation.
std::vector< IT > criticalPoints
std::vector< IT > segment
static int unify(Propagation< IT > *p0, Propagation< IT > *p1)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)