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( \
146 this->threadNumber_) if(nAuthorizedExtremaIndices > 1000)
148 for(IT i = 0; i < nAuthorizedExtremaIndices; i++)
149 authorizationMask[authorizedExtremaIndices[i]] = -2;
153#ifdef TTK_ENABLE_OPENMP
154#pragma omp parallel for num_threads(this->threadNumber_)
156 for(IT v = 0; v < nVertices; v++) {
159 if(authorizationMask[v] == -2)
163 bool hasLargerNeighbor =
false;
164 const IT &vOrder = order[v];
165 const IT nNeighbors = triangulation->getVertexNeighborNumber(v);
166 for(IT n = 0; n < nNeighbors; n++) {
168 triangulation->getVertexNeighbor(v, n, u);
169 if(vOrder < order[u]) {
170 hasLargerNeighbor =
true;
176 if(hasLargerNeighbor)
180 IT localWriteIndex = 0;
181#ifdef TTK_ENABLE_OPENMP
182#pragma omp atomic capture
184 localWriteIndex = writeIndex++;
187#ifdef TTK_ENABLE_OPENMP
188#pragma omp atomic write
190 maximaBuffer[localWriteIndex] = v;
194 std::sort(maximaBuffer, maximaBuffer + writeIndex,
195 [=](
const IT &a,
const IT &b) ->
bool {
196 return order[a] < order[b];
201 if(nAuthorizedExtremaIndices < 1)
205 propagations.resize(writeIndex);
206#ifdef TTK_ENABLE_OPENMP
207#pragma omp parallel for num_threads(this->threadNumber_)
209 for(IT p = 0; p < writeIndex; p++) {
210 propagations[p].criticalPoints.push_back(maximaBuffer[p]);
213 this->
printMsg(
"Initializing Propagations ("
214 + std::to_string(writeIndex) +
"|"
215 + std::to_string(nVertices) +
")",
226 template <
typename IT,
typename TT>
234 const TT *triangulation,
235 const IT *order)
const {
238 auto *currentPropagation = &propagation;
242 auto queue = ¤tPropagation->queue;
243 queue->emplace(order[segmentId], segmentId);
245 queueMask[segmentId] = segmentId;
250 while(!queue->empty()) {
251 v = std::get<1>(queue->top());
255 if(propagationMask[v] !=
nullptr)
258 const IT &orderV = order[v];
261 bool isSaddle =
false;
262 const IT nNeighbors = triangulation->getVertexNeighborNumber(v);
264 IT numberOfLargerNeighbors = 0;
265 IT numberOfLargerNeighborsThisThreadVisited = 0;
266 for(IT n = 0; n < nNeighbors; n++) {
268 triangulation->getVertexNeighbor(v, n, u);
270 const IT &orderU = order[u];
273 if(orderU > orderV) {
274 numberOfLargerNeighbors++;
276 auto uPropagation = propagationMask[u];
277 if(uPropagation ==
nullptr
278 || currentPropagation != uPropagation->find())
281 numberOfLargerNeighborsThisThreadVisited++;
282 }
else if(queueMask[u] != segmentId) {
283 queue->emplace(orderU, u);
284 queueMask[u] = segmentId;
293 IT numberOfRegisteredLargerVertices = 0;
294#ifdef TTK_ENABLE_OPENMP
295#pragma omp atomic capture
298 segmentation[v] -= numberOfLargerNeighborsThisThreadVisited;
299 numberOfRegisteredLargerVertices = segmentation[v];
304 if(numberOfRegisteredLargerVertices != -numberOfLargerNeighbors - 1)
308 std::vector<Propagation<IT> *> neighborPropagations(
309 nNeighbors,
nullptr);
310 for(IT n = 0; n < nNeighbors; n++) {
312 triangulation->getVertexNeighbor(v, n, u);
313 if(propagationMask[u] !=
nullptr) {
314 auto &neighborPropagation = neighborPropagations[n];
315 neighborPropagation = propagationMask[u]->
find();
316 if(order[neighborPropagation->criticalPoints[0]]
317 > order[currentPropagation->criticalPoints[0]])
318 currentPropagation = neighborPropagation;
323 for(IT n = 0; n < nNeighbors; n++) {
325 currentPropagation, neighborPropagations[n]);
328 queue = ¤tPropagation->queue;
329 segmentId = currentPropagation->criticalPoints[0];
333 propagationMask[v] = currentPropagation;
334 segmentation[v] = segmentId;
339 "Simple propagations should never reach global minimum/maximum.");
348 template <
typename IT,
typename DT,
typename TT>
356 const TT *triangulation,
359 const DT persistenceThreshold)
const {
362 auto *currentPropagation = &propagation;
366 auto queue = ¤tPropagation->queue;
367 queue->emplace(order[segmentId], segmentId);
369 DT s0 = scalars[segmentId];
371 queueMask[segmentId] = segmentId;
376 while(!queue->empty()) {
377 v = std::get<1>(queue->top());
381 if(propagationMask[v] !=
nullptr)
385 const DT &s1 = scalars[v];
386 const DT &sd = s0 < s1 ? s1 - s0 : s0 - s1;
387 if(sd > persistenceThreshold) {
388 currentPropagation->aborted =
true;
392 const IT &orderV = order[v];
395 bool isSaddle =
false;
396 const IT nNeighbors = triangulation->getVertexNeighborNumber(v);
398 IT numberOfLargerNeighbors = 0;
399 IT numberOfLargerNeighborsThisThreadVisited = 0;
400 for(IT n = 0; n < nNeighbors; n++) {
402 triangulation->getVertexNeighbor(v, n, u);
404 const IT &orderU = order[u];
407 if(orderU > orderV) {
408 numberOfLargerNeighbors++;
410 auto uPropagation = propagationMask[u];
411 if(uPropagation ==
nullptr
412 || currentPropagation != uPropagation->find())
415 numberOfLargerNeighborsThisThreadVisited++;
416 }
else if(queueMask[u] != segmentId) {
417 queue->emplace(orderU, u);
418 queueMask[u] = segmentId;
427 IT numberOfRegisteredLargerVertices = 0;
428#ifdef TTK_ENABLE_OPENMP
429#pragma omp atomic capture
432 segmentation[v] -= numberOfLargerNeighborsThisThreadVisited;
433 numberOfRegisteredLargerVertices = segmentation[v];
438 if(numberOfRegisteredLargerVertices != -numberOfLargerNeighbors - 1)
442 std::vector<Propagation<IT> *> neighborPropagations(
443 nNeighbors,
nullptr);
444 for(IT n = 0; n < nNeighbors; n++) {
446 triangulation->getVertexNeighbor(v, n, u);
447 if(propagationMask[u] !=
nullptr) {
448 auto &neighborPropagation = neighborPropagations[n];
449 neighborPropagation = propagationMask[u]->
find();
450 if(order[neighborPropagation->criticalPoints[0]]
451 > order[currentPropagation->criticalPoints[0]])
452 currentPropagation = neighborPropagation;
457 for(IT n = 0; n < nNeighbors; n++) {
459 currentPropagation, neighborPropagations[n]);
462 queue = ¤tPropagation->queue;
463 segmentId = currentPropagation->criticalPoints[0];
464 s0 = scalars[segmentId];
468 propagationMask[v] = currentPropagation;
469 segmentation[v] = segmentId;
478 template <
typename IT,
class TT>
484 const TT *triangulation,
485 const IT *inputOrder)
const {
487 const IT nPropagations = propagations.size();
488 const std::string msg
489 =
"Computing Propagations (" + std::to_string(nPropagations) +
")";
495#ifdef TTK_ENABLE_OPENMP
496#pragma omp parallel for schedule(dynamic, 1) num_threads(this->threadNumber_)
498 for(IT p = 0; p < nPropagations; p++) {
499 int const localStatus = this->computeSimplePropagation<IT, TT>(
500 propagations[p], propagationMask, segmentation, queueMask,
502 triangulation, inputOrder);
518 template <
typename IT,
typename DT,
class TT>
525 const TT *triangulation,
528 const DT persistenceThreshold)
const {
530 const IT nPropagations = propagations.size();
531 const std::string msg =
"Computing Persistence-Sensitive Propagations ("
532 + std::to_string(nPropagations) +
")";
538#ifdef TTK_ENABLE_OPENMP
539#pragma omp parallel for schedule(dynamic, 1) num_threads(this->threadNumber_)
541 for(IT p = 0; p < nPropagations; p++) {
542 int const localStatus
543 = this->computePersistenceSensitivePropagation<IT, DT, TT>(
544 propagations[p], propagationMask, segmentation, queueMask,
546 triangulation, order, scalars, persistenceThreshold);
565 template <
typename IT>
570 const IT nVertices)
const {
573 const IT nPropagations = propagations.size();
576 "Finalizing Propagations (" + std::to_string(nPropagations) +
")", 0,
580 IT nSegmentVertices = 0;
581 IT nParentPropagations = 0;
582 parentPropagations.resize(nPropagations);
583 for(IT p = 0; p < nPropagations; p++) {
584 auto *propagation = &propagations[p];
585 if(!propagation->aborted
586 && (propagation->parent == propagation
587 || propagation->parent->aborted)) {
588 nSegmentVertices = nSegmentVertices + propagation->segmentSize;
589 parentPropagations[nParentPropagations++] = propagation;
592 parentPropagations.resize(nParentPropagations);
594 this->
printMsg(
"Finalizing Propagations ("
595 + std::to_string(nParentPropagations) +
"|"
596 +
toFixed(nParentPropagations, nPropagations) +
"|"
597 +
toFixed(nSegmentVertices, nVertices) +
")",
606 template <
typename IT,
class TT>
611 const TT *triangulation)
const {
615 const IT &saddleOrder = order[saddleIndex];
618 auto &segment = propagation->
segment;
628 queue[queueIndex++] = extremumIndex;
629 segmentation[extremumIndex] = -1000;
633 while(queueIndex > 0) {
634 const IT v = queue[--queueIndex];
636 segment[segmentIndex++] = v;
638 IT nNeighbors = triangulation->getVertexNeighborNumber(v);
639 for(IT n = 0; n < nNeighbors; n++) {
641 triangulation->getVertexNeighbor(v, n, u);
642 auto &s = segmentation[u];
643 if(s >= 0 && order[u] > saddleOrder) {
645 queue[queueIndex++] = u;
652 this->
printErr(
"Segment size incorrect: "
653 + std::to_string(segmentIndex) +
" "
658 for(
auto idx : propagation->
segment)
659 segmentation[idx] = extremumIndex;
665 template <
typename IT,
class TT>
670 const TT *triangulation)
const {
672 const IT nPropagations = propagations.size();
673 const IT nVertices = triangulation->getNumberOfVertices();
676 const std::string msg
677 =
"Computing Segments (" + std::to_string(nPropagations) +
")";
684#ifdef TTK_ENABLE_OPENMP
685#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
687 for(IT p = 0; p < nPropagations; p++) {
688 int const localStatus
689 = this->computeSegment<IT, TT>(segmentation, propagations[p],
691 order, triangulation);
703 IT min = propagations[0]->segmentSize;
707 for(IT p = 0; p < nPropagations; p++) {
708 const auto propagation = propagations[p];
709 if(min > propagation->segmentSize)
710 min = propagation->segmentSize;
711 if(max < propagation->segmentSize)
712 max = propagation->segmentSize;
713 avg += propagation->segmentSize;
716 avg /= nPropagations;
718 this->
printMsg(
"Computing Segments (" + std::to_string(nPropagations)
719 +
"|" +
toFixed(min, nVertices) +
"|"
720 +
toFixed(avg, nVertices) +
"|"
721 +
toFixed(max, nVertices) +
")",
728 template <
typename IT,
class TT>
731 IT *localVertexSequence,
733 const bool &performSuperlevelSetPropagation,
734 const TT *triangulation,
735 const IT *segmentation,
737 const std::vector<IT> &boundary,
738 const std::vector<IT> &segment,
739 const IT &saddleIdx)
const {
741 std::priority_queue<std::pair<IT, IT>, std::vector<std::pair<IT, IT>>>
744 IT nSegmentVertices = segment.size();
746 if(performSuperlevelSetPropagation) {
748 queue.emplace(std::numeric_limits<IT>::max(), saddleIdx);
751 IT offset = -nSegmentVertices - 1;
752 for(IT i = 0; i < nSegmentVertices; i++)
753 localOrder[segment[i]] = offset - localOrder[segment[i]];
756 for(
const auto &v : boundary) {
757 queue.emplace(localOrder[v], v);
762 queue.emplace(std::numeric_limits<IT>::min(), saddleIdx);
766 while(!queue.empty()) {
767 IT v = std::get<1>(queue.top());
770 localVertexSequence[q++] = v;
772 IT nNeighbors = triangulation->getVertexNeighborNumber(v);
773 for(IT n = 0; n < nNeighbors; n++) {
775 triangulation->getVertexNeighbor(v, n, u);
778 if(segmentation[u] == segmentId && localOrder[u] < 0) {
779 queue.emplace(localOrder[u], u);
785 if(performSuperlevelSetPropagation) {
787 for(IT i = 1; i <= nSegmentVertices; i++)
788 localOrder[localVertexSequence[i]] = -i;
790 IT order = -nSegmentVertices;
792 for(IT i = 0; i < nSegmentVertices; i++)
793 localOrder[localVertexSequence[i]] = order++;
799 template <
typename IT,
class TT>
803 const TT *triangulation,
804 const IT *segmentation,
805 const IT *inputOrder)
const {
808 localOrder[propagation->
segment[0]] = -2;
815 IT nVertices = triangulation->getNumberOfVertices();
816 for(
const auto &v : propagation->
segment)
817 localOrder[v] = inputOrder[v] - nVertices;
823 std::vector<IT> boundary;
826 std::vector<IT> localVertexSequence(propagation->
segmentSize + 1);
829 bool containsResidualExtrema =
true;
830 bool performSuperlevelSetPropagation =
true;
831 while(containsResidualExtrema) {
835 this->
printWrn(
"Unable to converge with less than 20 iterations!");
838 status = this->computeLocalOrderOfSegmentIteration<IT, TT>(
839 localOrder, localVertexSequence.data(),
841 performSuperlevelSetPropagation, triangulation, segmentation,
842 extremumIndex, boundary, propagation->
segment, saddleIndex);
846 performSuperlevelSetPropagation = !performSuperlevelSetPropagation;
848 IT boundaryWriteIdx = 0;
849 IT nResidualMaxima = 0;
850 IT nResidualMinima = 0;
852 for(
const auto &v : propagation->
segment) {
853 bool isOnSegmentBoundary =
false;
854 bool hasSmallerNeighbor =
false;
855 bool hasLargerNeighbor =
false;
857 const auto &vOrder = localOrder[v];
859 IT nNeighbors = triangulation->getVertexNeighborNumber(v);
860 for(IT n = 0; n < nNeighbors; n++) {
862 triangulation->getVertexNeighbor(v, n, u);
864 if(u == saddleIndex) {
865 hasLargerNeighbor =
true;
870 if(segmentation[u] != extremumIndex) {
871 isOnSegmentBoundary =
true;
873 if(localOrder[u] > vOrder)
874 hasLargerNeighbor =
true;
876 hasSmallerNeighbor =
true;
880 if(!hasLargerNeighbor)
883 if(isOnSegmentBoundary) {
884 localVertexSequence[boundaryWriteIdx++] = v;
885 }
else if(!hasSmallerNeighbor) {
890 containsResidualExtrema = nResidualMinima > 0 || nResidualMaxima > 0;
892 if(containsResidualExtrema && boundary.size() == 0) {
893 boundary.resize(boundaryWriteIdx);
894 for(IT i = 0; i < boundaryWriteIdx; i++) {
895 boundary[i] = localVertexSequence[i];
903 template <
typename IT,
class TT>
907 const TT *triangulation,
908 const IT *segmentation,
909 const IT *inputOrder,
913 const IT nPropagations = propagations.size();
914 this->
printMsg(
"Computing Local Order of Segments ("
915 + std::to_string(nPropagations) +
")",
919#ifdef TTK_ENABLE_OPENMP
920#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
922 for(IT p = 0; p < nPropagations; p++) {
923 int const localStatus = this->computeLocalOrderOfSegment<IT>(
926 propagations[p], triangulation, segmentation, inputOrder);
934#ifdef TTK_ENABLE_OPENMP
935#pragma omp parallel for num_threads(this->threadNumber_)
937 for(IT p = 0; p < nPropagations; p++) {
938 localOrder[propagations[p]->criticalPoints.back()]
939 = std::numeric_limits<IT>::max();
943 this->
printMsg(
"Computing Local Order of Segments ("
944 + std::to_string(nPropagations) +
")",
947 IT min = propagations[0]->nIterations;
951 for(IT p = 0; p < nPropagations; p++) {
952 const auto propagation = propagations[p];
953 if(min > propagation->nIterations)
954 min = propagation->nIterations;
955 if(max < propagation->nIterations)
956 max = propagation->nIterations;
957 avg += propagation->nIterations;
960 avg /= nPropagations;
962 this->
printMsg(
"Computing Local Order of Segments ("
963 + std::to_string(nPropagations) +
"|"
964 + std::to_string(min) +
"|" + std::to_string(avg)
965 +
"|" + std::to_string(max) +
")",
972 template <
typename IT>
981 const IT nParentPropagations = parentPropagations.size();
984#ifdef TTK_ENABLE_OPENMP
985#pragma omp parallel for num_threads(this->threadNumber_)
987 for(IT p = 0; p < nParentPropagations; p++) {
988 const auto *propagation = parentPropagations[p];
989 const auto &saddleOrder
990 = outputOrder[propagation->criticalPoints.back()];
991 for(
const auto &v : propagation->segment)
992 outputOrder[v] = saddleOrder;
996 this->threadNumber_);
1001 template <
typename DT,
typename IT>
1011 std::vector<const std::vector<Propagation<IT>> *>
const propagationsPair
1012 = {&propagationsA, &propagationsB};
1014 for(
const auto propagations : propagationsPair) {
1015 const IT nPropagations = propagations->size();
1018#ifdef TTK_ENABLE_OPENMP
1019#pragma omp parallel for schedule(dynamic) num_threads(this->threadNumber_)
1021 for(IT p = 0; p < nPropagations; p++) {
1022 const auto propagation = &((*propagations)[p]);
1024 if(!propagation->aborted
1025 && (propagation->parent == propagation
1026 || propagation->parent->aborted)) {
1027 const auto &saddleScalar
1028 = scalars[propagation->criticalPoints.back()];
1029 for(
const auto &v : propagation->segment)
1030 scalars[v] = saddleScalar;
1036 this->threadNumber_);
1041 template <
typename IT>
1044 const IT *localOrder,
1045 std::vector<std::tuple<IT, IT, IT>> &sortedIndices)
const {
1048 const IT nVertices = sortedIndices.size();
1051#ifdef TTK_ENABLE_OPENMP
1052#pragma omp parallel for num_threads(this->threadNumber_)
1054 for(IT i = 0; i < nVertices; i++) {
1055 auto &t = sortedIndices[i];
1056 std::get<0>(t) = order[i];
1057 std::get<1>(t) = localOrder[i];
1065 this->
threadNumber_, sortedIndices.begin(), sortedIndices.end());
1070#ifdef TTK_ENABLE_OPENMP
1071#pragma omp parallel for num_threads(this->threadNumber_)
1073 for(IT i = 0; i < nVertices; i++)
1074 order[std::get<2>(sortedIndices[i])] = i;
1077 this->threadNumber_);
1082 template <
typename DT,
typename IT>
1085 const std::vector<std::tuple<IT, IT, IT>> &sortedIndices,
1086 const bool descending =
false)
const {
1088 this->
printMsg(
"Applying numerical perturbation", 0, 0,
1091 const IT nVertices = sortedIndices.size();
1094 for(IT i = 1; i < nVertices; i++) {
1095 const IT &v0 = std::get<2>(sortedIndices[i - 1]);
1096 const IT &v1 = std::get<2>(sortedIndices[i]);
1097 if(scalars[v0] >= scalars[v1])
1098 scalars[v1] = boost::math::float_next(scalars[v0]);
1101 for(IT i = nVertices - 1; i > 0; i--) {
1102 const IT &v0 = std::get<2>(sortedIndices[i]);
1103 const IT &v1 = std::get<2>(sortedIndices[i - 1]);
1104 if(scalars[v0] >= scalars[v1])
1105 scalars[v1] = boost::math::float_next(scalars[v0]);
1108 this->
printMsg(
"Applying numerical perturbation", 1,
1114 template <
typename IT,
class TT>
1122 std::vector<std::tuple<IT, IT, IT>> &sortedIndices,
1124 const TT *triangulation,
1125 const IT *authorizedExtremaIndices,
1126 const IT &nAuthorizedExtremaIndices)
const {
1127 const IT nVertices = triangulation->getNumberOfVertices();
1132 status = this->initializeMemory<IT>(segmentation, queueMask, localOrder,
1140 status = this->initializePropagations<IT, TT>(
1147 authorizedExtremaIndices, nAuthorizedExtremaIndices, order,
1153 status = this->computeSimplePropagations<IT, TT>(
1154 propagations, propagationMask, segmentation, queueMask,
1156 triangulation, order);
1161 std::vector<Propagation<IT> *> parentPropagations;
1163 = this->finalizePropagations<IT>(parentPropagations, propagations,
1170 status = this->computeSegments<IT, TT>(segmentation, parentPropagations,
1172 order, triangulation);
1177 status = this->computeLocalOrderOfSegments<IT, TT>(
1180 triangulation, segmentation, order, parentPropagations);
1185 status = this->flattenOrder<IT>(order, parentPropagations);
1190 status = this->computeGlobalOrder<IT>(order, localOrder, sortedIndices);
1197 template <
typename IT,
typename DT,
class TT>
1206 std::vector<std::tuple<IT, IT, IT>> &sortedIndices,
1208 const TT *triangulation,
1209 const DT persistenceThreshold)
const {
1211 const IT nVertices = triangulation->getNumberOfVertices();
1216 status = this->initializeMemory<IT>(segmentation, queueMask, localOrder,
1224 status = this->initializePropagations<IT, TT>(
1230 nullptr, 0, order, triangulation);
1235 status = this->computePersistenceSensitivePropagations<IT, DT, TT>(
1236 propagations, propagationMask, segmentation, queueMask,
1238 triangulation, order, scalars, persistenceThreshold);
1243 std::vector<Propagation<IT> *> parentPropagations;
1245 = this->finalizePropagations<IT>(parentPropagations, propagations,
1252 status = this->computeSegments<IT, TT>(segmentation, parentPropagations,
1254 order, triangulation);
1259 status = this->computeLocalOrderOfSegments<IT, TT>(
1262 triangulation, segmentation, order, parentPropagations);
1267 status = this->flattenOrder<IT>(order, parentPropagations);
1272 status = this->computeGlobalOrder<IT>(order, localOrder, sortedIndices);
1276 status = this->flattenScalars<DT, IT>(scalars, propagations);
1283 template <
typename IT>
1289 const auto nVerticesM1 = nVertices - 1;
1291#ifdef TTK_ENABLE_OPENMP
1292#pragma omp parallel for num_threads(this->threadNumber_)
1294 for(IT v = 0; v < nVertices; v++)
1295 outputOrder[v] = nVerticesM1 - outputOrder[v];
1298 "Inverting Order", 1, timer.
getElapsedTime(), this->threadNumber_);
1303 template <
typename DT,
typename IT,
class TT>
1307 const TT *triangulation,
1308 const IT *authorizedExtremaIndices,
1309 const IT &nAuthorizedExtremaIndices,
1310 const bool &computePerturbation)
const {
1313 IT nVertices = triangulation->getNumberOfVertices();
1317 std::vector<IT> segmentation;
1318 std::vector<IT> queueMask;
1319 std::vector<IT> localOrder;
1320 std::vector<Propagation<IT> *> propagationMask;
1321 std::vector<Propagation<IT>> propagationsMax;
1322 std::vector<Propagation<IT>> propagationsMin;
1323 std::vector<std::tuple<IT, IT, IT>> sortedIndices;
1325 this->allocateMemory<IT>(segmentation, queueMask, localOrder,
1326 propagationMask, sortedIndices,
1330 bool hasMinima{
false};
1331 bool hasMaxima{
false};
1332 for(IT i = 0; i < nAuthorizedExtremaIndices; i++) {
1333 const auto &extremum{authorizedExtremaIndices[i]};
1334 const auto nNeigh{triangulation->getVertexNeighborNumber(extremum)};
1338 triangulation->getVertexNeighbor(extremum, 0, neigh);
1339 if(order[extremum] > order[neigh]) {
1346 if(hasMaxima && hasMinima) {
1353 this->
printMsg(
"----------- [Removing Unauthorized Maxima]",
1356 status = this->detectAndRemoveUnauthorizedMaxima<IT, TT>(
1357 order, segmentation.data(), queueMask.data(), localOrder.data(),
1358 propagationMask.data(), propagationsMax, sortedIndices,
1360 triangulation, authorizedExtremaIndices, nAuthorizedExtremaIndices);
1367 this->
printMsg(
"----------- [Removing Unauthorized Minima]",
1374 status = this->detectAndRemoveUnauthorizedMaxima<IT, TT>(
1375 order, segmentation.data(), queueMask.data(), localOrder.data(),
1376 propagationMask.data(), propagationsMin, sortedIndices,
1378 triangulation, authorizedExtremaIndices, nAuthorizedExtremaIndices);
1388 status = this->flattenScalars<DT, IT>(
1389 scalars, propagationsMax, propagationsMin);
1394 if(computePerturbation) {
1396 status = this->computeNumericalPerturbation<DT, IT>(
1397 scalars, sortedIndices);
1404 "Complete", 1, globalTimer.
getElapsedTime(), this->threadNumber_);
1411 template <
typename DT,
typename IT,
class TT>
1415 const TT *triangulation,
1416 const DT persistenceThreshold,
1417 const bool &computePerturbation,
1422 IT nVertices = triangulation->getNumberOfVertices();
1426 std::vector<IT> segmentation;
1427 std::vector<IT> queueMask;
1428 std::vector<IT> localOrder;
1429 std::vector<Propagation<IT> *> propagationMask;
1430 std::vector<Propagation<IT>> propagationsMax;
1431 std::vector<Propagation<IT>> propagationsMin;
1432 std::vector<std::tuple<IT, IT, IT>> sortedIndices;
1434 this->allocateMemory<IT>(segmentation, queueMask, localOrder,
1435 propagationMask, sortedIndices,
1442 this->
printMsg(
"----------- [Removing Non-Persistent Maxima]",
1445 status = this->detectAndRemoveNonPersistentMaxima<IT, DT, TT>(
1446 scalars, order, segmentation.data(), queueMask.data(),
1447 localOrder.data(), propagationMask.data(), propagationsMax,
1450 triangulation, persistenceThreshold);
1458 this->
printMsg(
"----------- [Removing Non-Persistent Minima]",
1464 status = this->detectAndRemoveNonPersistentMaxima<IT, DT, TT>(
1465 scalars, order, segmentation.data(), queueMask.data(),
1466 localOrder.data(), propagationMask.data(), propagationsMin,
1469 triangulation, persistenceThreshold);
1478 if(computePerturbation) {
1480 status = this->computeNumericalPerturbation<DT, IT>(
1488 "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()
Minimalist debugging class.
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)
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)