24template <
typename dataType,
typename triangulationType>
28 const dataType *
const scalars,
29 const triangulationType &triangulation)
const {
35template <
typename triangulationType>
39 auto &cacheHandler = *triangulation.getGradientCacheHandler();
40 const auto findGradient
48#ifdef TTK_ENABLE_OPENMP
49 if(!bypassCache && omp_in_parallel()) {
51 "buildGradient() called inside a parallel region, disabling cache...");
61 if(this->
gradient_ ==
nullptr || bypassCache) {
70 this->initMemory(triangulation);
77 "Built discrete gradient", 1.0, tm.getElapsedTime(), this->threadNumber_);
79 this->
printMsg(
"Fetched cached discrete gradient");
85template <
typename triangulationType>
87 const std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
88 std::vector<std::array<float, 3>> &points,
89 std::vector<char> &cellDimensions,
90 std::vector<SimplexId> &cellIds,
91 std::vector<char> &isOnBoundary,
92 std::vector<SimplexId> &PLVertexIdentifiers,
93 const triangulationType &triangulation)
const {
95 std::array<size_t, 5> partSums{};
96 for(
size_t i = 0; i < criticalCellsByDim.size(); ++i) {
97 partSums[i + 1] = partSums[i] + criticalCellsByDim[i].size();
100 const auto nCritPoints = partSums.back();
102 points.resize(nCritPoints);
103 cellDimensions.resize(nCritPoints);
104 cellIds.resize(nCritPoints);
105 isOnBoundary.resize(nCritPoints);
106 PLVertexIdentifiers.resize(nCritPoints);
108 for(
size_t i = 0; i < criticalCellsByDim.size(); ++i) {
109#ifdef TTK_ENABLE_OPENMP
110#pragma omp parallel for num_threads(threadNumber_)
112 for(
size_t j = 0; j < criticalCellsByDim[i].size(); ++j) {
113 const SimplexId cellId = criticalCellsByDim[i][j];
114 const int cellDim = i;
115 const auto o{partSums[i] + j};
117 triangulation.getCellIncenter(cellId, i, points[o].data());
118 cellDimensions[o] = cellDim;
121 triangulation.getDistributedGlobalCellId(cellId, cellDim, globalId);
122 cellIds[o] = globalId;
126 const Cell cell{
static_cast<int>(i), cellId};
127 isOnBoundary[o] = this->
isBoundary(cell, triangulation);
143template <
typename triangulationType>
145 std::vector<std::array<float, 3>> &points,
146 std::vector<char> &cellDimensions,
147 std::vector<SimplexId> &cellIds,
148 std::vector<char> &isOnBoundary,
149 std::vector<SimplexId> &PLVertexIdentifiers,
150 const triangulationType &triangulation)
const {
152 std::array<std::vector<SimplexId>, 4> criticalCellsByDim;
155 isOnBoundary, PLVertexIdentifiers, triangulation);
160template <
typename triangulationType>
162 std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
163 const triangulationType &triangulation)
const {
166 for(
int i = 0; i < dims; ++i) {
169 std::vector<std::vector<SimplexId>> critCellsPerThread(this->
threadNumber_);
175#ifdef TTK_ENABLE_OPENMP
176#pragma omp parallel for num_threads(this->threadNumber_) schedule(static)
178 for(
SimplexId j = 0; j < numberOfCells; ++j) {
179#ifdef TTK_ENABLE_OPENMP
180 const auto tid = omp_get_thread_num();
185 critCellsPerThread[tid].emplace_back(j);
190 criticalCellsByDim[i] = std::move(critCellsPerThread[0]);
191 for(
size_t j = 1; j < critCellsPerThread.size(); ++j) {
192 const auto &vec{critCellsPerThread[j]};
193 criticalCellsByDim[i].insert(
194 criticalCellsByDim[i].
end(), vec.begin(), vec.end());
201template <
typename triangulationType>
203 const int dimension,
const triangulationType &triangulation)
const {
211 return triangulation.getNumberOfVertices();
215 return triangulation.getNumberOfEdges();
219 return triangulation.getNumberOfTriangles();
223 return triangulation.getNumberOfCells();
230template <
typename triangulationType>
232 DiscreteGradient::lowerStar(lowerStarType &ls,
235 const triangulationType &triangulation)
const {
238 for(
auto &vec : ls) {
243 CellExt const localCellExt{0, a};
244 ls[0].emplace_back(localCellExt);
247 const auto nedges = triangulation.getVertexEdgeNumber(a);
248 ls[1].reserve(nedges);
251 triangulation.getVertexEdge(a, i, edgeId);
253 triangulation.getEdgeVertex(edgeId, 0, vertexId);
255 triangulation.getEdgeVertex(edgeId, 1, vertexId);
257 if(offsets[vertexId] < offsets[a]) {
258 ls[1].emplace_back(
CellExt{1, edgeId, {offsets[vertexId], -1, -1}, {}});
262 if(ls[1].size() < 2) {
267 const auto processTriangle
270 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
272 lowVerts[0] = offsets[v1];
273 lowVerts[1] = offsets[v2];
275 lowVerts[0] = offsets[v0];
276 lowVerts[1] = offsets[v2];
278 lowVerts[0] = offsets[v0];
279 lowVerts[1] = offsets[v1];
282 if(lowVerts[0] < lowVerts[1]) {
283 std::swap(lowVerts[0], lowVerts[1]);
285 if(offsets[a] > lowVerts[0]) {
288 std::array<uint8_t, 3> faces{};
289 for(
const auto &e : ls[1]) {
290 if(e.lowVerts_[0] == lowVerts[0] || e.lowVerts_[0] == lowVerts[1]) {
295 CellExt const localCellExt2{2, triangleId, lowVerts, faces};
296 ls[2].emplace_back(localCellExt2);
306 const auto ncells = triangulation.getVertexStarNumber(a);
307 ls[2].reserve(ncells);
310 triangulation.getVertexStar(a, i, cellId);
312 triangulation.getCellVertex(cellId, 0, v0);
313 triangulation.getCellVertex(cellId, 1, v1);
314 triangulation.getCellVertex(cellId, 2, v2);
315 processTriangle(cellId, v0, v1, v2);
319 const auto ntri = triangulation.getVertexTriangleNumber(a);
323 triangulation.getVertexTriangle(a, i, triangleId);
325 triangulation.getTriangleVertex(triangleId, 0, v0);
326 triangulation.getTriangleVertex(triangleId, 1, v1);
327 triangulation.getTriangleVertex(triangleId, 2, v2);
328 processTriangle(triangleId, v0, v1, v2);
332 if(ls[2].size() >= 3) {
334 const auto ncells = triangulation.getVertexStarNumber(a);
335 ls[3].reserve(ncells);
338 triangulation.getVertexStar(a, i, cellId);
339 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
341 triangulation.getCellVertex(cellId, 0, v0);
342 triangulation.getCellVertex(cellId, 1, v1);
343 triangulation.getCellVertex(cellId, 2, v2);
344 triangulation.getCellVertex(cellId, 3, v3);
346 lowVerts[0] = offsets[v1];
347 lowVerts[1] = offsets[v2];
348 lowVerts[2] = offsets[v3];
350 lowVerts[0] = offsets[v0];
351 lowVerts[1] = offsets[v2];
352 lowVerts[2] = offsets[v3];
354 lowVerts[0] = offsets[v0];
355 lowVerts[1] = offsets[v1];
356 lowVerts[2] = offsets[v3];
358 lowVerts[0] = offsets[v0];
359 lowVerts[1] = offsets[v1];
360 lowVerts[2] = offsets[v2];
362 if(offsets[a] > *std::max_element(
363 lowVerts.begin(), lowVerts.end())) {
366 std::sort(lowVerts.rbegin(), lowVerts.rend());
370 std::array<uint8_t, 3> faces{};
371 for(
const auto &t : ls[2]) {
374 if((t.lowVerts_[0] == lowVerts[0]
375 && (t.lowVerts_[1] == lowVerts[1]
376 || t.lowVerts_[1] == lowVerts[2]))
377 || (t.lowVerts_[0] == lowVerts[1]
378 && t.lowVerts_[1] == lowVerts[2])) {
384 CellExt const localCellExt3{3, cellId, lowVerts, faces};
385 ls[3].emplace_back(localCellExt3);
392template <
typename triangulationType>
393inline void DiscreteGradient::pairCells(
394 CellExt &alpha,
CellExt &beta,
const triangulationType &triangulation) {
395#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
396 char localBId{0}, localAId{0};
402 triangulation.getEdgeVertex(beta.
id_, i, a);
408 const auto nedges = triangulation.getVertexEdgeNumber(alpha.
id_);
410 triangulation.getVertexEdge(alpha.
id_, i, b);
416 }
else if(beta.
dim_ == 2) {
418 triangulation.getTriangleEdge(beta.
id_, i, a);
424 const auto ntri = triangulation.getEdgeTriangleNumber(alpha.
id_);
426 triangulation.getEdgeTriangle(alpha.
id_, i, b);
434 triangulation.getCellTriangle(beta.
id_, i, a);
440 const auto ntetra = triangulation.getTriangleStarNumber(alpha.
id_);
442 triangulation.getTriangleStar(alpha.
id_, i, b);
449 (*gradient_)[2 * alpha.
dim_][alpha.
id_] = localBId;
450 (*gradient_)[2 * alpha.
dim_ + 1][beta.
id_] = localAId;
453 (*gradient_)[2 * alpha.
dim_][alpha.
id_] = beta.
id_;
454 (*gradient_)[2 * alpha.
dim_ + 1][beta.
id_] = alpha.
id_;
460template <
typename triangulationType>
461int DiscreteGradient::processLowerStars(
462 const SimplexId *
const offsets,
const triangulationType &triangulation) {
466 auto nverts = triangulation.getNumberOfVertices();
469 const auto orderCells = [&](
const CellExt &a,
const CellExt &b) ->
bool {
475 = std::priority_queue<std::reference_wrapper<CellExt>,
476 std::vector<std::reference_wrapper<CellExt>>,
477 decltype(orderCells)>;
485 pqType pqZero{orderCells}, pqOne{orderCells};
490#ifdef TTK_ENABLE_OPENMP
491#pragma omp parallel for num_threads(threadNumber_) \
492 firstprivate(Lx, pqZero, pqOne)
498 while(!pqZero.empty()) {
501 while(!pqOne.empty()) {
506 const auto insertCofacets = [&](
const CellExt &ca, lowerStarType &ls) {
508 for(
auto &beta : ls[2]) {
510 || ls[1][beta.
faces_[1]].id_ == ca.
id_) {
512 if(numUnpairedFacesTriangle(beta, ls).first == 1) {
518 }
else if(ca.
dim_ == 2) {
519 for(
auto &beta : ls[3]) {
522 || ls[2][beta.
faces_[2]].id_ == ca.
id_) {
524 if(numUnpairedFacesTetra(beta, ls).first == 1) {
532 lowerStar(Lx, x, offsets, triangulation);
536 if(ttk::isRunningWithMPI()
538 int sizeDim = Lx.size();
539 for(
int i = 0; i < sizeDim; i++) {
540 int nCells = Lx[i].size();
541 for(
int j = 0; j < nCells; j++) {
542 setCellToGhost(Lx[i][j].dim_, Lx[i][j].id_);
553 for(
size_t i = 1; i < Lx[1].size(); ++i) {
554 const auto &a = Lx[1][minId].
lowVerts_[0];
555 const auto &b = Lx[1][i].lowVerts_[0];
562 auto &c_delta = Lx[1][minId];
565 pairCells(Lx[0][0], c_delta, triangulation);
568 for(
auto &alpha : Lx[1]) {
569 if(alpha.
id_ != c_delta.id_) {
577 insertCofacets(c_delta, Lx);
579 while(!pqOne.empty() || !pqZero.empty()) {
580 while(!pqOne.empty()) {
581 auto &c_alpha = pqOne.top().get();
583 auto unpairedFaces = numUnpairedFaces(c_alpha, Lx);
584 if(unpairedFaces.first == 0) {
585 pqZero.push(c_alpha);
587 auto &c_pair_alpha = Lx[c_alpha.dim_ - 1][unpairedFaces.second];
590 pairCells(c_pair_alpha, c_alpha, triangulation);
593 insertCofacets(c_alpha, Lx);
594 insertCofacets(c_pair_alpha, Lx);
600 while(!pqZero.empty() && pqZero.top().get().paired_) {
604 if(!pqZero.empty()) {
605 auto &c_gamma = pqZero.top().get();
610 c_gamma.paired_ =
true;
613 insertCofacets(c_gamma, Lx);
623template <
typename triangulationType>
625 const Cell &cell,
const triangulationType &triangulation)
const {
627 if(cell.
dim_ > this->dimensionality_ || cell.
dim_ < 0) {
632 return triangulation.isVertexOnBoundary(vert);
635template <
typename triangulationType>
638 const triangulationType &triangulation,
639 bool isReverse)
const {
643 std::is_base_of<AbstractTriangulation, triangulationType>(),
644 "triangulationType should be an AbstractTriangulation derivative");
646#ifndef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
650 if((cell.
dim_ > this->dimensionality_ - 1 && !isReverse)
651 || (cell.
dim_ > this->dimensionality_ && isReverse) || cell.
dim_ < 0) {
659#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
660 const auto locId{(*gradient_)[0][cell.
id_]};
662 triangulation.getVertexEdge(cell.
id_, locId,
id);
665 id = (*gradient_)[0][cell.
id_];
670 else if(cell.
dim_ == 1) {
672#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
673 const auto locId{(*gradient_)[1][cell.
id_]};
675 triangulation.getEdgeVertex(cell.
id_, locId,
id);
678 id = (*gradient_)[1][cell.
id_];
681#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
682 const auto locId{(*gradient_)[2][cell.
id_]};
684 triangulation.getEdgeTriangle(cell.
id_, locId,
id);
687 id = (*gradient_)[2][cell.
id_];
692 else if(cell.
dim_ == 2) {
694#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
695 const auto locId{(*gradient_)[3][cell.
id_]};
697 triangulation.getTriangleEdge(cell.
id_, locId,
id);
700 id = (*gradient_)[3][cell.
id_];
703#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
704 const auto locId{(*gradient_)[4][cell.
id_]};
706 triangulation.getTriangleStar(cell.
id_, locId,
id);
709 id = (*gradient_)[4][cell.
id_];
714 else if(cell.
dim_ == 3) {
716#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
717 const auto locId{(*gradient_)[5][cell.
id_]};
719 triangulation.getCellTriangle(cell.
id_, locId,
id);
722 id = (*gradient_)[5][cell.
id_];
730template <
typename triangulationType>
733 std::vector<Cell> &vpath,
734 const triangulationType &triangulation)
const {
742 const Cell vertex(0, currentId);
743 vpath.push_back(vertex);
750 if(connectedEdgeId == -1) {
755 const Cell edge(1, connectedEdgeId);
756 vpath.push_back(edge);
762 for(
int i = 0; i < 2; ++i) {
764 triangulation.getEdgeVertex(connectedEdgeId, i, vertexId);
766 if(vertexId != currentId) {
767 currentId = vertexId;
772 }
while(connectedEdgeId != -1);
778template <
typename triangulationType>
782 const std::vector<bool> &isVisited,
783 std::vector<Cell> *
const vpath,
784 const triangulationType &triangulation,
785 const bool stopIfMultiConnected,
786 const bool enableCycleDetector)
const {
789 const SimplexId numberOfEdges = triangulation.getNumberOfEdges();
790 std::vector<bool> isCycle;
791 if(enableCycleDetector) {
792 isCycle.resize(numberOfEdges,
false);
797 if(vpath !=
nullptr) {
798 vpath->push_back(saddle2);
803 int nconnections = 0;
804 for(
int i = 0; i < 3; ++i) {
806 triangulation.getTriangleEdge(saddle2.
id_, i, edgeId);
807 if(isVisited[edgeId]) {
810 if(vpath !=
nullptr) {
811 vpath->push_back(
Cell(1, edgeId));
820 if(stopIfMultiConnected && nconnections > 1) {
829 if(enableCycleDetector) {
830 if(not isCycle[currentId]) {
831 isCycle[currentId] =
true;
833 this->
printErr(
"Cycle detected on the wall of 1-saddle "
842 const Cell edge(1, currentId);
843 if(vpath !=
nullptr) {
844 vpath->push_back(edge);
854 const Cell triangle(2, connectedTriangleId);
855 if(vpath !=
nullptr) {
856 vpath->push_back(triangle);
863 int nconnections = 0;
864 for(
int i = 0; i < 3; ++i) {
866 triangulation.getTriangleEdge(connectedTriangleId, i, edgeId);
868 if(isVisited[edgeId] and edgeId != oldId) {
873 if(stopIfMultiConnected && nconnections > 1) {
878 }
while(currentId != oldId);
884template <
typename triangulationType>
886 std::vector<Cell> &vpath,
887 const triangulationType &triangulation,
888 const bool enableCycleDetector)
const {
890 const SimplexId numberOfCells = triangulation.getNumberOfCells();
891 std::vector<bool> isCycle;
892 if(enableCycleDetector) {
893 isCycle.resize(numberOfCells,
false);
905 const Cell triangle(2, currentId);
906 vpath.push_back(triangle);
914 if(connectedEdgeId == -1) {
919 const Cell edge(1, connectedEdgeId);
920 vpath.push_back(edge);
927 = triangulation.getEdgeStarNumber(connectedEdgeId);
928 for(
SimplexId i = 0; i < starNumber; ++i) {
930 triangulation.getEdgeStar(connectedEdgeId, i, starId);
932 if(starId != currentId) {
939 }
while(currentId != oldId);
949 if(enableCycleDetector) {
950 if(not isCycle[currentId]) {
951 isCycle[currentId] =
true;
953 this->
printErr(
"cycle detected in the path from tetra "
962 const Cell tetra(3, currentId);
963 vpath.push_back(tetra);
971 if(connectedTriangleId == -1) {
976 const Cell triangle(2, connectedTriangleId);
977 vpath.push_back(triangle);
984 = triangulation.getTriangleStarNumber(connectedTriangleId);
985 for(
SimplexId i = 0; i < starNumber; ++i) {
987 triangulation.getTriangleStar(connectedTriangleId, i, starId);
989 if(starId != currentId) {
996 }
while(currentId != oldId);
1003template <
typename triangulationType>
1005 const Cell &saddle1,
1006 const Cell &saddle2,
1007 const std::vector<bool> &isVisited,
1008 std::vector<Cell> *
const vpath,
1009 const triangulationType &triangulation,
1010 const bool stopIfMultiConnected,
1011 const bool enableCycleDetector,
1012 bool *
const cycleFound)
const {
1015 const SimplexId numberOfTriangles = triangulation.getNumberOfTriangles();
1016 std::vector<bool> isCycle;
1017 if(enableCycleDetector) {
1018 isCycle.resize(numberOfTriangles,
false);
1023 if(vpath !=
nullptr) {
1024 vpath->push_back(saddle1);
1029 int nconnections = 0;
1031 = triangulation.getEdgeTriangleNumber(saddle1.
id_);
1032 for(
SimplexId i = 0; i < triangleNumber; ++i) {
1034 triangulation.getEdgeTriangle(saddle1.
id_, i, triangleId);
1035 if(isVisited[triangleId]) {
1038 if(vpath !=
nullptr) {
1039 vpath->push_back(
Cell(2, triangleId));
1044 currentId = triangleId;
1048 if(stopIfMultiConnected && nconnections > 1) {
1053 if(currentId == -1) {
1061 if(enableCycleDetector) {
1062 if(not isCycle[currentId]) {
1063 isCycle[currentId] =
true;
1068 this->
printErr(
"Cycle detected on the wall of 2-saddle "
1077 const Cell triangle(2, currentId);
1078 if(vpath !=
nullptr) {
1079 vpath->push_back(triangle);
1090 const Cell edge(1, connectedEdgeId);
1091 if(vpath !=
nullptr) {
1092 vpath->push_back(edge);
1099 int nconnections = 0;
1101 = triangulation.getEdgeTriangleNumber(connectedEdgeId);
1102 for(
SimplexId i = 0; i < triangleNumber; ++i) {
1104 triangulation.getEdgeTriangle(connectedEdgeId, i, triangleId);
1106 if(isVisited[triangleId] and triangleId != oldId) {
1107 currentId = triangleId;
1111 if(stopIfMultiConnected && nconnections > 1) {
1116 }
while(currentId != oldId);
1122template <
typename triangulationType>
1124 const Cell &cell,
const triangulationType &triangulation)
const {
1126 if(cell.
dim_ == 1) {
1131 std::queue<SimplexId> bfs;
1133 std::vector<bool> isVisited(triangulation.getNumberOfTriangles(),
false);
1136 while(!bfs.empty()) {
1137 const SimplexId triangleId = bfs.front();
1140 isVisited[triangleId] =
true;
1142 for(
int j = 0; j < 3; ++j) {
1144 triangulation.getTriangleEdge(triangleId, j, edgeId);
1149 if(triangleId == pairedCellId or pairedCellId == -1)
1152 if(isVisited[pairedCellId])
1155 bfs.push(pairedCellId);
1163template <
typename triangulationType>
1167 const triangulationType &triangulation,
1168 std::vector<Cell> *
const wall,
1169 std::vector<SimplexId> *
const saddles)
const {
1171 if(saddles !=
nullptr) {
1176 if(cell.
dim_ == 2) {
1180 std::queue<SimplexId> bfs;
1184 while(!bfs.empty()) {
1185 const SimplexId triangleId = bfs.front();
1193 if(wall !=
nullptr) {
1194 wall->push_back(
Cell(2, triangleId));
1197 for(
int j = 0; j < 3; ++j) {
1199 triangulation.getTriangleEdge(triangleId, j, edgeId);
1202 saddles->emplace_back(edgeId);
1208 if(pairedCellId != -1 and pairedCellId != triangleId) {
1209 bfs.push(pairedCellId);
1215 if(saddles !=
nullptr && saddles->size() > 1) {
1216 std::sort(saddles->begin(), saddles->end());
1217 const auto last = std::unique(saddles->begin(), saddles->end());
1218 saddles->erase(last, saddles->end());
1226template <
typename triangulationType>
1230 const triangulationType &triangulation,
1231 std::vector<Cell> *
const wall,
1232 std::vector<SimplexId> *
const saddles)
const {
1234 if(saddles !=
nullptr) {
1239 if(cell.
dim_ == 1) {
1243 std::queue<SimplexId> bfs;
1247 while(!bfs.empty()) {
1256 if(wall !=
nullptr) {
1257 wall->push_back(
Cell(1, edgeId));
1261 = triangulation.getEdgeTriangleNumber(edgeId);
1262 for(
SimplexId j = 0; j < triangleNumber; ++j) {
1264 triangulation.getEdgeTriangle(edgeId, j, triangleId);
1266 if((saddles !=
nullptr) and
isSaddle2(
Cell(2, triangleId))) {
1267 saddles->emplace_back(triangleId);
1273 if(pairedCellId != -1 and pairedCellId != edgeId) {
1274 bfs.push(pairedCellId);
1280 if(saddles !=
nullptr && saddles->size() > 1) {
1281 std::sort(saddles->begin(), saddles->end());
1282 const auto last = std::unique(saddles->begin(), saddles->end());
1283 saddles->erase(last, saddles->end());
1291template <
typename triangulationType>
1293 const std::vector<Cell> &vpath,
1294 const triangulationType &triangulation)
const {
1298 const SimplexId numberOfCellsInPath = vpath.size();
1299 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
1301 const SimplexId triangleId = vpath[i + 1].id_;
1303#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1304 for(
int k = 0; k < 3; ++k) {
1306 triangulation.getCellEdge(triangleId, k, tmp);
1308 (*gradient_)[3][triangleId] = k;
1312 for(
int k = 0; k < triangulation.getEdgeStarNumber(edgeId); ++k) {
1314 triangulation.getEdgeStar(edgeId, k, tmp);
1315 if(tmp == triangleId) {
1316 (*gradient_)[2][edgeId] = k;
1322 (*gradient_)[3][triangleId] = edgeId;
1323 (*gradient_)[2][edgeId] = triangleId;
1328 const SimplexId numberOfCellsInPath = vpath.size();
1329 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
1330 const SimplexId triangleId = vpath[i].id_;
1331 const SimplexId tetraId = vpath[i + 1].id_;
1333#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1334 for(
int k = 0; k < 4; ++k) {
1336 triangulation.getCellTriangle(tetraId, k, tmp);
1337 if(tmp == triangleId) {
1338 (*gradient_)[5][tetraId] = k;
1342 for(
int k = 0; k < triangulation.getTriangleStarNumber(triangleId); ++k) {
1344 triangulation.getTriangleStar(triangleId, k, tmp);
1345 if(tmp == tetraId) {
1346 (*gradient_)[4][triangleId] = k;
1351 (*gradient_)[5][tetraId] = triangleId;
1352 (*gradient_)[4][triangleId] = tetraId;
1360template <
typename triangulationType>
1362 const std::vector<Cell> &vpath,
1363 const triangulationType &triangulation)
const {
1366 for(
size_t i = 0; i < vpath.size(); i += 2) {
1368 const SimplexId vertId = vpath[i + 1].id_;
1370#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1371 const auto nneighs = triangulation.getVertexEdgeNumber();
1372 for(
int k = 0; k < nneighs; ++k) {
1374 triangulation.getVertexEdge(vertId, k, tmp);
1376 (*gradient_)[0][vertId] = k;
1380 const auto nverts = triangulation.getEdgeStarNumber(edgeId);
1381 for(
int k = 0; k < nverts; ++k) {
1383 triangulation.getEdgeVertex(edgeId, k, tmp);
1385 (*gradient_)[1][edgeId] = k;
1391 (*gradient_)[0][vertId] = edgeId;
1392 (*gradient_)[1][edgeId] = vertId;
1399template <
typename triangulationType>
1401 const std::vector<Cell> &vpath,
1402 const triangulationType &triangulation,
1403 bool cancelReversal)
const {
1407 if(cancelReversal) {
1412 if(vpath.size() <= 1)
1414 (*gradient_)[3][vpath[vpath.size() - 1].id_] =
NULL_GRADIENT;
1416 const SimplexId numberOfCellsInPath = vpath.size();
1417 const SimplexId startIndex = (cancelReversal ? 2 : 0);
1418 for(
SimplexId i = startIndex; i < numberOfCellsInPath; i += 2) {
1420 const SimplexId vpathTriangleIndex = (cancelReversal ? i - 1 : i + 1);
1421 const SimplexId edgeId = vpath[vpathEdgeIndex].id_;
1422 const SimplexId triangleId = vpath[vpathTriangleIndex].id_;
1424#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1425 for(
int k = 0; k < 3; ++k) {
1427 triangulation.getTriangleEdge(triangleId, k, tmp);
1429 (*gradient_)[3][triangleId] = k;
1433 for(
int k = 0; k < triangulation.getEdgeTriangleNumber(edgeId); ++k) {
1435 triangulation.getEdgeTriangle(edgeId, k, tmp);
1436 if(tmp == triangleId) {
1437 (*gradient_)[2][edgeId] = k;
1443 (*gradient_)[3][triangleId] = edgeId;
1444 (*gradient_)[2][edgeId] = triangleId;
1452template <
typename triangulationType>
1454 const std::vector<Cell> &vpath,
1455 const triangulationType &triangulation)
const {
1459 const SimplexId numberOfCellsInPath = vpath.size();
1460 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
1461 const SimplexId triangleId = vpath[i].id_;
1462 const SimplexId edgeId = vpath[i + 1].id_;
1464#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1465 for(
int k = 0; k < 3; ++k) {
1467 triangulation.getTriangleEdge(triangleId, k, tmp);
1469 (*gradient_)[3][triangleId] = k;
1473 for(
int k = 0; k < triangulation.getEdgeTriangleNumber(edgeId); ++k) {
1475 triangulation.getEdgeTriangle(edgeId, k, tmp);
1476 if(tmp == triangleId) {
1477 (*gradient_)[2][edgeId] = k;
1483 (*gradient_)[2][edgeId] = triangleId;
1484 (*gradient_)[3][triangleId] = edgeId;
1492template <
typename triangulationType>
1494 const Cell c,
const triangulationType &triangulation)
const {
1498 auto cellDim = c.
dim_;
1499 auto cellId = c.
id_;
1506 else if(cellDim == 1) {
1509 triangulation.getEdgeVertex(cellId, 0, v0);
1510 triangulation.getEdgeVertex(cellId, 1, v1);
1512 if(offsets[v0] > offsets[v1]) {
1519 else if(cellDim == 2) {
1521 triangulation.getTriangleVertex(cellId, 0, v0);
1522 triangulation.getTriangleVertex(cellId, 1, v1);
1523 triangulation.getTriangleVertex(cellId, 2, v2);
1524 if(offsets[v0] > offsets[v1] && offsets[v0] > offsets[v2]) {
1526 }
else if(offsets[v1] > offsets[v0] && offsets[v1] > offsets[v2]) {
1533 else if(cellDim == 3) {
1535 triangulation.getCellVertex(cellId, 0, v0);
1536 triangulation.getCellVertex(cellId, 1, v1);
1537 triangulation.getCellVertex(cellId, 2, v2);
1538 triangulation.getCellVertex(cellId, 3, v3);
1539 if(offsets[v0] > offsets[v1] && offsets[v0] > offsets[v2]
1540 && offsets[v0] > offsets[v3]) {
1542 }
else if(offsets[v1] > offsets[v0] && offsets[v1] > offsets[v2]
1543 && offsets[v1] > offsets[v3]) {
1545 }
else if(offsets[v2] > offsets[v0] && offsets[v2] > offsets[v1]
1546 && offsets[v2] > offsets[v3]) {
1555template <
typename triangulationType>
1557 const Cell c,
const triangulationType &triangulation)
const {
1561 auto cellDim = c.
dim_;
1562 auto cellId = c.
id_;
1569 else if(cellDim == 1) {
1572 triangulation.getEdgeVertex(cellId, 0, v0);
1573 triangulation.getEdgeVertex(cellId, 1, v1);
1575 if(offsets[v0] < offsets[v1]) {
1582 else if(cellDim == 2) {
1584 triangulation.getTriangleVertex(cellId, 0, v0);
1585 triangulation.getTriangleVertex(cellId, 1, v1);
1586 triangulation.getTriangleVertex(cellId, 2, v2);
1587 if(offsets[v0] < offsets[v1] && offsets[v0] < offsets[v2]) {
1589 }
else if(offsets[v1] < offsets[v0] && offsets[v1] < offsets[v2]) {
1596 else if(cellDim == 3) {
1598 triangulation.getCellVertex(cellId, 0, v0);
1599 triangulation.getCellVertex(cellId, 1, v1);
1600 triangulation.getCellVertex(cellId, 2, v2);
1601 triangulation.getCellVertex(cellId, 3, v3);
1602 if(offsets[v0] < offsets[v1] && offsets[v0] < offsets[v2]
1603 && offsets[v0] < offsets[v3]) {
1605 }
else if(offsets[v1] < offsets[v0] && offsets[v1] < offsets[v2]
1606 && offsets[v1] < offsets[v3]) {
1608 }
else if(offsets[v2] < offsets[v0] && offsets[v2] < offsets[v1]
1609 && offsets[v2] < offsets[v3]) {
1618template <
typename triangulationType>
1620 std::vector<std::array<float, 3>> &points,
1621 std::vector<char> &points_pairOrigins,
1622 std::vector<char> &cells_pairTypes,
1623 std::vector<SimplexId> &cellIds,
1624 std::vector<char> &cellDimensions,
1625 const triangulationType &triangulation)
const {
1630 std::vector<size_t> nGlyphsPerDim(nDims);
1632#ifdef TTK_ENABLE_OPENMP
1633#pragma omp parallel for num_threads(threadNumber_)
1635 for(
int i = 0; i < nDims - 1; ++i) {
1645 std::vector<size_t> offsets(nDims + 1);
1647 offsets[i + 1] = offsets[i] + nGlyphsPerDim[i];
1651 const auto nGlyphs = offsets.back();
1654 points.resize(2 * nGlyphs);
1655 points_pairOrigins.resize(2 * nGlyphs);
1656 cells_pairTypes.resize(nGlyphs);
1657 cellIds.resize(2 * nGlyphs);
1658 cellDimensions.resize(2 * nGlyphs);
1660#ifdef TTK_ENABLE_OPENMP
1661#pragma omp parallel for num_threads(threadNumber_)
1663 for(
int i = 0; i < nDims - 1; ++i) {
1665 size_t nProcessedGlyphs{offsets[i]};
1670 const Cell pc{i + 1, pcid};
1671 triangulation.getCellIncenter(
1672 c.id_, c.dim_, points[2 * nProcessedGlyphs].data());
1673 triangulation.getCellIncenter(
1674 pc.id_, pc.dim_, points[2 * nProcessedGlyphs + 1].data());
1675 points_pairOrigins[2 * nProcessedGlyphs] = 0;
1676 points_pairOrigins[2 * nProcessedGlyphs + 1] = 1;
1677 cells_pairTypes[nProcessedGlyphs] = i;
1678#ifdef TTK_ENABLE_MPI
1680 triangulation.getDistributedGlobalCellId(j, i, globalId);
1681 cellIds[2 * nProcessedGlyphs + 0] = globalId;
1682 triangulation.getDistributedGlobalCellId(pcid, i + 1, globalId);
1683 cellIds[2 * nProcessedGlyphs + 1] = globalId;
1685 cellIds[2 * nProcessedGlyphs + 0] = j;
1686 cellIds[2 * nProcessedGlyphs + 1] = pcid;
1688 cellDimensions[2 * nProcessedGlyphs + 0] = i;
1689 cellDimensions[2 * nProcessedGlyphs + 1] = i + 1;
#define TTK_FORCE_USE(x)
Force the compiler to use the function/method parameter.
std::array< std::vector< gradIdType >, 6 > gradientType
Discrete gradient internal struct.
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
TTK discreteGradient processing package.
SimplexId getCellLowerVertex(const Cell c, const triangulationType &triangulation) const
int reverseAscendingPath(const std::vector< Cell > &vpath, const triangulationType &triangulation) const
int reverseDescendingPath(const std::vector< Cell > &vpath, const triangulationType &triangulation) const
int setGradientGlyphs(std::vector< std::array< float, 3 > > &points, std::vector< char > &points_pairOrigins, std::vector< char > &cells_pairTypes, std::vector< SimplexId > &cellsIds, std::vector< char > &cellsDimensions, const triangulationType &triangulation) const
int reverseAscendingPathOnWall(const std::vector< Cell > &vpath, const triangulationType &triangulation, bool cancelReversal=false) const
bool getDescendingPathThroughWall(const Cell &saddle2, const Cell &saddle1, const std::vector< bool > &isVisited, std::vector< Cell > *const vpath, const triangulationType &triangulation, const bool stopIfMultiConnected=false, const bool enableCycleDetector=false) const
bool isSaddle1(const Cell &cell) const
bool isSaddle2(const Cell &cell) const
AbstractTriangulation::gradientKeyType inputScalarField_
SimplexId getNumberOfCells(const int dimension, const triangulationType &triangulation) const
SimplexId numberOfVertices_
bool isBoundary(const Cell &cell, const triangulationType &triangulation) const
bool isCellCritical(const int cellDim, const SimplexId cellId) const
SimplexId getPairedCell(const Cell &cell, const triangulationType &triangulation, bool isReverse=false) const
int getAscendingWall(const Cell &cell, VisitedMask &mask, const triangulationType &triangulation, std::vector< Cell > *const wall=nullptr, std::vector< SimplexId > *const saddles=nullptr) const
int reverseDescendingPathOnWall(const std::vector< Cell > &vpath, const triangulationType &triangulation) const
SimplexId getCellGreaterVertex(const Cell c, const triangulationType &triangulation) const
int getCriticalPoints(std::array< std::vector< SimplexId >, 4 > &criticalCellsByDim, const triangulationType &triangulation) const
bool getAscendingPathThroughWall(const Cell &saddle1, const Cell &saddle2, const std::vector< bool > &isVisited, std::vector< Cell > *const vpath, const triangulationType &triangulation, const bool stopIfMultiConnected=false, const bool enableCycleDetector=false, bool *const cycleFound=nullptr) const
dataType getPersistence(const Cell &up, const Cell &down, const dataType *const scalars, const triangulationType &triangulation) const
int buildGradient(const triangulationType &triangulation, bool bypassCache=false)
int setCriticalPoints(const std::array< std::vector< SimplexId >, 4 > &criticalCellsByDim, std::vector< std::array< float, 3 > > &points, std::vector< char > &cellDimensions, std::vector< SimplexId > &cellIds, std::vector< char > &isOnBoundary, std::vector< SimplexId > &PLVertexIdentifiers, const triangulationType &triangulation) const
int getDescendingPath(const Cell &cell, std::vector< Cell > &vpath, const triangulationType &triangulation) const
bool detectGradientCycle(const Cell &cell, const triangulationType &triangulation) const
int getAscendingPath(const Cell &cell, std::vector< Cell > &vpath, const triangulationType &triangulation, const bool enableCycleDetector=false) const
AbstractTriangulation::gradientType localGradient_
int getNumberOfDimensions() const
int getDescendingWall(const Cell &cell, VisitedMask &mask, const triangulationType &triangulation, std::vector< Cell > *const wall=nullptr, std::vector< SimplexId > *const saddles=nullptr) const
AbstractTriangulation::gradientType * gradient_
const SimplexId * inputOffsets_
std::string to_string(__int128)
COMMON_EXPORTS int MPIrank_
int SimplexId
Identifier type for simplices of any dimension.
T end(std::pair< T, T > &p)
Auto-cleaning re-usable graph propagations data structure.
std::vector< bool > & isVisited_
std::vector< SimplexId > & visitedIds_
Extended Cell structure for processLowerStars.
const std::array< SimplexId, 3 > lowVerts_
const std::array< uint8_t, 3 > faces_
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)