TTK
Loading...
Searching...
No Matches
TrackingFromPersistenceDiagrams.cpp
Go to the documentation of this file.
2
6
9
10 // Check the consistency of the variables
11#ifndef TTK_ENABLE_KAMIKAZE
13 return -1;
14 if(!inputData_)
15 return -3;
16
17 for(int i = 0; i < numberOfInputs_; i++) {
18 if(!inputData_[i])
19 return -4;
20 }
21#endif
22
23 this->printMsg("Complete", 1, t.getElapsedTime(), threadNumber_);
24
25 return 0;
26}
27
29 int i,
30 std::vector<ttk::DiagramType> &inputPersistenceDiagrams,
31 std::vector<std::vector<MatchingType>> &outputMatchings,
32 const std::string &algorithm,
33 const std::string &wasserstein,
34 double tolerance,
35 double px,
36 double py,
37 double pz,
38 double ps,
39 double pe) {
40 ttk::BottleneckDistance bottleneckDistance_;
41 // bottleneckDistance_.setWrapper(this);
42 bottleneckDistance_.setPersistencePercentThreshold(tolerance);
43 bottleneckDistance_.setPX(px);
44 bottleneckDistance_.setPY(py);
45 bottleneckDistance_.setPZ(pz);
46 bottleneckDistance_.setPS(ps);
47 bottleneckDistance_.setPE(pe);
48 bottleneckDistance_.setAlgorithm(algorithm);
49 bottleneckDistance_.setWasserstein(wasserstein);
50
51 bottleneckDistance_.execute(inputPersistenceDiagrams[i],
52 inputPersistenceDiagrams[i + 1],
53 outputMatchings[i]);
54
55 return 0;
56}
57
59 int numInputs,
60 std::vector<ttk::DiagramType> &inputPersistenceDiagrams,
61 std::vector<std::vector<MatchingType>> &outputMatchings,
62 const std::string &algorithm,
63 const std::string &wasserstein,
64 double tolerance,
65 double px,
66 double py,
67 double pz,
68 double ps,
69 double pe) {
70
71#ifdef TTK_ENABLE_OPENMP
72#pragma omp parallel for num_threads(threadNumber_)
73#endif // TTK_ENABLE_OPENMP
74 for(int i = 0; i < numInputs - 1; ++i) {
76 i, inputPersistenceDiagrams, outputMatchings,
77 algorithm, // Not from paraview, from enclosing tracking plugin
78 wasserstein, tolerance, px, py, pz, ps, pe // Coefficients
79 );
80 }
81
82 // Never from PV,
83 // Alaways activate output matchings.
84 return 0;
85}
86
88 std::vector<ttk::DiagramType> &allDiagrams,
89 std::vector<std::vector<MatchingType>> &allMatchings,
90 std::vector<trackingTuple> &trackings) {
91
92 auto numPersistenceDiagramsInput = (int)allDiagrams.size();
93 for(int in = 1; in < numPersistenceDiagramsInput - 1; ++in) {
94
95 std::vector<MatchingType> matchings1 = allMatchings[in - 1];
96 std::vector<MatchingType> matchings2 = allMatchings[in];
97
98 auto matchingsSize1 = (int)matchings1.size();
99 auto matchingsSize2 = (int)matchings2.size();
100
101 int const endIndex = numPersistenceDiagramsInput - 2;
102
103 for(int i = 0; i < matchingsSize1; ++i) {
104 const auto m1ai0 = std::get<0>(matchings1[i]);
105 const auto m1ai1 = std::get<1>(matchings1[i]);
106 for(int j = 0; j < matchingsSize2; ++j) {
107
108 const auto m2aj0 = std::get<0>(matchings2[j]);
109 const auto m2aj1 = std::get<1>(matchings2[j]);
110
111 if(m1ai1 != m2aj0)
112 continue;
113
114 // Detect in trackings and push.
115 bool found = false;
116 for(trackingTuple &tt : trackings) {
117 int const chainStart = std::get<0>(tt);
118 int const chainEnd = std::get<1>(tt);
119 std::vector<SimplexId> &chain = std::get<2>(tt);
120
121 if(chainEnd == -1) {
122 auto chainSize = (int)chain.size();
123 if(chainSize == 0) {
124 // Should not happen
125 this->printErr("Brain error.");
126 } else if(chainStart + chainSize == in
127 && chain.at((unsigned long)chainSize - 1) == m1ai0) {
128 found = true;
129 chain.push_back(m1ai1);
130 int const numEnd = in == endIndex ? endIndex : -1;
131 if(in == endIndex) {
132 chain.push_back(m2aj1);
133 std::get<1>(tt) = numEnd;
134 }
135 std::get<2>(tt) = chain;
136 }
137 }
138 tt = std::make_tuple(chainStart, chainEnd, chain);
139 }
140
141 if(!found) {
142 std::vector<SimplexId> chain;
143 chain.push_back(m1ai0);
144 chain.push_back(m1ai1);
145 if(in == endIndex) {
146 chain.push_back(m2aj1);
147 }
148 int const numEnd = in == endIndex ? endIndex : -1;
149 trackingTuple const tt = std::make_tuple(in - 1, numEnd, chain);
150 trackings.push_back(tt);
151 }
152 // Create new.
153 }
154 }
155
156 // End non-matched chains.
157 for(trackingTuple &tt : trackings) {
158 int const chainStart = std::get<0>(tt);
159 int const chainEnd = std::get<1>(tt);
160 if(chainEnd == -1) {
161 std::vector<SimplexId> const &chain = std::get<2>(tt);
162 auto chainSize = (int)chain.size();
163 if(chainStart + chainSize - 1 < in)
164 std::get<1>(tt) = in - 1;
165 }
166 }
167 }
168
169 // Post-processing
170 std::sort(trackings.begin(), trackings.end(),
171 [](const trackingTuple &a, const trackingTuple &b) -> bool {
172 return std::get<0>(a) < std::get<0>(b);
173 });
174
175 return 0;
176}
177
179 const std::vector<ttk::DiagramType> &allDiagrams,
180 const std::vector<trackingTuple> &trackings,
181 std::vector<std::set<int>> &trackingTupleToMerged,
182 const double postProcThresh) {
183
184 const int numPersistenceDiagramsInput = allDiagrams.size();
185
186 // Merge close connected components with threshold.
187 for(size_t k = 0; k < trackings.size(); ++k) {
188 const auto &tk = trackings[k];
189 int const startK = std::get<0>(tk);
190 int endK = std::get<1>(tk);
191 if(endK < 0)
192 endK = numPersistenceDiagramsInput - 1;
193 const std::vector<SimplexId> &chainK = std::get<2>(tk);
194 const ttk::DiagramType &diagramStartK = allDiagrams[startK];
195 const ttk::DiagramType &diagramEndK = allDiagrams[endK];
196
197 const auto n1 = chainK.front();
198 const auto n2 = chainK.back();
199 const auto &tuple1 = diagramStartK[n1];
200 const auto &tuple2 = diagramEndK[n2];
201
202 double x1, y1, z1, x2, y2, z2;
203
204 const auto point1Type1 = tuple1.birth.type;
205 const auto point1Type2 = tuple1.death.type;
206 bool const t11Min = point1Type1 == CriticalType::Local_minimum;
207 bool const t11Max = point1Type1 == CriticalType::Local_maximum;
208 bool const t12Min = point1Type2 == CriticalType::Local_minimum;
209 bool const t12Max = point1Type2 == CriticalType::Local_maximum;
210 // bool bothEx1 = t11Ex && t12Ex;
211 bool const t1Max = t11Max || t12Max;
212 bool const t1Min = !t1Max && (t11Min || t12Min);
213
214 x1 = t1Max ? tuple1.death.coords[0] : t1Min ? tuple1.birth.coords[0] : 0;
215 y1 = t1Max ? tuple1.death.coords[1] : t1Min ? tuple1.birth.coords[1] : 0;
216 z1 = t1Max ? tuple1.death.coords[2] : t1Min ? tuple1.birth.coords[2] : 0;
217
218 const auto point2Type1 = tuple2.birth.type;
219 const auto point2Type2 = tuple2.death.type;
220 bool const t21Min = point2Type1 == CriticalType::Local_minimum;
221 bool const t21Max = point2Type1 == CriticalType::Local_maximum;
222 bool const t22Min = point2Type2 == CriticalType::Local_minimum;
223 bool const t22Max = point2Type2 == CriticalType::Local_maximum;
224 // bool bothEx2 = t21Ex && t22Ex;
225 bool const t2Max = t21Max || t22Max;
226 bool const t2Min = !t2Max && (t21Min || t22Min);
227
228 // if (bothEx2) {
229 x2 = t2Max ? tuple2.death.coords[0] : t2Min ? tuple2.birth.coords[0] : 0;
230 y2 = t2Max ? tuple2.death.coords[1] : t2Min ? tuple2.birth.coords[1] : 0;
231 z2 = t2Max ? tuple2.death.coords[2] : t2Min ? tuple2.birth.coords[2] : 0;
232 // }
233 // if (!bothEx1 && !bothEx2)
234 // continue;
235
236 // Saddle-saddle matching not supported.
237 if(!t1Min && !t2Min && !t1Max && !t2Max)
238 continue;
239
240 // Check every other tracking trajectory.
241 for(size_t m = k + 1; m < trackings.size(); ++m) {
242 const auto &tm = trackings[m];
243 int const startM = std::get<0>(tm);
244 int const endM = std::get<1>(tm);
245 const std::vector<SimplexId> &chainM = std::get<2>(tm);
246 if((endK > 0 && startM > endK) || (endM > 0 && startK > endM))
247 continue;
248
249 for(int c = 0; c < (int)chainM.size(); ++c) {
250 bool const doMatch1 = startM + c == startK;
251 bool const doMatch2 = startM + c == endK;
252
253 // if (startM + c != startK && startM + c != endK) continue;
254 if(!doMatch1 && !doMatch2)
255 continue;
256
258 const auto n3 = chainM[c];
259 const ttk::DiagramType &diagramM = allDiagrams[startM + c];
260 const auto &tuple3 = diagramM[n3];
261 double x3, y3, z3;
262 const auto point3Type1 = tuple3.birth.type;
263 const auto point3Type2 = tuple3.death.type;
264 bool const t31Min = point3Type1 == CriticalType::Local_minimum;
265 bool const t31Max = point3Type1 == CriticalType::Local_maximum;
266 bool const t32Min = point3Type2 == CriticalType::Local_minimum;
267 bool const t32Max = point3Type2 == CriticalType::Local_maximum;
268 // bool bothEx3 = t31Ex && t32Ex;
269 // if (!bothEx3)
270 // continue;
271 bool const t3Max = t31Max || t32Max;
272 bool const t3Min = !t3Max && (t31Min || t32Min);
273
274 x3 = t3Max ? tuple3.death.coords[0]
275 : t3Min ? tuple3.birth.coords[0]
276 : 0;
277 y3 = t3Max ? tuple3.death.coords[1]
278 : t3Min ? tuple3.birth.coords[1]
279 : 0;
280 z3 = t3Max ? tuple3.death.coords[2]
281 : t3Min ? tuple3.birth.coords[2]
282 : 0;
283
284 double dist = 0;
285 bool hasMatched = false;
286 const auto square = [](const double a) { return a * a; };
287 if(doMatch1 && ((t3Max && t1Max) || (t3Min && t1Min))) {
288 double const dist13
289 = std::sqrt(square(x1 - x3) + square(y1 - y3) + square(z1 - z3));
290 dist = dist13;
291 if(dist13 >= postProcThresh)
292 continue;
293 hasMatched = true;
294 }
295
296 if(doMatch2 && ((t3Max && t2Max) || (t3Min && t2Min))) {
297 double const dist23
298 = std::sqrt(square(x2 - x3) + square(y2 - y3) + square(z2 - z3));
299 dist = dist23;
300 if(dist23 >= postProcThresh)
301 continue;
302 hasMatched = true;
303 }
304
305 if(!hasMatched)
306 continue;
307
309 std::stringstream msg;
310 msg << "Merged " << m << " with " << k << ": d = " << dist << ".";
311 printMsg(msg.str());
312
313 // Get every other tracking trajectory.
314 std::set<int> &mergedM = trackingTupleToMerged[m];
315 // std::set<int> mergedK = trackingTupleToMerged[k];
316
317 // Push for others to merge.
318 // for (auto& i : mergedM) mergedK.insert(i);
319 // for (auto& i : mergedK) mergedM.insert(i);
320 // mergedK.insert(m);
321 mergedM.insert(k);
322 break;
323 }
324 }
325 }
326
327 return 0;
328}
void setWasserstein(const std::string &wasserstein)
void setPY(const double py)
int execute(const ttk::DiagramType &diag0, const ttk::DiagramType &diag1, std::vector< MatchingType > &matchings)
void setPX(const double px)
void setAlgorithm(const std::string &algorithm)
void setPZ(const double pz)
void setPersistencePercentThreshold(const double t)
void setPS(const double ps)
void setPE(const double pe)
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
double getElapsedTime()
Definition Timer.h:15
int performSingleMatching(int i, std::vector< ttk::DiagramType > &inputPersistenceDiagrams, std::vector< std::vector< MatchingType > > &outputMatchings, const std::string &algorithm, const std::string &wasserstein, double tolerance, double px, double py, double pz, double ps, double pe)
int performMatchings(int numInputs, std::vector< ttk::DiagramType > &inputPersistenceDiagrams, std::vector< std::vector< MatchingType > > &outputMatchings, const std::string &algorithm, const std::string &wasserstein, double tolerance, double px, double py, double pz, double ps, double pe)
int performTracking(std::vector< ttk::DiagramType > &allDiagrams, std::vector< std::vector< MatchingType > > &allMatchings, std::vector< trackingTuple > &trackings)
int performPostProcess(const std::vector< ttk::DiagramType > &allDiagrams, const std::vector< trackingTuple > &trackings, std::vector< std::set< int > > &trackingTupleToMerged, const double postProcThresh)
std::tuple< int, int, std::vector< SimplexId > > trackingTuple
std::vector< PersistencePair > DiagramType
Persistence Diagram type as a vector of Persistence pairs.
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)