49 std::vector<std::array<float, 3>>
points_{};
117 template <
typename dataType,
typename triangulationType>
122 const dataType *
const vectors,
123 const size_t vectorsMTime,
124 const triangulationType &triangulation);
138 const bool doDescending,
139 const bool doSaddleConnectors) {
149 const bool doRepelling) {
158 const bool doDescending) {
167 const bool doDescending,
168 const bool doMorseSmale) {
228 template <
typename dataType,
typename triangulationType>
231 std::vector<Separatrix> &separatrices,
232 const triangulationType &triangulation)
const;
238 template <
typename dataType,
typename triangulationType>
240 std::vector<Separatrix> &separatrices,
241 const triangulationType &triangulation)
const;
247 template <
typename triangulationType>
249 std::vector<Separatrix> &separatrices,
250 const triangulationType &triangulation)
const;
256 template <
typename triangulationType>
258 const triangulationType &triangulation)
const;
264 template <
typename triangulationType>
266 const triangulationType &triangulation)
const;
271 template <
typename dataType,
typename triangulationType>
273 const std::vector<Separatrix> &separatrices,
274 const triangulationType &triangulation)
const;
280 template <
typename triangulationType>
282 const std::vector<SimplexId> &saddles2,
283 std::vector<Separatrix> &separatrices,
284 std::vector<std::vector<SimplexId>> &separatricesSaddles,
285 const triangulationType &triangulation)
const;
291 template <
typename triangulationType>
294 const std::vector<Separatrix> &separatrices,
295 const std::vector<std::vector<SimplexId>> &separatricesSaddles,
296 const triangulationType &triangulation)
const;
303 template <
typename triangulationType>
306 const size_t polSize,
307 const triangulationType &triangulation)
const;
312 template <
typename triangulationType>
314 const size_t polSize,
315 const triangulationType &triangulation)
const;
321 template <
typename triangulationType>
323 const std::vector<SimplexId> &saddles1,
324 std::vector<Separatrix> &separatrices,
325 std::vector<std::vector<SimplexId>> &separatricesSaddles,
326 const triangulationType &triangulation)
const;
332 template <
typename triangulationType>
335 const std::vector<Separatrix> &separatrices,
336 const std::vector<std::vector<SimplexId>> &separatricesSaddles,
337 const triangulationType &triangulation)
const;
343 std::vector<std::vector<Separatrix>> &separatrices)
const;
349 template <
typename triangulationType>
351 std::vector<Separatrix> &repellingOrbits,
353 const triangulationType &triangulation)
const;
359 template <
typename triangulationType>
361 std::vector<Separatrix> &attractingOrbits,
363 const triangulationType &triangulation)
const;
369 template <
typename triangulationType>
371 const SimplexId *
const ascendingManifold,
372 const SimplexId *
const descendingManifold,
374 const triangulationType &triangulation)
const;
400template <
typename dataType,
typename triangulationType>
405 const dataType *
const vectors,
406 const size_t vectorsMTime,
407 const triangulationType &triangulation) {
408#ifndef TTK_ENABLE_KAMIKAZE
409 if(vectors ==
nullptr) {
410 this->
printErr(
"Input vector field pointer is null.");
420 const auto dim = triangulation.getDimensionality();
425 vectors, vectorsMTime, triangulation);
429 std::vector<ttk::VectorSimplification::PlotPoint> emptyPlot;
431 persistenceThreshold,
false, emptyPlot, triangulation);
434 std::array<std::vector<SimplexId>, 4> criticalPoints{};
438 criticalPoints, triangulation);
439 this->
printMsg(
" Critical points extracted", 1.0, tm.getElapsedTime(),
444 std::vector<std::vector<Separatrix>> separatrices1{};
451 separatrices1.emplace_back();
453 criticalPoints[1], separatrices1.back(), triangulation);
455 this->
printMsg(
" Descending 1-separatrices computed", 1.0,
462 separatrices1.emplace_back();
465 criticalPoints[dim - 1], separatrices1.back(), triangulation);
467 this->
printMsg(
" Ascending 1-separatrices computed", 1.0,
472 std::vector<Separatrix> attractingCycles{};
480 separatrices1.emplace_back(attractingCycles);
486 std::vector<Separatrix> repellingCycles{};
494 separatrices1.emplace_back(repellingCycles);
503 separatrices1.emplace_back();
517 if(separatrices1.size() > 0) {
520 outSeps1, separatrices1[0], triangulation);
523 this->
printMsg(
" 1-separatrices set", 1.0, tmp.getElapsedTime(),
527 this->
printMsg(
"1-separatrices computed", 1.0, tm1sep.getElapsedTime(),
528 this->threadNumber_);
536 std::vector<Separatrix> separatrices;
537 std::vector<std::vector<SimplexId>> separatricesSaddles;
539 criticalPoints[2], separatrices, separatricesSaddles, triangulation);
541 outSeps2, separatrices, separatricesSaddles, triangulation);
543 this->
printMsg(
" Descending 2-separatrices computed", 1.0,
550 std::vector<Separatrix> separatrices;
551 std::vector<std::vector<SimplexId>> separatricesSaddles;
553 criticalPoints[1], separatrices, separatricesSaddles, triangulation);
555 outSeps2, separatrices, separatricesSaddles, triangulation);
557 this->
printMsg(
" Ascending 2-separatrices computed", 1.0,
564 this->
printMsg(
"2-separatrices computed", 1.0, tm2sep.getElapsedTime(),
565 this->threadNumber_);
581 && criticalPoints[0].size() > 0) {
583 + repellingCycles.size());
590 "Segmentation computed", 1.0, tmp.
getElapsedTime(), this->threadNumber_);
594 this->
simplifierField_.dcvf_.setCriticalPoints<dataType, triangulationType>(
606 + std::to_string(triangulation.getNumberOfVertices())
607 +
" points) processed",
617template <
typename dataType,
typename triangulationType>
619 const std::vector<SimplexId> &saddles,
620 std::vector<Separatrix> &separatrices,
621 const triangulationType &triangulation)
const {
623 const SimplexId numberOfSaddles = saddles.size();
626 const SimplexId numberOfSeparatrices = 2 * numberOfSaddles;
627 separatrices.resize(numberOfSeparatrices);
630#ifdef TTK_ENABLE_OPENMP
631#pragma omp parallel for num_threads(threadNumber_)
633 for(
SimplexId i = 0; i < numberOfSaddles; ++i) {
634 const Cell saddle{1, saddles[i]};
638 const Cell &saddle1 = saddle;
640 for(
int j = 0; j < 2; ++j) {
642 triangulation.getEdgeVertex(saddle1.
id_, j, vertexId);
644 std::vector<Cell> vpath;
645 vpath.emplace_back(saddle1);
647 Cell(0, vertexId), vpath, triangulation,
true);
649 const Cell &lastCell = vpath.back();
650 if(lastCell.dim_ == 0
652 separatrices[2 * i + j].source_ = saddle;
653 separatrices[2 * i + j].destination_ = lastCell;
654 separatrices[2 * i + j].geometry_ = std::move(vpath);
656 separatrices[2 * i + j].source_ = saddle;
657 separatrices[2 * i + j].destination_ =
Cell(0, -1);
658 separatrices[2 * i + j].geometry_ = std::move(vpath);
667template <
typename dataType,
typename triangulationType>
669 const std::vector<SimplexId> &saddles,
670 std::vector<Separatrix> &separatrices,
671 const triangulationType &triangulation)
const {
673 const auto dim{triangulation.getDimensionality()};
676 auto getFaceStarNumber = &triangulationType::getTriangleStarNumber;
677 auto getFaceStar = &triangulationType::getTriangleStar;
680 getFaceStarNumber = &triangulationType::getEdgeStarNumber;
681 getFaceStar = &triangulationType::getEdgeStar;
684 const SimplexId numberOfSaddles = saddles.size();
686 std::vector<std::vector<Separatrix>> sepsPerSaddle(numberOfSaddles);
689#ifdef TTK_ENABLE_OPENMP
690#pragma omp parallel for num_threads(threadNumber_)
692 for(
SimplexId i = 0; i < numberOfSaddles; ++i) {
693 const Cell saddle{dim - 1, saddles[i]};
696 const auto starNumber{(triangulation.*getFaceStarNumber)(saddle.id_)};
697 for(
SimplexId j = 0; j < starNumber; ++j) {
700 (triangulation.*getFaceStar)(saddle.id_, j, sId);
702 std::vector<Cell> vpath{saddle};
704 Cell(dim, sId), vpath, triangulation,
true);
706 const Cell &lastCell = vpath.back();
707 if(lastCell.dim_ == dim
709 sepsPerSaddle[i].emplace_back();
710 sepsPerSaddle[i].back().source_ = saddle;
711 sepsPerSaddle[i].back().destination_ = lastCell;
712 sepsPerSaddle[i].back().geometry_ = std::move(vpath);
714 sepsPerSaddle[i].emplace_back();
715 sepsPerSaddle[i].back().source_ = saddle;
716 sepsPerSaddle[i].back().destination_ =
Cell(dim, -1);
717 sepsPerSaddle[i].back().geometry_ = std::move(vpath);
722 if(numberOfSaddles != 0) {
725 separatrices = std::move(sepsPerSaddle[0]);
730template <
typename triangulationType>
732 const std::vector<SimplexId> &saddles2,
733 std::vector<Separatrix> &separatrices,
734 const triangulationType &triangulation)
const {
736 const auto nTriangles = triangulation.getNumberOfTriangles();
738 std::vector<bool> isVisited(nTriangles,
false);
739 std::vector<SimplexId> visitedTriangles{};
741 using Vpath = std::vector<Cell>;
743 const auto dim{triangulation.getDimensionality()};
745 std::vector<std::vector<Separatrix>> sepsByThread(saddles2.size());
746 std::vector<SimplexId> saddles1{};
748#ifdef TTK_ENABLE_OPENMP
749#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) \
750 firstprivate(isVisited, visitedTriangles, saddles1)
752 for(
size_t i = 0; i < saddles2.size(); ++i) {
753 const Cell s2{dim - 1, saddles2[i]};
757 s2, mask, triangulation,
nullptr, &saddles1);
759 for(
const auto saddle1Id : saddles1) {
760 const Cell s1{1, saddle1Id};
764 s1, s2, isVisited, &vpath, triangulation);
770 const auto &last = vpath.back();
772 if(last.dim_ == s2.dim_ && last.id_ == s2.id_) {
773 sepsByThread[i].emplace_back();
774 sepsByThread[i].back().source_ = s1;
775 sepsByThread[i].back().destination_ = s2;
776 sepsByThread[i].back().geometry_ = std::move(vpath);
780 if(saddles2.size() != 0) {
783 separatrices = std::move(sepsByThread[0]);
789template <
typename triangulationType>
791 std::vector<Separatrix> &separatrices,
792 const triangulationType &triangulation)
const {
794 std::map<SimplexId, std::vector<Cell>> minToCycles;
796 const auto nVerts{triangulation.getNumberOfVertices()};
798 std::vector<SimplexId> visited{};
799 std::vector<char> isCycle;
800 isCycle.resize(nVerts, 0);
801 std::vector<char> hasChecked;
802 hasChecked.resize(nVerts, 0);
804#ifdef TTK_ENABLE_OPENMP
805#pragma omp parallel for num_threads(threadNumber_) \
806 firstprivate(visited, isCycle)
809 if(hasChecked[i] != 0) {
814 while(hasChecked[curr] == 0) {
816 if(isCycle[curr] == 1) {
817 std::vector<Cell> cyclePath{
Cell{0, curr}};
819 while(visited.back() != curr) {
820 cyclePath.emplace_back(
Cell{0, visited.back()});
822 hasChecked[visited.back()] = 1;
823 if(visited.back() < currentMin) {
824 currentMin = visited.back();
828 cyclePath.emplace_back(
Cell{0, curr});
832 if(minToCycles[currentMin].size() == 0) {
833 minToCycles[currentMin] = cyclePath;
843 Cell{0, curr}, triangulation)};
845 triangulation.getEdgeVertex(pairedEdge, 0, next);
847 triangulation.getEdgeVertex(pairedEdge, 1, next);
849 visited.emplace_back(curr);
853 for(
const auto el : visited) {
860 for(
auto it = minToCycles.begin(); it != minToCycles.end(); ++it) {
861 auto vpath = it->second;
862 auto startCell = vpath.back();
863 separatrices.emplace_back();
864 separatrices.back().source_ = startCell;
865 separatrices.back().destination_ = startCell;
866 separatrices.back().geometry_ = std::move(vpath);
872template <
typename triangulationType>
874 std::vector<Separatrix> &separatrices,
875 const triangulationType &triangulation)
const {
877 std::map<SimplexId, std::vector<Cell>> minToCycles;
879 const auto nCells{triangulation.getNumberOfCells()};
881 const auto dim{triangulation.getDimensionality()};
884 auto getFaceStarNumber = &triangulationType::getTriangleStarNumber;
885 auto getFaceStar = &triangulationType::getTriangleStar;
888 getFaceStarNumber = &triangulationType::getEdgeStarNumber;
889 getFaceStar = &triangulationType::getEdgeStar;
890 }
else if(dim == 1) {
892 getFaceStarNumber = &triangulationType::getVertexStarNumber;
893 getFaceStar = &triangulationType::getVertexStar;
897 std::vector<SimplexId> visited{};
899 std::vector<char> hasChecked;
900 hasChecked.resize(nCells, 0);
902 std::vector<char> isCycle;
903 isCycle.resize(nCells, 0);
905#ifdef TTK_ENABLE_OPENMP
906#pragma omp parallel for num_threads(threadNumber_) \
907 firstprivate(visited, isCycle)
910 if(hasChecked[i] != 0) {
915 while(hasChecked[curr] == 0) {
916 if(isCycle[curr] == 1) {
917 std::vector<Cell> cyclePath{
Cell{dim, curr}};
919 while(visited.back() != curr) {
920 cyclePath.emplace_back(
Cell{dim, visited.back()});
921 hasChecked[visited.back()] = 1;
922 if(visited.back() < currentMin) {
923 currentMin = visited.back();
927 cyclePath.emplace_back(
Cell{dim, curr});
931 if(minToCycles[currentMin].size() == 0) {
932 minToCycles[currentMin] = cyclePath;
944 Cell{dim, curr}, triangulation,
true)};
946 const auto nStars{(triangulation.*getFaceStarNumber)(paired)};
948 (triangulation.*getFaceStar)(paired, j, next);
954 visited.emplace_back(curr);
962 for(
const auto el : visited) {
969 for(
auto it = minToCycles.begin(); it != minToCycles.end(); ++it) {
970 auto vpath = it->second;
971 auto startCell = vpath.back();
972 separatrices.emplace_back();
973 separatrices.back().source_ = startCell;
974 separatrices.back().destination_ = startCell;
975 separatrices.back().geometry_ = std::move(vpath);
981template <
typename dataType,
typename triangulationType>
984 const std::vector<Separatrix> &separatrices,
985 const triangulationType &triangulation)
const {
1000 std::vector<size_t> geomPointsBegId{npoints};
1002 std::vector<size_t> geomCellsBegId{ncells};
1005 for(
size_t i = 0; i < separatrices.size(); ++i) {
1006 const auto &sep = separatrices[i];
1007 const auto sepSize = sep.geometry_.size();
1009 ncells += sepSize - 1;
1010 geomPointsBegId.emplace_back(npoints);
1011 geomCellsBegId.emplace_back(ncells);
1014 const int dimensionality = triangulation.getCellVertexNumber(0) - 1;
1017 outSeps1.
pt.
points_.resize(3 * npoints);
1031#ifdef TTK_ENABLE_OPENMP
1032#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic)
1034 for(
size_t i = 0; i < separatrices.size(); ++i) {
1035 const auto &sep = separatrices[i];
1036 const auto &sepGeom = sep.geometry_;
1037 const auto sepId = separatrixId + i;
1041 const dcg::Cell &dst = sep.destination_;
1044 const auto saddleConnector
1045 = dimensionality == 3 && src.
dim_ == 1 && dst.
dim_ == 2;
1047 = saddleConnector ? 1 : std::min(dst.
dim_, dimensionality - 1);
1050 const auto onBoundary
1051 =
static_cast<char>(
1053 src, triangulation))
1054 +
static_cast<char>(
1056 dst, triangulation));
1058 for(
size_t j = 0; j < sepGeom.size(); ++j) {
1059 const auto &cell = sepGeom[j];
1060 std::array<float, 3> pt{};
1061 triangulation.getCellIncenter(cell.id_, cell.dim_, pt.data());
1064 const auto k = geomPointsBegId[i] + j;
1066 points[3 * k + 0] = pt[0];
1067 points[3 * k + 1] = pt[1];
1068 points[3 * k + 2] = pt[2];
1071 = (j == 0 || j == sepGeom.size() - 1) ? 0 : 1;
1080 const auto l = geomCellsBegId[i] + j - 1;
1082 cellsConn[2 * l + 0] = k - 1;
1083 cellsConn[2 * l + 1] = k;
1105template <
typename triangulationType>
1107 const std::vector<SimplexId> &saddles1,
1108 std::vector<Separatrix> &separatrices,
1109 std::vector<std::vector<SimplexId>> &separatricesSaddles,
1110 const triangulationType &triangulation)
const {
1111 const Cell emptyCell;
1113 const SimplexId numberOfSaddles = saddles1.size();
1117 const SimplexId numberOfSeparatrices = numberOfSaddles;
1118 separatrices.resize(numberOfSeparatrices);
1119 separatricesSaddles.resize(numberOfSeparatrices);
1121 const auto nEdges = triangulation.getNumberOfEdges();
1122 std::vector<bool> isVisited(nEdges,
false);
1123 std::vector<SimplexId> visitedEdges{};
1126#ifdef TTK_ENABLE_OPENMP
1127#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) \
1128 firstprivate(isVisited, visitedEdges)
1130 for(
SimplexId i = 0; i < numberOfSaddles; ++i) {
1131 const Cell saddle1{1, saddles1[i]};
1133 std::vector<Cell> wall;
1136 saddle1, mask, triangulation, &wall, &separatricesSaddles[i]);
1138 separatrices[i].source_ = saddle1;
1139 separatrices[i].destination_ = emptyCell;
1140 separatrices[i].geometry_ = std::move(wall);
1146template <
typename triangulationType>
1148 const std::vector<SimplexId> &saddles2,
1149 std::vector<Separatrix> &separatrices,
1150 std::vector<std::vector<SimplexId>> &separatricesSaddles,
1151 const triangulationType &triangulation)
const {
1152 const Cell emptyCell;
1154 const SimplexId numberOfSaddles = saddles2.size();
1158 const SimplexId numberOfSeparatrices = numberOfSaddles;
1159 separatrices.resize(numberOfSeparatrices);
1160 separatricesSaddles.resize(numberOfSeparatrices);
1162 const auto nTriangles = triangulation.getNumberOfTriangles();
1163 std::vector<bool> isVisited(nTriangles,
false);
1164 std::vector<SimplexId> visitedTriangles{};
1166 const auto dim{triangulation.getDimensionality()};
1169#ifdef TTK_ENABLE_OPENMP
1170#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic) \
1171 firstprivate(isVisited, visitedTriangles)
1173 for(
SimplexId i = 0; i < numberOfSaddles; ++i) {
1174 const Cell saddle2{dim - 1, saddles2[i]};
1176 std::vector<Cell> wall;
1179 saddle2, mask, triangulation, &wall, &separatricesSaddles[i]);
1181 separatrices[i].source_ = saddle2;
1182 separatrices[i].destination_ = emptyCell;
1183 separatrices[i].geometry_ = std::move(wall);
1189template <
typename triangulationType>
1193 const size_t polSize,
1194 const triangulationType &triangulation)
const {
1196 for(
size_t i = 0; i < polSize; ++i) {
1198 triangulation.getEdgeStar(edgeId, i, starId);
1199 polygon[i] = starId;
1205template <
typename triangulationType>
1208 const size_t polSize,
1209 const triangulationType &triangulation)
const {
1211 for(
size_t i = 1; i < polSize; ++i) {
1214 bool isFound =
false;
1216 for(; j < polSize; ++j) {
1219 k < triangulation.getCellNeighborNumber(polygon[i - 1]); ++k) {
1221 triangulation.getCellNeighbor(polygon[i - 1], k, neighborId);
1222 if(neighborId == polygon[j]) {
1233 std::swap(polygon[j], polygon[i]);
1240template <
typename triangulationType>
1243 const std::vector<Separatrix> &separatrices,
1244 const std::vector<std::vector<SimplexId>> &separatricesSaddles,
1245 const triangulationType &triangulation)
const {
1260 const auto noldcells{ncells};
1264 std::vector<size_t> geomCellsBegId{ncells};
1267 for(
size_t i = 0; i < separatrices.size(); ++i) {
1268 const auto &sep = separatrices[i];
1269 ncells += sep.geometry_.size();
1270 geomCellsBegId.emplace_back(ncells);
1274 std::vector<SimplexId> sepSourceIds(separatrices.size());
1275 std::vector<SimplexId> sepIds(separatrices.size());
1276 std::vector<char> sepOnBoundary(separatrices.size());
1279 std::vector<SimplexId> polygonNTetras(ncells - noldcells);
1280 std::vector<SimplexId> polygonEdgeIds(ncells - noldcells);
1281 std::vector<SimplexId> polygonSepInfosIds(ncells - noldcells);
1283#ifdef TTK_ENABLE_OPENMP
1284#pragma omp parallel for num_threads(threadNumber_) schedule(dynamic)
1286 for(
size_t i = 0; i < separatrices.size(); ++i) {
1287 const auto &sep = separatrices[i];
1288 const auto &sepGeom = sep.geometry_;
1289 const auto &sepSaddles = separatricesSaddles[i];
1290 const auto sepId = separatrixId + i;
1294 const char onBoundary
1295 = (sepSaddles.empty()
1297 : std::count_if(sepSaddles.begin(), sepSaddles.end(),
1299 return triangulation.isTriangleOnBoundary(a);
1301 + triangulation.isEdgeOnBoundary(src.
id_);
1304 sepSourceIds[i] = src.
id_;
1305 sepOnBoundary[i] = onBoundary;
1307 for(
size_t j = 0; j < sepGeom.size(); ++j) {
1308 const auto &cell = sepGeom[j];
1310 const auto k = geomCellsBegId[i] + j - noldcells;
1312 polygonNTetras[k] = triangulation.getEdgeStarNumber(cell.id_);
1314 if(polygonNTetras[k] > 2) {
1315 polygonEdgeIds[k] = cell.id_;
1316 polygonSepInfosIds[k] = i;
1322 std::vector<SimplexId> validTetraIds{};
1323 validTetraIds.reserve(polygonNTetras.size());
1325 for(
size_t i = 0; i < polygonNTetras.size(); ++i) {
1326 if(polygonNTetras[i] > 2) {
1327 validTetraIds.emplace_back(i);
1332 size_t nnewpoints{};
1333 std::vector<SimplexId> pointsPerCell(validTetraIds.size() + 1);
1334 for(
size_t i = 0; i < validTetraIds.size(); ++i) {
1335 nnewpoints += polygonNTetras[validTetraIds[i]];
1336 pointsPerCell[i + 1] = nnewpoints;
1343 std::vector<SimplexId> cellVertsIds(nnewpoints);
1345#ifdef TTK_ENABLE_OPENMP
1346#pragma omp parallel for num_threads(threadNumber_)
1348 for(
size_t i = 0; i < validTetraIds.size(); ++i) {
1349 const auto k = validTetraIds[i];
1352 getDualPolygon(polygonEdgeIds[k], &cellVertsIds[pointsPerCell[i]],
1353 polygonNTetras[k], triangulation);
1356 &cellVertsIds[pointsPerCell[i]], polygonNTetras[k], triangulation);
1358 for(
SimplexId j = 0; j < polygonNTetras[k]; ++j) {
1359 cellsConn[pointsPerCell[i] + j] = cellVertsIds[pointsPerCell[i] + j];
1364 const auto last = std::unique(cellVertsIds.begin(), cellVertsIds.end());
1365 cellVertsIds.erase(last, cellVertsIds.end());
1368 std::vector<SimplexId> vertId2PointsId(triangulation.getNumberOfCells());
1370 const auto noldpoints{npoints};
1371 npoints += cellVertsIds.size();
1372 ncells = noldcells + validTetraIds.size();
1375 outSeps2.
pt.
points_.resize(3 * npoints);
1376 auto points = &outSeps2.
pt.
points_[3 * noldpoints];
1379 auto cellsOff = &outSeps2.
cl.
offsets_[noldcells];
1385#ifdef TTK_ENABLE_OPENMP
1386#pragma omp parallel for num_threads(threadNumber_)
1388 for(
size_t i = 0; i < cellVertsIds.size(); ++i) {
1390 triangulation.getTetraIncenter(cellVertsIds[i], &points[3 * i]);
1392 vertId2PointsId[cellVertsIds[i]] = i + noldpoints;
1395#ifdef TTK_ENABLE_OPENMP
1396#pragma omp parallel for num_threads(threadNumber_)
1398 for(
size_t i = 0; i < validTetraIds.size(); ++i) {
1399 const auto m = validTetraIds[i];
1400 const auto k = pointsPerCell[i];
1401 for(
SimplexId j = 0; j < polygonNTetras[m]; ++j) {
1402 cellsConn[k + j] = vertId2PointsId[cellsConn[k + j]];
1404 const auto l = i + noldcells;
1405 const auto n = polygonSepInfosIds[m];
1412 for(
size_t i = 0; i < validTetraIds.size(); ++i) {
1414 cellsOff[i + 1] = cellsOff[i] + polygonNTetras[validTetraIds[i]];
1423template <
typename triangulationType>
1426 const std::vector<Separatrix> &separatrices,
1427 const std::vector<std::vector<SimplexId>> &separatricesSaddles,
1428 const triangulationType &triangulation)
const {
1443 const auto noldcells{ncells};
1448 std::vector<size_t> geomCellsBegId{ncells};
1451 for(
size_t i = 0; i < separatrices.size(); ++i) {
1452 const auto &sep = separatrices[i];
1453 ncells += sep.geometry_.size();
1454 geomCellsBegId.emplace_back(ncells);
1461 firstCellId + 3 * (ncells - noldcells));
1462 auto cellsOff = &outSeps2.
cl.
offsets_[noldcells];
1470 std::vector<SimplexId> cellVertsIds(3 * (ncells - noldcells));
1472#ifdef TTK_ENABLE_OPENMP
1473#pragma omp parallel for num_threads(threadNumber_)
1475 for(
size_t i = 0; i < separatrices.size(); ++i) {
1476 const auto &sep = separatrices[i];
1477 const auto &sepGeom = sep.geometry_;
1478 const auto &sepSaddles = separatricesSaddles[i];
1479 const auto sepId = separatrixId + i;
1481 const char sepType = 2;
1484 const char onBoundary
1485 = (sepSaddles.empty()
1487 : std::count_if(sepSaddles.begin(), sepSaddles.end(),
1489 return triangulation.isEdgeOnBoundary(a);
1491 + triangulation.isTriangleOnBoundary(src.
id_);
1493 for(
size_t j = 0; j < sepGeom.size(); ++j) {
1494 const auto &cell = sepGeom[j];
1498 triangulation.getTriangleVertex(cell.id_, 0, v0);
1499 triangulation.getTriangleVertex(cell.id_, 1, v1);
1500 triangulation.getTriangleVertex(cell.id_, 2, v2);
1503 const auto l = geomCellsBegId[i] + j;
1505 const auto m = l - noldcells;
1507 cellsConn[3 * m + 0] = v0;
1508 cellsConn[3 * m + 1] = v1;
1509 cellsConn[3 * m + 2] = v2;
1510 cellVertsIds[3 * m + 0] = v0;
1511 cellVertsIds[3 * m + 1] = v1;
1512 cellVertsIds[3 * m + 2] = v2;
1524 const auto last = std::unique(cellVertsIds.begin(), cellVertsIds.end());
1525 cellVertsIds.erase(last, cellVertsIds.end());
1528 std::vector<size_t> vertId2PointsId(triangulation.getNumberOfVertices());
1530 const auto noldpoints{npoints};
1531 npoints += cellVertsIds.size();
1532 outSeps2.
pt.
points_.resize(3 * npoints);
1533 auto points = &outSeps2.
pt.
points_[3 * noldpoints];
1535#ifdef TTK_ENABLE_OPENMP
1536#pragma omp parallel for num_threads(threadNumber_)
1538 for(
size_t i = 0; i < cellVertsIds.size(); ++i) {
1540 triangulation.getVertexPoint(
1541 cellVertsIds[i], points[3 * i + 0], points[3 * i + 1], points[3 * i + 2]);
1543 vertId2PointsId[cellVertsIds[i]] = i + noldpoints;
1546 const auto lastOffset = noldcells == 0 ? 0 : cellsOff[-1];
1548#ifdef TTK_ENABLE_OPENMP
1549#pragma omp parallel for num_threads(threadNumber_)
1551 for(
size_t i = 0; i < ncells - noldcells; ++i) {
1552 cellsOff[i] = 3 * i + lastOffset;
1553 cellsConn[3 * i + 0] = vertId2PointsId[cellsConn[3 * i + 0]];
1554 cellsConn[3 * i + 1] = vertId2PointsId[cellsConn[3 * i + 1]];
1555 cellsConn[3 * i + 2] = vertId2PointsId[cellsConn[3 * i + 2]];
1558 cellsOff[ncells - noldcells] = cellsOff[ncells - noldcells - 1] + 3;
1570template <
typename triangulationType>
1572 const std::vector<SimplexId> &maxima,
1573 std::vector<Separatrix> &repellingOrbits,
1575 const triangulationType &triangulation)
const {
1577 const auto thisDim{triangulation.getDimensionality()};
1579 if(morseSmaleManifold ==
nullptr) {
1580 this->
printErr(
"Could not compute ascending segmentation");
1586 const auto nVerts{triangulation.getNumberOfVertices()};
1587 std::fill(morseSmaleManifold, morseSmaleManifold + nVerts, -1);
1588 if(maxima.empty()) {
1593 const auto nCells{triangulation.getNumberOfCells()};
1594 std::vector<SimplexId> morseSmaleManifoldOnCells(nCells, -1);
1597 for(
const auto &
id : maxima) {
1599 morseSmaleManifoldOnCells[id] = nMax++;
1601 for(
const auto &orbit : repellingOrbits) {
1603 auto cycleCells = orbit.geometry_;
1604 auto cycleNumber = nMax++;
1605 for(
auto &cell : cycleCells) {
1606 if(cell.dim_ == thisDim) {
1607 morseSmaleManifoldOnCells[cell.id_] = cycleNumber;
1612 const auto dim{triangulation.getDimensionality()};
1615 auto getFaceStarNumber = &triangulationType::getTriangleStarNumber;
1616 auto getFaceStar = &triangulationType::getTriangleStar;
1619 getFaceStarNumber = &triangulationType::getEdgeStarNumber;
1620 getFaceStar = &triangulationType::getEdgeStar;
1621 }
else if(dim == 1) {
1623 getFaceStarNumber = &triangulationType::getVertexStarNumber;
1624 getFaceStar = &triangulationType::getVertexStar;
1628 std::vector<SimplexId> visited{};
1630 std::vector<uint8_t> isMarked(nCells, 0);
1632 std::vector<char> isCycle;
1633 isCycle.resize(nCells, 0);
1635#ifdef TTK_ENABLE_OPENMP
1636#pragma omp parallel for num_threads(threadNumber_) \
1637 firstprivate(visited, isCycle)
1640 if(isMarked[i] == 1) {
1645 while(morseSmaleManifoldOnCells[curr] == -1) {
1646 if(isMarked[curr] == 1) {
1648 }
else if(isCycle[curr] == 1) {
1649 morseSmaleManifoldOnCells[curr]
1656 Cell{dim, curr}, triangulation,
true)};
1658 const auto nStars{(triangulation.*getFaceStarNumber)(paired)};
1660 (triangulation.*getFaceStar)(paired, j, next);
1666 visited.emplace_back(curr);
1674 for(
const auto el : visited) {
1675 morseSmaleManifoldOnCells[el] = morseSmaleManifoldOnCells[curr];
1680#ifdef TTK_ENABLE_OPENMP
1681#pragma omp parallel for num_threads(threadNumber_)
1684 if(triangulation.getVertexStarNumber(i) < 1) {
1689 triangulation.getVertexStar(i, 0, starId);
1691 morseSmaleManifold[i] = morseSmaleManifoldOnCells[starId];
1694 this->
printMsg(
" Ascending segmentation computed", 1.0, tm.getElapsedTime(),
1701template <
typename triangulationType>
1703 const std::vector<SimplexId> &minima,
1704 std::vector<Separatrix> &attractingOrbits,
1706 const triangulationType &triangulation)
const {
1708 if(morseSmaleManifold ==
nullptr) {
1709 this->
printErr(
"Could not compute descending segmentation");
1715 const auto nVerts{triangulation.getNumberOfVertices()};
1717 if(minima.size() == 1) {
1719 std::fill(morseSmaleManifold, morseSmaleManifold + nVerts, 0);
1723 std::fill(morseSmaleManifold, morseSmaleManifold + nVerts, -1);
1726 for(
const auto &cp : minima) {
1728 morseSmaleManifold[cp] = nMin++;
1731 for(
const auto &orbit : attractingOrbits) {
1732 auto cycleCells = orbit.geometry_;
1733 auto cycleNumber = nMin++;
1734 for(
auto &cell : cycleCells) {
1735 if(cell.dim_ == 0) {
1736 morseSmaleManifold[cell.id_] = cycleNumber;
1741 std::vector<SimplexId> visited{};
1742 std::vector<char> isCycle;
1743 isCycle.resize(nVerts, 0);
1745#ifdef TTK_ENABLE_OPENMP
1746#pragma omp parallel for num_threads(threadNumber_) \
1747 firstprivate(visited, isCycle)
1750 if(morseSmaleManifold[i] != -1) {
1755 while(morseSmaleManifold[curr] == -1) {
1757 if(isCycle[curr] == 1) {
1758 morseSmaleManifold[curr]
1764 Cell{0, curr}, triangulation)};
1766 triangulation.getEdgeVertex(pairedEdge, 0, next);
1768 triangulation.getEdgeVertex(pairedEdge, 1, next);
1770 visited.emplace_back(curr);
1774 for(
const auto el : visited) {
1775 morseSmaleManifold[el] = morseSmaleManifold[curr];
1779 this->
printMsg(
" Descending segmentation computed", 1.0, tm.getElapsedTime(),
1786template <
typename triangulationType>
1789 const SimplexId *
const ascendingManifold,
1790 const SimplexId *
const descendingManifold,
1792 const triangulationType &triangulation)
const {
1794 if(ascendingManifold ==
nullptr || descendingManifold ==
nullptr
1795 || morseSmaleManifold ==
nullptr) {
1796 this->
printErr(
"Could not compute final segmentation");
1802 const size_t nVerts = triangulation.getNumberOfVertices();
1806#ifdef TTK_ENABLE_OPENMP
1807#pragma omp parallel for num_threads(threadNumber_)
1809 for(
size_t i = 0; i < nVerts; ++i) {
1810 const auto d = ascendingManifold[i];
1811 const auto a = descendingManifold[i];
1812 if(a == -1 || d == -1 || a == -2 || d == -2) {
1813 morseSmaleManifold[i] = -1;
1815 morseSmaleManifold[i] = a * numberOfMaxima + d;
1820 std::vector<SimplexId> sparseRegionIds(
1821 morseSmaleManifold, morseSmaleManifold + nVerts);
1825 this->
threadNumber_, sparseRegionIds.begin(), sparseRegionIds.end());
1826 const auto last = std::unique(sparseRegionIds.begin(), sparseRegionIds.end());
1827 sparseRegionIds.erase(last, sparseRegionIds.end());
1830 std::map<SimplexId, size_t> sparseToDenseRegionId{};
1832 for(
size_t i = 0; i < sparseRegionIds.size(); ++i) {
1833 sparseToDenseRegionId[sparseRegionIds[i]] = i;
1838#ifdef TTK_ENABLE_OPENMP
1839#pragma omp parallel for num_threads(threadNumber_)
1841 for(
size_t i = 0; i < nVerts; ++i) {
1842 morseSmaleManifold[i] = sparseToDenseRegionId[morseSmaleManifold[i]];
1845 this->
printMsg(
" Final segmentation computed", 1.0, tm.getElapsedTime(),
#define TTK_FORCE_USE(x)
Force the compiler to use the function/method parameter.
#define TTK_PSORT(NTHREADS,...)
Parallel sort macro.
AbstractTriangulation is an interface class that defines an interface for efficient traversal methods...
virtual int preconditionCellNeighbors()
virtual int preconditionCellEdges()
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
int getAscendingSeparatrices2(const std::vector< SimplexId > &saddles1, std::vector< Separatrix > &separatrices, std::vector< std::vector< SimplexId > > &separatricesSaddles, const triangulationType &triangulation) const
bool ComputeDescendingSeparatrices2
int sortDualPolygonVertices(SimplexId *const polygon, const size_t polSize, const triangulationType &triangulation) const
int setAscendingSegmentation(const std::vector< SimplexId > &maxima, std::vector< Separatrix > &repellingOrbits, SimplexId *const morseSmaleManifold, const triangulationType &triangulation) const
int setFinalSegmentation(const SimplexId numberOfMaxima, const SimplexId *const ascendingManifold, const SimplexId *const descendingManifold, SimplexId *const morseSmaleManifold, const triangulationType &triangulation) const
bool ComputeAttractingCycles1
int getAscendingSeparatrices1(const std::vector< SimplexId > &saddles, std::vector< Separatrix > &separatrices, const triangulationType &triangulation) const
int setDescendingSegmentation(const std::vector< SimplexId > &minima, std::vector< Separatrix > &attractingOrbits, SimplexId *const morseSmaleManifold, const triangulationType &triangulation) const
int getAttractingCycles1(std::vector< Separatrix > &separatrices, const triangulationType &triangulation) const
void setComputeCriticalPoints(const bool state)
int getDualPolygon(const SimplexId edgeId, SimplexId *const polygon, const size_t polSize, const triangulationType &triangulation) const
void setRunSimplification(const bool state)
int getDescendingSeparatrices1(const std::vector< SimplexId > &saddles, std::vector< Separatrix > &separatrices, const triangulationType &triangulation) const
int setDescendingSeparatrices2(Output2Separatrices &outSeps2, const std::vector< Separatrix > &separatrices, const std::vector< std::vector< SimplexId > > &separatricesSaddles, const triangulationType &triangulation) const
void setFullOrbits(const bool fullOrbits)
bool ComputeAscendingSeparatrices2
bool ComputeAscendingSeparatrices1
VectorSimplification simplifierField_
bool ComputeCriticalPoints
bool ComputeDescendingSeparatrices1
int setSeparatrices1(Output1Separatrices &outSeps1, const std::vector< Separatrix > &separatrices, const triangulationType &triangulation) const
bool ComputeDescendingSegmentation
bool ComputeAscendingSegmentation
int getDescendingSeparatrices2(const std::vector< SimplexId > &saddles2, std::vector< Separatrix > &separatrices, std::vector< std::vector< SimplexId > > &separatricesSaddles, const triangulationType &triangulation) const
void setComputeCycles1(const bool doAttracting, const bool doRepelling)
void preconditionTriangulation(AbstractTriangulation *const data)
void setComputeSegmentation(const bool doAscending, const bool doDescending, const bool doMorseSmale)
void flattenSeparatricesVectors(std::vector< std::vector< Separatrix > > &separatrices) const
Flatten the vectors of vectors into their first component.
void setComputeSeparatrices2(const bool doAscending, const bool doDescending)
int execute(OutputCriticalPoints &outCP, Output1Separatrices &outSeps1, Output2Separatrices &outSeps2, OutputManifold &outManifold, const dataType *const vectors, const size_t vectorsMTime, const triangulationType &triangulation)
void setSimplificationThreshold(const double threshold)
int setAscendingSeparatrices2(Output2Separatrices &outSeps2, const std::vector< Separatrix > &separatrices, const std::vector< std::vector< SimplexId > > &separatricesSaddles, const triangulationType &triangulation) const
bool ComputeSaddleConnectors
bool ComputeFinalSegmentation
bool ComputeRepellingCycles1
double SimplificationThreshold
int getRepellingCycles1(std::vector< Separatrix > &separatrices, const triangulationType &triangulation) const
void setComputeSeparatrices1(const bool doAscending, const bool doDescending, const bool doSaddleConnectors)
int getSaddleConnectors(const std::vector< SimplexId > &saddles2, std::vector< Separatrix > &separatrices, const triangulationType &triangulation) const
TTK VectorSimplification processing package.
TTK base package defining the standard types.
int SimplexId
Identifier type for simplices of any dimension.
1-Separatrices point and cell data arrays
std::vector< ttk::SimplexId > sourceIds_
std::vector< char > cellDimensions_
std::vector< ttk::SimplexId > cellIds_
std::vector< char > smoothingMask_
std::vector< float > points_
std::vector< char > isOnBoundary_
std::vector< ttk::SimplexId > separatrixIds_
std::vector< char > isOrbit_
SimplexId numberOfPoints_
std::vector< char > separatrixTypes_
struct ttk::TopologicalSkeleton::Output1Separatrices::@022074354300050243331256337257312310012152134015 cl
std::vector< ttk::SimplexId > connectivity_
struct ttk::TopologicalSkeleton::Output1Separatrices::@054324302236307005372226032341307172275306336073 pt
std::vector< ttk::SimplexId > destinationIds_
2-Separatrices point and cell data arrays
std::vector< ttk::SimplexId > offsets_
std::vector< ttk::SimplexId > sourceIds_
struct ttk::TopologicalSkeleton::Output2Separatrices::@262226051151230331113327275342331147011262135307 pt
std::vector< ttk::SimplexId > separatrixIds_
SimplexId numberOfPoints_
std::vector< char > isOnBoundary_
std::vector< ttk::SimplexId > connectivity_
std::vector< float > points_
struct ttk::TopologicalSkeleton::Output2Separatrices::@146237176251162053201273250302122352264036260035 cl
std::vector< char > separatrixTypes_
Critical points data arrays.
std::vector< SimplexId > cellIds_
std::vector< SimplexId > PLVertexIdentifiers_
std::vector< char > isOnBoundary_
std::vector< char > cellDimensions_
std::vector< SimplexId > manifoldSize_
std::vector< std::array< float, 3 > > points_
Pointers to pre-allocated segmentation point data arrays.
std::vector< dcg::Cell > geometry_
Auto-cleaning re-usable graph propagations data structure.
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)