TTK
Loading...
Searching...
No Matches
ScalarFieldCriticalPoints.cpp
Go to the documentation of this file.
2
4 this->setDebugMsgPrefix("ScalarFieldCriticalPoints");
5#ifdef TTK_ENABLE_MPI
6 hasMPISupport_ = true;
7#endif
8}
9
11 const SimplexId &vertexId,
12 const SimplexId *const offsets,
13 const std::vector<std::pair<SimplexId, SimplexId>> &vertexLink) const {
14
15 std::map<SimplexId, SimplexId> global2LowerLink, global2UpperLink;
16 std::map<SimplexId, SimplexId>::iterator neighborIt;
17
18 SimplexId lowerCount = 0, upperCount = 0;
19
20 for(SimplexId i = 0; i < (SimplexId)vertexLink.size(); i++) {
21
22 SimplexId neighborId = vertexLink[i].first;
23
24 // first vertex
25 // lower link search
26 if(offsets[neighborId] < offsets[vertexId]) {
27
28 neighborIt = global2LowerLink.find(neighborId);
29 if(neighborIt == global2LowerLink.end()) {
30 // not in there, add it
31 global2LowerLink[neighborId] = lowerCount;
32 lowerCount++;
33 }
34 }
35
36 // upper link
37 if(offsets[neighborId] > offsets[vertexId]) {
38
39 neighborIt = global2UpperLink.find(neighborId);
40 if(neighborIt == global2UpperLink.end()) {
41 // not in there, add it
42 global2UpperLink[neighborId] = upperCount;
43 upperCount++;
44 }
45 }
46
47 // second vertex
48 neighborId = vertexLink[i].second;
49
50 // lower link search
51 if(offsets[neighborId] < offsets[vertexId]) {
52
53 neighborIt = global2LowerLink.find(neighborId);
54 if(neighborIt == global2LowerLink.end()) {
55 // not in there, add it
56 global2LowerLink[neighborId] = lowerCount;
57 lowerCount++;
58 }
59 }
60
61 // upper link
62 if(offsets[neighborId] > offsets[vertexId]) {
63
64 neighborIt = global2UpperLink.find(neighborId);
65 if(neighborIt == global2UpperLink.end()) {
66 // not in there, add it
67 global2UpperLink[neighborId] = upperCount;
68 upperCount++;
69 }
70 }
71 }
72
73 if(debugLevel_ >= (int)(debug::Priority::VERBOSE)) {
74 printMsg("Vertex #" + std::to_string(vertexId) + " lower link ("
75 + std::to_string(lowerCount) + " vertices)",
77 printMsg("Vertex #" + std::to_string(vertexId) + " upper link ("
78 + std::to_string(upperCount) + " vertices)",
80 }
81
82 if(!lowerCount) {
83 // minimum
84 return (char)(CriticalType::Local_minimum);
85 }
86 if(!upperCount) {
87 // maximum
88 return (char)(CriticalType::Local_maximum);
89 }
90
91 // so far 40% of the computation, that's ok.
92
93 // now enumerate the connected components of the lower and upper links
94 // NOTE: a breadth first search might be faster than a UF
95 // if so, one would need the one-skeleton data structure, not the edge list
96 std::vector<UnionFind> lowerSeeds(lowerCount);
97 std::vector<UnionFind> upperSeeds(upperCount);
98 std::vector<UnionFind *> lowerList(lowerCount);
99 std::vector<UnionFind *> upperList(upperCount);
100 for(SimplexId i = 0; i < (SimplexId)lowerList.size(); i++)
101 lowerList[i] = &(lowerSeeds[i]);
102 for(SimplexId i = 0; i < (SimplexId)upperList.size(); i++)
103 upperList[i] = &(upperSeeds[i]);
104
105 for(SimplexId i = 0; i < (SimplexId)vertexLink.size(); i++) {
106
107 SimplexId neighborId0 = vertexLink[i].first;
108 SimplexId neighborId1 = vertexLink[i].second;
109
110 // process the lower link
111 if(offsets[neighborId0] < offsets[vertexId]
112 && offsets[neighborId1] < offsets[vertexId]) {
113
114 // both vertices are lower, let's add that edge and update the UF
115 std::map<SimplexId, SimplexId>::iterator n0It
116 = global2LowerLink.find(neighborId0);
117 std::map<SimplexId, SimplexId>::iterator n1It
118 = global2LowerLink.find(neighborId1);
119
120 lowerList[n0It->second] = UnionFind::makeUnion(
121 lowerList[n0It->second], lowerList[n1It->second]);
122 lowerList[n1It->second] = lowerList[n0It->second];
123 }
124
125 // process the upper link
126 if(offsets[neighborId0] > offsets[vertexId]
127 && offsets[neighborId1] > offsets[vertexId]) {
128
129 // both vertices are lower, let's add that edge and update the UF
130 std::map<SimplexId, SimplexId>::iterator n0It
131 = global2UpperLink.find(neighborId0);
132 std::map<SimplexId, SimplexId>::iterator n1It
133 = global2UpperLink.find(neighborId1);
134
135 upperList[n0It->second] = UnionFind::makeUnion(
136 upperList[n0It->second], upperList[n1It->second]);
137 upperList[n1It->second] = upperList[n0It->second];
138 }
139 }
140
141 // let's remove duplicates
142 std::vector<UnionFind *>::iterator it;
143 // update the UFs if necessary
144 for(SimplexId i = 0; i < (SimplexId)lowerList.size(); i++)
145 lowerList[i] = lowerList[i]->find();
146 for(SimplexId i = 0; i < (SimplexId)upperList.size(); i++)
147 upperList[i] = upperList[i]->find();
148
149 sort(lowerList.begin(), lowerList.end());
150 it = unique(lowerList.begin(), lowerList.end());
151 lowerList.resize(distance(lowerList.begin(), it));
152
153 sort(upperList.begin(), upperList.end());
154 it = unique(upperList.begin(), upperList.end());
155 upperList.resize(distance(upperList.begin(), it));
156
157 if(debugLevel_ >= (int)(debug::Priority::VERBOSE)) {
158 printMsg("Vertex #" + std::to_string(vertexId)
159 + ": lowerLink-#CC=" + std::to_string(lowerList.size())
160 + " upperLink-#CC=" + std::to_string(upperList.size()),
162 }
163
164 if((lowerList.size() == 1) && (upperList.size() == 1))
165 // regular point
166 return (char)(CriticalType::Regular);
167 else {
168 // saddles
169 if(dimension_ == 2) {
170 if((lowerList.size() > 2) || (upperList.size() > 2)) {
171 // monkey saddle
172 return (char)(CriticalType::Degenerate);
173 } else {
174 // regular saddle
175 return (char)(CriticalType::Saddle1);
176 // NOTE: you may have multi-saddles on the boundary in that
177 // configuration
178 // to make this computation 100% correct, one would need to disambiguate
179 // boundary from interior vertices
180 }
181 } else if(dimension_ == 3) {
182 if((lowerList.size() == 2) && (upperList.size() == 1)) {
183 return (char)(CriticalType::Saddle1);
184 } else if((lowerList.size() == 1) && (upperList.size() == 2)) {
185 return (char)(CriticalType::Saddle2);
186 } else {
187 // monkey saddle
188 return (char)(CriticalType::Degenerate);
189 // NOTE: we may have a similar effect in 3D (TODO)
190 }
191 }
192 }
193
194 // -2: regular points
195 return (char)(CriticalType::Regular);
196}
197
199
200 SimplexId minimumNumber = 0, maximumNumber = 0, saddleNumber = 0,
201 oneSaddleNumber = 0, twoSaddleNumber = 0, monkeySaddleNumber = 0;
202
203 if(debugLevel_ >= (int)debug::Priority::INFO) {
204 if(dimension_ == 3) {
205 for(size_t i = 0; i < criticalPoints_->size(); i++) {
206 switch((*criticalPoints_)[i].second) {
207
208 case(char)(CriticalType::Local_minimum):
209 minimumNumber++;
210 break;
211
212 case(char)(CriticalType::Saddle1):
213 oneSaddleNumber++;
214 break;
215
216 case(char)(CriticalType::Saddle2):
217 twoSaddleNumber++;
218 break;
219
220 case(char)(CriticalType::Local_maximum):
221 maximumNumber++;
222 break;
223
224 case(char)(CriticalType::Degenerate):
225 monkeySaddleNumber++;
226 break;
227 }
228 }
229 } else if(dimension_ == 2) {
230 for(size_t i = 0; i < criticalPoints_->size(); i++) {
231 switch((*criticalPoints_)[i].second) {
232
233 case(char)(CriticalType::Local_minimum):
234 minimumNumber++;
235 break;
236
237 case(char)(CriticalType::Saddle1):
238 saddleNumber++;
239 break;
240
241 case(char)(CriticalType::Local_maximum):
242 maximumNumber++;
243 break;
244
245 case(char)(CriticalType::Degenerate):
246 monkeySaddleNumber++;
247 break;
248 }
249 }
250 }
251
252 {
253 std::vector<std::vector<std::string>> stats;
254 stats.push_back({" #Minima", std::to_string(minimumNumber)});
255 if(dimension_ == 3) {
256 stats.push_back({" #1-saddles", std::to_string(oneSaddleNumber)});
257 stats.push_back({" #2-saddles", std::to_string(twoSaddleNumber)});
258 }
259 if(dimension_ == 2) {
260 stats.push_back({" #Saddles", std::to_string(saddleNumber)});
261 }
262 stats.push_back({" #Multi-saddles", std::to_string(monkeySaddleNumber)});
263 stats.push_back({" #Maxima", std::to_string(maximumNumber)});
264
265 printMsg(stats);
266 }
267 }
268}
void setDebugMsgPrefix(const std::string &prefix)
Definition: Debug.h:364
char getCriticalType(const SimplexId &vertexId, const SimplexId *const offsets, const triangulationType *triangulation, std::vector< std::vector< ttk::SimplexId > > *upperComponents=nullptr, std::vector< std::vector< ttk::SimplexId > > *lowerComponents=nullptr) const
static UnionFind * makeUnion(UnionFind *uf0, UnionFind *uf1)
Definition: UnionFind.h:40
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)