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 this->neighborsToId_);
137 ttk::preconditionNeighborsUsingRankArray<ttk::SimplexId>(
138 this->neighborRanks_, this->neighborsToId_,
139 [
this](
const ttk::SimplexId a) {
return this->getVertexRank(a); },
140 this->vertexNumber_, ttk::MPIcomm_);
146int ExplicitTriangulation::preconditionCellRankArray() {
147 if(cellRankArray_.size() == 0) {
148 this->cellRankArray_.resize(this->cellNumber_, 0);
149 if(ttk::isRunningWithMPI()) {
150 ttk::produceRankArray(this->cellRankArray_, this->cellGid_,
151 this->cellGhost_, this->cellNumber_,
152 this->boundingBox_.data(), this->neighborRanks_,
153 this->neighborsToId_);
159int ExplicitTriangulation::preconditionEdgeRankArray() {
161 edgeRankArray_.resize(edgeNumber, 0);
162 if(ttk::isRunningWithMPI()) {
172 if(this->cellRankArray_[sid] < this->cellRankArray_[min_id]) {
176 edgeRankArray_[id] = cellRankArray_[min_id];
182int ExplicitTriangulation::preconditionTriangleRankArray() {
184 triangleRankArray_.resize(triangleNumber, 0);
185 if(ttk::isRunningWithMPI()) {
196 if(this->cellRankArray_[sid] < this->cellRankArray_[min_id]) {
200 triangleRankArray_[id] = cellRankArray_[min_id];
210 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
212 if(!(ttk::isRunningWithMPI()))
214 this->
printErr(
"Empty dataset, precondition skipped");
234 for(
size_t i = 0; i < triangleStarData_.size(); i++) {
235 if(triangleStarData_[i].size() == 1) {
241 printErr(
"Unsupported dimension for triangle boundary precondition");
247 if(ttk::isRunningWithMPI()) {
249 std::vector<unsigned char> charBoundary(triangleNumber,
false);
250 for(
int i = 0; i < triangleNumber; ++i) {
253 ttk::exchangeGhostDataWithoutTriangulation(
255 [
this](
const SimplexId a) { return this->triangleRankArray_[a]; },
256 [
this](
const SimplexId a) { return this->triangleLidToGid_[a]; },
257 [
this](
const SimplexId a) { return this->triangleGidToLid_[a]; },
258 triangleNumber, ttk::MPIcomm_, this->getNeighborRanks());
259 for(
int i = 0; i < triangleNumber; ++i) {
266 this->
printMsg(
"Extracted boundary triangles", 1.0, tm.getElapsedTime(), 1);
273 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
275 if(!(ttk::isRunningWithMPI()))
277 this->
printErr(
"Empty dataset, precondition skipped");
294 for(
size_t i = 0; i < vertexStarData_.size(); i++) {
295 if(vertexStarData_[i].size() == 1) {
304 if(edgeStarData_[i].size() == 1) {
313 for(
size_t i = 0; i < triangleStarData_.size(); i++) {
314 if(triangleStarData_[i].size() == 1) {
322 printErr(
"Unsupported dimension for vertex boundary precondition");
328 if(ttk::isRunningWithMPI()) {
329 this->preconditionDistributedVertices();
330 std::vector<unsigned char> charBoundary(vertexNumber_,
false);
331 for(
int i = 0; i < vertexNumber_; ++i) {
334 ttk::exchangeGhostVertices<unsigned char, ExplicitTriangulation>(
335 charBoundary.data(),
this, ttk::MPIcomm_);
337 for(
int i = 0; i < vertexNumber_; ++i) {
346 this->
printMsg(
"Extracted boundary vertices", 1.0, tm.getElapsedTime(), 1);
353 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
355 if(!(ttk::isRunningWithMPI()))
357 this->
printErr(
"Empty dataset, precondition skipped");
371 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
373 if(!(ttk::isRunningWithMPI()))
375 this->
printErr(
"Empty dataset, precondition skipped");
379 if(cellNeighborData_.empty()) {
384 vertexNumber_, *cellArray_, cellNeighborData_, &triangleStarData_);
390 *cellArray_, cellNeighborData_, edgeStarData_);
399 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
401 if(!(ttk::isRunningWithMPI()))
403 this->
printErr(
"Empty dataset, precondition skipped");
414 if(!triangleStarData_.empty()) {
421 nullptr, &triangleStarData_,
426 if(!triangleStarData_.empty()) {
445 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
447 if(!(ttk::isRunningWithMPI()))
449 this->
printErr(
"Empty dataset, precondition skipped");
459 std::vector<std::array<SimplexId, 1>> tmp{};
461 vertexNumber_, *cellArray_,
edgeList_, edgeStarData_, tmp);
476 return this->preconditionDistributedEdges();
486 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
488 if(!(ttk::isRunningWithMPI()))
490 this->
printErr(
"Empty dataset, precondition skipped");
494 if(edgeLinkData_.empty()) {
503 edgeList_, edgeStarData_, *cellArray_, edgeLinkData_);
515 printErr(
"Unsupported dimension for edge link precondition");
525 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
527 if(!(ttk::isRunningWithMPI()))
529 this->
printErr(
"Empty dataset, precondition skipped");
533 if(edgeStarData_.empty()) {
541 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
543 if(!(ttk::isRunningWithMPI()))
545 this->
printErr(
"Empty dataset, precondition skipped");
549 if(edgeTriangleData_.empty()) {
565 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
567 if(!(ttk::isRunningWithMPI()))
569 this->
printErr(
"Empty dataset, precondition skipped");
582 this->preconditionDistributedTriangles();
591 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
593 if(!(ttk::isRunningWithMPI()))
595 this->
printErr(
"Empty dataset, precondition skipped");
621 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
623 if(!(ttk::isRunningWithMPI()))
625 this->
printErr(
"Empty dataset, precondition skipped");
629 if(triangleLinkData_.empty()) {
636 triangleList_, triangleStarData_, *cellArray_, triangleLinkData_);
644 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
646 if(!(ttk::isRunningWithMPI()))
648 this->
printErr(
"Empty dataset, precondition skipped");
652 if(triangleStarData_.empty()) {
657 vertexNumber_, *cellArray_, &
triangleList_, &triangleStarData_);
665 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
667 if(!(ttk::isRunningWithMPI()))
669 this->
printErr(
"Empty dataset, precondition skipped");
673 if((
SimplexId)vertexEdgeData_.size() != vertexNumber_) {
682 vertexNumber_,
edgeList_, vertexEdgeData_);
689 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
691 if(!(ttk::isRunningWithMPI()))
693 this->
printErr(
"Empty dataset, precondition skipped");
697 if((
SimplexId)vertexLinkData_.size() != vertexNumber_) {
717 printErr(
"Unsupported dimension for vertex link precondition");
726 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
728 if(!(ttk::isRunningWithMPI()))
730 this->
printErr(
"Empty dataset, precondition skipped");
734 if((
SimplexId)vertexNeighborData_.size() != vertexNumber_) {
739 vertexNumber_, vertexNeighborData_,
edgeList_);
746 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
748 if(!(ttk::isRunningWithMPI()))
750 this->
printErr(
"Empty dataset, precondition skipped");
754 if((
SimplexId)vertexStarData_.size() != vertexNumber_) {
759 vertexNumber_, *cellArray_, vertexStarData_);
766 if(this->cellArray_ ==
nullptr || this->vertexNumber_ == 0) {
768 if(!(ttk::isRunningWithMPI()))
770 this->
printErr(
"Empty dataset, precondition skipped");
774 if((
SimplexId)vertexTriangleData_.size() != vertexNumber_) {
795 simplexStar = &this->triangleStarData_;
798 simplexStar = &this->edgeStarData_;
801 simplexStar = &this->vertexStarData_;
804 if(simplexStar ==
nullptr) {
808 for(
const auto star : *simplexStar) {
809 if(star.size() < 1 || star.size() > 2) {
811 this->
printWrn(
"Non manifold data-set detected");
821int ExplicitTriangulation::preconditionDistributedCells() {
822 if(this->hasPreconditionedDistributedCells_) {
825 if(!ttk::hasInitializedMPI()) {
828 if(this->cellGid_ ==
nullptr) {
829 this->
printErr(
"Missing global cell identifiers array!");
835 this->preconditionCellRankArray();
841 this->cellGidToLid_.reserve(nLocCells);
843 this->cellGidToLid_[this->cellGid_[lcid]] = lcid;
846 this->preconditionExchangeGhostCells();
848 this->preconditionDistributedCellRanges();
850 this->hasPreconditionedDistributedCells_ =
true;
854 + std::to_string(this->gatheredCellRanges_.back().end + 1)
856 1.0, tm.getElapsedTime(), this->threadNumber_);
862int ttk::ExplicitTriangulation::preconditionExchangeGhostCells() {
864 if(this->hasPreconditionedExchangeGhostCells_) {
867 if(!ttk::hasInitializedMPI()) {
870 if(this->cellGid_ ==
nullptr) {
871 this->printErr(
"Missing global cell identifiers array!");
878 const auto nLocCells{this->getNumberOfCells()};
883 this->ghostCellsPerOwner_[this->cellRankArray_[lcid]].emplace_back(
884 this->cellGid_[lcid]);
895 for(
const auto neigh : this->neighborRanks_) {
897 const auto nCells{this->ghostCellsPerOwner_[neigh].size()};
898 MPI_Sendrecv(&nCells, 1, ttk::getMPIType(nCells), neigh,
ttk::MPIrank_,
899 &nOwnedGhostCellsPerRank[neigh], 1, ttk::getMPIType(nCells),
900 neigh, neigh, ttk::MPIcomm_, MPI_STATUS_IGNORE);
901 this->remoteGhostCells_[neigh].resize(nOwnedGhostCellsPerRank[neigh]);
904 MPI_Sendrecv(this->ghostCellsPerOwner_[neigh].data(),
905 this->ghostCellsPerOwner_[neigh].size(), MIT, neigh,
907 this->remoteGhostCells_[neigh].size(), MIT, neigh, neigh,
908 ttk::MPIcomm_, MPI_STATUS_IGNORE);
911 this->hasPreconditionedExchangeGhostCells_ =
true;
915int ttk::ExplicitTriangulation::preconditionDistributedCellRanges() {
919 std::vector<SimplexId> localCellIds{};
920 localCellIds.reserve(this->getNumberOfCells());
921 for(
SimplexId i = 0; i < this->getNumberOfCells(); ++i) {
923 localCellIds.emplace_back(i);
927 TTK_PSORT(this->threadNumber_, localCellIds.begin(), localCellIds.end(),
929 return this->cellGid_[a] < this->cellGid_[b];
935 while(begRange < localCellIds.size()) {
936 size_t endRange{begRange + 1};
938 if(begRange < localCellIds.size() - 1) {
939 for(
size_t j = begRange + 1; j < localCellIds.size(); ++j) {
940 if(this->cellGid_[localCellIds[j]]
941 > this->cellGid_[localCellIds[j - 1]] + 1) {
946 if(endRange == begRange + 1
947 && this->cellGid_[localCellIds[endRange]]
948 == this->cellGid_[localCellIds[endRange - 1]] + 1) {
949 endRange = localCellIds.size();
953 const size_t gbeg = this->cellGid_[localCellIds[begRange]];
954 const size_t gend = this->cellGid_[localCellIds[endRange - 1]];
955 const auto nRanges{this->localCellRanges_.size()};
958 this->localCellRanges_.emplace_back(
959 CellRange{nRanges, gbeg, gend,
static_cast<size_t>(
ttk::MPIrank_)});
970 const int rangeSize = this->localCellRanges_.size();
971 MPI_Gather(&rangeSize, 1, ttk::getMPIType(rangeSize),
972 this->nRangesPerRank_.data(), 1, ttk::getMPIType(rangeSize), 0,
975 std::vector<int> displacements{};
978 const auto nRanges{std::accumulate(
979 this->nRangesPerRank_.begin(), this->nRangesPerRank_.end(), 0)};
980 this->gatheredCellRanges_.resize(nRanges);
981 displacements.resize(this->nRangesPerRank_.size());
983 for(
size_t i = 0; i < this->nRangesPerRank_.size() - 1; ++i) {
984 displacements[i + 1] = displacements[i] + this->nRangesPerRank_[i];
988 auto cellRangeDT{CellRange::getMPIType()};
989 MPI_Type_commit(&cellRangeDT);
991 MPI_Gatherv(this->localCellRanges_.data(), this->localCellRanges_.size(),
992 cellRangeDT, this->gatheredCellRanges_.data(),
993 this->nRangesPerRank_.data(), displacements.data(), cellRangeDT,
996 MPI_Type_free(&cellRangeDT);
1002 this->threadNumber_, this->gatheredCellRanges_.begin(),
1003 this->gatheredCellRanges_.end(),
1004 [](
const CellRange &a,
const CellRange &b) { return a.begin < b.begin; });
1010size_t ttk::ExplicitTriangulation::computeCellRangeOffsets(
1011 std::vector<size_t> &nSimplicesPerRange)
const {
1015 std::vector<std::vector<size_t>> nSimplicesPerRangePerRank{};
1018 nSimplicesPerRangePerRank.resize(this->nRangesPerRank_.size());
1020 nSimplicesPerRangePerRank[i].resize(this->nRangesPerRank_[i]);
1027 MPI_Recv(nSimplicesPerRangePerRank[i].data(),
1028 nSimplicesPerRangePerRank[i].size(), ttk::getMPIType(
size_t{}),
1029 i, MPI_ANY_TAG, ttk::MPIcomm_, MPI_STATUS_IGNORE);
1031 std::swap(nSimplicesPerRangePerRank[0], nSimplicesPerRange);
1033 MPI_Send(nSimplicesPerRange.data(), nSimplicesPerRange.size(),
1034 ttk::getMPIType(
size_t{}), 0, 0, ttk::MPIcomm_);
1039 size_t nSimplices{};
1042 for(
const auto &range : this->gatheredCellRanges_) {
1043 auto &pSum{nSimplicesPerRangePerRank[range.rank][range.id]};
1044 std::swap(pSum, nSimplices);
1053 MPI_Send(nSimplicesPerRangePerRank[i].data(),
1054 nSimplicesPerRangePerRank[i].size(), ttk::getMPIType(
size_t{}),
1055 i, 0, ttk::MPIcomm_);
1057 std::swap(nSimplicesPerRange, nSimplicesPerRangePerRank[0]);
1059 MPI_Recv(nSimplicesPerRange.data(), nSimplicesPerRange.size(),
1060 ttk::getMPIType(
size_t{}), MPI_ANY_TAG, 0, ttk::MPIcomm_,
1067template <
typename Func0,
typename Func1,
typename Func2>
1068int ttk::ExplicitTriangulation::exchangeDistributedInternal(
1069 const Func0 &getGlobalSimplexId,
1070 const Func1 &storeGlobalSimplexId,
1071 const Func2 &iterCond,
1072 const int nSimplicesPerCell) {
1075 std::vector<std::vector<SimplexId>> globalIdPerOwnedGhostCell(
ttk::MPIsize_);
1077 std::vector<std::vector<SimplexId>> globalIdPerLocalGhostCell(
ttk::MPIsize_);
1092 for(
const auto neigh : this->neighborRanks_) {
1094 globalIdPerOwnedGhostCell[neigh].resize(
1095 nSimplicesPerCell * this->remoteGhostCells_[neigh].size());
1096 for(
size_t i = 0; i < this->remoteGhostCells_[neigh].size(); ++i) {
1097 const auto lcid{this->cellGidToLid_[this->remoteGhostCells_[neigh][i]]};
1098 for(
int j = 0; j < nSimplicesPerCell; ++j) {
1099 globalIdPerOwnedGhostCell[neigh][nSimplicesPerCell * i + j]
1100 = getGlobalSimplexId(lcid, j);
1104 globalIdPerLocalGhostCell[neigh].resize(
1105 nSimplicesPerCell * this->ghostCellsPerOwner_[neigh].size());
1108 MPI_Sendrecv(globalIdPerOwnedGhostCell[neigh].data(),
1109 globalIdPerOwnedGhostCell[neigh].size(), MIT, neigh,
1111 globalIdPerLocalGhostCell[neigh].size(), MIT, neigh, neigh,
1112 ttk::MPIcomm_, MPI_STATUS_IGNORE);
1116 for(
const auto neigh : this->neighborRanks_) {
1117 for(
size_t i = 0; i < this->ghostCellsPerOwner_[neigh].size(); ++i) {
1118 const auto gcid{this->ghostCellsPerOwner_[neigh][i]};
1119 const auto lcid{this->cellGidToLid_[gcid]};
1120 for(
int j = 0; j < nSimplicesPerCell; ++j) {
1122 globalIdPerLocalGhostCell[neigh][nSimplicesPerCell * i + j]};
1123 storeGlobalSimplexId(lcid, geid, j);
1140 MPI_Bcast(&doNextIter, 1, ttk::getMPIType(doNextIter), i, ttk::MPIcomm_);
1141 doIter |= (doNextIter == 1);
1145 this->
printMsg(
"Re-sending global ids to neighbors...");
1152int ExplicitTriangulation::preconditionDistributedEdges() {
1153 if(this->hasPreconditionedDistributedEdges_) {
1156 if(!ttk::hasInitializedMPI()) {
1159 if(this->cellGid_ ==
nullptr) {
1160 this->
printErr(
"Missing global cell identifiers array!");
1174 this->preconditionDistributedCells();
1183 std::vector<size_t> nEdgesPerRange(this->localCellRanges_.size());
1185 const auto edgeAlreadyProcessed = [
this](
const SimplexId leid,
1191 if(sid == -1 || sid == lcid) {
1196 if(this->cellRankArray_[sid] < this->cellRankArray_[lcid]) {
1204 const auto countCellEdges
1205 = [
this, &edgeAlreadyProcessed](
const SimplexId lcid,
1206 std::vector<SimplexId> &edgeGid,
1207 std::vector<SimplexId> &edgeRangeId,
1208 const size_t rangeId,
size_t &edgeCount) {
1210 if(this->maxCellDim_ == 3) {
1212 }
else if(this->maxCellDim_ == 2) {
1217 if(this->maxCellDim_ == 3) {
1219 }
else if(this->maxCellDim_ == 2) {
1222 const auto alreadyProcessed = edgeAlreadyProcessed(leid, lcid);
1223 if(!alreadyProcessed) {
1224 edgeGid[leid] = edgeCount;
1225 edgeRangeId[leid] = rangeId;
1231#ifdef TTK_ENABLE_OPENMP
1232#pragma omp parallel for num_threads(this->threadNumber_)
1234 for(
size_t i = 0; i < this->localCellRanges_.size(); ++i) {
1235 auto &range{this->localCellRanges_[i]};
1237 for(
size_t j = range.begin; j <= range.end; ++j) {
1239 const auto lcid{this->cellGidToLid_[j]};
1240 countCellEdges(lcid, this->edgeLidToGid_, edgeLidToRangeId, range.id,
1246 const auto nEdges = this->computeCellRangeOffsets(nEdgesPerRange);
1251 if(this->edgeLidToGid_[leid] == -1) {
1255 const auto geid{this->edgeLidToGid_[leid]
1256 + nEdgesPerRange[edgeLidToRangeId[leid]]};
1257 this->edgeLidToGid_[leid] = geid;
1258 this->edgeGidToLid_[geid] = leid;
1264 this->exchangeDistributedInternal(
1265 [
this](
const SimplexId lcid,
const int j) {
1268 return this->edgeLidToGid_[leid];
1273 if(this->edgeLidToGid_[leid] == -1 && geid != -1) {
1274 this->edgeLidToGid_[leid] = geid;
1275 this->edgeGidToLid_[geid] = leid;
1280 this->edgeLidToGid_.begin(), this->edgeLidToGid_.end(), -1)
1285 this->preconditionEdgeRankArray();
1288 this->
printMsg(
"Domain contains " + std::to_string(nEdges) +
" edges", 1.0,
1289 tm.getElapsedTime(), 1);
1292 this->hasPreconditionedDistributedEdges_ =
true;
1297int ExplicitTriangulation::preconditionDistributedTriangles() {
1298 if(this->hasPreconditionedDistributedTriangles_) {
1301 if(!ttk::hasInitializedMPI()) {
1304 if(this->cellGid_ ==
nullptr) {
1305 this->
printErr(
"Missing global cell identifiers array!");
1315 this->preconditionDistributedCells();
1323 std::vector<SimplexId> triangleLidToRangeId(
1325 std::vector<size_t> nTrianglesPerRange(this->localCellRanges_.size());
1327 const auto triangleAlreadyProcessed
1334 if(sid == -1 || sid == lcid) {
1339 if(this->cellRankArray_[sid] < this->cellRankArray_[lcid]) {
1347 const auto countCellTriangles
1348 = [
this, &triangleAlreadyProcessed](
1349 const SimplexId lcid, std::vector<SimplexId> &triangleGid,
1350 std::vector<SimplexId> &triangleRangeId,
const size_t rangeId,
1351 size_t &triangleCount) {
1353 for(
SimplexId k = 0; k < nTriangles; ++k) {
1356 const auto alreadyProcessed = triangleAlreadyProcessed(leid, lcid);
1357 if(!alreadyProcessed) {
1358 triangleGid[leid] = triangleCount;
1359 triangleRangeId[leid] = rangeId;
1365#ifdef TTK_ENABLE_OPENMP
1366#pragma omp parallel for num_threads(this->threadNumber_)
1368 for(
size_t i = 0; i < this->localCellRanges_.size(); ++i) {
1369 auto &range{this->localCellRanges_[i]};
1371 for(
size_t j = range.begin; j <= range.end; ++j) {
1373 const auto lcid{this->cellGidToLid_[j]};
1374 countCellTriangles(lcid, this->triangleLidToGid_, triangleLidToRangeId,
1375 range.id, nTrianglesPerRange[i]);
1380 const auto nTriangles = this->computeCellRangeOffsets(nTrianglesPerRange);
1385 if(this->triangleLidToGid_[leid] == -1) {
1389 const auto geid{this->triangleLidToGid_[leid]
1390 + nTrianglesPerRange[triangleLidToRangeId[leid]]};
1391 this->triangleLidToGid_[leid] = geid;
1392 this->triangleGidToLid_[geid] = leid;
1397 const auto nTrianglesPerCell{4};
1398 this->exchangeDistributedInternal(
1399 [
this](
const SimplexId lcid,
const int j) {
1402 return this->triangleLidToGid_[ltid];
1407 if(this->triangleLidToGid_[ltid] == -1 && gtid != -1) {
1408 this->triangleLidToGid_[ltid] = gtid;
1409 this->triangleGidToLid_[gtid] = ltid;
1413 return std::count(this->triangleLidToGid_.begin(),
1414 this->triangleLidToGid_.end(), -1)
1419 this->preconditionTriangleRankArray();
1423 "Domain contains " + std::to_string(nTriangles) +
" triangles", 1.0,
1424 tm.getElapsedTime(), 1);
1427 this->hasPreconditionedDistributedTriangles_ =
true;
1432int ExplicitTriangulation::preconditionDistributedVertices() {
1433 if(this->hasPreconditionedDistributedVertices_) {
1436 if(!hasInitializedMPI()) {
1439 if(this->vertGid_ ==
nullptr) {
1440 this->
printErr(
"Missing global vertex identifiers array!");
1444 this->hasPreconditionedDistributedVertices_ =
true;
1445 this->preconditionVertexRankArray();
1451 this->vertexGidToLid_.reserve(nLocVertices);
1453 this->vertexGidToLid_[this->vertGid_[lvid]] = lvid;
1456 this->preconditionExchangeGhostVertices();
1461int ttk::ExplicitTriangulation::preconditionExchangeGhostVertices() {
1463 if(this->hasPreconditionedExchangeGhostVertices_) {
1466 if(!ttk::hasInitializedMPI()) {
1469 if(this->vertGid_ ==
nullptr) {
1470 this->printErr(
"Missing global vertex identifiers array!");
1475 const auto nLocVertices{this->getNumberOfVertices()};
1482 this->ghostVerticesPerOwner_[this->vertexRankArray_[lvid]].emplace_back(
1483 this->vertGid_[lvid]);
1492 std::vector<size_t> nOwnedGhostVerticesPerRank(
ttk::MPIsize_);
1494 for(
const auto neigh : this->neighborRanks_) {
1496 const auto nVerts{this->ghostVerticesPerOwner_[neigh].size()};
1497 MPI_Sendrecv(&nVerts, 1, ttk::getMPIType(nVerts), neigh,
ttk::MPIrank_,
1498 &nOwnedGhostVerticesPerRank[neigh], 1, ttk::getMPIType(nVerts),
1499 neigh, neigh, ttk::MPIcomm_, MPI_STATUS_IGNORE);
1500 this->remoteGhostVertices_[neigh].resize(nOwnedGhostVerticesPerRank[neigh]);
1503 MPI_Sendrecv(this->ghostVerticesPerOwner_[neigh].data(),
1504 this->ghostVerticesPerOwner_[neigh].size(), MIT, neigh,
1506 this->remoteGhostVertices_[neigh].size(), MIT, neigh, neigh,
1507 ttk::MPIcomm_, MPI_STATUS_IGNORE);
1510 this->hasPreconditionedExchangeGhostVertices_ =
true;
1517template <
typename T>
1519 stream.write(
reinterpret_cast<const char *
>(&var),
sizeof(var));
1522template <
typename T>
1524 const T *
const buff,
1525 const size_t size) {
1526 stream.write(
reinterpret_cast<const char *
>(buff), size *
sizeof(T));
1530const char *ExplicitTriangulation::magicBytes_ =
"TTKTriangulationFileFormat";
1531const unsigned long ExplicitTriangulation::formatVersion_ = 1;
1536 stream.write(ttk::ExplicitTriangulation::magicBytes_,
1537 std::strlen(ttk::ExplicitTriangulation::magicBytes_));
1539 writeBin(stream, ttk::ExplicitTriangulation::formatVersion_);
1547 const auto edgesNumber = [
this, dim]() ->
SimplexId {
1550 }
else if(dim > 1) {
1555 const auto nEdges = edgesNumber();
1558 const auto trianglesNumber = [
this, dim]() ->
SimplexId {
1561 }
else if(dim == 3) {
1566 const auto nTriangles = trianglesNumber();
1577#define WRITE_FIXED(ARRAY) \
1578 if(ARRAY.empty()) { \
1579 writeBin(stream, char{0}); \
1581 writeBin(stream, char{1}); \
1582 writeBinArray(stream, ARRAY.data(), ARRAY.size()); \
1598#define WRITE_GUARD(ARRAY) \
1599 if(ARRAY.empty()) { \
1600 writeBin(stream, char{0}); \
1603 writeBin(stream, char{1}); \
1614 write_variable(this->vertexNeighborData_);
1616 write_variable(this->cellNeighborData_);
1618 write_variable(this->vertexEdgeData_);
1620 write_variable(this->vertexTriangleData_);
1622 write_variable(this->edgeTriangleData_);
1624 write_variable(this->vertexStarData_);
1626 write_variable(this->edgeStarData_);
1628 write_variable(this->triangleStarData_);
1630 write_variable(this->vertexLinkData_);
1632 write_variable(this->edgeLinkData_);
1634 write_variable(this->triangleLinkData_);
1636 const auto write_bool = [&stream](
const std::vector<bool> &arr) {
1639 for(
size_t i = 0; i < arr.size(); ++i) {
1640 const auto b =
static_cast<char>(arr[i]);
1657 stream << ttk::ExplicitTriangulation::magicBytes_ <<
'\n';
1659 stream << ttk::ExplicitTriangulation::formatVersion_ + 1 <<
'\n';
1662 stream <<
"dim " << dim <<
'\n';
1665 const auto edgesNumber = [
this, dim]() ->
SimplexId {
1668 }
else if(dim > 1) {
1673 const auto nEdges = edgesNumber();
1674 const auto trianglesNumber = [
this, dim]() ->
SimplexId {
1677 }
else if(dim == 3) {
1682 const auto nTriangles = trianglesNumber();
1684 stream << nVerts <<
' ' << nEdges <<
' ' << nTriangles <<
' ' << nTetras
1687#define WRITE_ASCII(ARRAY) \
1688 stream << #ARRAY << '\n'; \
1689 for(const auto &slice : ARRAY) { \
1690 for(size_t i = 0; i < slice.size(); ++i) { \
1694 stream << slice[i]; \
1699 const auto writeCellArray = [
this, &stream]() {
1700 stream <<
"this->cellArray_\n";
1701 for(
SimplexId i = 0; i < this->cellNumber_; ++i) {
1702 for(
SimplexId j = 0; j < this->cellArray_->getCellVertexNumber(i); ++j) {
1703 stream << this->cellArray_->getCellVertex(i, j) <<
' ';
1731#define WRITE_BOOL(ARRAY) \
1732 stream << #ARRAY << '\n'; \
1733 for(const auto el : ARRAY) { \
1734 stream << el << '\n'; \
1745template <
typename T>
1747 stream.read(
reinterpret_cast<char *
>(&res),
sizeof(res));
1750template <
typename T>
1752 stream.read(
reinterpret_cast<char *
>(res), size *
sizeof(T));
1758 const auto magicBytesLen
1759 = std::strlen(ttk::ExplicitTriangulation::magicBytes_);
1760 std::vector<char> mBytes(magicBytesLen + 1);
1761 stream.read(mBytes.data(), magicBytesLen);
1762 const auto hasMagicBytes
1763 = std::strcmp(mBytes.data(), ttk::ExplicitTriangulation::magicBytes_) == 0;
1764 if(!hasMagicBytes) {
1765 this->
printErr(
"Could not find magic bytes in input files!");
1770 unsigned long version{};
1772 if(version != ttk::ExplicitTriangulation::formatVersion_) {
1773 this->
printWrn(
"File format version (" + std::to_string(version)
1774 +
") and software version ("
1775 + std::to_string(ttk::ExplicitTriangulation::formatVersion_)
1776 +
") are different!");
1780 SimplexId nVerts{}, nEdges{}, nTriangles{}, nTetras{};
1794 this->
printErr(
"Incorrect dimension!");
1798 this->
printErr(
"Incorrect number of vertices!");
1803 this->
printErr(
"Incorrect number of cells!");
1809 const auto read_guard = [&stream]() {
1815#define READ_FIXED(ARRAY, N_ITEMS) \
1816 if(!read_guard()) { \
1817 ARRAY.resize(N_ITEMS); \
1818 readBinArray(stream, ARRAY.data(), N_ITEMS); \
1834 const auto read_variable
1840 std::vector<SimplexId> offsets{}, data{};
1841 offsets.resize(n_items + 1);
1843 data.resize(offsets.back());
1845 arr.setData(std::move(data), std::move(offsets));
1849 read_variable(this->vertexNeighborData_, nVerts);
1853 read_variable(this->vertexEdgeData_, nVerts);
1855 read_variable(this->vertexTriangleData_, nVerts);
1857 read_variable(this->edgeTriangleData_, nEdges);
1859 read_variable(this->vertexStarData_, nVerts);
1861 read_variable(this->edgeStarData_, nEdges);
1863 read_variable(this->triangleStarData_, nTriangles);
1865 read_variable(this->vertexLinkData_, nVerts);
1867 read_variable(this->edgeLinkData_, nEdges);
1869 read_variable(this->triangleLinkData_, nTriangles);
1871 const auto read_bool
1872 = [&stream, &read_guard](std::vector<bool> &arr,
const SimplexId n_items) {
1878 arr.resize(n_items);
1879 for(
SimplexId i = 0; i < n_items; ++i) {
1881 stream.read(&b,
sizeof(b));
1882 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 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
SimplexId TTK_TRIANGULATION_INTERNAL getNumberOfCells() const override
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
int preconditionCellEdgesInternal() override
int preconditionVertexLinksInternal() override
int preconditionTriangleLinksInternal() override
int preconditionManifoldInternal() override
int TTK_TRIANGULATION_INTERNAL getDimensionality() const override
~ExplicitTriangulation() override
SimplexId TTK_TRIANGULATION_INTERNAL getTriangleStarNumber(const SimplexId &triangleId) const override
int preconditionEdgeLinksInternal() override
int preconditionVertexStarsInternal() override
int preconditionVertexEdgesInternal() override
SimplexId TTK_TRIANGULATION_INTERNAL getNumberOfVertices() const override
int TTK_TRIANGULATION_INTERNAL getTriangleStar(const SimplexId &triangleId, const int &localStarId, SimplexId &starId) const override
int preconditionBoundaryEdgesInternal() override
int preconditionEdgeTrianglesInternal() override
int getCellEdgeInternal(const SimplexId &cellId, const int &localEdgeId, SimplexId &edgeId) const override
SimplexId TTK_TRIANGULATION_INTERNAL getEdgeStarNumber(const SimplexId &edgeId) const override
int preconditionBoundaryVerticesInternal() override
SimplexId getNumberOfEdgesInternal() const override
int preconditionTriangleEdgesInternal() 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
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.
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
TTK base package defining the standard types.
COMMON_EXPORTS int MPIsize_
int SimplexId
Identifier type for simplices of any dimension.
COMMON_EXPORTS int MPIrank_
long long int LongSimplexId
Identifier type for simplices of any dimension.
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)