7 const dataTypeU *
const uField,
8 const dataTypeV *
const vField,
9 const triangulationType &triangulation,
10 std::vector<char> *isPareto) {
15#ifndef TTK_ENABLE_KAMIKAZE
16 if((triangulation.isEmpty())) {
30 SimplexId const edgeNumber = triangulation.getNumberOfEdges();
32 std::vector<std::vector<std::pair<SimplexId, char>>> threadedCriticalTypes(
35#ifdef TTK_ENABLE_OPENMP
36#pragma omp parallel for num_threads(threadNumber_)
38 for(
SimplexId i = 0; i < edgeNumber; i++) {
44#ifdef TTK_ENABLE_OPENMP
45 const auto tid = omp_get_thread_num();
49 threadedCriticalTypes[tid].emplace_back(i, type);
54 size_t jacobiSetSize{};
55 for(
const auto &vec : threadedCriticalTypes) {
56 jacobiSetSize += vec.size();
58 jacobiSet.reserve(jacobiSetSize);
61 for(
size_t j = 0; j < threadedCriticalTypes[i].size(); j++) {
62 jacobiSet.push_back(threadedCriticalTypes[i][j]);
66 SimplexId minimumNumber = 0, saddleNumber = 0, maximumNumber = 0,
67 monkeySaddleNumber = 0;
69 for(
size_t i = 0; i < jacobiSet.size(); i++) {
70 switch(jacobiSet[i].second) {
87 isPareto->resize(jacobiSet.size(), 0);
88#ifdef TTK_ENABLE_OPENMP
89#pragma omp parallel for num_threads(threadNumber_)
91 for(
int i = 0; i < (int)jacobiSet.size(); i++) {
92 int const edgeId = jacobiSet[i].first;
94 triangulation.getEdgeVertex(edgeId, 0, vertexId0);
95 triangulation.getEdgeVertex(edgeId, 1, vertexId1);
96 double denominator = vField[vertexId1] - vField[vertexId0];
99 if((uField[vertexId1] - uField[vertexId0]) / denominator < 0)
105 std::vector<std::vector<std::string>>{
106 {
"#Minimum edges", std::to_string(minimumNumber)},
107 {
"#Saddle edges", std::to_string(saddleNumber)},
108 {
"#Maximum edges", std::to_string(maximumNumber)},
109 {
"#Multi-saddle edges", std::to_string(monkeySaddleNumber)}},
113 "Data-set processed", 1.0, t.
getElapsedTime(), this->threadNumber_);
115 + std::to_string(100.0 * jacobiSet.size() / (
double)edgeNumber)
123 std::vector<std::pair<SimplexId, char>> &jacobiSet,
124 const dataTypeU *
const uField,
125 const dataTypeV *
const vField) {
129 this->printWrn(
"Using legacy implementation...");
132#ifndef TTK_ENABLE_KAMIKAZE
141 if(!edgeFanLinkEdgeLists_)
156 std::vector<std::vector<double>> threadedDistanceField(threadNumber_);
157 for(
size_t i = 0; i < threadedDistanceField.size(); i++) {
158 threadedDistanceField[i].resize(vertexNumber_);
161 std::vector<ScalarFieldCriticalPoints> threadedCriticalPoints(threadNumber_);
162 for(
ThreadId i = 0; i < threadNumber_; i++) {
163 threadedCriticalPoints[i].setDomainDimension(2);
164 threadedCriticalPoints[i].setVertexNumber(vertexNumber_);
167 std::vector<std::vector<std::pair<SimplexId, char>>> threadedCriticalTypes(
170#ifdef TTK_ENABLE_OPENMP
171#pragma omp parallel for num_threads(threadNumber_)
173 for(
size_t i = 0; i < edgeList_->size(); i++) {
176 if((!wrapper_) || ((wrapper_) && (!wrapper_->needsToAbort()))) {
179#ifdef TTK_ENABLE_OPENMP
180 threadId = omp_get_thread_num();
184 SimplexId const pivotVertexId = (*edgeList_)[i].first;
185 SimplexId const otherExtremityId = (*edgeList_)[i].second;
188 double projectedPivotVertex[2];
189 projectedPivotVertex[0] = uField[pivotVertexId];
190 projectedPivotVertex[1] = vField[pivotVertexId];
192 double projectedOtherVertex[2];
193 projectedOtherVertex[0] = uField[otherExtremityId];
194 projectedOtherVertex[1] = vField[otherExtremityId];
197 rangeEdge[0] = projectedOtherVertex[0] - projectedPivotVertex[0];
198 rangeEdge[1] = projectedOtherVertex[1] - projectedPivotVertex[1];
200 double rangeNormal[2];
201 rangeNormal[0] = -rangeEdge[1];
202 rangeNormal[1] = rangeEdge[0];
204 for(
size_t j = 0; j < (*edgeFans_)[i].size() / 4; j++) {
205 for(
int k = 0; k < 3; k++) {
207 SimplexId const vertexId = (*edgeFans_)[i][j * 4 + 1 + k];
210 double projectedVertex[2];
211 projectedVertex[0] = uField[vertexId];
212 projectedVertex[1] = vField[vertexId];
214 double vertexRangeEdge[2];
215 vertexRangeEdge[0] = projectedVertex[0] - projectedPivotVertex[0];
216 vertexRangeEdge[1] = projectedVertex[1] - projectedPivotVertex[1];
219 threadedDistanceField[threadId][vertexId]
220 = vertexRangeEdge[0] * rangeNormal[0]
221 + vertexRangeEdge[1] * rangeNormal[1];
231 char const type = threadedCriticalPoints[threadId].getCriticalType(
232 pivotVertexId, sosOffsetsU_, (*edgeFanLinkEdgeLists_)[i]);
236 threadedCriticalTypes[threadId].emplace_back(i, type);
241#ifdef TTK_ENABLE_OPENMP
245 if((wrapper_) && (!(count % ((vertexNumber_) / 10)))) {
246 wrapper_->updateProgress((count + 1.0) / vertexNumber_);
256 for(
ThreadId i = 0; i < threadNumber_; i++) {
257 for(
size_t j = 0; j < threadedCriticalTypes[i].size(); j++) {
258 jacobiSet.push_back(threadedCriticalTypes[i][j]);
262 SimplexId minimumNumber = 0, saddleNumber = 0, maximumNumber = 0,
263 monkeySaddleNumber = 0;
265 for(
size_t i = 0; i < jacobiSet.size(); i++) {
266 switch(jacobiSet[i].second) {
277 monkeySaddleNumber++;
283 std::vector<std::vector<std::string>>{
284 {
"#Minimum edges", std::to_string(minimumNumber)},
285 {
"#Saddle edges", std::to_string(saddleNumber)},
286 {
"#Maximum edges", std::to_string(maximumNumber)},
287 {
"#Multi-saddle edges", std::to_string(monkeySaddleNumber)}},
291 "Data-set processed", 1.0, t.
getElapsedTime(), this->threadNumber_);
294 + std::to_string(100.0 * (jacobiSet.size() / ((
double)edgeList_->size())))
302 const dataTypeU *
const uField,
303 const dataTypeV *
const vField,
304 const triangulationType &triangulation) {
306 SimplexId vertexId0 = -1, vertexId1 = -1;
307 triangulation.getEdgeVertex(edgeId, 0, vertexId0);
308 triangulation.getEdgeVertex(edgeId, 1, vertexId1);
310 double projectedPivotVertex[2];
311 projectedPivotVertex[0] = uField[vertexId0];
312 projectedPivotVertex[1] = vField[vertexId0];
314 double projectedOtherVertex[2];
315 projectedOtherVertex[0] = uField[vertexId1];
316 projectedOtherVertex[1] = vField[vertexId1];
319 rangeEdge[0] = projectedOtherVertex[0] - projectedPivotVertex[0];
320 rangeEdge[1] = projectedOtherVertex[1] - projectedPivotVertex[1];
322 double rangeNormal[2];
323 rangeNormal[0] = -rangeEdge[1];
324 rangeNormal[1] = rangeEdge[0];
326 SimplexId const starNumber = triangulation.getEdgeStarNumber(edgeId);
327 std::vector<SimplexId> lowerNeighbors, upperNeighbors;
331 for(
SimplexId i = 0; i < starNumber; i++) {
334 triangulation.getEdgeStar(edgeId, i, tetId);
336 SimplexId const vertexNumber = triangulation.getCellVertexNumber(tetId);
337 for(
SimplexId j = 0; j < vertexNumber; j++) {
339 triangulation.getCellVertex(tetId, j, vertexId);
341 if((vertexId != -1) && (vertexId != vertexId0)
342 && (vertexId != vertexId1)) {
345 for(
size_t k = 0; k < lowerNeighbors.size(); k++) {
346 if(vertexId == lowerNeighbors[k]) {
353 for(
size_t k = 0; k < upperNeighbors.size(); k++) {
354 if(vertexId == upperNeighbors[k]) {
364 double projectedVertex[2];
365 projectedVertex[0] = uField[vertexId];
366 projectedVertex[1] = vField[vertexId];
368 double vertexRangeEdge[2];
369 vertexRangeEdge[0] = projectedVertex[0] - projectedPivotVertex[0];
370 vertexRangeEdge[1] = projectedVertex[1] - projectedPivotVertex[1];
373 double distance = vertexRangeEdge[0] * rangeNormal[0]
374 + vertexRangeEdge[1] * rangeNormal[1];
379 lowerNeighbors.push_back(vertexId);
380 }
else if(distance > 0) {
381 upperNeighbors.push_back(vertexId);
385 double offsetProjectedPivotVertex[2];
386 offsetProjectedPivotVertex[0] = sosOffsetsU_[vertexId0];
387 offsetProjectedPivotVertex[1]
388 = sosOffsetsV_[vertexId0] * sosOffsetsV_[vertexId0];
390 double offsetProjectedOtherVertex[2];
391 offsetProjectedOtherVertex[0] = sosOffsetsU_[vertexId1];
392 offsetProjectedOtherVertex[1]
393 = sosOffsetsV_[vertexId1] * sosOffsetsV_[vertexId1];
395 double offsetRangeEdge[2];
397 = offsetProjectedOtherVertex[0] - offsetProjectedPivotVertex[0];
399 = offsetProjectedOtherVertex[1] - offsetProjectedPivotVertex[1];
401 double offsetRangeNormal[2];
402 offsetRangeNormal[0] = -offsetRangeEdge[1];
403 offsetRangeNormal[1] = offsetRangeEdge[0];
405 projectedVertex[0] = sosOffsetsU_[vertexId];
407 = sosOffsetsV_[vertexId] * sosOffsetsV_[vertexId];
410 = projectedVertex[0] - offsetProjectedPivotVertex[0];
412 = projectedVertex[1] - offsetProjectedPivotVertex[1];
414 distance = vertexRangeEdge[0] * offsetRangeNormal[0]
415 + vertexRangeEdge[1] * offsetRangeNormal[1];
418 lowerNeighbors.push_back(vertexId);
419 }
else if(distance > 0) {
420 upperNeighbors.push_back(vertexId);
423 "Inconsistent (non-bijective?) offsets for vertex #"
424 + std::to_string(vertexId));
433 if((
SimplexId)(lowerNeighbors.size() + upperNeighbors.size())
439 if(lowerNeighbors.empty()) {
440 if(rangeNormal[0] + rangeNormal[1] > 0)
444 return triangulation.getDimensionality() - 1;
446 if(upperNeighbors.empty()) {
447 if(rangeNormal[0] + rangeNormal[1] > 0)
449 return triangulation.getDimensionality() - 1;
455 std::vector<UnionFind> lowerSeeds(lowerNeighbors.size());
456 std::vector<UnionFind *> lowerList(lowerNeighbors.size());
457 std::vector<UnionFind> upperSeeds(upperNeighbors.size());
458 std::vector<UnionFind *> upperList(upperNeighbors.size());
460 for(
size_t i = 0; i < lowerSeeds.size(); i++) {
461 lowerList[i] = &(lowerSeeds[i]);
463 for(
size_t i = 0; i < upperSeeds.size(); i++) {
464 upperList[i] = &(upperSeeds[i]);
467 for(
SimplexId i = 0; i < starNumber; i++) {
470 triangulation.getEdgeStar(edgeId, i, tetId);
472 SimplexId const vertexNumber = triangulation.getCellVertexNumber(tetId);
473 for(
SimplexId j = 0; j < vertexNumber; j++) {
475 triangulation.getCellVertex(tetId, j, edgeVertexId0);
476 if((edgeVertexId0 != vertexId0) && (edgeVertexId0 != vertexId1)) {
477 for(
SimplexId k = j + 1; k < vertexNumber; k++) {
479 triangulation.getCellVertex(tetId, k, edgeVertexId1);
480 if((edgeVertexId1 != vertexId0) && (edgeVertexId1 != vertexId1)) {
485 for(
size_t l = 0; l < lowerNeighbors.size(); l++) {
486 if(lowerNeighbors[l] == edgeVertexId0) {
492 for(
size_t l = 0; l < lowerNeighbors.size(); l++) {
493 if(lowerNeighbors[l] == edgeVertexId1) {
499 auto *neighbors = &lowerNeighbors;
500 auto *seeds = &lowerList;
503 neighbors = &upperNeighbors;
507 if(lower0 == lower1) {
510 for(
size_t l = 0; l < neighbors->size(); l++) {
511 if((*neighbors)[l] == edgeVertexId0) {
514 if((*neighbors)[l] == edgeVertexId1) {
519 if((lowerId0 != -1) && (lowerId1 != -1)) {
521 (*seeds)[lowerId0], (*seeds)[lowerId1]);
522 (*seeds)[lowerId1] = (*seeds)[lowerId0];
534 for(
size_t i = 0; i < lowerList.size(); i++)
535 lowerList[i] = lowerList[i]->find();
536 for(
size_t i = 0; i < upperList.size(); i++)
537 upperList[i] = upperList[i]->find();
540 std::sort(lowerList.begin(), lowerList.end());
541 const auto it = std::unique(lowerList.begin(), lowerList.end());
542 lowerList.erase(it, lowerList.end());
545 std::sort(upperList.begin(), upperList.end());
546 const auto it = std::unique(upperList.begin(), upperList.end());
547 upperList.erase(it, upperList.end());
550 if((upperList.size() == 1) && (lowerList.size() == 1))