TTK
Loading...
Searching...
No Matches
ttkTrackingFromFields.cpp
Go to the documentation of this file.
1#include <vtkDoubleArray.h>
2#include <vtkInformation.h>
3#include <vtkPointData.h>
4
5#include <ttkMacros.h>
8#include <ttkUtils.h>
9
11
13 this->SetNumberOfInputPorts(1);
14 this->SetNumberOfOutputPorts(1);
15}
16
18 vtkInformation *info) {
19 if(port == 0) {
20 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
21 return 1;
22 }
23 return 0;
24}
26 vtkInformation *info) {
27 if(port == 0) {
28 info->Set(vtkAlgorithm::INPUT_IS_REPEATABLE(), 1);
29 return 1;
30 }
31 return 0;
32}
33
34// (*) Persistence-driven approach
35template <class dataType, class triangulationType>
36int ttkTrackingFromFields::trackWithPersistenceMatching(
37 vtkUnstructuredGrid *output,
38 unsigned long fieldNumber,
39 const triangulationType *triangulation) {
40
41 std::vector<ttk::DiagramType> persistenceDiagrams(fieldNumber);
42
44 (int)fieldNumber, persistenceDiagrams, triangulation);
45
46 std::vector<std::vector<ttk::MatchingType>> outputMatchings(fieldNumber - 1);
47
48 double const spacing = Spacing;
49 std::string const algorithm = DistanceAlgorithm;
50 double const tolerance = Tolerance;
51 std::string const wasserstein = WassersteinMetric;
52
55 tfp.setDebugLevel(this->debugLevel_);
56 tfp.performMatchings(
57 (int)fieldNumber, persistenceDiagrams, outputMatchings,
58 algorithm, // Not from paraview, from enclosing tracking plugin
59 wasserstein, tolerance, PX, PY, PZ, PS, PE // Coefficients
60 );
61
62 vtkNew<vtkPoints> const points{};
63 vtkNew<vtkUnstructuredGrid> const persistenceDiagram{};
64
65 vtkNew<vtkDoubleArray> persistenceScalars{};
66 vtkNew<vtkDoubleArray> valueScalars{};
67 vtkNew<vtkIntArray> matchingIdScalars{};
68 vtkNew<vtkIntArray> lengthScalars{};
69 vtkNew<vtkIntArray> timeScalars{};
70 vtkNew<vtkIntArray> componentIds{};
71 vtkNew<vtkIntArray> pointTypeScalars{};
72
73 persistenceScalars->SetName("Cost");
74 valueScalars->SetName("Scalar");
75 matchingIdScalars->SetName("MatchingIdentifier");
76 lengthScalars->SetName("ComponentLength");
77 timeScalars->SetName("TimeStep");
78 componentIds->SetName("ConnectedComponentId");
79 pointTypeScalars->SetName("CriticalType");
80
81 std::vector<ttk::trackingTuple> trackingsBase;
82 tfp.performTracking(persistenceDiagrams, outputMatchings, trackingsBase);
83
84 std::vector<std::set<int>> trackingTupleToMerged(trackingsBase.size());
85
86 if(DoPostProc) {
87 tfp.performPostProcess(persistenceDiagrams, trackingsBase,
88 trackingTupleToMerged, PostProcThresh);
89 }
90
91 bool const useGeometricSpacing = UseGeometricSpacing;
92
93 // Build mesh.
95 trackingsBase, outputMatchings, persistenceDiagrams, useGeometricSpacing,
96 spacing, DoPostProc, trackingTupleToMerged, points, persistenceDiagram,
97 persistenceScalars, valueScalars, matchingIdScalars, lengthScalars,
98 timeScalars, componentIds, pointTypeScalars, *this);
99
100 output->ShallowCopy(persistenceDiagram);
101
102 return 1;
103}
104
105template <class dataType, class triangulationType>
106int ttkTrackingFromFields::trackWithCriticalPointMatching(
107 vtkUnstructuredGrid *output,
108 unsigned long fieldNumber,
109 const triangulationType *triangulation) {
110
111 ttk::Timer t{};
112
113 float x = 0, y = 0, z = 0;
114 float maxX = 0, minX = 0, maxY = 0, minY = 0, maxZ = 0, minZ = 0;
115 triangulation->getVertexPoint(0, minX, minY, minZ);
116 triangulation->getVertexPoint(0, maxX, maxY, maxZ);
117
118 for(int i = 0; i < triangulation->getNumberOfVertices(); i++) {
119 triangulation->getVertexPoint(i, x, y, z);
120 maxX = std::max(x, maxX);
121 maxX = std::min(x, minX);
122 maxY = std::max(y, maxX);
123 minY = std::min(y, minY);
124 maxZ = std::max(z, maxZ);
125 minZ = std::min(z, minZ);
126 }
127
128 double const relativeDestructionCost = RelativeDestructionCost;
129 double const tolerance = (double)Tolerance;
130 float meshDiameter
131 = std::sqrt(std::pow(maxX - minX, 2) + std::pow(maxY - minY, 2)
132 + std::pow(maxZ - minZ, 2));
133 int assignmentMethod = AssignmentMethod;
134
135 ttk::TrackingFromCriticalPoints tracker;
136 tracker.setMeshDiameter(meshDiameter);
137 tracker.setTolerance(tolerance);
138 tracker.setEpsilon(relativeDestructionCost);
139 tracker.setAssignmentMethod(assignmentMethod);
140 tracker.setWeights(PX, PY, PZ, PF);
141 tracker.setAssignmentPrecision(AssignmentPrecision);
142
143 tracker.setThreadNumber(this->threadNumber_);
144 tracker.setDebugLevel(this->debugLevel_);
145
146 std::vector<ttk::DiagramType> persistenceDiagrams(fieldNumber);
148 (int)fieldNumber, persistenceDiagrams, triangulation);
149
150 this->printMsg("Diagram computed", 1, t.getElapsedTime(), threadNumber_);
151 double previousStepTime = t.getElapsedTime();
152
153 std::vector<std::vector<ttk::MatchingType>> maximaMatchings(fieldNumber - 1);
154 std::vector<std::vector<ttk::MatchingType>> sad_1_Matchings(fieldNumber - 1);
155 std::vector<std::vector<ttk::MatchingType>> sad_2_Matchings(fieldNumber - 1);
156 std::vector<std::vector<ttk::MatchingType>> minimaMatchings(fieldNumber - 1);
157
158 std::vector<std::vector<ttk::SimplexId>> maxMap(fieldNumber);
159 std::vector<std::vector<ttk::SimplexId>> sad_1Map(fieldNumber);
160 std::vector<std::vector<ttk::SimplexId>> sad_2Map(fieldNumber);
161 std::vector<std::vector<ttk::SimplexId>> minMap(fieldNumber);
162
163 tracker.performMatchings(persistenceDiagrams, maximaMatchings,
164 sad_1_Matchings, sad_2_Matchings, minimaMatchings,
165 maxMap, sad_1Map, sad_2Map, minMap);
166
167 this->printMsg("Matchings computed", 1, t.getElapsedTime() - previousStepTime,
169 previousStepTime = t.getElapsedTime();
170
171 vtkNew<vtkPoints> const points{};
172 vtkNew<vtkUnstructuredGrid> const outputMesh{};
173
174 vtkNew<vtkDoubleArray> costs{};
175 vtkNew<vtkDoubleArray> averagePersistences{};
176 vtkNew<vtkDoubleArray> integratedPersistences{};
177 vtkNew<vtkDoubleArray> maximalPersistences{};
178 vtkNew<vtkDoubleArray> minimalPersistences{};
179 vtkNew<vtkDoubleArray> instantPersistences{};
180 vtkNew<vtkDoubleArray> valueScalars{};
181 vtkNew<vtkIntArray> globalVertexIds{};
182 vtkNew<vtkIntArray> lengthScalars{};
183 vtkNew<vtkIntArray> timeScalars{};
184 vtkNew<vtkIntArray> connectedComponentIds{};
185 vtkNew<vtkIntArray> pointsCriticalType{};
186
187 costs->SetName("Costs");
188 averagePersistences->SetName("AveragePersistence");
189 integratedPersistences->SetName("IntegratedPersistence");
190 maximalPersistences->SetName("MaximalPersistence");
191 minimalPersistences->SetName("MinimalPersistence");
192 instantPersistences->SetName("InstantPersistence");
193 valueScalars->SetName("Scalar");
194 globalVertexIds->SetName("VertexGlobalId");
195 lengthScalars->SetName("ComponentLength");
196 timeScalars->SetName("TimeStep");
197 connectedComponentIds->SetName("ConnectedComponentId");
198 pointsCriticalType->SetName("CriticalType");
199
200 std::vector<ttk::trackingTuple> allTrackings;
201 std::vector<std::vector<double>> allTrackingsCosts;
202 std::vector<std::vector<double>> allTrackingsInstantPersistence;
203
204 unsigned int typesArrayLimits[3] = {};
205
206 tracker.performTrackings(
207 persistenceDiagrams, maximaMatchings, sad_1_Matchings, sad_2_Matchings,
208 minimaMatchings, maxMap, sad_1Map, sad_2Map, minMap, allTrackings,
209 allTrackingsCosts, allTrackingsInstantPersistence, typesArrayLimits);
210
211 this->printMsg("Trackings computed", 1, t.getElapsedTime() - previousStepTime,
213 previousStepTime = t.getElapsedTime();
214
215 double const spacing = Spacing;
216 bool const useGeometricSpacing = UseGeometricSpacing;
217
219 triangulation, allTrackings, allTrackingsCosts,
220 allTrackingsInstantPersistence, useGeometricSpacing, spacing, points,
221 outputMesh, pointsCriticalType, timeScalars, lengthScalars, globalVertexIds,
222 connectedComponentIds, costs, averagePersistences, integratedPersistences,
223 maximalPersistences, minimalPersistences, instantPersistences,
224 typesArrayLimits);
225
226 this->printMsg(
227 "Mesh built", 1, t.getElapsedTime() - previousStepTime, threadNumber_);
228 this->printMsg("Total run time ", 1, t.getElapsedTime(), this->threadNumber_);
229
230 output->ShallowCopy(outputMesh);
231
232 return 1;
233}
234
236 vtkInformationVector **inputVector,
237 vtkInformationVector *outputVector) {
238
239 auto input = vtkDataSet::GetData(inputVector[0]);
240 auto output = vtkUnstructuredGrid::GetData(outputVector);
242 if(!triangulation)
243 return 0;
244
245 this->preconditionTriangulation(triangulation);
246
247 // Test validity of datasets
248 if(input == nullptr || output == nullptr) {
249 return -1;
250 }
251
252 // Get number and list of inputs.
253 std::vector<vtkDataArray *> inputScalarFieldsRaw;
254 std::vector<vtkDataArray *> inputScalarFields;
255 const auto pointData = input->GetPointData();
256 int numberOfInputFields = pointData->GetNumberOfArrays();
257 if(numberOfInputFields < 3) {
258 this->printErr("Not enough input fields to perform tracking.");
259 }
260
261 vtkDataArray *firstScalarField = pointData->GetArray(0);
262
263 for(int i = 0; i < numberOfInputFields; ++i) {
264 vtkDataArray *currentScalarField = pointData->GetArray(i);
265 if(currentScalarField == nullptr
266 || currentScalarField->GetName() == nullptr) {
267 continue;
268 }
269 std::string const sfname{currentScalarField->GetName()};
270 if(sfname.rfind("_Order") == (sfname.size() - 6)) {
271 continue;
272 }
273 if(firstScalarField->GetDataType() != currentScalarField->GetDataType()) {
274 this->printErr("Inconsistent field data type or size between fields `"
275 + std::string{firstScalarField->GetName()} + "' and `"
276 + sfname + "'");
277 return -1;
278 }
279 inputScalarFieldsRaw.push_back(currentScalarField);
280 }
281
282 std::sort(inputScalarFieldsRaw.begin(), inputScalarFieldsRaw.end(),
283 [](vtkDataArray *a, vtkDataArray *b) {
284 std::string s1 = a->GetName();
285 std::string s2 = b->GetName();
286 return std::lexicographical_compare(
287 s1.begin(), s1.end(), s2.begin(), s2.end());
288 });
289
290 numberOfInputFields = inputScalarFieldsRaw.size();
291 int const end = EndTimestep <= 0 ? numberOfInputFields
292 : std::min(numberOfInputFields, EndTimestep);
293 for(int i = StartTimestep; i < end; i += Sampling) {
294 vtkDataArray *currentScalarField = inputScalarFieldsRaw[i];
295 // Print scalar field names:
296 // std::cout << currentScalarField->GetName() << std::endl;
297 inputScalarFields.push_back(currentScalarField);
298 }
299
300 // Input -> persistence filter.
301 std::string const algorithm = DistanceAlgorithm;
302 int const pvalg = PVAlgorithm;
303 bool useTTKMethod = false;
304 bool trackWithCriticalPoints = (pvalg == 2);
305
306 if(pvalg >= 0) {
307 switch(pvalg) {
308 case 0:
309 case 1:
310 case 2:
311 case 3:
312 useTTKMethod = true;
313 break;
314 case 4:
315 break;
316 default:
317 this->printMsg("Unrecognized tracking method.");
318 break;
319 }
320 } else {
321 using ttk::str2int;
322 switch(str2int(algorithm.c_str())) {
323 case str2int("0"):
324 case str2int("ttk"):
325 case str2int("1"):
326 case str2int("legacy"):
327 case str2int("2"):
328 case str2int("geometric"):
329 case str2int("3"):
330 case str2int("parallel"):
331 useTTKMethod = true;
332 break;
333 case str2int("4"):
334 case str2int("greedy"):
335 break;
336 default:
337 this->printMsg("Unrecognized tracking method.");
338 break;
339 }
340 }
341
342 // 0. get data
343 int const fieldNumber = inputScalarFields.size();
344 std::vector<void *> inputFields(fieldNumber);
345 for(int i = 0; i < fieldNumber; i++) {
346 inputFields[i] = ttkUtils::GetVoidPointer(inputScalarFields[i]);
347 }
348 this->setInputScalars(inputFields);
349
350 // 0'. get offsets
351 std::vector<ttk::SimplexId *> inputOrders(fieldNumber);
352 for(int i = 0; i < fieldNumber; ++i) {
353 this->SetInputArrayToProcess(0, 0, 0, 0, inputScalarFields[i]->GetName());
354 auto orderArray
355 = this->GetOrderArray(input, 0, triangulation, false, 0, false);
356 inputOrders[i]
357 = static_cast<ttk::SimplexId *>(ttkUtils::GetVoidPointer(orderArray));
358 }
359 this->setInputOffsets(inputOrders);
360
361 int status = 0;
362 this->printMsg("Tracking trajectories over " + std::to_string(fieldNumber)
363 + " timesteps");
364 if(useTTKMethod && !trackWithCriticalPoints) {
366 inputScalarFields[0]->GetDataType(), triangulation->getType(),
367 (status = this->trackWithPersistenceMatching<VTK_TT, TTK_TT>(
368 output, fieldNumber, (TTK_TT *)triangulation->getData())));
369 } else if(useTTKMethod && trackWithCriticalPoints) {
371 inputScalarFields[0]->GetDataType(), triangulation->getType(),
372 (status = this->trackWithCriticalPointMatching<VTK_TT, TTK_TT>(
373 output, fieldNumber, (TTK_TT *)triangulation->getData())));
374 } else {
375 this->printMsg("The specified matching method is not supported.");
376 }
377
378 return status;
379}
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition BaseClass.h:47
ttk::Triangulation * GetTriangulation(vtkDataSet *dataSet)
vtkDataArray * GetOrderArray(vtkDataSet *const inputData, const int scalarArrayIdx, ttk::Triangulation *triangulation, const bool getGlobalOrder=false, const int orderArrayIdx=0, const bool enforceOrderArrayIdx=false)
TTK VTK-filter that takes an input time-varying data set (represented by a list of scalar fields) and...
int FillOutputPortInformation(int port, vtkInformation *info) override
int FillInputPortInformation(int port, vtkInformation *info) override
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
static int buildMeshAlt(const triangulationType *triangulation, const std::vector< ttk::trackingTuple > &trackings, const std::vector< std::vector< double > > &allTrackingsCosts, const std::vector< std::vector< double > > &allTrackingsInstantPersistence, const bool useGeometricSpacing, const double spacing, vtkPoints *points, vtkUnstructuredGrid *outputMesh, vtkIntArray *pointsCriticalType, vtkIntArray *timeScalars, vtkIntArray *lengthScalars, vtkIntArray *globalVertexIds, vtkIntArray *connectedComponentIds, vtkDoubleArray *costs, vtkDoubleArray *averagePersistence, vtkDoubleArray *integratedPersistence, vtkDoubleArray *maximalPersistence, vtkDoubleArray *minimalPersistence, vtkDoubleArray *instantPersistence, unsigned int *sizes)
static int buildMesh(const std::vector< ttk::trackingTuple > &trackings, const std::vector< std::vector< ttk::MatchingType > > &outputMatchings, const std::vector< ttk::DiagramType > &inputPersistenceDiagrams, const bool useGeometricSpacing, const double spacing, const bool doPostProc, const std::vector< std::set< int > > &trackingTupleToMerged, vtkPoints *points, vtkUnstructuredGrid *persistenceDiagram, vtkDoubleArray *persistenceScalars, vtkDoubleArray *valueScalars, vtkIntArray *matchingIdScalars, vtkIntArray *lengthScalars, vtkIntArray *timeScalars, vtkIntArray *componentIds, vtkIntArray *pointTypeScalars, const ttk::Debug &dbg)
static void * GetVoidPointer(vtkDataArray *array, vtkIdType start=0)
Definition ttkUtils.cpp:226
virtual int setThreadNumber(const int threadNumber)
Definition BaseClass.h:80
int debugLevel_
Definition Debug.h:379
virtual int setDebugLevel(const int &debugLevel)
Definition Debug.cpp:147
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
void setWeights(double PX, double PY, double PZ, double PF)
void performMatchings(const std::vector< DiagramType > &persistenceDiagrams, std::vector< std::vector< MatchingType > > &maximaMatchings, std::vector< std::vector< MatchingType > > &sad_1_Matchings, std::vector< std::vector< MatchingType > > &sad_2_Matchings, std::vector< std::vector< MatchingType > > &minimaMatchings, std::vector< std::vector< SimplexId > > &maxMap, std::vector< std::vector< SimplexId > > &sad_1Map, std::vector< std::vector< SimplexId > > &sad_2Map, std::vector< std::vector< SimplexId > > &minMap)
void performTrackings(const std::vector< DiagramType > &persistenceDiagrams, const std::vector< std::vector< MatchingType > > &maximaMatchings, const std::vector< std::vector< MatchingType > > &sad_1_Matchings, const std::vector< std::vector< MatchingType > > &sad_2_Matchings, const std::vector< std::vector< MatchingType > > &minimaMatchings, const std::vector< std::vector< SimplexId > > &maxMap, const std::vector< std::vector< SimplexId > > &sad_1Map, const std::vector< std::vector< SimplexId > > &sad_2Map, const std::vector< std::vector< SimplexId > > &minMap, std::vector< trackingTuple > &allTrackings, std::vector< std::vector< double > > &allTrackingsCost, std::vector< std::vector< double > > &allTrackingsInstantPersistences, unsigned int(&typesArrayLimits)[3])
void setInputOffsets(std::vector< SimplexId * > &io)
void preconditionTriangulation(AbstractTriangulation *triangulation)
void setInputScalars(std::vector< void * > &is)
int performDiagramComputation(int fieldNumber, std::vector< ttk::DiagramType > &persistenceDiagrams, const triangulationType *triangulation)
Triangulation is a class that provides time and memory efficient traversal methods on triangulations ...
AbstractTriangulation * getData()
Triangulation::Type getType() const
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
constexpr unsigned long long str2int(const char *str, int h=0)
T end(std::pair< T, T > &p)
Definition ripser.cpp:503
#define ttkVtkTemplateMacro(dataType, triangulationType, call)
Definition ttkMacros.h:69
vtkStandardNewMacro(ttkTrackingFromFields)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)