TTK
Loading...
Searching...
No Matches
ExplicitTriangulation.cpp
Go to the documentation of this file.
2
3#include <OneSkeleton.h>
4#include <ThreeSkeleton.h>
5#include <TwoSkeleton.h>
6#include <ZeroSkeleton.h>
7
8#include <cstring>
9#include <numeric>
10
11using namespace ttk;
12
14
15 setDebugMsgPrefix("ExplicitTriangulation");
16
17 clear();
18}
19
21
23 vertexNumber_ = 0;
24 cellNumber_ = 0;
25 doublePrecision_ = false;
26
27 printMsg("Triangulation cleared.", debug::Priority::DETAIL);
28
30}
31
32size_t ExplicitTriangulation::footprint(size_t size) const {
33
34 const auto printArrayFootprint
35 = [this](const FlatJaggedArray &array, const std::string &name) {
36 if(!array.empty() && !name.empty()) {
37 this->printMsg(name + std::string{": "}
38 + std::to_string(array.footprint()) + " bytes");
39 }
40 return array.footprint();
41 };
42
43 size += printArrayFootprint(vertexNeighborData_, "vertexNeighborData_");
44 size += printArrayFootprint(cellNeighborData_, "cellNeighborData_");
45 size += printArrayFootprint(vertexEdgeData_, "vertexEdgeData_");
46 size += printArrayFootprint(vertexTriangleData_, "vertexTriangleData_");
47 size += printArrayFootprint(edgeTriangleData_, "edgeTriangleData_");
48 size += printArrayFootprint(vertexStarData_, "vertexStarData_");
49 size += printArrayFootprint(edgeStarData_, "edgeStarData_");
50 size += printArrayFootprint(triangleStarData_, "triangleStarData_");
51 size += printArrayFootprint(vertexLinkData_, "vertexLinkData_");
52 size += printArrayFootprint(edgeLinkData_, "edgeLinkData_");
53 size += printArrayFootprint(triangleLinkData_, "triangleLinkData_");
54
56}
57
59
60 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
61#ifdef TTK_ENABLE_MPI
62 if(!(ttk::isRunningWithMPI()))
63#endif
64 this->printErr("Empty dataset, precondition skipped");
65 return 1;
66 }
67
68 if((!boundaryEdges_.empty()) && (boundaryEdges_.size() == edgeList_.size())) {
69 return 0;
70 }
71
72 Timer tm{};
73
75 boundaryEdges_.resize(edgeList_.size(), false);
76
77 if(getDimensionality() == 2) {
79 for(SimplexId i = 0; i < (SimplexId)edgeStarData_.size(); i++) {
80 if(edgeStarData_[i].size() == 1) {
81 boundaryEdges_[i] = true;
82 }
83 }
84 } else if(getDimensionality() == 3) {
87
88 for(size_t i = 0; i < triangleStarData_.size(); i++) {
89 if(triangleStarData_[i].size() == 1) {
90 for(int j = 0; j < 3; j++) {
92 }
93 }
94 }
95 } else {
96 // unsupported dimension
97 printErr("Unsupported dimension for edge boundary precondition");
98 return -1;
99 }
100
101#ifdef TTK_ENABLE_MPI
102
103 if(ttk::isRunningWithMPI()) {
104 ttk::SimplexId edgeNumber = edgeList_.size();
105 std::vector<unsigned char> charBoundary(edgeNumber, false);
106 for(int i = 0; i < edgeNumber; ++i) {
107 charBoundary[i] = boundaryEdges_[i] ? '1' : '0';
108 }
109 ttk::exchangeGhostDataWithoutTriangulation(
110 charBoundary.data(),
111 [this](const SimplexId a) { return this->edgeRankArray_[a]; },
112 [this](const SimplexId a) { return this->edgeLidToGid_[a]; },
113 [this](const SimplexId a) { return this->edgeGidToLid_[a]; }, edgeNumber,
114 ttk::MPIcomm_, this->getNeighborRanks());
115 for(int i = 0; i < edgeNumber; ++i) {
116 boundaryEdges_[i] = (charBoundary[i] == '1');
117 }
118 }
119
120#endif // TTK_ENABLE_MPI
121
122 this->printMsg("Extracted boundary edges", 1.0, tm.getElapsedTime(), 1);
123
124 return 0;
125}
126
127#ifdef TTK_ENABLE_MPI
128
129int ExplicitTriangulation::preconditionVertexRankArray() {
130 if(vertexRankArray_.size() == 0) {
131 this->vertexRankArray_.resize(this->vertexNumber_, 0);
132 if(ttk::isRunningWithMPI()) {
133 ttk::produceRankArray(this->vertexRankArray_, this->vertGid_,
134 this->vertexGhost_, this->vertexNumber_,
135 this->boundingBox_.data(), this->neighborRanks_);
136 ttk::preconditionNeighborsUsingRankArray<ttk::SimplexId>(
137 this->neighborRanks_,
138 [this](const ttk::SimplexId a) { return this->getVertexRank(a); },
139 this->vertexNumber_, ttk::MPIcomm_);
140 }
141 }
142 return 0;
143}
144
145int ExplicitTriangulation::preconditionCellRankArray() {
146 if(cellRankArray_.size() == 0) {
147 this->cellRankArray_.resize(this->cellNumber_, 0);
148 if(ttk::isRunningWithMPI()) {
149 ttk::produceRankArray(this->cellRankArray_, this->cellGid_,
150 this->cellGhost_, this->cellNumber_,
151 this->boundingBox_.data(), this->neighborRanks_);
152 }
153 }
154 return 0;
155}
156
157int ExplicitTriangulation::preconditionEdgeRankArray() {
158 ttk::SimplexId edgeNumber = this->getNumberOfEdgesInternal();
159 edgeRankArray_.resize(edgeNumber, 0);
160 if(ttk::isRunningWithMPI()) {
161 ttk::SimplexId min_id;
162 for(ttk::SimplexId id = 0; id < edgeNumber; id++) {
163 this->TTK_TRIANGULATION_INTERNAL(getEdgeStar)(id, 0, min_id);
164 const auto nStar{this->TTK_TRIANGULATION_INTERNAL(getEdgeStarNumber)(id)};
165 for(SimplexId i = 1; i < nStar; ++i) {
166 SimplexId sid{-1};
167 this->TTK_TRIANGULATION_INTERNAL(getEdgeStar)(id, i, sid);
168 // rule: an edge is owned by the cell in its star with the
169 // lowest global id
170 if(this->cellGid_[sid] < this->cellGid_[min_id]) {
171 min_id = sid;
172 }
173 }
174 edgeRankArray_[id] = cellRankArray_[min_id];
175 }
176 }
177 return 0;
178}
179
180int ExplicitTriangulation::preconditionTriangleRankArray() {
181 ttk::SimplexId triangleNumber = this->getNumberOfTrianglesInternal();
182 triangleRankArray_.resize(triangleNumber, 0);
183 if(ttk::isRunningWithMPI()) {
184 ttk::SimplexId min_id;
185 for(ttk::SimplexId id = 0; id < triangleNumber; id++) {
186 this->TTK_TRIANGULATION_INTERNAL(getTriangleStar)(id, 0, min_id);
187 const auto nStar{
189 for(SimplexId i = 1; i < nStar; ++i) {
190 SimplexId sid{-1};
192 // rule: an triangle is owned by the cell in its star with the
193 // lowest global id
194 if(this->cellGid_[sid] < this->cellGid_[min_id]) {
195 min_id = sid;
196 }
197 }
198 triangleRankArray_[id] = cellRankArray_[min_id];
199 }
200 }
201 return 0;
202}
203
204#endif // TTK_ENABLE_MPI
205
207
208 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
209#ifdef TTK_ENABLE_MPI
210 if(!(ttk::isRunningWithMPI()))
211#endif
212 this->printErr("Empty dataset, precondition skipped");
213 return 1;
214 }
215
216 if(getDimensionality() == 2)
217 return 0;
218
219 Timer tm{};
220
221 if((!boundaryTriangles_.empty())
222 && (boundaryTriangles_.size() == triangleList_.size())) {
223 return 0;
224 }
225
227 boundaryTriangles_.resize(triangleList_.size(), false);
228
229 if(getDimensionality() == 3) {
231
232 for(size_t i = 0; i < triangleStarData_.size(); i++) {
233 if(triangleStarData_[i].size() == 1) {
234 boundaryTriangles_[i] = true;
235 }
236 }
237 } else {
238 // unsupported dimension
239 printErr("Unsupported dimension for triangle boundary precondition");
240 return -1;
241 }
242
243#ifdef TTK_ENABLE_MPI
244
245 if(ttk::isRunningWithMPI()) {
246 ttk::SimplexId triangleNumber = triangleList_.size();
247 std::vector<unsigned char> charBoundary(triangleNumber, false);
248 for(int i = 0; i < triangleNumber; ++i) {
249 charBoundary[i] = boundaryTriangles_[i] ? '1' : '0';
250 }
251 ttk::exchangeGhostDataWithoutTriangulation(
252 charBoundary.data(),
253 [this](const SimplexId a) { return this->triangleRankArray_[a]; },
254 [this](const SimplexId a) { return this->triangleLidToGid_[a]; },
255 [this](const SimplexId a) { return this->triangleGidToLid_[a]; },
256 triangleNumber, ttk::MPIcomm_, this->getNeighborRanks());
257 for(int i = 0; i < triangleNumber; ++i) {
258 boundaryTriangles_[i] = (charBoundary[i] == '1');
259 }
260 }
261
262#endif // TTK_ENABLE_MPI
263
264 this->printMsg("Extracted boundary triangles", 1.0, tm.getElapsedTime(), 1);
265
266 return 0;
267}
268
270
271 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
272#ifdef TTK_ENABLE_MPI
273 if(!(ttk::isRunningWithMPI()))
274#endif
275 this->printErr("Empty dataset, precondition skipped");
276 return 1;
277 }
278
279 if((!boundaryVertices_.empty())
280 && ((SimplexId)boundaryVertices_.size() == vertexNumber_))
281 return 0;
282
283 Timer tm{};
284
285 boundaryVertices_.resize(vertexNumber_, false);
286
287 // create the list of boundary elements
288 // create their star
289 // look for singletons
290 if(getDimensionality() == 1) {
292 for(size_t i = 0; i < vertexStarData_.size(); i++) {
293 if(vertexStarData_[i].size() == 1) {
294 boundaryVertices_[i] = true;
295 }
296 }
297 } else if(getDimensionality() == 2) {
300
301 for(SimplexId i = 0; i < (SimplexId)edgeStarData_.size(); i++) {
302 if(edgeStarData_[i].size() == 1) {
303 boundaryVertices_[edgeList_[i][0]] = true;
304 boundaryVertices_[edgeList_[i][1]] = true;
305 }
306 }
307 } else if(getDimensionality() == 3) {
310
311 for(size_t i = 0; i < triangleStarData_.size(); i++) {
312 if(triangleStarData_[i].size() == 1) {
313 boundaryVertices_[triangleList_[i][0]] = true;
314 boundaryVertices_[triangleList_[i][1]] = true;
315 boundaryVertices_[triangleList_[i][2]] = true;
316 }
317 }
318 } else {
319 // unsupported dimension
320 printErr("Unsupported dimension for vertex boundary precondition");
321 return -1;
322 }
323
324#ifdef TTK_ENABLE_MPI
325
326 if(ttk::isRunningWithMPI()) {
327 this->preconditionDistributedVertices();
328 std::vector<unsigned char> charBoundary(vertexNumber_, false);
329 for(int i = 0; i < vertexNumber_; ++i) {
330 charBoundary[i] = boundaryVertices_[i] ? '1' : '0';
331 }
332 ttk::exchangeGhostVertices<unsigned char, ExplicitTriangulation>(
333 charBoundary.data(), this, ttk::MPIcomm_);
334
335 for(int i = 0; i < vertexNumber_; ++i) {
336 if(vertexRankArray_[i] != ttk::MPIrank_) {
337 boundaryVertices_[i] = (charBoundary[i] == '1');
338 }
339 }
340 }
341
342#endif // TTK_ENABLE_MPI
343
344 this->printMsg("Extracted boundary vertices", 1.0, tm.getElapsedTime(), 1);
345
346 return 0;
347}
348
350
351 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
352#ifdef TTK_ENABLE_MPI
353 if(!(ttk::isRunningWithMPI()))
354#endif
355 this->printErr("Empty dataset, precondition skipped");
356 return 1;
357 }
358
359 if((tetraEdgeList_.empty() && getDimensionality() == 3)
360 || (triangleEdgeList_.empty() && getDimensionality() == 2)) {
362 }
363
364 return 0;
365}
366
368
369 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
370#ifdef TTK_ENABLE_MPI
371 if(!(ttk::isRunningWithMPI()))
372#endif
373 this->printErr("Empty dataset, precondition skipped");
374 return 1;
375 }
376
377 if(cellNeighborData_.empty()) {
378 if(getDimensionality() == 3) {
379 ThreeSkeleton threeSkeleton;
380 threeSkeleton.setWrapper(this);
382 vertexNumber_, *cellArray_, cellNeighborData_, &triangleStarData_);
383 } else if(getDimensionality() == 2) {
385 TwoSkeleton twoSkeleton;
386 twoSkeleton.setWrapper(this);
387 twoSkeleton.buildCellNeighborsFromEdges(
388 *cellArray_, cellNeighborData_, edgeStarData_);
389 }
390 }
391
392 return 0;
393}
394
396
397 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
398#ifdef TTK_ENABLE_MPI
399 if(!(ttk::isRunningWithMPI()))
400#endif
401 this->printErr("Empty dataset, precondition skipped");
402 return 1;
403 }
404
405 if(tetraTriangleList_.empty()) {
406
407 TwoSkeleton twoSkeleton;
408 twoSkeleton.setWrapper(this);
409
410 if(triangleList_.size()) {
411 // we already computed this guy, let's just get the cell triangles
412 if(!triangleStarData_.empty()) {
413 return twoSkeleton.buildTriangleList(
414 vertexNumber_, *cellArray_, nullptr, nullptr, &tetraTriangleList_);
415 } else {
416 // let's compute the triangle star while we're at it...
417 // it's just a tiny overhead.
418 return twoSkeleton.buildTriangleList(vertexNumber_, *cellArray_,
419 nullptr, &triangleStarData_,
421 }
422 } else {
423 // we have not computed this guy, let's do it while we're at it
424 if(!triangleStarData_.empty()) {
425 return twoSkeleton.buildTriangleList(vertexNumber_, *cellArray_,
426 &triangleList_, nullptr,
428 } else {
429 // let's compute the triangle star while we're at it...
430 // it's just a tiny overhead.
431 return twoSkeleton.buildTriangleList(vertexNumber_, *cellArray_,
432 &triangleList_, &triangleStarData_,
434 }
435 }
436 }
437
438 return 0;
439}
440
442
443 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
444#ifdef TTK_ENABLE_MPI
445 if(!(ttk::isRunningWithMPI()))
446#endif
447 this->printErr("Empty dataset, precondition skipped");
448 return 1;
449 }
450
451 if(edgeList_.empty()) {
452 OneSkeleton oneSkeleton;
453 oneSkeleton.setWrapper(this);
454 // also computes edgeStar and triangleEdge / tetraEdge lists for free...
455 int ret{};
456 if(getDimensionality() == 1) {
457 std::vector<std::array<SimplexId, 1>> tmp{};
458 return oneSkeleton.buildEdgeList<1>(
459 vertexNumber_, *cellArray_, edgeList_, edgeStarData_, tmp);
460 } else if(getDimensionality() == 2) {
461 ret = oneSkeleton.buildEdgeList(vertexNumber_, *cellArray_, edgeList_,
462 edgeStarData_, triangleEdgeList_);
463 } else if(getDimensionality() == 3) {
464 ret = oneSkeleton.buildEdgeList(
465 vertexNumber_, *cellArray_, edgeList_, edgeStarData_, tetraEdgeList_);
466 }
467
468 if(ret != 0) {
469 return ret;
470 }
471
472#ifdef TTK_ENABLE_MPI
473 if(this->getDimensionality() == 2 || this->getDimensionality() == 3) {
474 return this->preconditionDistributedEdges();
475 }
476#endif // TTK_ENABLE_MPI
477 }
478
479 return 0;
480}
481
483
484 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
485#ifdef TTK_ENABLE_MPI
486 if(!(ttk::isRunningWithMPI()))
487#endif
488 this->printErr("Empty dataset, precondition skipped");
489 return 1;
490 }
491
492 if(edgeLinkData_.empty()) {
493
494 if(getDimensionality() == 2) {
497
498 OneSkeleton oneSkeleton;
499 oneSkeleton.setWrapper(this);
500 return oneSkeleton.buildEdgeLinks(
501 edgeList_, edgeStarData_, *cellArray_, edgeLinkData_);
502 } else if(getDimensionality() == 3) {
506
507 OneSkeleton oneSkeleton;
508 oneSkeleton.setWrapper(this);
509 return oneSkeleton.buildEdgeLinks(
510 edgeList_, edgeStarData_, tetraEdgeList_, edgeLinkData_);
511 } else {
512 // unsupported dimension
513 printErr("Unsupported dimension for edge link precondition");
514 return -1;
515 }
516 }
517
518 return 0;
519}
520
522
523 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
524#ifdef TTK_ENABLE_MPI
525 if(!(ttk::isRunningWithMPI()))
526#endif
527 this->printErr("Empty dataset, precondition skipped");
528 return 1;
529 }
530
531 if(edgeStarData_.empty()) {
533 }
534 return 0;
535}
536
538
539 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
540#ifdef TTK_ENABLE_MPI
541 if(!(ttk::isRunningWithMPI()))
542#endif
543 this->printErr("Empty dataset, precondition skipped");
544 return 1;
545 }
546
547 if(edgeTriangleData_.empty()) {
550
551 TwoSkeleton twoSkeleton;
552 twoSkeleton.setWrapper(this);
553 return twoSkeleton.buildEdgeTriangles(vertexNumber_, *cellArray_,
554 edgeTriangleData_, edgeList_,
556 }
557
558 return 0;
559}
560
562
563 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
564#ifdef TTK_ENABLE_MPI
565 if(!(ttk::isRunningWithMPI()))
566#endif
567 this->printErr("Empty dataset, precondition skipped");
568 return 1;
569 }
570
571 if(triangleList_.empty()) {
572
573 TwoSkeleton twoSkeleton;
574 twoSkeleton.setWrapper(this);
575
576 twoSkeleton.buildTriangleList(vertexNumber_, *cellArray_, &triangleList_,
577 &triangleStarData_, &tetraTriangleList_);
578
579#ifdef TTK_ENABLE_MPI
580 this->preconditionDistributedTriangles();
581#endif // TTK_ENABLE_MPI
582 }
583
584 return 0;
585}
586
588
589 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
590#ifdef TTK_ENABLE_MPI
591 if(!(ttk::isRunningWithMPI()))
592#endif
593 this->printErr("Empty dataset, precondition skipped");
594 return 1;
595 }
596
597 if(triangleEdgeList_.empty()) {
599
600 // WARNING
601 // here triangleStarList and cellTriangleList will be computed (for
602 // free) although they are not requireed to get the edgeTriangleList.
603 // if memory usage is an issue, please change these pointers by nullptr.
604
605 TwoSkeleton twoSkeleton;
606 twoSkeleton.setWrapper(this);
607
608 return twoSkeleton.buildTriangleEdgeList(
609 vertexNumber_, *cellArray_, triangleEdgeList_, edgeList_,
610 &vertexEdgeData_, &triangleList_, &triangleStarData_,
612 }
613
614 return 0;
615}
616
618
619 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
620#ifdef TTK_ENABLE_MPI
621 if(!(ttk::isRunningWithMPI()))
622#endif
623 this->printErr("Empty dataset, precondition skipped");
624 return 1;
625 }
626
627 if(triangleLinkData_.empty()) {
628
630
631 TwoSkeleton twoSkeleton;
632 twoSkeleton.setWrapper(this);
633 return twoSkeleton.buildTriangleLinks(
634 triangleList_, triangleStarData_, *cellArray_, triangleLinkData_);
635 }
636
637 return 0;
638}
639
641
642 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
643#ifdef TTK_ENABLE_MPI
644 if(!(ttk::isRunningWithMPI()))
645#endif
646 this->printErr("Empty dataset, precondition skipped");
647 return 1;
648 }
649
650 if(triangleStarData_.empty()) {
651
652 TwoSkeleton twoSkeleton;
653 twoSkeleton.setWrapper(this);
654 return twoSkeleton.buildTriangleList(
655 vertexNumber_, *cellArray_, &triangleList_, &triangleStarData_);
656 }
657
658 return 0;
659}
660
662
663 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
664#ifdef TTK_ENABLE_MPI
665 if(!(ttk::isRunningWithMPI()))
666#endif
667 this->printErr("Empty dataset, precondition skipped");
668 return 1;
669 }
670
671 if((SimplexId)vertexEdgeData_.size() != vertexNumber_) {
672 ZeroSkeleton zeroSkeleton;
673
674 if(edgeList_.empty()) {
676 }
677
678 zeroSkeleton.setWrapper(this);
679 return zeroSkeleton.buildVertexEdges(
680 vertexNumber_, edgeList_, vertexEdgeData_);
681 }
682 return 0;
683}
684
686
687 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
688#ifdef TTK_ENABLE_MPI
689 if(!(ttk::isRunningWithMPI()))
690#endif
691 this->printErr("Empty dataset, precondition skipped");
692 return 1;
693 }
694
695 if((SimplexId)vertexLinkData_.size() != vertexNumber_) {
696
697 if(getDimensionality() == 2) {
700
701 ZeroSkeleton zeroSkeleton;
702 zeroSkeleton.setWrapper(this);
703 return zeroSkeleton.buildVertexLinks(
704 vertexStarData_, triangleEdgeList_, edgeList_, vertexLinkData_);
705 } else if(getDimensionality() == 3) {
708
709 ZeroSkeleton zeroSkeleton;
710 zeroSkeleton.setWrapper(this);
711 return zeroSkeleton.buildVertexLinks(
712 vertexStarData_, tetraTriangleList_, triangleList_, vertexLinkData_);
713 } else {
714 // unsupported dimension
715 printErr("Unsupported dimension for vertex link precondition");
716 return -1;
717 }
718 }
719 return 0;
720}
721
723
724 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
725#ifdef TTK_ENABLE_MPI
726 if(!(ttk::isRunningWithMPI()))
727#endif
728 this->printErr("Empty dataset, precondition skipped");
729 return 1;
730 }
731
732 if((SimplexId)vertexNeighborData_.size() != vertexNumber_) {
734 ZeroSkeleton zeroSkeleton;
735 zeroSkeleton.setWrapper(this);
736 return zeroSkeleton.buildVertexNeighbors(
737 vertexNumber_, vertexNeighborData_, edgeList_);
738 }
739 return 0;
740}
741
743
744 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
745#ifdef TTK_ENABLE_MPI
746 if(!(ttk::isRunningWithMPI()))
747#endif
748 this->printErr("Empty dataset, precondition skipped");
749 return 1;
750 }
751
752 if((SimplexId)vertexStarData_.size() != vertexNumber_) {
753 ZeroSkeleton zeroSkeleton;
754 zeroSkeleton.setWrapper(this);
755
756 return zeroSkeleton.buildVertexStars(
757 vertexNumber_, *cellArray_, vertexStarData_);
758 }
759 return 0;
760}
761
763
764 if(this->cellArray_ == nullptr || this->vertexNumber_ == 0) {
765#ifdef TTK_ENABLE_MPI
766 if(!(ttk::isRunningWithMPI()))
767#endif
768 this->printErr("Empty dataset, precondition skipped");
769 return 1;
770 }
771
772 if((SimplexId)vertexTriangleData_.size() != vertexNumber_) {
773
775
776 TwoSkeleton twoSkeleton;
777 twoSkeleton.setWrapper(this);
778
779 twoSkeleton.buildVertexTriangles(
780 vertexNumber_, triangleList_, vertexTriangleData_);
781 }
782
783 return 0;
784}
785
787
788 // quick check by numbering (d-1)-simplices star
789 FlatJaggedArray *simplexStar{};
790
791 if(this->getDimensionality() == 3) {
792 this->preconditionTriangleStarsInternal();
793 simplexStar = &this->triangleStarData_;
794 } else if(this->getDimensionality() == 2) {
795 this->preconditionEdgeStarsInternal();
796 simplexStar = &this->edgeStarData_;
797 } else if(this->getDimensionality() == 1) {
798 this->preconditionVertexStarsInternal();
799 simplexStar = &this->vertexStarData_;
800 }
801
802 if(simplexStar == nullptr) {
803 return 0;
804 }
805
806 for(const auto star : *simplexStar) {
807 if(star.size() < 1 || star.size() > 2) {
808 this->isManifold_ = false;
809 this->printWrn("Non manifold data-set detected");
810 break;
811 }
812 }
813
814 return 0;
815}
816
817#ifdef TTK_ENABLE_MPI
818
819int ExplicitTriangulation::preconditionDistributedCells() {
820 if(this->hasPreconditionedDistributedCells_) {
821 return 0;
822 }
823 if(!ttk::hasInitializedMPI()) {
824 return -1;
825 }
826 if(this->cellGid_ == nullptr) {
827 this->printErr("Missing global cell identifiers array!");
828 return -2;
829 }
830
831 Timer tm{};
832
833 this->preconditionCellRankArray();
834
835 // number of local cells (with ghost cells...)
836 const auto nLocCells{this->getNumberOfCells()};
837
838 // global cell id -> local cell id (reverse of this->cellGid_)
839 this->cellGidToLid_.reserve(nLocCells);
840 for(LongSimplexId lcid = 0; lcid < nLocCells; ++lcid) {
841 this->cellGidToLid_[this->cellGid_[lcid]] = lcid;
842 }
843
844 this->preconditionExchangeGhostCells();
845
846 this->preconditionDistributedCellRanges();
847
848 this->hasPreconditionedDistributedCells_ = true;
849
850 if(ttk::MPIrank_ == 0) {
851 this->printMsg("Domain contains "
852 + std::to_string(this->gatheredCellRanges_.back().end + 1)
853 + " cells",
854 1.0, tm.getElapsedTime(), this->threadNumber_);
855 }
856
857 return 0;
858}
859
860int ttk::ExplicitTriangulation::preconditionExchangeGhostCells() {
861
862 if(this->hasPreconditionedExchangeGhostCells_) {
863 return 0;
864 }
865 if(!ttk::hasInitializedMPI()) {
866 return -1;
867 }
868 if(this->cellGid_ == nullptr) {
869 this->printErr("Missing global cell identifiers array!");
870 return -2;
871 }
872
873 this->ghostCellsPerOwner_.resize(ttk::MPIsize_);
874
875 // number of local cells (with ghost cells...)
876 const auto nLocCells{this->getNumberOfCells()};
877
878 for(LongSimplexId lcid = 0; lcid < nLocCells; ++lcid) {
879 if(this->cellRankArray_[lcid] != ttk::MPIrank_) {
880 // store ghost cell global ids (per rank)
881 this->ghostCellsPerOwner_[this->cellRankArray_[lcid]].emplace_back(
882 this->cellGid_[lcid]);
883 }
884 }
885
886 // for each rank, store the global id of local cells that are ghost cells of
887 // other ranks.
888 const auto MIT{ttk::getMPIType(ttk::SimplexId{})};
889 this->remoteGhostCells_.resize(ttk::MPIsize_);
890 // number of owned cells that are ghost cells of other ranks
891 std::vector<size_t> nOwnedGhostCellsPerRank(ttk::MPIsize_);
892
893 for(const auto neigh : this->neighborRanks_) {
894 // 1. send to neigh number of ghost cells owned by neigh
895 const auto nCells{this->ghostCellsPerOwner_[neigh].size()};
896 MPI_Sendrecv(&nCells, 1, ttk::getMPIType(nCells), neigh, ttk::MPIrank_,
897 &nOwnedGhostCellsPerRank[neigh], 1, ttk::getMPIType(nCells),
898 neigh, neigh, ttk::MPIcomm_, MPI_STATUS_IGNORE);
899 this->remoteGhostCells_[neigh].resize(nOwnedGhostCellsPerRank[neigh]);
900
901 // 2. send to neigh list of ghost cells owned by neigh
902 MPI_Sendrecv(this->ghostCellsPerOwner_[neigh].data(),
903 this->ghostCellsPerOwner_[neigh].size(), MIT, neigh,
904 ttk::MPIrank_, this->remoteGhostCells_[neigh].data(),
905 this->remoteGhostCells_[neigh].size(), MIT, neigh, neigh,
906 ttk::MPIcomm_, MPI_STATUS_IGNORE);
907 }
908
909 this->hasPreconditionedExchangeGhostCells_ = true;
910 return 0;
911}
912
913int ttk::ExplicitTriangulation::preconditionDistributedCellRanges() {
914
915 // 1. store all local cells owned by current rank by global id
916
917 std::vector<SimplexId> localCellIds{};
918 localCellIds.reserve(this->getNumberOfCells());
919 for(SimplexId i = 0; i < this->getNumberOfCells(); ++i) {
920 if(this->cellRankArray_[i] == ttk::MPIrank_) {
921 localCellIds.emplace_back(i);
922 }
923 }
924
925 TTK_PSORT(this->threadNumber_, localCellIds.begin(), localCellIds.end(),
926 [this](const SimplexId a, const SimplexId b) {
927 return this->cellGid_[a] < this->cellGid_[b];
928 });
929
930 // 2. determine ranges of contiguous cell global ids
931
932 size_t begRange{};
933 while(begRange < localCellIds.size()) {
934 size_t endRange{begRange + 1};
935
936 if(begRange < localCellIds.size() - 1) {
937 for(size_t j = begRange + 1; j < localCellIds.size(); ++j) {
938 if(this->cellGid_[localCellIds[j]]
939 > this->cellGid_[localCellIds[j - 1]] + 1) {
940 endRange = j;
941 break;
942 }
943 }
944 if(endRange == begRange + 1
945 && this->cellGid_[localCellIds[endRange]]
946 == this->cellGid_[localCellIds[endRange - 1]] + 1) {
947 endRange = localCellIds.size();
948 }
949 }
950
951 const size_t gbeg = this->cellGid_[localCellIds[begRange]];
952 const size_t gend = this->cellGid_[localCellIds[endRange - 1]];
953 const auto nRanges{this->localCellRanges_.size()};
954
955 // inclusive range
956 this->localCellRanges_.emplace_back(
957 CellRange{nRanges, gbeg, gend, static_cast<size_t>(ttk::MPIrank_)});
958
959 begRange = endRange;
960 }
961
962 // 3. send to rank 0 the vector of ranges so it can compute range offsets
963
964 if(ttk::MPIrank_ == 0) {
965 this->nRangesPerRank_.resize(ttk::MPIsize_);
966 }
967
968 const int rangeSize = this->localCellRanges_.size();
969 MPI_Gather(&rangeSize, 1, ttk::getMPIType(rangeSize),
970 this->nRangesPerRank_.data(), 1, ttk::getMPIType(rangeSize), 0,
971 ttk::MPIcomm_);
972
973 std::vector<int> displacements{};
974
975 if(ttk::MPIrank_ == 0) {
976 const auto nRanges{std::accumulate(
977 this->nRangesPerRank_.begin(), this->nRangesPerRank_.end(), 0)};
978 this->gatheredCellRanges_.resize(nRanges);
979 displacements.resize(this->nRangesPerRank_.size());
980
981 for(size_t i = 0; i < this->nRangesPerRank_.size() - 1; ++i) {
982 displacements[i + 1] = displacements[i] + this->nRangesPerRank_[i];
983 }
984 }
985
986 auto cellRangeDT{CellRange::getMPIType()};
987 MPI_Type_commit(&cellRangeDT);
988
989 MPI_Gatherv(this->localCellRanges_.data(), this->localCellRanges_.size(),
990 cellRangeDT, this->gatheredCellRanges_.data(),
991 this->nRangesPerRank_.data(), displacements.data(), cellRangeDT,
992 0, ttk::MPIcomm_);
993
994 MPI_Type_free(&cellRangeDT);
995
996 // 4. sort range vector on rank 0
997
998 if(ttk::MPIrank_ == 0) {
999 TTK_PSORT(
1000 this->threadNumber_, this->gatheredCellRanges_.begin(),
1001 this->gatheredCellRanges_.end(),
1002 [](const CellRange &a, const CellRange &b) { return a.begin < b.begin; });
1003 }
1004
1005 return 0;
1006}
1007
1008size_t ttk::ExplicitTriangulation::computeCellRangeOffsets(
1009 std::vector<size_t> &nSimplicesPerRange) const {
1010
1011 // 1. send to rank 0 number of edges per cell range
1012
1013 std::vector<std::vector<size_t>> nSimplicesPerRangePerRank{};
1014
1015 if(ttk::MPIrank_ == 0) {
1016 nSimplicesPerRangePerRank.resize(this->nRangesPerRank_.size());
1017 for(int i = 0; i < ttk::MPIsize_; ++i) {
1018 nSimplicesPerRangePerRank[i].resize(this->nRangesPerRank_[i]);
1019 }
1020 for(int i = 0; i < ttk::MPIsize_; ++i) {
1021 if(i == 0) {
1022 continue;
1023 }
1024 // receive src content from other ranks
1025 MPI_Recv(nSimplicesPerRangePerRank[i].data(),
1026 nSimplicesPerRangePerRank[i].size(), ttk::getMPIType(size_t{}),
1027 i, MPI_ANY_TAG, ttk::MPIcomm_, MPI_STATUS_IGNORE);
1028 }
1029 std::swap(nSimplicesPerRangePerRank[0], nSimplicesPerRange);
1030 } else {
1031 MPI_Send(nSimplicesPerRange.data(), nSimplicesPerRange.size(),
1032 ttk::getMPIType(size_t{}), 0, 0, ttk::MPIcomm_);
1033 }
1034
1035 // 2. compute range offsets on rank 0
1036
1037 size_t nSimplices{};
1038 if(ttk::MPIrank_ == 0) {
1039
1040 for(const auto &range : this->gatheredCellRanges_) {
1041 auto &pSum{nSimplicesPerRangePerRank[range.rank][range.id]};
1042 std::swap(pSum, nSimplices);
1043 nSimplices += pSum;
1044 }
1045 }
1046
1047 // 3. send back range offsets to other ranks
1048
1049 if(ttk::MPIrank_ == 0) {
1050 for(int i = 1; i < ttk::MPIsize_; ++i) {
1051 MPI_Send(nSimplicesPerRangePerRank[i].data(),
1052 nSimplicesPerRangePerRank[i].size(), ttk::getMPIType(size_t{}),
1053 i, 0, ttk::MPIcomm_);
1054 }
1055 std::swap(nSimplicesPerRange, nSimplicesPerRangePerRank[0]);
1056 } else {
1057 MPI_Recv(nSimplicesPerRange.data(), nSimplicesPerRange.size(),
1058 ttk::getMPIType(size_t{}), MPI_ANY_TAG, 0, ttk::MPIcomm_,
1059 MPI_STATUS_IGNORE);
1060 }
1061
1062 return nSimplices;
1063}
1064
1065template <typename Func0, typename Func1, typename Func2>
1066int ttk::ExplicitTriangulation::exchangeDistributedInternal(
1067 const Func0 &getGlobalSimplexId,
1068 const Func1 &storeGlobalSimplexId,
1069 const Func2 &iterCond,
1070 const int nSimplicesPerCell) {
1071
1072 // per neighbor, owned ghost cell simplex global ids to transfer back
1073 std::vector<std::vector<SimplexId>> globalIdPerOwnedGhostCell(ttk::MPIsize_);
1074 // per neighbor, non-owned ghost cell simplex global ids to transfer back
1075 std::vector<std::vector<SimplexId>> globalIdPerLocalGhostCell(ttk::MPIsize_);
1076
1077 const auto MIT{ttk::getMPIType(ttk::SimplexId{})};
1078
1079 // make sure that all simplices are correctly labelled: for a given
1080 // rank, a simplex can be owned by a ghost cell from a neighboring
1081 // rank but in reality can be owned by another ghost cell in a third
1082 // rank
1083 bool doIter{true};
1084
1085 while(doIter) {
1086
1087 doIter = false;
1088
1089 // 3. for each list of ghost cell, accumulate the global simplex id
1090 for(const auto neigh : this->neighborRanks_) {
1091 // sending side
1092 globalIdPerOwnedGhostCell[neigh].resize(
1093 nSimplicesPerCell * this->remoteGhostCells_[neigh].size());
1094 for(size_t i = 0; i < this->remoteGhostCells_[neigh].size(); ++i) {
1095 const auto lcid{this->cellGidToLid_[this->remoteGhostCells_[neigh][i]]};
1096 for(int j = 0; j < nSimplicesPerCell; ++j) {
1097 globalIdPerOwnedGhostCell[neigh][nSimplicesPerCell * i + j]
1098 = getGlobalSimplexId(lcid, j);
1099 }
1100 }
1101 // receiving side
1102 globalIdPerLocalGhostCell[neigh].resize(
1103 nSimplicesPerCell * this->ghostCellsPerOwner_[neigh].size());
1104
1105 // 4. transfer back global simplex ids
1106 MPI_Sendrecv(globalIdPerOwnedGhostCell[neigh].data(),
1107 globalIdPerOwnedGhostCell[neigh].size(), MIT, neigh,
1108 ttk::MPIrank_, globalIdPerLocalGhostCell[neigh].data(),
1109 globalIdPerLocalGhostCell[neigh].size(), MIT, neigh, neigh,
1110 ttk::MPIcomm_, MPI_STATUS_IGNORE);
1111 }
1112
1113 // 5. extend local <-> global simplex ids mappings
1114 for(const auto neigh : this->neighborRanks_) {
1115 for(size_t i = 0; i < this->ghostCellsPerOwner_[neigh].size(); ++i) {
1116 const auto gcid{this->ghostCellsPerOwner_[neigh][i]};
1117 const auto lcid{this->cellGidToLid_[gcid]};
1118 for(int j = 0; j < nSimplicesPerCell; ++j) {
1119 const auto geid{
1120 globalIdPerLocalGhostCell[neigh][nSimplicesPerCell * i + j]};
1121 storeGlobalSimplexId(lcid, geid, j);
1122 }
1123 }
1124 }
1125
1126 // do an additional transmission if there still is some locally
1127 // non-labelled simplices
1128 int doNextIter{0};
1129 if(iterCond()) {
1130 doNextIter = 1;
1131 doIter = true;
1132 }
1133 for(int i = 0; i < ttk::MPIsize_; ++i) {
1134 if(doIter) {
1135 // reset doNextIter (might have been erased by the MPI_Bcast)
1136 doNextIter = 1;
1137 }
1138 MPI_Bcast(&doNextIter, 1, ttk::getMPIType(doNextIter), i, ttk::MPIcomm_);
1139 doIter |= (doNextIter == 1);
1140 }
1141
1142 if(doIter && ttk::MPIrank_ == 0) {
1143 this->printMsg("Re-sending global ids to neighbors...");
1144 }
1145 }
1146
1147 return 0;
1148}
1149
1150int ExplicitTriangulation::preconditionDistributedEdges() {
1151 if(this->hasPreconditionedDistributedEdges_) {
1152 return 0;
1153 }
1154 if(!ttk::hasInitializedMPI()) {
1155 return -1;
1156 }
1157 if(this->cellGid_ == nullptr) {
1158 this->printErr("Missing global cell identifiers array!");
1159 return -2;
1160 }
1161
1162 if(this->getDimensionality() != 2 && this->getDimensionality() != 3) {
1163 return -3;
1164 }
1165
1166 if(this->getDimensionality() == 2) {
1168 }
1169
1170 Timer tm{};
1171
1172 this->preconditionDistributedCells();
1173
1174 // allocate memory
1175 this->edgeLidToGid_.resize(this->getNumberOfEdgesInternal(), -1);
1176 this->edgeGidToLid_.reserve(this->getNumberOfEdgesInternal());
1177
1178 // 1. for every range of local cells, number the edges locally
1179
1180 std::vector<SimplexId> edgeLidToRangeId(this->getNumberOfEdgesInternal(), -1);
1181 std::vector<size_t> nEdgesPerRange(this->localCellRanges_.size());
1182
1183 const auto edgeAlreadyProcessed = [this](const SimplexId leid,
1184 const SimplexId lcid) {
1185 const auto nStar{this->TTK_TRIANGULATION_INTERNAL(getEdgeStarNumber)(leid)};
1186 for(SimplexId i = 0; i < nStar; ++i) {
1187 SimplexId sid{-1};
1188 this->TTK_TRIANGULATION_INTERNAL(getEdgeStar)(leid, i, sid);
1189 if(sid == -1 || sid == lcid) {
1190 continue;
1191 }
1192 // rule: an edge is owned by the cell in its star with the
1193 // lowest global id
1194 if(this->cellGid_[sid] < this->cellGid_[lcid]) {
1195 return true;
1196 break;
1197 }
1198 }
1199 return false;
1200 };
1201
1202 const auto countCellEdges
1203 = [this, &edgeAlreadyProcessed](const SimplexId lcid,
1204 std::vector<SimplexId> &edgeGid,
1205 std::vector<SimplexId> &edgeRangeId,
1206 const size_t rangeId, size_t &edgeCount) {
1207 SimplexId nEdges{};
1208 if(this->maxCellDim_ == 3) {
1209 nEdges = this->getCellEdgeNumberInternal(lcid);
1210 } else if(this->maxCellDim_ == 2) {
1211 nEdges = this->getTriangleEdgeNumberInternal(lcid);
1212 }
1213 for(SimplexId k = 0; k < nEdges; ++k) {
1214 SimplexId leid{-1};
1215 if(this->maxCellDim_ == 3) {
1216 this->getCellEdgeInternal(lcid, k, leid);
1217 } else if(this->maxCellDim_ == 2) {
1218 this->getTriangleEdge(lcid, k, leid);
1219 }
1220 const auto alreadyProcessed = edgeAlreadyProcessed(leid, lcid);
1221 if(!alreadyProcessed) {
1222 edgeGid[leid] = edgeCount;
1223 edgeRangeId[leid] = rangeId;
1224 edgeCount++;
1225 }
1226 }
1227 };
1228
1229#ifdef TTK_ENABLE_OPENMP
1230#pragma omp parallel for num_threads(this->threadNumber_)
1231#endif // TTK_ENABLE_OPENMP
1232 for(size_t i = 0; i < this->localCellRanges_.size(); ++i) {
1233 auto &range{this->localCellRanges_[i]};
1234 range.id = i;
1235 for(size_t j = range.begin; j <= range.end; ++j) {
1236 // local cell id
1237 const auto lcid{this->cellGidToLid_[j]};
1238 countCellEdges(lcid, this->edgeLidToGid_, edgeLidToRangeId, range.id,
1239 nEdgesPerRange[i]);
1240 }
1241 }
1242
1243 // 2. compute range offset on rank 0
1244 const auto nEdges = this->computeCellRangeOffsets(nEdgesPerRange);
1245
1246 // 3. locally edit the edge global id with range offsets
1247
1248 for(SimplexId leid = 0; leid < this->getNumberOfEdgesInternal(); ++leid) {
1249 if(this->edgeLidToGid_[leid] == -1) {
1250 // not owned by a cell of this rank
1251 continue;
1252 }
1253 const auto geid{this->edgeLidToGid_[leid]
1254 + nEdgesPerRange[edgeLidToRangeId[leid]]};
1255 this->edgeLidToGid_[leid] = geid;
1256 this->edgeGidToLid_[geid] = leid;
1257 }
1258
1259 // 4. exchange global ids between ghost cells
1260
1261 const auto nEdgesPerCell{this->getDimensionality() == 3 ? 6 : 3};
1262 this->exchangeDistributedInternal(
1263 [this](const SimplexId lcid, const int j) {
1264 SimplexId leid{};
1265 this->getCellEdgeInternal(lcid, j, leid);
1266 return this->edgeLidToGid_[leid];
1267 },
1268 [this](const SimplexId lcid, const SimplexId geid, const int j) {
1269 SimplexId leid{};
1270 this->getCellEdgeInternal(lcid, j, leid);
1271 if(this->edgeLidToGid_[leid] == -1 && geid != -1) {
1272 this->edgeLidToGid_[leid] = geid;
1273 this->edgeGidToLid_[geid] = leid;
1274 }
1275 },
1276 [this]() {
1277 return std::count(
1278 this->edgeLidToGid_.begin(), this->edgeLidToGid_.end(), -1)
1279 > 0;
1280 },
1281 nEdgesPerCell);
1282
1283 this->preconditionEdgeRankArray();
1284
1285 if(MPIrank_ == 0) {
1286 this->printMsg("Domain contains " + std::to_string(nEdges) + " edges", 1.0,
1287 tm.getElapsedTime(), 1);
1288 }
1289
1290 this->hasPreconditionedDistributedEdges_ = true;
1291
1292 return 0;
1293}
1294
1295int ExplicitTriangulation::preconditionDistributedTriangles() {
1296 if(this->hasPreconditionedDistributedTriangles_) {
1297 return 0;
1298 }
1299 if(!ttk::hasInitializedMPI()) {
1300 return -1;
1301 }
1302 if(this->cellGid_ == nullptr) {
1303 this->printErr("Missing global cell identifiers array!");
1304 return -2;
1305 }
1306
1307 if(this->getDimensionality() != 3) {
1308 return -3;
1309 }
1310
1311 Timer tm{};
1312
1313 this->preconditionDistributedCells();
1314
1315 // allocate memory
1316 this->triangleLidToGid_.resize(this->getNumberOfTrianglesInternal(), -1);
1317 this->triangleGidToLid_.reserve(this->getNumberOfTrianglesInternal());
1318
1319 // 1. for every range of local cells, number the edges locally
1320
1321 std::vector<SimplexId> triangleLidToRangeId(
1322 this->getNumberOfTrianglesInternal(), -1);
1323 std::vector<size_t> nTrianglesPerRange(this->localCellRanges_.size());
1324
1325 const auto triangleAlreadyProcessed
1326 = [this](const SimplexId leid, const SimplexId lcid) {
1327 const auto nStar{
1329 for(SimplexId i = 0; i < nStar; ++i) {
1330 SimplexId sid{-1};
1331 this->TTK_TRIANGULATION_INTERNAL(getTriangleStar)(leid, i, sid);
1332 if(sid == -1 || sid == lcid) {
1333 continue;
1334 }
1335 // rule: an triangle is owned by the cell in its star with the
1336 // lowest global id
1337 if(this->cellGid_[sid] < this->cellGid_[lcid]) {
1338 return true;
1339 break;
1340 }
1341 }
1342 return false;
1343 };
1344
1345 const auto countCellTriangles
1346 = [this, &triangleAlreadyProcessed](
1347 const SimplexId lcid, std::vector<SimplexId> &triangleGid,
1348 std::vector<SimplexId> &triangleRangeId, const size_t rangeId,
1349 size_t &triangleCount) {
1350 const auto nTriangles{this->getCellTriangleNumberInternal(lcid)};
1351 for(SimplexId k = 0; k < nTriangles; ++k) {
1352 SimplexId leid{-1};
1353 this->getCellTriangleInternal(lcid, k, leid);
1354 const auto alreadyProcessed = triangleAlreadyProcessed(leid, lcid);
1355 if(!alreadyProcessed) {
1356 triangleGid[leid] = triangleCount;
1357 triangleRangeId[leid] = rangeId;
1358 triangleCount++;
1359 }
1360 }
1361 };
1362
1363#ifdef TTK_ENABLE_OPENMP
1364#pragma omp parallel for num_threads(this->threadNumber_)
1365#endif // TTK_ENABLE_OPENMP
1366 for(size_t i = 0; i < this->localCellRanges_.size(); ++i) {
1367 auto &range{this->localCellRanges_[i]};
1368 range.id = i;
1369 for(size_t j = range.begin; j <= range.end; ++j) {
1370 // local cell id
1371 const auto lcid{this->cellGidToLid_[j]};
1372 countCellTriangles(lcid, this->triangleLidToGid_, triangleLidToRangeId,
1373 range.id, nTrianglesPerRange[i]);
1374 }
1375 }
1376
1377 // 2. compute range offset on rank 0
1378 const auto nTriangles = this->computeCellRangeOffsets(nTrianglesPerRange);
1379
1380 // 3. locally edit the triangle global id with range offsets
1381
1382 for(SimplexId leid = 0; leid < this->getNumberOfTrianglesInternal(); ++leid) {
1383 if(this->triangleLidToGid_[leid] == -1) {
1384 // not owned by a cell of this rank
1385 continue;
1386 }
1387 const auto geid{this->triangleLidToGid_[leid]
1388 + nTrianglesPerRange[triangleLidToRangeId[leid]]};
1389 this->triangleLidToGid_[leid] = geid;
1390 this->triangleGidToLid_[geid] = leid;
1391 }
1392
1393 // 4. exchange global ids between ghost cells
1394
1395 const auto nTrianglesPerCell{4};
1396 this->exchangeDistributedInternal(
1397 [this](const SimplexId lcid, const int j) {
1398 SimplexId ltid{};
1399 this->getCellTriangleInternal(lcid, j, ltid);
1400 return this->triangleLidToGid_[ltid];
1401 },
1402 [this](const SimplexId lcid, const SimplexId gtid, const int j) {
1403 SimplexId ltid{};
1404 this->getCellTriangleInternal(lcid, j, ltid);
1405 if(this->triangleLidToGid_[ltid] == -1 && gtid != -1) {
1406 this->triangleLidToGid_[ltid] = gtid;
1407 this->triangleGidToLid_[gtid] = ltid;
1408 }
1409 },
1410 [this]() {
1411 return std::count(this->triangleLidToGid_.begin(),
1412 this->triangleLidToGid_.end(), -1)
1413 > 0;
1414 },
1415 nTrianglesPerCell);
1416
1417 this->preconditionTriangleRankArray();
1418
1419 if(MPIrank_ == 0) {
1420 this->printMsg(
1421 "Domain contains " + std::to_string(nTriangles) + " triangles", 1.0,
1422 tm.getElapsedTime(), 1);
1423 }
1424
1425 this->hasPreconditionedDistributedTriangles_ = true;
1426
1427 return 0;
1428}
1429
1430int ExplicitTriangulation::preconditionDistributedVertices() {
1431 if(this->hasPreconditionedDistributedVertices_) {
1432 return 0;
1433 }
1434 if(!hasInitializedMPI()) {
1435 return -1;
1436 }
1437 if(this->vertGid_ == nullptr) {
1438 this->printErr("Missing global vertex identifiers array!");
1439 return -2;
1440 }
1441
1442 this->hasPreconditionedDistributedVertices_ = true;
1443 this->preconditionVertexRankArray();
1444
1445 // number of local vertices (with ghost vertices...)
1446 const auto nLocVertices{this->getNumberOfVertices()};
1447
1448 // global vertex id -> local vertex id (reverse of this->vertGid_)
1449 this->vertexGidToLid_.reserve(nLocVertices);
1450 for(LongSimplexId lvid = 0; lvid < nLocVertices; ++lvid) {
1451 this->vertexGidToLid_[this->vertGid_[lvid]] = lvid;
1452 }
1453
1454 this->preconditionExchangeGhostVertices();
1455
1456 return 0;
1457}
1458
1459int ttk::ExplicitTriangulation::preconditionExchangeGhostVertices() {
1460
1461 if(this->hasPreconditionedExchangeGhostVertices_) {
1462 return 0;
1463 }
1464 if(!ttk::hasInitializedMPI()) {
1465 return -1;
1466 }
1467 if(this->vertGid_ == nullptr) {
1468 this->printErr("Missing global vertex identifiers array!");
1469 return -2;
1470 }
1471
1472 // number of local vertices (with ghost vertices...)
1473 const auto nLocVertices{this->getNumberOfVertices()};
1474
1475 this->ghostVerticesPerOwner_.resize(ttk::MPIsize_);
1476
1477 for(LongSimplexId lvid = 0; lvid < nLocVertices; ++lvid) {
1478 if(this->vertexRankArray_[lvid] != ttk::MPIrank_) {
1479 // store ghost cell global ids (per rank)
1480 this->ghostVerticesPerOwner_[this->vertexRankArray_[lvid]].emplace_back(
1481 this->vertGid_[lvid]);
1482 }
1483 }
1484
1485 // for each rank, store the global id of local cells that are ghost cells of
1486 // other ranks.
1487 const auto MIT{ttk::getMPIType(ttk::SimplexId{})};
1488 this->remoteGhostVertices_.resize(ttk::MPIsize_);
1489 // number of owned cells that are ghost cells of other ranks
1490 std::vector<size_t> nOwnedGhostVerticesPerRank(ttk::MPIsize_);
1491
1492 for(const auto neigh : this->neighborRanks_) {
1493 // 1. send to neigh number of ghost cells owned by neigh
1494 const auto nVerts{this->ghostVerticesPerOwner_[neigh].size()};
1495 MPI_Sendrecv(&nVerts, 1, ttk::getMPIType(nVerts), neigh, ttk::MPIrank_,
1496 &nOwnedGhostVerticesPerRank[neigh], 1, ttk::getMPIType(nVerts),
1497 neigh, neigh, ttk::MPIcomm_, MPI_STATUS_IGNORE);
1498 this->remoteGhostVertices_[neigh].resize(nOwnedGhostVerticesPerRank[neigh]);
1499
1500 // 2. send to neigh list of ghost cells owned by neigh
1501 MPI_Sendrecv(this->ghostVerticesPerOwner_[neigh].data(),
1502 this->ghostVerticesPerOwner_[neigh].size(), MIT, neigh,
1503 ttk::MPIrank_, this->remoteGhostVertices_[neigh].data(),
1504 this->remoteGhostVertices_[neigh].size(), MIT, neigh, neigh,
1505 ttk::MPIcomm_, MPI_STATUS_IGNORE);
1506 }
1507
1508 this->hasPreconditionedExchangeGhostVertices_ = true;
1509
1510 return 0;
1511}
1512
1513#endif // TTK_ENABLE_MPI
1514
1515template <typename T>
1516void writeBin(std::ofstream &stream, const T var) {
1517 stream.write(reinterpret_cast<const char *>(&var), sizeof(var));
1518}
1519
1520template <typename T>
1521void writeBinArray(std::ofstream &stream,
1522 const T *const buff,
1523 const size_t size) {
1524 stream.write(reinterpret_cast<const char *>(buff), size * sizeof(T));
1525}
1526
1527// initialize static member variables
1528const char *ExplicitTriangulation::magicBytes_ = "TTKTriangulationFileFormat";
1529const unsigned long ExplicitTriangulation::formatVersion_ = 1;
1530
1531int ExplicitTriangulation::writeToFile(std::ofstream &stream) const {
1532
1533 // 1. magic bytes (char *)
1534 stream.write(ttk::ExplicitTriangulation::magicBytes_,
1535 std::strlen(ttk::ExplicitTriangulation::magicBytes_));
1536 // 2. format version (unsigned long)
1537 writeBin(stream, ttk::ExplicitTriangulation::formatVersion_);
1538 // 3. dimensionality (int)
1539 const auto dim = this->getDimensionality();
1540 writeBin(stream, dim);
1541 // 4. number of vertices (SimplexId)
1542 const auto nVerts = this->getNumberOfVertices();
1543 writeBin(stream, nVerts);
1544 // 5. number of edges (SimplexId)
1545 const auto edgesNumber = [this, dim]() -> SimplexId {
1546 if(dim == 1) {
1547 return this->getNumberOfCells();
1548 } else if(dim > 1) {
1549 return this->edgeList_.size();
1550 }
1551 return 0;
1552 };
1553 const auto nEdges = edgesNumber();
1554 writeBin(stream, nEdges);
1555 // 6. number of triangles (SimplexId, 0 in 1D)
1556 const auto trianglesNumber = [this, dim]() -> SimplexId {
1557 if(dim == 2) {
1558 return this->getNumberOfCells();
1559 } else if(dim == 3) {
1560 return this->triangleList_.size();
1561 }
1562 return 0;
1563 };
1564 const auto nTriangles = trianglesNumber();
1565 writeBin(stream, nTriangles);
1566 // 7. number of tetrahedron (SimplexId, 0 in 2D)
1567 const auto nTetras = dim > 2 ? this->getNumberOfCells() : 0;
1568 writeBin(stream, nTetras);
1569
1570 // only write buffers oustside this->cellArray_ (cellVertex, vertexCoords),
1571 // those ones will be provided by VTK
1572
1573 // fixed-size arrays (in AbstractTriangulation.h)
1574
1575#define WRITE_FIXED(ARRAY) \
1576 if(ARRAY.empty()) { \
1577 writeBin(stream, char{0}); \
1578 } else { \
1579 writeBin(stream, char{1}); \
1580 writeBinArray(stream, ARRAY.data(), ARRAY.size()); \
1581 }
1582
1583 // 8. edgeList (SimplexId array)
1584 WRITE_FIXED(this->edgeList_);
1585 // 9. triangleList (SimplexId array)
1587 // 10. triangleEdgeList (SimplexId array)
1589 // 11. tetraEdgeList (SimplexId array)
1591 // 12. tetraTriangleList (SimplexId array)
1593
1594 // variable-size arrays (FlatJaggedArray in ExplicitTriangulation.h)
1595
1596#define WRITE_GUARD(ARRAY) \
1597 if(ARRAY.empty()) { \
1598 writeBin(stream, char{0}); \
1599 return; \
1600 } else { \
1601 writeBin(stream, char{1}); \
1602 }
1603
1604 const auto write_variable = [&stream](const FlatJaggedArray &arr) {
1605 // empty array guard
1606 WRITE_GUARD(arr);
1607 writeBinArray(stream, arr.offset_ptr(), arr.size() + 1);
1608 writeBinArray(stream, arr.get_ptr(0, 0), arr.dataSize());
1609 };
1610
1611 // 13. vertexNeighbors (SimplexId array, offsets then data)
1612 write_variable(this->vertexNeighborData_);
1613 // 14. cellNeighbors (SimplexId array, offsets then data)
1614 write_variable(this->cellNeighborData_);
1615 // 15. vertexEdges (SimplexId array, offsets then data)
1616 write_variable(this->vertexEdgeData_);
1617 // 16. vertexTriangles (SimplexId array, offsets then data)
1618 write_variable(this->vertexTriangleData_);
1619 // 17. edgeTriangles (SimplexId array, offsets then data)
1620 write_variable(this->edgeTriangleData_);
1621 // 18. vertexStars (SimplexId array, offsets then data)
1622 write_variable(this->vertexStarData_);
1623 // 19. edgeStars (SimplexId array, offsets then data)
1624 write_variable(this->edgeStarData_);
1625 // 20. triangleStars (SimplexId array, offsets then data)
1626 write_variable(this->triangleStarData_);
1627 // 21. vertexLinks (SimplexId array, offsets then data)
1628 write_variable(this->vertexLinkData_);
1629 // 22. edgeLinks (SimplexId array, offsets then data)
1630 write_variable(this->edgeLinkData_);
1631 // 23. triangleLinks (SimplexId array, offsets then data)
1632 write_variable(this->triangleLinkData_);
1633
1634 const auto write_bool = [&stream](const std::vector<bool> &arr) {
1635 // empty array guard
1636 WRITE_GUARD(arr);
1637 for(size_t i = 0; i < arr.size(); ++i) {
1638 const auto b = static_cast<char>(arr[i]);
1639 writeBin(stream, b);
1640 }
1641 };
1642
1643 // 24. boundary vertices (bool array)
1644 write_bool(this->boundaryVertices_);
1645 // 25. boundary edges (bool array)
1646 write_bool(this->boundaryEdges_);
1647 // 26. boundary triangles (bool array)
1648 write_bool(this->boundaryTriangles_);
1649
1650 return 0;
1651}
1652
1653int ExplicitTriangulation::writeToFileASCII(std::ofstream &stream) const {
1654 // 1. magic bytes
1655 stream << ttk::ExplicitTriangulation::magicBytes_ << '\n';
1656 // 2. format version
1657 stream << ttk::ExplicitTriangulation::formatVersion_ + 1 << '\n';
1658 // 3. dimensionality
1659 const auto dim = this->getDimensionality();
1660 stream << "dim " << dim << '\n';
1661 // 4. -> 7. number of simplices
1662 const auto nVerts = this->getNumberOfVertices();
1663 const auto edgesNumber = [this, dim]() -> SimplexId {
1664 if(dim == 1) {
1665 return this->getNumberOfCells();
1666 } else if(dim > 1) {
1667 return this->edgeList_.size();
1668 }
1669 return 0;
1670 };
1671 const auto nEdges = edgesNumber();
1672 const auto trianglesNumber = [this, dim]() -> SimplexId {
1673 if(dim == 2) {
1674 return this->getNumberOfCells();
1675 } else if(dim == 3) {
1676 return this->triangleList_.size();
1677 }
1678 return 0;
1679 };
1680 const auto nTriangles = trianglesNumber();
1681 const auto nTetras = dim > 2 ? this->getNumberOfCells() : 0;
1682 stream << nVerts << ' ' << nEdges << ' ' << nTriangles << ' ' << nTetras
1683 << '\n';
1684
1685#define WRITE_ASCII(ARRAY) \
1686 stream << #ARRAY << '\n'; \
1687 for(const auto &slice : ARRAY) { \
1688 for(size_t i = 0; i < slice.size(); ++i) { \
1689 if(i > 0) { \
1690 stream << ' '; \
1691 } \
1692 stream << slice[i]; \
1693 } \
1694 stream << '\n'; \
1695 }
1696
1697 const auto writeCellArray = [this, &stream]() {
1698 stream << "this->cellArray_\n";
1699 for(SimplexId i = 0; i < this->cellNumber_; ++i) {
1700 for(SimplexId j = 0; j < this->cellArray_->getCellVertexNumber(i); ++j) {
1701 stream << this->cellArray_->getCellVertex(i, j) << ' ';
1702 }
1703 stream << '\n';
1704 }
1705 };
1706
1707 // ?. cellArray_
1708 writeCellArray();
1709
1710 // 8. -> 12. fixed-size arrays
1711 WRITE_ASCII(this->edgeList_);
1715
1716 // 13. -> 23. variable-size arrays
1717 WRITE_ASCII(this->vertexNeighborData_);
1718 WRITE_ASCII(this->cellNeighborData_);
1719 WRITE_ASCII(this->vertexEdgeData_);
1720 WRITE_ASCII(this->vertexTriangleData_);
1721 WRITE_ASCII(this->edgeTriangleData_);
1722 WRITE_ASCII(this->vertexStarData_);
1723 WRITE_ASCII(this->edgeStarData_);
1724 WRITE_ASCII(this->triangleStarData_);
1725 WRITE_ASCII(this->vertexLinkData_);
1726 WRITE_ASCII(this->edgeLinkData_);
1727 WRITE_ASCII(this->triangleLinkData_);
1728
1729#define WRITE_BOOL(ARRAY) \
1730 stream << #ARRAY << '\n'; \
1731 for(const auto el : ARRAY) { \
1732 stream << el << '\n'; \
1733 }
1734
1735 // 24. -> 26. boolean arrays
1739
1740 return 0;
1741}
1742
1743template <typename T>
1744void readBin(std::ifstream &stream, T &res) {
1745 stream.read(reinterpret_cast<char *>(&res), sizeof(res));
1746}
1747
1748template <typename T>
1749void readBinArray(std::ifstream &stream, T *const res, const size_t size) {
1750 stream.read(reinterpret_cast<char *>(res), size * sizeof(T));
1751}
1752
1753int ExplicitTriangulation::readFromFile(std::ifstream &stream) {
1754
1755 // 1. magic bytes (char *)
1756 const auto magicBytesLen
1757 = std::strlen(ttk::ExplicitTriangulation::magicBytes_);
1758 std::vector<char> mBytes(magicBytesLen + 1);
1759 stream.read(mBytes.data(), magicBytesLen);
1760 const auto hasMagicBytes
1761 = std::strcmp(mBytes.data(), ttk::ExplicitTriangulation::magicBytes_) == 0;
1762 if(!hasMagicBytes) {
1763 this->printErr("Could not find magic bytes in input files!");
1764 this->printErr("Aborting...");
1765 return 0;
1766 }
1767 // 2. format version (unsigned long)
1768 unsigned long version{};
1769 readBin(stream, version);
1770 if(version != ttk::ExplicitTriangulation::formatVersion_) {
1771 this->printWrn("File format version (" + std::to_string(version)
1772 + ") and software version ("
1773 + std::to_string(ttk::ExplicitTriangulation::formatVersion_)
1774 + ") are different!");
1775 }
1776
1777 int dim{};
1778 SimplexId nVerts{}, nEdges{}, nTriangles{}, nTetras{};
1779
1780 // 3. dimensionality (int)
1781 readBin(stream, dim);
1782 // 4. number of vertices (SimplexId)
1783 readBin(stream, nVerts);
1784 // 5. number of edges (SimplexId)
1785 readBin(stream, nEdges);
1786 // 6. number of triangles (SimplexId, 0 in 1D)
1787 readBin(stream, nTriangles);
1788 // 7. number of tetrahedron (SimplexId, 0 in 2D)
1789 readBin(stream, nTetras);
1790
1791 if(dim != this->getDimensionality()) {
1792 this->printErr("Incorrect dimension!");
1793 return 0;
1794 }
1795 if(nVerts != this->getNumberOfVertices()) {
1796 this->printErr("Incorrect number of vertices!");
1797 return 0;
1798 }
1799 if((dim == 2 && nTriangles != this->getNumberOfCells())
1800 || (dim == 3 && nTetras != this->getNumberOfCells())) {
1801 this->printErr("Incorrect number of cells!");
1802 return 0;
1803 }
1804
1805 // fixed-size arrays (in AbstractTriangulation.h)
1806
1807 const auto read_guard = [&stream]() {
1808 char g{};
1809 readBin(stream, g);
1810 return g == 0;
1811 };
1812
1813#define READ_FIXED(ARRAY, N_ITEMS) \
1814 if(!read_guard()) { \
1815 ARRAY.resize(N_ITEMS); \
1816 readBinArray(stream, ARRAY.data(), N_ITEMS); \
1817 }
1818
1819 // 8. edgeList (SimplexId array)
1820 READ_FIXED(this->edgeList_, nEdges);
1821 // 9. triangleList (SimplexId array)
1822 READ_FIXED(this->triangleList_, nTriangles);
1823 // 10. triangleEdgeList (SimplexId array)
1824 READ_FIXED(this->triangleEdgeList_, nTriangles);
1825 // 11. tetraEdgeList (SimplexId array)
1826 READ_FIXED(this->tetraEdgeList_, nTetras);
1827 // 12. tetraTriangleList (SimplexId array)
1828 READ_FIXED(this->tetraTriangleList_, nTetras);
1829
1830 // variable-size arrays (FlagJaggedArrays in ExplicitTriangulation.h)
1831
1832 const auto read_variable
1833 = [&stream, &read_guard](FlatJaggedArray &arr, const SimplexId n_items) {
1834 // empty array guard
1835 if(read_guard()) {
1836 return;
1837 }
1838 std::vector<SimplexId> offsets{}, data{};
1839 offsets.resize(n_items + 1);
1840 readBinArray(stream, offsets.data(), offsets.size());
1841 data.resize(offsets.back());
1842 readBinArray(stream, data.data(), data.size());
1843 arr.setData(std::move(data), std::move(offsets));
1844 };
1845
1846 // 13. vertexNeighbors (SimplexId array, offsets then data)
1847 read_variable(this->vertexNeighborData_, nVerts);
1848 // 14. cellNeighbors (SimplexId array, offsets then data)
1849 read_variable(this->cellNeighborData_, this->getNumberOfCells());
1850 // 15. vertexEdges (SimplexId array, offsets then data)
1851 read_variable(this->vertexEdgeData_, nVerts);
1852 // 16. vertexTriangles (SimplexId array, offsets then data)
1853 read_variable(this->vertexTriangleData_, nVerts);
1854 // 17. edgeTriangles (SimplexId array, offsets then data)
1855 read_variable(this->edgeTriangleData_, nEdges);
1856 // 18. vertexStars (SimplexId array, offsets then data)
1857 read_variable(this->vertexStarData_, nVerts);
1858 // 19. edgeStars (SimplexId array, offsets then data)
1859 read_variable(this->edgeStarData_, nEdges);
1860 // 20. triangleStars (SimplexId array, offsets then data)
1861 read_variable(this->triangleStarData_, nTriangles);
1862 // 21. vertexLinks (SimplexId array, offsets then data)
1863 read_variable(this->vertexLinkData_, nVerts);
1864 // 22. edgeLinks (SimplexId array, offsets then data)
1865 read_variable(this->edgeLinkData_, nEdges);
1866 // 23. triangleLinks (SimplexId array, offsets then data)
1867 read_variable(this->triangleLinkData_, nTriangles);
1868
1869 const auto read_bool
1870 = [&stream, &read_guard](std::vector<bool> &arr, const SimplexId n_items) {
1871 // empty array guard
1872 if(read_guard()) {
1873 return;
1874 }
1875 // resize vector
1876 arr.resize(n_items);
1877 for(SimplexId i = 0; i < n_items; ++i) {
1878 char b{};
1879 stream.read(&b, sizeof(b));
1880 arr[i] = static_cast<bool>(b);
1881 }
1882 };
1883
1884 // 24. boundary vertices (bool array)
1885 read_bool(this->boundaryVertices_, nVerts);
1886 // 25. boundary edges (bool array)
1887 read_bool(this->boundaryEdges_, nEdges);
1888 // 26. boundary triangles (bool array)
1889 read_bool(this->boundaryTriangles_, nTriangles);
1890
1891 return 0;
1892}
#define TTK_TRIANGULATION_INTERNAL(NAME)
void readBinArray(std::ifstream &stream, T *const res, const size_t size)
void writeBin(std::ofstream &stream, const T var)
void readBin(std::ifstream &stream, T &res)
#define READ_FIXED(ARRAY, N_ITEMS)
#define WRITE_GUARD(ARRAY)
#define WRITE_FIXED(ARRAY)
void writeBinArray(std::ofstream &stream, const T *const buff, const size_t size)
#define WRITE_BOOL(ARRAY)
#define WRITE_ASCII(ARRAY)
#define TTK_PSORT(NTHREADS,...)
Parallel sort macro.
Definition: OpenMP.h:46
std::vector< std::array< SimplexId, 3 > > triangleList_
virtual int getTriangleEdge(const SimplexId &triangleId, const int &localEdgeId, SimplexId &edgeId) const
std::vector< bool > boundaryTriangles_
std::vector< std::array< SimplexId, 4 > > tetraTriangleList_
std::vector< bool > boundaryVertices_
std::vector< std::array< SimplexId, 2 > > edgeList_
std::vector< std::array< SimplexId, 6 > > tetraEdgeList_
size_t footprint(size_t size=0) const
std::vector< std::array< SimplexId, 3 > > triangleEdgeList_
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition: Debug.h:159
int setWrapper(const Wrapper *wrapper) override
Definition: Debug.cpp:155
void setDebugMsgPrefix(const std::string &prefix)
Definition: Debug.h:364
int printMsg(const std::string &msg, const debug::Priority &priority=debug::Priority::INFO, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cout) const
Definition: Debug.h:118
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition: Debug.h:149
SimplexId getTriangleEdgeNumberInternal(const SimplexId &triangleId) const override
size_t footprint(size_t size=0) const
int preconditionTriangleStarsInternal() override
SimplexId getNumberOfTrianglesInternal() const override
SimplexId getCellEdgeNumberInternal(const SimplexId &cellId) const override
int writeToFile(std::ofstream &stream) const
Write internal state to disk.
int preconditionBoundaryTrianglesInternal() override
int preconditionCellTrianglesInternal() override
int preconditionVertexNeighborsInternal() override
SimplexId TTK_TRIANGULATION_INTERNAL() getNumberOfCells() const override
int TTK_TRIANGULATION_INTERNAL() getTriangleStar(const SimplexId &triangleId, const int &localStarId, SimplexId &starId) const override
SimplexId TTK_TRIANGULATION_INTERNAL() getTriangleStarNumber(const SimplexId &triangleId) const override
int preconditionTriangleLinksInternal() override
int preconditionBoundaryEdgesInternal() override
int preconditionEdgeTrianglesInternal() override
int getCellEdgeInternal(const SimplexId &cellId, const int &localEdgeId, SimplexId &edgeId) const override
int preconditionBoundaryVerticesInternal() override
SimplexId getNumberOfEdgesInternal() const override
int preconditionTriangleEdgesInternal() override
SimplexId TTK_TRIANGULATION_INTERNAL() getEdgeStarNumber(const SimplexId &edgeId) const override
int TTK_TRIANGULATION_INTERNAL() getDimensionality() const override
int TTK_TRIANGULATION_INTERNAL() getEdgeStar(const SimplexId &edgeId, const int &localStarId, SimplexId &starId) const override
int preconditionCellNeighborsInternal() override
int writeToFileASCII(std::ofstream &stream) const
Write internal state to disk using an ASCII format.
SimplexId getCellTriangleNumberInternal(const SimplexId &cellId) const override
SimplexId TTK_TRIANGULATION_INTERNAL() getNumberOfVertices() const override
int getCellTriangleInternal(const SimplexId &cellId, const int &localTriangleId, SimplexId &triangleId) const override
int preconditionVertexTrianglesInternal() override
int readFromFile(std::ifstream &stream)
Read from disk into internal state.
Replacement for std::vector<std::vector<SimplexId>>
size_t footprint() const
Computes the memory footprint of the array.
SimplexId size(SimplexId id) const
Get the size of a particular sub-vector.
bool empty() const
If the underlying buffers are empty.
OneSkeleton processing package.
Definition: OneSkeleton.h:25
int buildEdgeLinks(const std::vector< std::array< SimplexId, 2 > > &edgeList, const FlatJaggedArray &edgeStars, const CellArray &cellArray, FlatJaggedArray &edgeLinks) const
Definition: OneSkeleton.cpp:11
int buildEdgeList(const SimplexId &vertexNumber, const CellArray &cellArray, std::vector< std::array< SimplexId, 2 > > &edgeList, FlatJaggedArray &edgeStars, std::vector< std::array< SimplexId, n > > &cellEdgeList) const
ThreeSkeleton processing package.
Definition: ThreeSkeleton.h:26
int buildCellNeighborsFromTriangles(const SimplexId &vertexNumber, const CellArray &cellArray, FlatJaggedArray &cellNeighbors, FlatJaggedArray *triangleStars=nullptr) const
TwoSkeleton processing package.
Definition: TwoSkeleton.h:24
int buildTriangleEdgeList(const SimplexId &vertexNumber, const CellArray &cellArray, std::vector< std::array< SimplexId, 3 > > &triangleEdgeList, const std::vector< std::array< SimplexId, 2 > > &edgeList, FlatJaggedArray *vertexEdgeList=nullptr, std::vector< std::array< SimplexId, 3 > > *triangleList=nullptr, FlatJaggedArray *triangleStarList=nullptr, std::vector< std::array< SimplexId, 4 > > *cellTriangleList=nullptr) const
int buildVertexTriangles(const SimplexId &vertexNumber, const std::vector< std::array< SimplexId, 3 > > &triangleList, FlatJaggedArray &vertexTriangles) const
int buildCellNeighborsFromEdges(const CellArray &cellArray, FlatJaggedArray &cellNeighbors, const FlatJaggedArray &edgeStars) const
Definition: TwoSkeleton.cpp:10
int buildTriangleLinks(const std::vector< std::array< SimplexId, 3 > > &triangleList, const FlatJaggedArray &triangleStars, const CellArray &cellArray, FlatJaggedArray &triangleLinks) const
int buildTriangleList(const SimplexId &vertexNumber, const CellArray &cellArray, std::vector< std::array< SimplexId, 3 > > *triangleList=nullptr, FlatJaggedArray *triangleStars=nullptr, std::vector< std::array< SimplexId, 4 > > *cellTriangleList=nullptr) const
int buildEdgeTriangles(const SimplexId &vertexNumber, const CellArray &cellArray, FlatJaggedArray &edgeTriangleList, const std::vector< std::array< SimplexId, 2 > > &edgeList, std::vector< std::array< SimplexId, 3 > > *triangleEdgeList=nullptr) const
ZeroSkeleton processing package.
Definition: ZeroSkeleton.h:25
int buildVertexEdges(const SimplexId &vertexNumber, const std::vector< std::array< SimplexId, 2 > > &edgeList, FlatJaggedArray &vertexEdges) const
Definition: ZeroSkeleton.cpp:9
int buildVertexStars(const SimplexId &vertexNumber, const CellArray &cellArray, FlatJaggedArray &vertexStars) const
int buildVertexLinks(const FlatJaggedArray &vertexStars, const std::vector< std::array< SimplexId, 3 > > &cellEdges, const std::vector< std::array< SimplexId, 2 > > &edgeList, FlatJaggedArray &vertexLinks) const
int buildVertexNeighbors(const SimplexId &vertexNumber, FlatJaggedArray &vertexNeighbors, const std::vector< std::array< SimplexId, 2 > > &edgeList) const
The Topology ToolKit.
COMMON_EXPORTS int MPIsize_
Definition: BaseClass.cpp:10
COMMON_EXPORTS int MPIrank_
Definition: BaseClass.cpp:9
long long int LongSimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:15
int SimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:22
printMsg(debug::output::GREEN+"                           "+debug::output::ENDCOLOR+debug::output::GREEN+"▒"+debug::output::ENDCOLOR+debug::output::GREEN+"▒▒▒▒▒▒▒▒▒▒▒▒▒░"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)