25 doublePrecision_ =
false;
34 const auto printArrayFootprint
36 if(!array.
empty() && !name.empty()) {
37 this->
printMsg(name + std::string{
": "}
38 + std::to_string(array.
footprint()) +
" bytes");
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_");
60 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
62 if(!(ttk::isRunningWithMPI()))
64 this->
printErr(
"Empty dataset, precondition skipped");
80 if(edgeStarData_[i].size() == 1) {
88 for(
size_t i = 0; i < triangleStarData_.
size(); i++) {
89 if(triangleStarData_[i].size() == 1) {
90 for(
int j = 0; j < 3; j++) {
97 printErr(
"Unsupported dimension for edge boundary precondition");
103 if(ttk::isRunningWithMPI()) {
105 std::vector<unsigned char> charBoundary(edgeNumber,
false);
106 for(
int i = 0; i < edgeNumber; ++i) {
109 ttk::exchangeGhostDataWithoutTriangulation(
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) {
122 this->
printMsg(
"Extracted boundary edges", 1.0, tm.getElapsedTime(), 1);
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_);
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_);
157int ExplicitTriangulation::preconditionEdgeRankArray() {
159 edgeRankArray_.resize(edgeNumber, 0);
160 if(ttk::isRunningWithMPI()) {
170 if(this->cellGid_[sid] < this->cellGid_[min_id]) {
174 edgeRankArray_[id] = cellRankArray_[min_id];
180int ExplicitTriangulation::preconditionTriangleRankArray() {
182 triangleRankArray_.resize(triangleNumber, 0);
183 if(ttk::isRunningWithMPI()) {
194 if(this->cellGid_[sid] < this->cellGid_[min_id]) {
198 triangleRankArray_[id] = cellRankArray_[min_id];
208 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
210 if(!(ttk::isRunningWithMPI()))
212 this->
printErr(
"Empty dataset, precondition skipped");
232 for(
size_t i = 0; i < triangleStarData_.
size(); i++) {
233 if(triangleStarData_[i].size() == 1) {
239 printErr(
"Unsupported dimension for triangle boundary precondition");
245 if(ttk::isRunningWithMPI()) {
247 std::vector<unsigned char> charBoundary(triangleNumber,
false);
248 for(
int i = 0; i < triangleNumber; ++i) {
251 ttk::exchangeGhostDataWithoutTriangulation(
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) {
264 this->
printMsg(
"Extracted boundary triangles", 1.0, tm.getElapsedTime(), 1);
271 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
273 if(!(ttk::isRunningWithMPI()))
275 this->
printErr(
"Empty dataset, precondition skipped");
292 for(
size_t i = 0; i < vertexStarData_.
size(); i++) {
293 if(vertexStarData_[i].size() == 1) {
302 if(edgeStarData_[i].size() == 1) {
311 for(
size_t i = 0; i < triangleStarData_.
size(); i++) {
312 if(triangleStarData_[i].size() == 1) {
320 printErr(
"Unsupported dimension for vertex boundary precondition");
326 if(ttk::isRunningWithMPI()) {
327 this->preconditionDistributedVertices();
328 std::vector<unsigned char> charBoundary(vertexNumber_,
false);
329 for(
int i = 0; i < vertexNumber_; ++i) {
332 ttk::exchangeGhostVertices<unsigned char, ExplicitTriangulation>(
333 charBoundary.data(),
this, ttk::MPIcomm_);
335 for(
int i = 0; i < vertexNumber_; ++i) {
344 this->
printMsg(
"Extracted boundary vertices", 1.0, tm.getElapsedTime(), 1);
351 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
353 if(!(ttk::isRunningWithMPI()))
355 this->
printErr(
"Empty dataset, precondition skipped");
369 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
371 if(!(ttk::isRunningWithMPI()))
373 this->
printErr(
"Empty dataset, precondition skipped");
377 if(cellNeighborData_.
empty()) {
382 vertexNumber_, *cellArray_, cellNeighborData_, &triangleStarData_);
388 *cellArray_, cellNeighborData_, edgeStarData_);
397 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
399 if(!(ttk::isRunningWithMPI()))
401 this->
printErr(
"Empty dataset, precondition skipped");
412 if(!triangleStarData_.
empty()) {
419 nullptr, &triangleStarData_,
424 if(!triangleStarData_.
empty()) {
443 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
445 if(!(ttk::isRunningWithMPI()))
447 this->
printErr(
"Empty dataset, precondition skipped");
457 std::vector<std::array<SimplexId, 1>> tmp{};
459 vertexNumber_, *cellArray_,
edgeList_, edgeStarData_, tmp);
474 return this->preconditionDistributedEdges();
484 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
486 if(!(ttk::isRunningWithMPI()))
488 this->
printErr(
"Empty dataset, precondition skipped");
492 if(edgeLinkData_.
empty()) {
501 edgeList_, edgeStarData_, *cellArray_, edgeLinkData_);
513 printErr(
"Unsupported dimension for edge link precondition");
523 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
525 if(!(ttk::isRunningWithMPI()))
527 this->
printErr(
"Empty dataset, precondition skipped");
531 if(edgeStarData_.
empty()) {
539 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
541 if(!(ttk::isRunningWithMPI()))
543 this->
printErr(
"Empty dataset, precondition skipped");
547 if(edgeTriangleData_.
empty()) {
563 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
565 if(!(ttk::isRunningWithMPI()))
567 this->
printErr(
"Empty dataset, precondition skipped");
580 this->preconditionDistributedTriangles();
589 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
591 if(!(ttk::isRunningWithMPI()))
593 this->
printErr(
"Empty dataset, precondition skipped");
619 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
621 if(!(ttk::isRunningWithMPI()))
623 this->
printErr(
"Empty dataset, precondition skipped");
627 if(triangleLinkData_.
empty()) {
634 triangleList_, triangleStarData_, *cellArray_, triangleLinkData_);
642 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
644 if(!(ttk::isRunningWithMPI()))
646 this->
printErr(
"Empty dataset, precondition skipped");
650 if(triangleStarData_.
empty()) {
655 vertexNumber_, *cellArray_, &
triangleList_, &triangleStarData_);
663 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
665 if(!(ttk::isRunningWithMPI()))
667 this->
printErr(
"Empty dataset, precondition skipped");
680 vertexNumber_,
edgeList_, vertexEdgeData_);
687 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
689 if(!(ttk::isRunningWithMPI()))
691 this->
printErr(
"Empty dataset, precondition skipped");
715 printErr(
"Unsupported dimension for vertex link precondition");
724 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
726 if(!(ttk::isRunningWithMPI()))
728 this->
printErr(
"Empty dataset, precondition skipped");
737 vertexNumber_, vertexNeighborData_,
edgeList_);
744 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
746 if(!(ttk::isRunningWithMPI()))
748 this->
printErr(
"Empty dataset, precondition skipped");
757 vertexNumber_, *cellArray_, vertexStarData_);
764 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
766 if(!(ttk::isRunningWithMPI()))
768 this->
printErr(
"Empty dataset, precondition skipped");
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_;
802 if(simplexStar ==
nullptr) {
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");
819int ExplicitTriangulation::preconditionDistributedCells() {
820 if(this->hasPreconditionedDistributedCells_) {
823 if(!ttk::hasInitializedMPI()) {
826 if(this->cellGid_ ==
nullptr) {
827 this->
printErr(
"Missing global cell identifiers array!");
833 this->preconditionCellRankArray();
839 this->cellGidToLid_.reserve(nLocCells);
841 this->cellGidToLid_[this->cellGid_[lcid]] = lcid;
844 this->preconditionExchangeGhostCells();
846 this->preconditionDistributedCellRanges();
848 this->hasPreconditionedDistributedCells_ =
true;
852 + std::to_string(this->gatheredCellRanges_.back().end + 1)
854 1.0, tm.getElapsedTime(), this->threadNumber_);
860int ttk::ExplicitTriangulation::preconditionExchangeGhostCells() {
862 if(this->hasPreconditionedExchangeGhostCells_) {
865 if(!ttk::hasInitializedMPI()) {
868 if(this->cellGid_ ==
nullptr) {
869 this->printErr(
"Missing global cell identifiers array!");
876 const auto nLocCells{this->getNumberOfCells()};
881 this->ghostCellsPerOwner_[this->cellRankArray_[lcid]].emplace_back(
882 this->cellGid_[lcid]);
893 for(
const auto neigh : this->neighborRanks_) {
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]);
902 MPI_Sendrecv(this->ghostCellsPerOwner_[neigh].data(),
903 this->ghostCellsPerOwner_[neigh].size(), MIT, neigh,
905 this->remoteGhostCells_[neigh].size(), MIT, neigh, neigh,
906 ttk::MPIcomm_, MPI_STATUS_IGNORE);
909 this->hasPreconditionedExchangeGhostCells_ =
true;
913int ttk::ExplicitTriangulation::preconditionDistributedCellRanges() {
917 std::vector<SimplexId> localCellIds{};
918 localCellIds.reserve(this->getNumberOfCells());
919 for(
SimplexId i = 0; i < this->getNumberOfCells(); ++i) {
921 localCellIds.emplace_back(i);
925 TTK_PSORT(this->threadNumber_, localCellIds.begin(), localCellIds.end(),
927 return this->cellGid_[a] < this->cellGid_[b];
933 while(begRange < localCellIds.size()) {
934 size_t endRange{begRange + 1};
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) {
944 if(endRange == begRange + 1
945 && this->cellGid_[localCellIds[endRange]]
946 == this->cellGid_[localCellIds[endRange - 1]] + 1) {
947 endRange = localCellIds.size();
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()};
956 this->localCellRanges_.emplace_back(
957 CellRange{nRanges, gbeg, gend,
static_cast<size_t>(
ttk::MPIrank_)});
968 const int rangeSize = this->localCellRanges_.size();
969 MPI_Gather(&rangeSize, 1, ttk::getMPIType(rangeSize),
970 this->nRangesPerRank_.data(), 1, ttk::getMPIType(rangeSize), 0,
973 std::vector<int> displacements{};
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());
981 for(
size_t i = 0; i < this->nRangesPerRank_.size() - 1; ++i) {
982 displacements[i + 1] = displacements[i] + this->nRangesPerRank_[i];
986 auto cellRangeDT{CellRange::getMPIType()};
987 MPI_Type_commit(&cellRangeDT);
989 MPI_Gatherv(this->localCellRanges_.data(), this->localCellRanges_.size(),
990 cellRangeDT, this->gatheredCellRanges_.data(),
991 this->nRangesPerRank_.data(), displacements.data(), cellRangeDT,
994 MPI_Type_free(&cellRangeDT);
1000 this->threadNumber_, this->gatheredCellRanges_.begin(),
1001 this->gatheredCellRanges_.end(),
1002 [](
const CellRange &a,
const CellRange &b) { return a.begin < b.begin; });
1008size_t ttk::ExplicitTriangulation::computeCellRangeOffsets(
1009 std::vector<size_t> &nSimplicesPerRange)
const {
1013 std::vector<std::vector<size_t>> nSimplicesPerRangePerRank{};
1016 nSimplicesPerRangePerRank.resize(this->nRangesPerRank_.size());
1018 nSimplicesPerRangePerRank[i].resize(this->nRangesPerRank_[i]);
1025 MPI_Recv(nSimplicesPerRangePerRank[i].data(),
1026 nSimplicesPerRangePerRank[i].size(), ttk::getMPIType(
size_t{}),
1027 i, MPI_ANY_TAG, ttk::MPIcomm_, MPI_STATUS_IGNORE);
1029 std::swap(nSimplicesPerRangePerRank[0], nSimplicesPerRange);
1031 MPI_Send(nSimplicesPerRange.data(), nSimplicesPerRange.size(),
1032 ttk::getMPIType(
size_t{}), 0, 0, ttk::MPIcomm_);
1037 size_t nSimplices{};
1040 for(
const auto &range : this->gatheredCellRanges_) {
1041 auto &pSum{nSimplicesPerRangePerRank[range.rank][range.id]};
1042 std::swap(pSum, nSimplices);
1051 MPI_Send(nSimplicesPerRangePerRank[i].data(),
1052 nSimplicesPerRangePerRank[i].size(), ttk::getMPIType(
size_t{}),
1053 i, 0, ttk::MPIcomm_);
1055 std::swap(nSimplicesPerRange, nSimplicesPerRangePerRank[0]);
1057 MPI_Recv(nSimplicesPerRange.data(), nSimplicesPerRange.size(),
1058 ttk::getMPIType(
size_t{}), MPI_ANY_TAG, 0, ttk::MPIcomm_,
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) {
1073 std::vector<std::vector<SimplexId>> globalIdPerOwnedGhostCell(
ttk::MPIsize_);
1075 std::vector<std::vector<SimplexId>> globalIdPerLocalGhostCell(
ttk::MPIsize_);
1090 for(
const auto neigh : this->neighborRanks_) {
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);
1102 globalIdPerLocalGhostCell[neigh].resize(
1103 nSimplicesPerCell * this->ghostCellsPerOwner_[neigh].size());
1106 MPI_Sendrecv(globalIdPerOwnedGhostCell[neigh].data(),
1107 globalIdPerOwnedGhostCell[neigh].size(), MIT, neigh,
1109 globalIdPerLocalGhostCell[neigh].size(), MIT, neigh, neigh,
1110 ttk::MPIcomm_, MPI_STATUS_IGNORE);
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) {
1120 globalIdPerLocalGhostCell[neigh][nSimplicesPerCell * i + j]};
1121 storeGlobalSimplexId(lcid, geid, j);
1138 MPI_Bcast(&doNextIter, 1, ttk::getMPIType(doNextIter), i, ttk::MPIcomm_);
1139 doIter |= (doNextIter == 1);
1143 this->
printMsg(
"Re-sending global ids to neighbors...");
1150int ExplicitTriangulation::preconditionDistributedEdges() {
1151 if(this->hasPreconditionedDistributedEdges_) {
1154 if(!ttk::hasInitializedMPI()) {
1157 if(this->cellGid_ ==
nullptr) {
1158 this->
printErr(
"Missing global cell identifiers array!");
1172 this->preconditionDistributedCells();
1181 std::vector<size_t> nEdgesPerRange(this->localCellRanges_.size());
1183 const auto edgeAlreadyProcessed = [
this](
const SimplexId leid,
1189 if(sid == -1 || sid == lcid) {
1194 if(this->cellGid_[sid] < this->cellGid_[lcid]) {
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) {
1208 if(this->maxCellDim_ == 3) {
1210 }
else if(this->maxCellDim_ == 2) {
1215 if(this->maxCellDim_ == 3) {
1217 }
else if(this->maxCellDim_ == 2) {
1220 const auto alreadyProcessed = edgeAlreadyProcessed(leid, lcid);
1221 if(!alreadyProcessed) {
1222 edgeGid[leid] = edgeCount;
1223 edgeRangeId[leid] = rangeId;
1229#ifdef TTK_ENABLE_OPENMP
1230#pragma omp parallel for num_threads(this->threadNumber_)
1232 for(
size_t i = 0; i < this->localCellRanges_.size(); ++i) {
1233 auto &range{this->localCellRanges_[i]};
1235 for(
size_t j = range.begin; j <= range.end; ++j) {
1237 const auto lcid{this->cellGidToLid_[j]};
1238 countCellEdges(lcid, this->edgeLidToGid_, edgeLidToRangeId, range.id,
1244 const auto nEdges = this->computeCellRangeOffsets(nEdgesPerRange);
1249 if(this->edgeLidToGid_[leid] == -1) {
1253 const auto geid{this->edgeLidToGid_[leid]
1254 + nEdgesPerRange[edgeLidToRangeId[leid]]};
1255 this->edgeLidToGid_[leid] = geid;
1256 this->edgeGidToLid_[geid] = leid;
1262 this->exchangeDistributedInternal(
1263 [
this](
const SimplexId lcid,
const int j) {
1266 return this->edgeLidToGid_[leid];
1271 if(this->edgeLidToGid_[leid] == -1 && geid != -1) {
1272 this->edgeLidToGid_[leid] = geid;
1273 this->edgeGidToLid_[geid] = leid;
1278 this->edgeLidToGid_.begin(), this->edgeLidToGid_.end(), -1)
1283 this->preconditionEdgeRankArray();
1286 this->
printMsg(
"Domain contains " + std::to_string(nEdges) +
" edges", 1.0,
1287 tm.getElapsedTime(), 1);
1290 this->hasPreconditionedDistributedEdges_ =
true;
1295int ExplicitTriangulation::preconditionDistributedTriangles() {
1296 if(this->hasPreconditionedDistributedTriangles_) {
1299 if(!ttk::hasInitializedMPI()) {
1302 if(this->cellGid_ ==
nullptr) {
1303 this->
printErr(
"Missing global cell identifiers array!");
1313 this->preconditionDistributedCells();
1321 std::vector<SimplexId> triangleLidToRangeId(
1323 std::vector<size_t> nTrianglesPerRange(this->localCellRanges_.size());
1325 const auto triangleAlreadyProcessed
1332 if(sid == -1 || sid == lcid) {
1337 if(this->cellGid_[sid] < this->cellGid_[lcid]) {
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) {
1351 for(
SimplexId k = 0; k < nTriangles; ++k) {
1354 const auto alreadyProcessed = triangleAlreadyProcessed(leid, lcid);
1355 if(!alreadyProcessed) {
1356 triangleGid[leid] = triangleCount;
1357 triangleRangeId[leid] = rangeId;
1363#ifdef TTK_ENABLE_OPENMP
1364#pragma omp parallel for num_threads(this->threadNumber_)
1366 for(
size_t i = 0; i < this->localCellRanges_.size(); ++i) {
1367 auto &range{this->localCellRanges_[i]};
1369 for(
size_t j = range.begin; j <= range.end; ++j) {
1371 const auto lcid{this->cellGidToLid_[j]};
1372 countCellTriangles(lcid, this->triangleLidToGid_, triangleLidToRangeId,
1373 range.id, nTrianglesPerRange[i]);
1378 const auto nTriangles = this->computeCellRangeOffsets(nTrianglesPerRange);
1383 if(this->triangleLidToGid_[leid] == -1) {
1387 const auto geid{this->triangleLidToGid_[leid]
1388 + nTrianglesPerRange[triangleLidToRangeId[leid]]};
1389 this->triangleLidToGid_[leid] = geid;
1390 this->triangleGidToLid_[geid] = leid;
1395 const auto nTrianglesPerCell{4};
1396 this->exchangeDistributedInternal(
1397 [
this](
const SimplexId lcid,
const int j) {
1400 return this->triangleLidToGid_[ltid];
1405 if(this->triangleLidToGid_[ltid] == -1 && gtid != -1) {
1406 this->triangleLidToGid_[ltid] = gtid;
1407 this->triangleGidToLid_[gtid] = ltid;
1411 return std::count(this->triangleLidToGid_.begin(),
1412 this->triangleLidToGid_.end(), -1)
1417 this->preconditionTriangleRankArray();
1421 "Domain contains " + std::to_string(nTriangles) +
" triangles", 1.0,
1422 tm.getElapsedTime(), 1);
1425 this->hasPreconditionedDistributedTriangles_ =
true;
1430int ExplicitTriangulation::preconditionDistributedVertices() {
1431 if(this->hasPreconditionedDistributedVertices_) {
1434 if(!hasInitializedMPI()) {
1437 if(this->vertGid_ ==
nullptr) {
1438 this->
printErr(
"Missing global vertex identifiers array!");
1442 this->hasPreconditionedDistributedVertices_ =
true;
1443 this->preconditionVertexRankArray();
1449 this->vertexGidToLid_.reserve(nLocVertices);
1451 this->vertexGidToLid_[this->vertGid_[lvid]] = lvid;
1454 this->preconditionExchangeGhostVertices();
1459int ttk::ExplicitTriangulation::preconditionExchangeGhostVertices() {
1461 if(this->hasPreconditionedExchangeGhostVertices_) {
1464 if(!ttk::hasInitializedMPI()) {
1467 if(this->vertGid_ ==
nullptr) {
1468 this->printErr(
"Missing global vertex identifiers array!");
1473 const auto nLocVertices{this->getNumberOfVertices()};
1480 this->ghostVerticesPerOwner_[this->vertexRankArray_[lvid]].emplace_back(
1481 this->vertGid_[lvid]);
1490 std::vector<size_t> nOwnedGhostVerticesPerRank(
ttk::MPIsize_);
1492 for(
const auto neigh : this->neighborRanks_) {
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]);
1501 MPI_Sendrecv(this->ghostVerticesPerOwner_[neigh].data(),
1502 this->ghostVerticesPerOwner_[neigh].size(), MIT, neigh,
1504 this->remoteGhostVertices_[neigh].size(), MIT, neigh, neigh,
1505 ttk::MPIcomm_, MPI_STATUS_IGNORE);
1508 this->hasPreconditionedExchangeGhostVertices_ =
true;
1515template <
typename T>
1517 stream.write(
reinterpret_cast<const char *
>(&var),
sizeof(var));
1520template <
typename T>
1522 const T *
const buff,
1523 const size_t size) {
1524 stream.write(
reinterpret_cast<const char *
>(buff), size *
sizeof(T));
1528const char *ExplicitTriangulation::magicBytes_ =
"TTKTriangulationFileFormat";
1529const unsigned long ExplicitTriangulation::formatVersion_ = 1;
1534 stream.write(ttk::ExplicitTriangulation::magicBytes_,
1535 std::strlen(ttk::ExplicitTriangulation::magicBytes_));
1537 writeBin(stream, ttk::ExplicitTriangulation::formatVersion_);
1545 const auto edgesNumber = [
this, dim]() ->
SimplexId {
1548 }
else if(dim > 1) {
1553 const auto nEdges = edgesNumber();
1556 const auto trianglesNumber = [
this, dim]() ->
SimplexId {
1559 }
else if(dim == 3) {
1564 const auto nTriangles = trianglesNumber();
1575#define WRITE_FIXED(ARRAY) \
1576 if(ARRAY.empty()) { \
1577 writeBin(stream, char{0}); \
1579 writeBin(stream, char{1}); \
1580 writeBinArray(stream, ARRAY.data(), ARRAY.size()); \
1596#define WRITE_GUARD(ARRAY) \
1597 if(ARRAY.empty()) { \
1598 writeBin(stream, char{0}); \
1601 writeBin(stream, char{1}); \
1612 write_variable(this->vertexNeighborData_);
1614 write_variable(this->cellNeighborData_);
1616 write_variable(this->vertexEdgeData_);
1618 write_variable(this->vertexTriangleData_);
1620 write_variable(this->edgeTriangleData_);
1622 write_variable(this->vertexStarData_);
1624 write_variable(this->edgeStarData_);
1626 write_variable(this->triangleStarData_);
1628 write_variable(this->vertexLinkData_);
1630 write_variable(this->edgeLinkData_);
1632 write_variable(this->triangleLinkData_);
1634 const auto write_bool = [&stream](
const std::vector<bool> &arr) {
1637 for(
size_t i = 0; i < arr.size(); ++i) {
1638 const auto b =
static_cast<char>(arr[i]);
1655 stream << ttk::ExplicitTriangulation::magicBytes_ <<
'\n';
1657 stream << ttk::ExplicitTriangulation::formatVersion_ + 1 <<
'\n';
1660 stream <<
"dim " << dim <<
'\n';
1663 const auto edgesNumber = [
this, dim]() ->
SimplexId {
1666 }
else if(dim > 1) {
1671 const auto nEdges = edgesNumber();
1672 const auto trianglesNumber = [
this, dim]() ->
SimplexId {
1675 }
else if(dim == 3) {
1680 const auto nTriangles = trianglesNumber();
1682 stream << nVerts <<
' ' << nEdges <<
' ' << nTriangles <<
' ' << nTetras
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) { \
1692 stream << slice[i]; \
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) <<
' ';
1729#define WRITE_BOOL(ARRAY) \
1730 stream << #ARRAY << '\n'; \
1731 for(const auto el : ARRAY) { \
1732 stream << el << '\n'; \
1743template <
typename T>
1745 stream.read(
reinterpret_cast<char *
>(&res),
sizeof(res));
1748template <
typename T>
1750 stream.read(
reinterpret_cast<char *
>(res), size *
sizeof(T));
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!");
1768 unsigned long 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!");
1778 SimplexId nVerts{}, nEdges{}, nTriangles{}, nTetras{};
1792 this->
printErr(
"Incorrect dimension!");
1796 this->
printErr(
"Incorrect number of vertices!");
1801 this->
printErr(
"Incorrect number of cells!");
1807 const auto read_guard = [&stream]() {
1813#define READ_FIXED(ARRAY, N_ITEMS) \
1814 if(!read_guard()) { \
1815 ARRAY.resize(N_ITEMS); \
1816 readBinArray(stream, ARRAY.data(), N_ITEMS); \
1832 const auto read_variable
1838 std::vector<SimplexId> offsets{}, data{};
1839 offsets.resize(n_items + 1);
1841 data.resize(offsets.back());
1843 arr.setData(std::move(data), std::move(offsets));
1847 read_variable(this->vertexNeighborData_, nVerts);
1851 read_variable(this->vertexEdgeData_, nVerts);
1853 read_variable(this->vertexTriangleData_, nVerts);
1855 read_variable(this->edgeTriangleData_, nEdges);
1857 read_variable(this->vertexStarData_, nVerts);
1859 read_variable(this->edgeStarData_, nEdges);
1861 read_variable(this->triangleStarData_, nTriangles);
1863 read_variable(this->vertexLinkData_, nVerts);
1865 read_variable(this->edgeLinkData_, nEdges);
1867 read_variable(this->triangleLinkData_, nTriangles);
1869 const auto read_bool
1870 = [&stream, &read_guard](std::vector<bool> &arr,
const SimplexId n_items) {
1876 arr.resize(n_items);
1877 for(
SimplexId i = 0; i < n_items; ++i) {
1879 stream.read(&b,
sizeof(b));
1880 arr[i] =
static_cast<bool>(b);
#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.
std::vector< std::array< SimplexId, 3 > > triangleList_
std::vector< bool > boundaryEdges_
virtual int getTriangleEdge(const SimplexId &triangleId, const int &localEdgeId, SimplexId &edgeId) const
std::vector< bool > boundaryTriangles_
std::vector< std::array< SimplexId, 4 > > tetraTriangleList_
virtual int preconditionTriangleEdges()
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
int setWrapper(const Wrapper *wrapper) override
void setDebugMsgPrefix(const std::string &prefix)
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
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
SimplexId getTriangleEdgeNumberInternal(const SimplexId &triangleId) const override
int preconditionEdgeStarsInternal() override
size_t footprint(size_t size=0) const
int preconditionTriangleStarsInternal() override
int preconditionTrianglesInternal() 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 preconditionEdgesInternal() 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
int preconditionCellEdgesInternal() override
int preconditionVertexLinksInternal() override
SimplexId TTK_TRIANGULATION_INTERNAL() getTriangleStarNumber(const SimplexId &triangleId) const override
int preconditionTriangleLinksInternal() override
int preconditionManifoldInternal() override
~ExplicitTriangulation() override
int preconditionEdgeLinksInternal() override
int preconditionVertexStarsInternal() override
int preconditionVertexEdgesInternal() 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.
int buildEdgeLinks(const std::vector< std::array< SimplexId, 2 > > &edgeList, const FlatJaggedArray &edgeStars, const CellArray &cellArray, FlatJaggedArray &edgeLinks) const
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.
int buildCellNeighborsFromTriangles(const SimplexId &vertexNumber, const CellArray &cellArray, FlatJaggedArray &cellNeighbors, FlatJaggedArray *triangleStars=nullptr) const
TwoSkeleton processing package.
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
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.
int buildVertexEdges(const SimplexId &vertexNumber, const std::vector< std::array< SimplexId, 2 > > &edgeList, FlatJaggedArray &vertexEdges) const
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
COMMON_EXPORTS int MPIsize_
COMMON_EXPORTS int MPIrank_
long long int LongSimplexId
Identifier type for simplices of any dimension.
int SimplexId
Identifier type for simplices of any dimension.
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)