24template <
typename dataType,
typename triangulationType>
28 const dataType *
const scalars,
29 const triangulationType &triangulation)
const {
35template <
typename triangulationType>
38 const std::vector<bool> *updateMask) {
40 auto &cacheHandler = *triangulation.getGradientCacheHandler();
41 const auto findGradient
49#ifdef TTK_ENABLE_OPENMP
50 if(!bypassCache && omp_in_parallel()) {
52 "buildGradient() called inside a parallel region, disabling cache...");
62 if(this->
gradient_ ==
nullptr || bypassCache) {
71 this->initMemory(triangulation);
76 this->processLowerStarsWithMask(
78 this->
printMsg(
"Update cached discrete gradient", 1.0,
79 tm.getElapsedTime(), this->threadNumber_);
82 this->
printMsg(
"Built discrete gradient", 1.0, tm.getElapsedTime(),
86 this->
printMsg(
"Fetched cached discrete gradient");
89 this->processLowerStarsWithMask(
91 this->
printMsg(
"Update cached discrete gradient", 1.0,
92 tm.getElapsedTime(), this->threadNumber_);
99template <
typename triangulationType>
101 const std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
102 std::vector<std::array<float, 3>> &points,
103 std::vector<char> &cellDimensions,
104 std::vector<SimplexId> &cellIds,
105 std::vector<char> &isOnBoundary,
106 std::vector<SimplexId> &PLVertexIdentifiers,
107 const triangulationType &triangulation)
const {
109 std::array<size_t, 5> partSums{};
110 for(
size_t i = 0; i < criticalCellsByDim.size(); ++i) {
111 partSums[i + 1] = partSums[i] + criticalCellsByDim[i].size();
114 const auto nCritPoints = partSums.back();
116 points.resize(nCritPoints);
117 cellDimensions.resize(nCritPoints);
118 cellIds.resize(nCritPoints);
119 isOnBoundary.resize(nCritPoints);
120 PLVertexIdentifiers.resize(nCritPoints);
122 for(
size_t i = 0; i < criticalCellsByDim.size(); ++i) {
123#ifdef TTK_ENABLE_OPENMP
124#pragma omp parallel for num_threads(threadNumber_)
126 for(
size_t j = 0; j < criticalCellsByDim[i].size(); ++j) {
127 const SimplexId cellId = criticalCellsByDim[i][j];
128 const int cellDim = i;
129 const auto o{partSums[i] + j};
131 triangulation.getCellIncenter(cellId, i, points[o].data());
132 cellDimensions[o] = cellDim;
135 triangulation.getDistributedGlobalCellId(cellId, cellDim, globalId);
136 cellIds[o] = globalId;
140 const Cell cell{
static_cast<int>(i), cellId};
141 isOnBoundary[o] = this->
isBoundary(cell, triangulation);
149 = std::vector<std::string>{
"#" + std::to_string(i) +
"-cell(s)",
150 std::to_string(criticalCellsByDim[i].size())};
157template <
typename triangulationType>
159 std::vector<std::array<float, 3>> &points,
160 std::vector<char> &cellDimensions,
161 std::vector<SimplexId> &cellIds,
162 std::vector<char> &isOnBoundary,
163 std::vector<SimplexId> &PLVertexIdentifiers,
164 const triangulationType &triangulation)
const {
166 std::array<std::vector<SimplexId>, 4> criticalCellsByDim;
169 isOnBoundary, PLVertexIdentifiers, triangulation);
174template <
typename triangulationType>
176 std::array<std::vector<SimplexId>, 4> &criticalCellsByDim,
177 const triangulationType &triangulation)
const {
180 for(
int i = 0; i < dims; ++i) {
183 std::vector<std::vector<SimplexId>> critCellsPerThread(this->
threadNumber_);
189#ifdef TTK_ENABLE_OPENMP
190#pragma omp parallel for num_threads(this->threadNumber_) schedule(static)
192 for(
SimplexId j = 0; j < numberOfCells; ++j) {
193#ifdef TTK_ENABLE_OPENMP
194 const auto tid = omp_get_thread_num();
199 critCellsPerThread[tid].emplace_back(j);
204 criticalCellsByDim[i] = std::move(critCellsPerThread[0]);
205 for(
size_t j = 1; j < critCellsPerThread.size(); ++j) {
206 const auto &vec{critCellsPerThread[j]};
207 criticalCellsByDim[i].insert(
208 criticalCellsByDim[i].
end(), vec.begin(), vec.end());
215template <
typename triangulationType>
217 const int dimension,
const triangulationType &triangulation)
const {
225 return triangulation.getNumberOfVertices();
229 return triangulation.getNumberOfEdges();
233 return triangulation.getNumberOfTriangles();
237 return triangulation.getNumberOfCells();
244template <
typename triangulationType>
245inline void DiscreteGradient::lowerStarWithMask(
249 const triangulationType &triangulation,
250 const std::vector<bool> *updateMask)
const {
253 for(
auto &vec : ls) {
258 ls[0].emplace_back(
CellExt{0, a});
260 if(updateMask !=
nullptr) {
261 for(
auto &vec : ls[0]) {
262 int vertexId = vec.id_;
263 int edgeId = (*gradient_)[0][vertexId];
265 (*gradient_)[0][vertexId] = -1;
267 (*gradient_)[1][edgeId] = -1;
273 const auto nedges = triangulation.getVertexEdgeNumber(a);
274 ls[1].reserve(nedges);
277 triangulation.getVertexEdge(a, i, edgeId);
279 triangulation.getEdgeVertex(edgeId, 0, vertexId);
281 triangulation.getEdgeVertex(edgeId, 1, vertexId);
283 if(offsets[vertexId] < offsets[a]) {
284 ls[1].emplace_back(
CellExt{1, edgeId, {offsets[vertexId], -1, -1}, {}});
288 if(updateMask !=
nullptr) {
289 for(
auto &vec : ls[1]) {
290 int edgeId = vec.id_;
291 int vertexId = (*gradient_)[1][edgeId];
292 int triangleId = (*gradient_)[2][edgeId];
294 (*gradient_)[1][edgeId] = -1;
296 (*gradient_)[0][vertexId] = -1;
299 (*gradient_)[2][edgeId] = -1;
300 if(triangleId != -1) {
301 (*gradient_)[3][triangleId] = -1;
306 if(ls[1].size() < 2) {
311 const auto processTriangle
314 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
316 lowVerts[0] = offsets[v1];
317 lowVerts[1] = offsets[v2];
319 lowVerts[0] = offsets[v0];
320 lowVerts[1] = offsets[v2];
322 lowVerts[0] = offsets[v0];
323 lowVerts[1] = offsets[v1];
326 if(lowVerts[0] < lowVerts[1]) {
327 std::swap(lowVerts[0], lowVerts[1]);
329 if(offsets[a] > lowVerts[0]) {
332 std::array<uint8_t, 3> faces{};
333 for(
const auto &e : ls[1]) {
334 if(e.lowVerts_[0] == lowVerts[0] || e.lowVerts_[0] == lowVerts[1]) {
339 ls[2].emplace_back(
CellExt{2, triangleId, lowVerts, faces});
349 const auto ncells = triangulation.getVertexStarNumber(a);
350 ls[2].reserve(ncells);
353 triangulation.getVertexStar(a, i, cellId);
355 triangulation.getCellVertex(cellId, 0, v0);
356 triangulation.getCellVertex(cellId, 1, v1);
357 triangulation.getCellVertex(cellId, 2, v2);
358 processTriangle(cellId, v0, v1, v2);
361 if(updateMask !=
nullptr) {
362 for(
auto &vec : ls[2]) {
363 int triangleId = vec.id_;
364 int edgeId = (*gradient_)[3][triangleId];
366 (*gradient_)[3][triangleId] = -1;
368 (*gradient_)[2][edgeId] = -1;
375 const auto ntri = triangulation.getVertexTriangleNumber(a);
379 triangulation.getVertexTriangle(a, i, triangleId);
381 triangulation.getTriangleVertex(triangleId, 0, v0);
382 triangulation.getTriangleVertex(triangleId, 1, v1);
383 triangulation.getTriangleVertex(triangleId, 2, v2);
384 processTriangle(triangleId, v0, v1, v2);
387 if(updateMask !=
nullptr) {
388 for(
auto &vec : ls[2]) {
389 int triangleId = vec.id_;
390 int edgeId = (*gradient_)[3][triangleId];
391 int tetraId = (*gradient_)[4][triangleId];
393 (*gradient_)[3][triangleId] = -1;
395 (*gradient_)[2][edgeId] = -1;
398 (*gradient_)[4][triangleId] = -1;
400 (*gradient_)[5][tetraId] = -1;
406 if(ls[2].size() >= 3) {
408 const auto ncells = triangulation.getVertexStarNumber(a);
409 ls[3].reserve(ncells);
412 triangulation.getVertexStar(a, i, cellId);
413 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
415 triangulation.getCellVertex(cellId, 0, v0);
416 triangulation.getCellVertex(cellId, 1, v1);
417 triangulation.getCellVertex(cellId, 2, v2);
418 triangulation.getCellVertex(cellId, 3, v3);
420 lowVerts[0] = offsets[v1];
421 lowVerts[1] = offsets[v2];
422 lowVerts[2] = offsets[v3];
424 lowVerts[0] = offsets[v0];
425 lowVerts[1] = offsets[v2];
426 lowVerts[2] = offsets[v3];
428 lowVerts[0] = offsets[v0];
429 lowVerts[1] = offsets[v1];
430 lowVerts[2] = offsets[v3];
432 lowVerts[0] = offsets[v0];
433 lowVerts[1] = offsets[v1];
434 lowVerts[2] = offsets[v2];
436 if(offsets[a] > *std::max_element(
437 lowVerts.begin(), lowVerts.end())) {
440 std::sort(lowVerts.rbegin(), lowVerts.rend());
444 std::array<uint8_t, 3> faces{};
445 for(
const auto &t : ls[2]) {
448 if((t.lowVerts_[0] == lowVerts[0]
449 && (t.lowVerts_[1] == lowVerts[1]
450 || t.lowVerts_[1] == lowVerts[2]))
451 || (t.lowVerts_[0] == lowVerts[1]
452 && t.lowVerts_[1] == lowVerts[2])) {
458 ls[3].emplace_back(
CellExt{3, cellId, lowVerts, faces});
462 if(updateMask !=
nullptr) {
463 for(
auto &vec : ls[3]) {
464 int tetraId = vec.id_;
465 int triangleId = (*gradient_)[5][tetraId];
466 (*gradient_)[5][tetraId] = -1;
467 if(triangleId != -1) {
468 (*gradient_)[4][triangleId] = -1;
476template <
typename triangulationType>
478 DiscreteGradient::lowerStar(lowerStarType &ls,
481 const triangulationType &triangulation)
const {
488 for(
auto &vec : ls) {
493 CellExt const localCellExt{0, a};
494 ls[0].emplace_back(localCellExt);
497 const auto nedges = triangulation.getVertexEdgeNumber(a);
498 ls[1].reserve(nedges);
501 triangulation.getVertexEdge(a, i, edgeId);
503 triangulation.getEdgeVertex(edgeId, 0, vertexId);
505 triangulation.getEdgeVertex(edgeId, 1, vertexId);
507 if(offsets[vertexId] < offsets[a]) {
508 ls[1].emplace_back(
CellExt{1, edgeId, {offsets[vertexId], -1, -1}, {}});
512 if(ls[1].size() < 2) {
517 const auto processTriangle
520 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
522 lowVerts[0] = offsets[v1];
523 lowVerts[1] = offsets[v2];
525 lowVerts[0] = offsets[v0];
526 lowVerts[1] = offsets[v2];
528 lowVerts[0] = offsets[v0];
529 lowVerts[1] = offsets[v1];
532 if(lowVerts[0] < lowVerts[1]) {
533 std::swap(lowVerts[0], lowVerts[1]);
535 if(offsets[a] > lowVerts[0]) {
538 std::array<uint8_t, 3> faces{};
539 for(
const auto &e : ls[1]) {
540 if(e.lowVerts_[0] == lowVerts[0] || e.lowVerts_[0] == lowVerts[1]) {
545 CellExt const localCellExt2{2, triangleId, lowVerts, faces};
546 ls[2].emplace_back(localCellExt2);
556 const auto ncells = triangulation.getVertexStarNumber(a);
557 ls[2].reserve(ncells);
560 triangulation.getVertexStar(a, i, cellId);
562 triangulation.getCellVertex(cellId, 0, v0);
563 triangulation.getCellVertex(cellId, 1, v1);
564 triangulation.getCellVertex(cellId, 2, v2);
565 processTriangle(cellId, v0, v1, v2);
569 const auto ntri = triangulation.getVertexTriangleNumber(a);
573 triangulation.getVertexTriangle(a, i, triangleId);
575 triangulation.getTriangleVertex(triangleId, 0, v0);
576 triangulation.getTriangleVertex(triangleId, 1, v1);
577 triangulation.getTriangleVertex(triangleId, 2, v2);
578 processTriangle(triangleId, v0, v1, v2);
582 if(ls[2].size() >= 3) {
584 const auto ncells = triangulation.getVertexStarNumber(a);
585 ls[3].reserve(ncells);
588 triangulation.getVertexStar(a, i, cellId);
589 std::array<SimplexId, 3> lowVerts{-1, -1, -1};
591 triangulation.getCellVertex(cellId, 0, v0);
592 triangulation.getCellVertex(cellId, 1, v1);
593 triangulation.getCellVertex(cellId, 2, v2);
594 triangulation.getCellVertex(cellId, 3, v3);
596 lowVerts[0] = offsets[v1];
597 lowVerts[1] = offsets[v2];
598 lowVerts[2] = offsets[v3];
600 lowVerts[0] = offsets[v0];
601 lowVerts[1] = offsets[v2];
602 lowVerts[2] = offsets[v3];
604 lowVerts[0] = offsets[v0];
605 lowVerts[1] = offsets[v1];
606 lowVerts[2] = offsets[v3];
608 lowVerts[0] = offsets[v0];
609 lowVerts[1] = offsets[v1];
610 lowVerts[2] = offsets[v2];
612 if(offsets[a] > *std::max_element(
613 lowVerts.begin(), lowVerts.end())) {
616 std::sort(lowVerts.rbegin(), lowVerts.rend());
620 std::array<uint8_t, 3> faces{};
621 for(
const auto &t : ls[2]) {
624 if((t.lowVerts_[0] == lowVerts[0]
625 && (t.lowVerts_[1] == lowVerts[1]
626 || t.lowVerts_[1] == lowVerts[2]))
627 || (t.lowVerts_[0] == lowVerts[1]
628 && t.lowVerts_[1] == lowVerts[2])) {
634 CellExt const localCellExt3{3, cellId, lowVerts, faces};
635 ls[3].emplace_back(localCellExt3);
642template <
typename triangulationType>
643inline void DiscreteGradient::pairCells(
644 CellExt &alpha,
CellExt &beta,
const triangulationType &triangulation) {
645#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
646 char localBId{0}, localAId{0};
652 triangulation.getEdgeVertex(beta.
id_, i, a);
658 const auto nedges = triangulation.getVertexEdgeNumber(alpha.
id_);
660 triangulation.getVertexEdge(alpha.
id_, i, b);
666 }
else if(beta.
dim_ == 2) {
668 triangulation.getTriangleEdge(beta.
id_, i, a);
674 const auto ntri = triangulation.getEdgeTriangleNumber(alpha.
id_);
676 triangulation.getEdgeTriangle(alpha.
id_, i, b);
684 triangulation.getCellTriangle(beta.
id_, i, a);
690 const auto ntetra = triangulation.getTriangleStarNumber(alpha.
id_);
692 triangulation.getTriangleStar(alpha.
id_, i, b);
699 (*gradient_)[2 * alpha.
dim_][alpha.
id_] = localBId;
700 (*gradient_)[2 * alpha.
dim_ + 1][beta.
id_] = localAId;
703 (*gradient_)[2 * alpha.
dim_][alpha.
id_] = beta.
id_;
704 (*gradient_)[2 * alpha.
dim_ + 1][beta.
id_] = alpha.
id_;
710template <
typename triangulationType>
711int DiscreteGradient::processLowerStars(
712 const SimplexId *
const offsets,
const triangulationType &triangulation) {
720 auto nverts = triangulation.getNumberOfVertices();
723 const auto orderCells = [&](
const CellExt &a,
const CellExt &b) ->
bool {
729 = std::priority_queue<std::reference_wrapper<CellExt>,
730 std::vector<std::reference_wrapper<CellExt>>,
731 decltype(orderCells)>;
739 pqType pqZero{orderCells}, pqOne{orderCells};
744#ifdef TTK_ENABLE_OPENMP
745#pragma omp parallel for num_threads(threadNumber_) \
746 firstprivate(Lx, pqZero, pqOne)
752 while(!pqZero.empty()) {
755 while(!pqOne.empty()) {
760 const auto insertCofacets = [&](
const CellExt &ca, lowerStarType &ls) {
762 for(
auto &beta : ls[2]) {
764 || ls[1][beta.
faces_[1]].id_ == ca.
id_) {
766 if(numUnpairedFacesTriangle(beta, ls).first == 1) {
772 }
else if(ca.
dim_ == 2) {
773 for(
auto &beta : ls[3]) {
776 || ls[2][beta.
faces_[2]].id_ == ca.
id_) {
778 if(numUnpairedFacesTetra(beta, ls).first == 1) {
786 lowerStar(Lx, x, offsets, triangulation);
790 if(ttk::isRunningWithMPI()
792 int sizeDim = Lx.size();
793 for(
int i = 0; i < sizeDim; i++) {
794 int nCells = Lx[i].size();
795 for(
int j = 0; j < nCells; j++) {
796 setCellToGhost(Lx[i][j].dim_, Lx[i][j].id_);
807 for(
size_t i = 1; i < Lx[1].size(); ++i) {
808 const auto &a = Lx[1][minId].
lowVerts_[0];
809 const auto &b = Lx[1][i].lowVerts_[0];
816 auto &c_delta = Lx[1][minId];
819 pairCells(Lx[0][0], c_delta, triangulation);
822 for(
auto &alpha : Lx[1]) {
823 if(alpha.
id_ != c_delta.id_) {
831 insertCofacets(c_delta, Lx);
833 while(!pqOne.empty() || !pqZero.empty()) {
834 while(!pqOne.empty()) {
835 auto &c_alpha = pqOne.top().get();
837 auto unpairedFaces = numUnpairedFaces(c_alpha, Lx);
838 if(unpairedFaces.first == 0) {
839 pqZero.push(c_alpha);
841 auto &c_pair_alpha = Lx[c_alpha.dim_ - 1][unpairedFaces.second];
844 pairCells(c_pair_alpha, c_alpha, triangulation);
847 insertCofacets(c_alpha, Lx);
848 insertCofacets(c_pair_alpha, Lx);
854 while(!pqZero.empty() && pqZero.top().get().paired_) {
858 if(!pqZero.empty()) {
859 auto &c_gamma = pqZero.top().get();
864 c_gamma.paired_ =
true;
867 insertCofacets(c_gamma, Lx);
877template <
typename triangulationType>
878int DiscreteGradient::processLowerStarsWithMask(
880 const triangulationType &triangulation,
881 const std::vector<bool> *updateMask) {
883 auto nverts = triangulation.getNumberOfVertices();
888 const auto orderCells = [&](
const CellExt &a,
const CellExt &b) ->
bool {
894 = std::priority_queue<std::reference_wrapper<CellExt>,
895 std::vector<std::reference_wrapper<CellExt>>,
896 decltype(orderCells)>;
904 pqType pqZero{orderCells}, pqOne{orderCells};
909#ifdef TTK_ENABLE_OPENMP
910#pragma omp parallel for num_threads(threadNumber_) \
911 firstprivate(Lx, pqZero, pqOne)
915 if((updateMask !=
nullptr) && ((*updateMask)[x] ==
false)) {
921 while(!pqZero.empty()) {
924 while(!pqOne.empty()) {
929 const auto insertCofacets = [&](
const CellExt &ca, lowerStarType &ls) {
931 for(
auto &beta : ls[2]) {
933 || ls[1][beta.
faces_[1]].id_ == ca.
id_) {
935 if(numUnpairedFacesTriangle(beta, ls).first == 1) {
941 }
else if(ca.
dim_ == 2) {
942 for(
auto &beta : ls[3]) {
945 || ls[2][beta.
faces_[2]].id_ == ca.
id_) {
947 if(numUnpairedFacesTetra(beta, ls).first == 1) {
955 lowerStarWithMask(Lx, x, offsets, triangulation, updateMask);
959 if(ttk::isRunningWithMPI()
961 int sizeDim = Lx.size();
962 for(
int i = 0; i < sizeDim; i++) {
963 int nCells = Lx[i].size();
964 for(
int j = 0; j < nCells; j++) {
965 setCellToGhost(Lx[i][j].dim_, Lx[i][j].id_);
976 for(
size_t i = 1; i < Lx[1].size(); ++i) {
977 const auto &a = Lx[1][minId].
lowVerts_[0];
978 const auto &b = Lx[1][i].lowVerts_[0];
985 auto &c_delta = Lx[1][minId];
988 pairCells(Lx[0][0], c_delta, triangulation);
991 for(
auto &alpha : Lx[1]) {
992 if(alpha.
id_ != c_delta.id_) {
1000 insertCofacets(c_delta, Lx);
1002 while(!pqOne.empty() || !pqZero.empty()) {
1003 while(!pqOne.empty()) {
1004 auto &c_alpha = pqOne.top().get();
1006 auto unpairedFaces = numUnpairedFaces(c_alpha, Lx);
1007 if(unpairedFaces.first == 0) {
1008 pqZero.push(c_alpha);
1010 auto &c_pair_alpha = Lx[c_alpha.dim_ - 1][unpairedFaces.second];
1013 pairCells(c_pair_alpha, c_alpha, triangulation);
1016 insertCofacets(c_alpha, Lx);
1017 insertCofacets(c_pair_alpha, Lx);
1023 while(!pqZero.empty() && pqZero.top().get().paired_) {
1027 if(!pqZero.empty()) {
1028 auto &c_gamma = pqZero.top().get();
1033 c_gamma.paired_ =
true;
1036 insertCofacets(c_gamma, Lx);
1046template <
typename triangulationType>
1048 const Cell &cell,
const triangulationType &triangulation)
const {
1050 if(cell.
dim_ > this->dimensionality_ || cell.
dim_ < 0) {
1055 return triangulation.isVertexOnBoundary(vert);
1058template <
typename triangulationType>
1061 const triangulationType &triangulation,
1062 bool isReverse)
const {
1066 std::is_base_of<AbstractTriangulation, triangulationType>(),
1067 "triangulationType should be an AbstractTriangulation derivative");
1069#ifndef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1073 if((cell.
dim_ > this->dimensionality_ - 1 && !isReverse)
1074 || (cell.
dim_ > this->dimensionality_ && isReverse) || cell.
dim_ < 0) {
1080 if(cell.
dim_ == 0) {
1082#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1083 const auto locId{(*gradient_)[0][cell.
id_]};
1085 triangulation.getVertexEdge(cell.
id_, locId,
id);
1088 id = (*gradient_)[0][cell.
id_];
1093 else if(cell.
dim_ == 1) {
1095#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1096 const auto locId{(*gradient_)[1][cell.
id_]};
1098 triangulation.getEdgeVertex(cell.
id_, locId,
id);
1101 id = (*gradient_)[1][cell.
id_];
1104#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1105 const auto locId{(*gradient_)[2][cell.
id_]};
1107 triangulation.getEdgeTriangle(cell.
id_, locId,
id);
1110 id = (*gradient_)[2][cell.
id_];
1115 else if(cell.
dim_ == 2) {
1117#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1118 const auto locId{(*gradient_)[3][cell.
id_]};
1120 triangulation.getTriangleEdge(cell.
id_, locId,
id);
1123 id = (*gradient_)[3][cell.
id_];
1126#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1127 const auto locId{(*gradient_)[4][cell.
id_]};
1129 triangulation.getTriangleStar(cell.
id_, locId,
id);
1132 id = (*gradient_)[4][cell.
id_];
1137 else if(cell.
dim_ == 3) {
1139#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1140 const auto locId{(*gradient_)[5][cell.
id_]};
1142 triangulation.getCellTriangle(cell.
id_, locId,
id);
1145 id = (*gradient_)[5][cell.
id_];
1153template <
typename triangulationType>
1156 std::vector<Cell> &vpath,
1157 const triangulationType &triangulation)
const {
1159 if(cell.
dim_ == 0) {
1165 const Cell vertex(0, currentId);
1166 vpath.push_back(vertex);
1173 if(connectedEdgeId == -1) {
1178 const Cell edge(1, connectedEdgeId);
1179 vpath.push_back(edge);
1185 for(
int i = 0; i < 2; ++i) {
1187 triangulation.getEdgeVertex(connectedEdgeId, i, vertexId);
1189 if(vertexId != currentId) {
1190 currentId = vertexId;
1195 }
while(connectedEdgeId != -1);
1201template <
typename triangulationType>
1203 const Cell &saddle2,
1204 const Cell &saddle1,
1205 const std::vector<bool> &isVisited,
1206 std::vector<Cell> *
const vpath,
1207 const triangulationType &triangulation,
1208 const bool stopIfMultiConnected,
1209 const bool enableCycleDetector)
const {
1212 const SimplexId numberOfEdges = triangulation.getNumberOfEdges();
1213 std::vector<bool> isCycle;
1214 if(enableCycleDetector) {
1215 isCycle.resize(numberOfEdges,
false);
1220 if(vpath !=
nullptr) {
1221 vpath->push_back(saddle2);
1226 int nconnections = 0;
1227 for(
int i = 0; i < 3; ++i) {
1229 triangulation.getTriangleEdge(saddle2.
id_, i, edgeId);
1230 if(isVisited[edgeId]) {
1233 if(vpath !=
nullptr) {
1234 vpath->push_back(
Cell(1, edgeId));
1243 if(stopIfMultiConnected && nconnections > 1) {
1252 if(enableCycleDetector) {
1253 if(not isCycle[currentId]) {
1254 isCycle[currentId] =
true;
1256 this->
printErr(
"Cycle detected on the wall of 1-saddle "
1257 + std::to_string(saddle1.
id_));
1265 const Cell edge(1, currentId);
1266 if(vpath !=
nullptr) {
1267 vpath->push_back(edge);
1277 const Cell triangle(2, connectedTriangleId);
1278 if(vpath !=
nullptr) {
1279 vpath->push_back(triangle);
1286 int nconnections = 0;
1287 for(
int i = 0; i < 3; ++i) {
1289 triangulation.getTriangleEdge(connectedTriangleId, i, edgeId);
1291 if(isVisited[edgeId] and edgeId != oldId) {
1296 if(stopIfMultiConnected && nconnections > 1) {
1301 }
while(currentId != oldId);
1307template <
typename triangulationType>
1309 std::vector<Cell> &vpath,
1310 const triangulationType &triangulation,
1311 const bool enableCycleDetector)
const {
1313 const SimplexId numberOfCells = triangulation.getNumberOfCells();
1314 std::vector<bool> isCycle;
1315 if(enableCycleDetector) {
1316 isCycle.resize(numberOfCells,
false);
1320 if(cell.
dim_ == 2) {
1328 const Cell triangle(2, currentId);
1329 vpath.push_back(triangle);
1337 if(connectedEdgeId == -1) {
1342 const Cell edge(1, connectedEdgeId);
1343 vpath.push_back(edge);
1350 = triangulation.getEdgeStarNumber(connectedEdgeId);
1351 for(
SimplexId i = 0; i < starNumber; ++i) {
1353 triangulation.getEdgeStar(connectedEdgeId, i, starId);
1355 if(starId != currentId) {
1362 }
while(currentId != oldId);
1365 if(cell.
dim_ == 3) {
1372 if(enableCycleDetector) {
1373 if(not isCycle[currentId]) {
1374 isCycle[currentId] =
true;
1376 this->
printErr(
"cycle detected in the path from tetra "
1377 + std::to_string(cell.
id_));
1385 const Cell tetra(3, currentId);
1386 vpath.push_back(tetra);
1394 if(connectedTriangleId == -1) {
1399 const Cell triangle(2, connectedTriangleId);
1400 vpath.push_back(triangle);
1407 = triangulation.getTriangleStarNumber(connectedTriangleId);
1408 for(
SimplexId i = 0; i < starNumber; ++i) {
1410 triangulation.getTriangleStar(connectedTriangleId, i, starId);
1412 if(starId != currentId) {
1419 }
while(currentId != oldId);
1426template <
typename triangulationType>
1428 const Cell &saddle1,
1429 const Cell &saddle2,
1430 const std::vector<bool> &isVisited,
1431 std::vector<Cell> *
const vpath,
1432 const triangulationType &triangulation,
1433 const bool stopIfMultiConnected,
1434 const bool enableCycleDetector,
1435 bool *
const cycleFound)
const {
1438 const SimplexId numberOfTriangles = triangulation.getNumberOfTriangles();
1439 std::vector<bool> isCycle;
1440 if(enableCycleDetector) {
1441 isCycle.resize(numberOfTriangles,
false);
1446 if(vpath !=
nullptr) {
1447 vpath->push_back(saddle1);
1452 int nconnections = 0;
1454 = triangulation.getEdgeTriangleNumber(saddle1.
id_);
1455 for(
SimplexId i = 0; i < triangleNumber; ++i) {
1457 triangulation.getEdgeTriangle(saddle1.
id_, i, triangleId);
1458 if(isVisited[triangleId]) {
1461 if(vpath !=
nullptr) {
1462 vpath->push_back(
Cell(2, triangleId));
1467 currentId = triangleId;
1471 if(stopIfMultiConnected && nconnections > 1) {
1476 if(currentId == -1) {
1484 if(enableCycleDetector) {
1485 if(not isCycle[currentId]) {
1486 isCycle[currentId] =
true;
1491 this->
printErr(
"Cycle detected on the wall of 2-saddle "
1492 + std::to_string(saddle2.
id_));
1500 const Cell triangle(2, currentId);
1501 if(vpath !=
nullptr) {
1502 vpath->push_back(triangle);
1513 const Cell edge(1, connectedEdgeId);
1514 if(vpath !=
nullptr) {
1515 vpath->push_back(edge);
1522 int nconnections = 0;
1524 = triangulation.getEdgeTriangleNumber(connectedEdgeId);
1525 for(
SimplexId i = 0; i < triangleNumber; ++i) {
1527 triangulation.getEdgeTriangle(connectedEdgeId, i, triangleId);
1529 if(isVisited[triangleId] and triangleId != oldId) {
1530 currentId = triangleId;
1534 if(stopIfMultiConnected && nconnections > 1) {
1539 }
while(currentId != oldId);
1545template <
typename triangulationType>
1547 const Cell &cell,
const triangulationType &triangulation)
const {
1549 if(cell.
dim_ == 1) {
1554 std::queue<SimplexId> bfs;
1556 std::vector<bool> isVisited(triangulation.getNumberOfTriangles(),
false);
1559 while(!bfs.empty()) {
1560 const SimplexId triangleId = bfs.front();
1563 isVisited[triangleId] =
true;
1565 for(
int j = 0; j < 3; ++j) {
1567 triangulation.getTriangleEdge(triangleId, j, edgeId);
1572 if(triangleId == pairedCellId or pairedCellId == -1)
1575 if(isVisited[pairedCellId])
1578 bfs.push(pairedCellId);
1586template <
typename triangulationType>
1590 const triangulationType &triangulation,
1591 std::vector<Cell> *
const wall,
1592 std::vector<SimplexId> *
const saddles)
const {
1594 if(saddles !=
nullptr) {
1599 if(cell.
dim_ == 2) {
1603 std::queue<SimplexId> bfs;
1607 while(!bfs.empty()) {
1608 const SimplexId triangleId = bfs.front();
1616 if(wall !=
nullptr) {
1617 wall->push_back(
Cell(2, triangleId));
1620 for(
int j = 0; j < 3; ++j) {
1622 triangulation.getTriangleEdge(triangleId, j, edgeId);
1625 saddles->emplace_back(edgeId);
1631 if(pairedCellId != -1 and pairedCellId != triangleId) {
1632 bfs.push(pairedCellId);
1638 if(saddles !=
nullptr && saddles->size() > 1) {
1639 std::sort(saddles->begin(), saddles->end());
1640 const auto last = std::unique(saddles->begin(), saddles->end());
1641 saddles->erase(last, saddles->end());
1649template <
typename triangulationType>
1653 const triangulationType &triangulation,
1654 std::vector<Cell> *
const wall,
1655 std::vector<SimplexId> *
const saddles)
const {
1657 if(saddles !=
nullptr) {
1662 if(cell.
dim_ == 1) {
1666 std::queue<SimplexId> bfs;
1670 while(!bfs.empty()) {
1679 if(wall !=
nullptr) {
1680 wall->push_back(
Cell(1, edgeId));
1684 = triangulation.getEdgeTriangleNumber(edgeId);
1685 for(
SimplexId j = 0; j < triangleNumber; ++j) {
1687 triangulation.getEdgeTriangle(edgeId, j, triangleId);
1689 if((saddles !=
nullptr) and
isSaddle2(
Cell(2, triangleId))) {
1690 saddles->emplace_back(triangleId);
1696 if(pairedCellId != -1 and pairedCellId != edgeId) {
1697 bfs.push(pairedCellId);
1703 if(saddles !=
nullptr && saddles->size() > 1) {
1704 std::sort(saddles->begin(), saddles->end());
1705 const auto last = std::unique(saddles->begin(), saddles->end());
1706 saddles->erase(last, saddles->end());
1714template <
typename triangulationType>
1716 const std::vector<Cell> &vpath,
1717 const triangulationType &triangulation)
const {
1721 const SimplexId numberOfCellsInPath = vpath.size();
1722 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
1724 const SimplexId triangleId = vpath[i + 1].id_;
1726#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1727 for(
int k = 0; k < 3; ++k) {
1729 triangulation.getCellEdge(triangleId, k, tmp);
1731 (*gradient_)[3][triangleId] = k;
1735 for(
int k = 0; k < triangulation.getEdgeStarNumber(edgeId); ++k) {
1737 triangulation.getEdgeStar(edgeId, k, tmp);
1738 if(tmp == triangleId) {
1739 (*gradient_)[2][edgeId] = k;
1745 (*gradient_)[3][triangleId] = edgeId;
1746 (*gradient_)[2][edgeId] = triangleId;
1751 const SimplexId numberOfCellsInPath = vpath.size();
1752 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
1753 const SimplexId triangleId = vpath[i].id_;
1754 const SimplexId tetraId = vpath[i + 1].id_;
1756#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1757 for(
int k = 0; k < 4; ++k) {
1759 triangulation.getCellTriangle(tetraId, k, tmp);
1760 if(tmp == triangleId) {
1761 (*gradient_)[5][tetraId] = k;
1765 for(
int k = 0; k < triangulation.getTriangleStarNumber(triangleId); ++k) {
1767 triangulation.getTriangleStar(triangleId, k, tmp);
1768 if(tmp == tetraId) {
1769 (*gradient_)[4][triangleId] = k;
1774 (*gradient_)[5][tetraId] = triangleId;
1775 (*gradient_)[4][triangleId] = tetraId;
1783template <
typename triangulationType>
1785 const std::vector<Cell> &vpath,
1786 const triangulationType &triangulation)
const {
1789 for(
size_t i = 0; i < vpath.size(); i += 2) {
1791 const SimplexId vertId = vpath[i + 1].id_;
1793#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1794 const auto nneighs = triangulation.getVertexEdgeNumber();
1795 for(
int k = 0; k < nneighs; ++k) {
1797 triangulation.getVertexEdge(vertId, k, tmp);
1799 (*gradient_)[0][vertId] = k;
1803 const auto nverts = triangulation.getEdgeStarNumber(edgeId);
1804 for(
int k = 0; k < nverts; ++k) {
1806 triangulation.getEdgeVertex(edgeId, k, tmp);
1808 (*gradient_)[1][edgeId] = k;
1814 (*gradient_)[0][vertId] = edgeId;
1815 (*gradient_)[1][edgeId] = vertId;
1822template <
typename triangulationType>
1824 const std::vector<Cell> &vpath,
1825 const triangulationType &triangulation,
1826 bool cancelReversal)
const {
1830 if(cancelReversal) {
1835 if(vpath.size() <= 1)
1837 (*gradient_)[3][vpath[vpath.size() - 1].id_] =
NULL_GRADIENT;
1839 const SimplexId numberOfCellsInPath = vpath.size();
1840 const SimplexId startIndex = (cancelReversal ? 2 : 0);
1841 for(
SimplexId i = startIndex; i < numberOfCellsInPath; i += 2) {
1843 const SimplexId vpathTriangleIndex = (cancelReversal ? i - 1 : i + 1);
1844 const SimplexId edgeId = vpath[vpathEdgeIndex].id_;
1845 const SimplexId triangleId = vpath[vpathTriangleIndex].id_;
1847#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1848 for(
int k = 0; k < 3; ++k) {
1850 triangulation.getTriangleEdge(triangleId, k, tmp);
1852 (*gradient_)[3][triangleId] = k;
1856 for(
int k = 0; k < triangulation.getEdgeTriangleNumber(edgeId); ++k) {
1858 triangulation.getEdgeTriangle(edgeId, k, tmp);
1859 if(tmp == triangleId) {
1860 (*gradient_)[2][edgeId] = k;
1866 (*gradient_)[3][triangleId] = edgeId;
1867 (*gradient_)[2][edgeId] = triangleId;
1875template <
typename triangulationType>
1877 const std::vector<Cell> &vpath,
1878 const triangulationType &triangulation)
const {
1882 const SimplexId numberOfCellsInPath = vpath.size();
1883 for(
SimplexId i = 0; i < numberOfCellsInPath; i += 2) {
1884 const SimplexId triangleId = vpath[i].id_;
1885 const SimplexId edgeId = vpath[i + 1].id_;
1887#ifdef TTK_ENABLE_DCG_OPTIMIZE_MEMORY
1888 for(
int k = 0; k < 3; ++k) {
1890 triangulation.getTriangleEdge(triangleId, k, tmp);
1892 (*gradient_)[3][triangleId] = k;
1896 for(
int k = 0; k < triangulation.getEdgeTriangleNumber(edgeId); ++k) {
1898 triangulation.getEdgeTriangle(edgeId, k, tmp);
1899 if(tmp == triangleId) {
1900 (*gradient_)[2][edgeId] = k;
1906 (*gradient_)[2][edgeId] = triangleId;
1907 (*gradient_)[3][triangleId] = edgeId;
1915template <
typename triangulationType>
1917 const Cell c,
const triangulationType &triangulation)
const {
1921 auto cellDim = c.
dim_;
1922 auto cellId = c.
id_;
1929 else if(cellDim == 1) {
1932 triangulation.getEdgeVertex(cellId, 0, v0);
1933 triangulation.getEdgeVertex(cellId, 1, v1);
1935 if(offsets[v0] > offsets[v1]) {
1942 else if(cellDim == 2) {
1944 triangulation.getTriangleVertex(cellId, 0, v0);
1945 triangulation.getTriangleVertex(cellId, 1, v1);
1946 triangulation.getTriangleVertex(cellId, 2, v2);
1947 if(offsets[v0] > offsets[v1] && offsets[v0] > offsets[v2]) {
1949 }
else if(offsets[v1] > offsets[v0] && offsets[v1] > offsets[v2]) {
1956 else if(cellDim == 3) {
1958 triangulation.getCellVertex(cellId, 0, v0);
1959 triangulation.getCellVertex(cellId, 1, v1);
1960 triangulation.getCellVertex(cellId, 2, v2);
1961 triangulation.getCellVertex(cellId, 3, v3);
1962 if(offsets[v0] > offsets[v1] && offsets[v0] > offsets[v2]
1963 && offsets[v0] > offsets[v3]) {
1965 }
else if(offsets[v1] > offsets[v0] && offsets[v1] > offsets[v2]
1966 && offsets[v1] > offsets[v3]) {
1968 }
else if(offsets[v2] > offsets[v0] && offsets[v2] > offsets[v1]
1969 && offsets[v2] > offsets[v3]) {
1978template <
typename triangulationType>
1980 const Cell c,
const triangulationType &triangulation)
const {
1984 auto cellDim = c.
dim_;
1985 auto cellId = c.
id_;
1992 else if(cellDim == 1) {
1995 triangulation.getEdgeVertex(cellId, 0, v0);
1996 triangulation.getEdgeVertex(cellId, 1, v1);
1998 if(offsets[v0] < offsets[v1]) {
2005 else if(cellDim == 2) {
2007 triangulation.getTriangleVertex(cellId, 0, v0);
2008 triangulation.getTriangleVertex(cellId, 1, v1);
2009 triangulation.getTriangleVertex(cellId, 2, v2);
2010 if(offsets[v0] < offsets[v1] && offsets[v0] < offsets[v2]) {
2012 }
else if(offsets[v1] < offsets[v0] && offsets[v1] < offsets[v2]) {
2019 else if(cellDim == 3) {
2021 triangulation.getCellVertex(cellId, 0, v0);
2022 triangulation.getCellVertex(cellId, 1, v1);
2023 triangulation.getCellVertex(cellId, 2, v2);
2024 triangulation.getCellVertex(cellId, 3, v3);
2025 if(offsets[v0] < offsets[v1] && offsets[v0] < offsets[v2]
2026 && offsets[v0] < offsets[v3]) {
2028 }
else if(offsets[v1] < offsets[v0] && offsets[v1] < offsets[v2]
2029 && offsets[v1] < offsets[v3]) {
2031 }
else if(offsets[v2] < offsets[v0] && offsets[v2] < offsets[v1]
2032 && offsets[v2] < offsets[v3]) {
2041template <
typename triangulationType>
2043 std::vector<std::array<float, 3>> &points,
2044 std::vector<char> &points_pairOrigins,
2045 std::vector<char> &cells_pairTypes,
2046 std::vector<SimplexId> &cellIds,
2047 std::vector<char> &cellDimensions,
2048 const triangulationType &triangulation)
const {
2053 std::vector<size_t> nGlyphsPerDim(nDims);
2055#ifdef TTK_ENABLE_OPENMP
2056#pragma omp parallel for num_threads(threadNumber_)
2058 for(
int i = 0; i < nDims - 1; ++i) {
2068 std::vector<size_t> offsets(nDims + 1);
2070 offsets[i + 1] = offsets[i] + nGlyphsPerDim[i];
2074 const auto nGlyphs = offsets.back();
2077 points.resize(2 * nGlyphs);
2078 points_pairOrigins.resize(2 * nGlyphs);
2079 cells_pairTypes.resize(nGlyphs);
2080 cellIds.resize(2 * nGlyphs);
2081 cellDimensions.resize(2 * nGlyphs);
2083#ifdef TTK_ENABLE_OPENMP
2084#pragma omp parallel for num_threads(threadNumber_)
2086 for(
int i = 0; i < nDims - 1; ++i) {
2088 size_t nProcessedGlyphs{offsets[i]};
2093 const Cell pc{i + 1, pcid};
2094 triangulation.getCellIncenter(
2095 c.id_, c.dim_, points[2 * nProcessedGlyphs].data());
2096 triangulation.getCellIncenter(
2097 pc.id_, pc.dim_, points[2 * nProcessedGlyphs + 1].data());
2098 points_pairOrigins[2 * nProcessedGlyphs] = 0;
2099 points_pairOrigins[2 * nProcessedGlyphs + 1] = 1;
2100 cells_pairTypes[nProcessedGlyphs] = i;
2101#ifdef TTK_ENABLE_MPI
2103 triangulation.getDistributedGlobalCellId(j, i, globalId);
2104 cellIds[2 * nProcessedGlyphs + 0] = globalId;
2105 triangulation.getDistributedGlobalCellId(pcid, i + 1, globalId);
2106 cellIds[2 * nProcessedGlyphs + 1] = globalId;
2108 cellIds[2 * nProcessedGlyphs + 0] = j;
2109 cellIds[2 * nProcessedGlyphs + 1] = pcid;
2111 cellDimensions[2 * nProcessedGlyphs + 0] = i;
2112 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
int buildGradient(const triangulationType &triangulation, bool bypassCache=false, const std::vector< bool > *updateMask=nullptr)
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 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_
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)