TTK
Loading...
Searching...
No Matches
ttkContourTreeAlignment.cpp
Go to the documentation of this file.
2
3#include <vtkCellArray.h>
4#include <vtkCellData.h>
5#include <vtkDataObject.h>
6#include <vtkFloatArray.h>
7#include <vtkIdTypeArray.h>
8#include <vtkInformationVector.h>
9#include <vtkLongLongArray.h>
10#include <vtkMultiBlockDataSet.h>
11#include <vtkPointData.h>
12#include <vtkUnstructuredGrid.h>
13
14#include <ttkMacros.h>
15#include <ttkUtils.h>
16
17using namespace std;
18using namespace ttk;
19
21
23 this->SetNumberOfInputPorts(1);
24 this->SetNumberOfOutputPorts(1);
25}
26
27// Specify the input data type of each input port
29 vtkInformation *info) {
30 if(port == 0) {
31 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
32 return 1;
33 }
34 return 0;
35}
36
37// Specify the data object type of each output port
39 vtkInformation *info) {
40 if(port == 0) {
41 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
42 return 1;
43 }
44 return 0;
45}
46
48 vtkInformationVector **inputVector,
49 vtkInformationVector *outputVector) {
50
51 //==================================================================================================================
52 // Print status
53 { this->printMsg("RequestData"); }
54
55 //==================================================================================================================
56 // Prepare input
57 vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
58 auto inputMB = vtkMultiBlockDataSet::SafeDownCast(
59 inInfo->Get(vtkDataObject::DATA_OBJECT()));
60
61 size_t const n = inputMB->GetNumberOfBlocks();
62
63 //==================================================================================================================
64 // print input info
65 this->printMsg(
66 {{"#Trees", std::to_string(n)}, {"Seed", std::to_string(RandomSeed)}});
67
68 //==================================================================================================================
69 // extract topologies
71 this->printMsg("Extracting topologies for " + std::to_string(n) + " trees",
72 debug::Priority::VERBOSE);
73 if(this->debugLevel_ < static_cast<int>(debug::Priority::VERBOSE)) {
74 this->printMsg("Extracting topologies for " + std::to_string(n) + " trees.",
75 0, debug::LineMode::REPLACE);
76 }
77
78 int scalarType = -1;
79 vector<void *> scalars(n); // scalar type will be determined dynamically
80 vector<int *> regionSizes(n);
81 vector<int *> segmentationIds(n);
82 vector<int *> segmentations;
83 vector<size_t> segSizes;
84 vector<long long *> topologies(n);
85 vector<size_t> nVertices(n);
86 vector<size_t> nEdges(n);
87
88 for(size_t i = 0; i < n; i++) {
89 auto contourTree = vtkUnstructuredGrid::SafeDownCast(inputMB->GetBlock(i));
90 vtkDataSet *segmentation = nullptr;
91
92 if(!contourTree) {
93 auto pair = vtkMultiBlockDataSet::SafeDownCast(inputMB->GetBlock(i));
94
95 if(!pair || pair->GetNumberOfBlocks() != 2) {
96 this->printErr("block " + std::to_string(i)
97 + " is not an unstructured grid or a pair of "
98 "unstructured grid and segmentation.");
99 return 0;
100 }
101
102 contourTree = vtkUnstructuredGrid::SafeDownCast(pair->GetBlock(0));
103 segmentation = vtkDataSet::SafeDownCast(pair->GetBlock(1));
104
105 if(!contourTree) {
106 this->printErr("block " + std::to_string(i)
107 + " is not an unstructured grid or a pair of "
108 "unstructured grid and segmentation.");
109 return 0;
110 }
111 }
112
113 this->printMsg("Block " + std::to_string(i) + " read from multiblock.",
114 debug::Priority::VERBOSE);
115 if(this->debugLevel_ < static_cast<int>(debug::Priority::VERBOSE)) {
116 this->printMsg("Extracting topologies for " + std::to_string(n)
117 + " trees (" + std::to_string(i) + "/"
118 + std::to_string(n) + ")",
119 (float)i / (float)n, debug::LineMode::REPLACE);
120 }
121
122 nVertices[i] = contourTree->GetNumberOfPoints();
123 nEdges[i] = contourTree->GetNumberOfCells();
124
125 // auto pData = contourTree->GetPointData();
126 // auto scalarArray = pData->GetArray( "Scalar" );
127
128 if(this->GetInputArrayAssociation(0, contourTree) != 0) {
129 printErr("Scalar array not point data.");
130 return 0;
131 }
132 auto scalarArray = this->GetInputArrayToProcess(0, contourTree);
133 if(!scalarArray) {
134 printErr("No Point Array \"Scalar\" found in contour tree.");
135 return 0;
136 }
137 scalars[i] = ttkUtils::GetVoidPointer(scalarArray);
138 scalarType = scalarArray->GetDataType();
139
140 this->printMsg(
141 "Scalar Array read from point data.", debug::Priority::VERBOSE);
142
143 // auto cData = contourTree->GetCellData();
144
145 // auto regionArray = cData->GetArray( "RegionSize" );
146 if(this->GetInputArrayAssociation(1, contourTree) != 1) {
147 printErr("Region size array not cell data.");
148 return 0;
149 }
150 auto regionArray = this->GetInputArrayToProcess(1, contourTree);
151 if(!regionArray) {
152 printErr("No Cell Array \"RegionSize\" found in contour tree.");
153 return 0;
154 }
155 regionSizes[i] = (int *)ttkUtils::GetVoidPointer(regionArray);
156 this->printMsg(
157 "RegionSize Array read from cell data.", debug::Priority::VERBOSE);
158
159 // auto segArray = cData->GetArray( "SegmentationId" );
160 if(this->GetInputArrayAssociation(2, contourTree) != 1) {
161 printErr("Segmentation Id array not cell data.");
162 return 0;
163 }
164 auto segArray = this->GetInputArrayToProcess(2, contourTree);
165 if(!segArray) {
166 printErr("No Cell Array \"SegmentationId\" found in contour tree.");
167 return 0;
168 }
169 segmentationIds[i] = (int *)ttkUtils::GetVoidPointer(segArray);
170 this->printMsg(
171 "SegmentationId Array read from cell data.", debug::Priority::VERBOSE);
172
173 if(segmentation) {
174 auto segArray_segmentation
175 = this->GetInputArrayToProcess(3, segmentation);
176 // auto segArray_segmentation =
177 // segmentation->GetPointData()->GetArray("SegmentationId");
178 if(!segArray_segmentation) {
179 printErr("No Cell Array \"SegmentationId\" found in segmentation.");
180 return 0;
181 }
182 segmentations.push_back(
183 (int *)ttkUtils::GetVoidPointer(segArray_segmentation));
184 this->printMsg("Segmentation read.", debug::Priority::VERBOSE);
185 segSizes.push_back(segArray_segmentation->GetNumberOfValues());
186 }
187
188 auto cells = contourTree->GetCells();
189 auto cellSizes
190 = (vtkIdType *)ttkUtils::GetVoidPointer(cells->GetOffsetsArray());
191 for(int cIdx = 0; cIdx < contourTree->GetNumberOfCells(); cIdx++) {
192 if(cellSizes[cIdx + 1] - cellSizes[cIdx] != 2) {
193 printErr("cell " + std::to_string(cIdx) + " of block "
194 + std::to_string(i)
195 + " not a line (input not a contour tree).");
196 return 0;
197 }
198 }
199 topologies[i]
200 = (long long *)ttkUtils::GetVoidPointer(cells->GetConnectivityArray());
201 }
202
203 if(scalarType < 0 || n < 1)
204 return 1;
205
206 //==================================================================================================================
207 // print status
208 this->printMsg(
209 "For " + std::to_string(n) + " trees topologies and data extracted.",
210 debug::Priority::VERBOSE);
211 if(this->debugLevel_ < static_cast<int>(debug::Priority::VERBOSE)) {
212 this->printMsg(
213 "Extracting topologies for " + std::to_string(n) + " trees", 1);
214 }
215
216 for(auto s : segSizes) {
217 this->printMsg(std::to_string(s));
218 }
219
220 this->printMsg("Starting alignment computation.");
221
222 //==================================================================================================================
223 // Compute Tree Alignment
224 vector<float> outputVertices;
225 vector<int> outputEdges;
226 vector<long long> outputFrequencies;
227 vector<long long> outputVertexIds;
228 vector<long long> outputBranchIds;
229 vector<long long> outputSegmentationIds;
230 vector<long long> outputArcIds;
231
232 this->setArcMatchMode(ArcMatchMode);
233 if(MatchTime)
235 else
236 this->setAlignmenttreeType(AlignmenttreeType);
237 this->setWeightArcMatch(WeightArcMatch);
238 this->setWeightCombinatorialMatch(WeightCombinatorialMatch);
239 this->setWeightScalarValueMatch(WeightScalarValueMatch);
240 this->setDebugLevel(this->debugLevel_);
241 this->setThreadNumber(this->threadNumber_);
242
243 int success = false;
244 switch(scalarType) {
245 vtkTemplateMacro({
246 success = this->execute<VTK_TT>(
247 scalars, regionSizes, segmentationIds, topologies, nVertices, nEdges,
248 segmentations, segSizes,
249
250 outputVertices, outputFrequencies, outputVertexIds, outputBranchIds,
251 outputSegmentationIds, outputArcIds, outputEdges,
252
253 RandomSeed);
254 });
255 }
256 if(!success) {
257 printErr("base layer execution failed.");
258 return 0;
259 }
260
261 //==================================================================================================================
262 // print status
264 this->printMsg("Alignment computed.");
265 this->printMsg("Writing paraview/vtk output.", 0, debug::LineMode::REPLACE);
266
267 //==================================================================================================================
268 // write paraview output
269
270 // Output
271 vtkInformation *outInfo = outputVector->GetInformationObject(0);
272 auto alignmentTree = vtkUnstructuredGrid::SafeDownCast(
273 outInfo->Get(vtkDataObject::DATA_OBJECT()));
274
275 // Prep Array
276 auto prepArray = [](vtkAbstractArray *array, const string &name,
277 size_t nComponents, size_t nTuples) {
278 array->SetName(name.data());
279 array->SetNumberOfComponents(nComponents);
280 array->SetNumberOfTuples(nTuples);
281 };
282
283 // Points
284 size_t const nOutputVertices = outputVertices.size();
285 auto points = vtkSmartPointer<vtkPoints>::New();
286 points->SetNumberOfPoints(nOutputVertices);
287 alignmentTree->SetPoints(points);
288
289 // Point Data
291 prepArray(freq, "Frequency", 1, nOutputVertices);
292 auto freqData = (long long *)ttkUtils::GetVoidPointer(freq);
293
295 prepArray(scalar, "Scalar", 1, nOutputVertices);
296 auto scalarData = (float *)ttkUtils::GetVoidPointer(scalar);
297
299 prepArray(vertexIDs, "VertexIDs", n, nOutputVertices);
300 auto vertexIDsData = (long long *)ttkUtils::GetVoidPointer(vertexIDs);
301
303 prepArray(branchIDs, "BranchIDs", 1, nOutputVertices);
304 auto branchIDsData = (long long *)ttkUtils::GetVoidPointer(branchIDs);
305
306 auto segmentationIDs = vtkSmartPointer<vtkLongLongArray>::New();
307 prepArray(segmentationIDs, "segmentationIDs", n, nOutputVertices);
308 auto segmentationIDsData
309 = (long long *)ttkUtils::GetVoidPointer(segmentationIDs);
310
312 prepArray(arcIDs, "arcIDs", n, nOutputVertices - 1);
313 auto arcIDsData = (long long *)ttkUtils::GetVoidPointer(arcIDs);
314
315 auto pointCoords = (float *)ttkUtils::GetVoidPointer(points);
316 for(size_t i = 0; i < nOutputVertices; i++) {
317 pointCoords[i * 3] = i;
318 pointCoords[i * 3 + 1] = outputVertices[i];
319 pointCoords[i * 3 + 2] = 0;
320
321 freqData[i] = outputFrequencies[i];
322 scalarData[i] = outputVertices[i];
323 branchIDsData[i] = outputBranchIds[i];
324 }
325 for(size_t i = 0; i < outputVertexIds.size(); i++)
326 vertexIDsData[i] = outputVertexIds[i];
327 for(size_t i = 0; i < outputSegmentationIds.size(); i++)
328 segmentationIDsData[i] = outputSegmentationIds[i];
329 for(size_t i = 0; i < outputArcIds.size(); i++)
330 arcIDsData[i] = outputArcIds[i];
331
332 // Add Data to Points
333 auto pointData = alignmentTree->GetPointData();
334 pointData->AddArray(freq);
335 pointData->AddArray(scalar);
336 pointData->AddArray(vertexIDs);
337 pointData->AddArray(branchIDs);
338 pointData->AddArray(segmentationIDs);
339
340 // Cells
341 size_t const nOutputEdges = outputEdges.size() / 2;
342 auto cellArray = vtkSmartPointer<vtkCellArray>::New();
343 // cellArray->SetCells(nOutputEdges, cells);
344
345 // auto cellConnectivity = vtkSmartPointer<vtkIdTypeArray>::New();
346 auto cellConnectivity = cellArray->GetConnectivityArray();
347 cellConnectivity->SetNumberOfTuples(nOutputEdges * 2);
348 auto cellIds = (vtkIdType *)ttkUtils::GetVoidPointer(cellConnectivity);
349
350 // auto cellOffsets = vtkSmartPointer<vtkIdTypeArray>::New();
351 auto cellOffsets = cellArray->GetOffsetsArray();
352 cellOffsets->SetNumberOfTuples(nOutputEdges + 1);
353 auto cellOffsetsData = (vtkIdType *)ttkUtils::GetVoidPointer(cellOffsets);
354
355 for(size_t i = 0; i < nOutputEdges; i++) {
356 cellOffsetsData[i] = i * 2;
357 cellIds[i * 2] = (vtkIdType)outputEdges[i * 2];
358 cellIds[i * 2 + 1] = (vtkIdType)outputEdges[i * 2 + 1];
359 }
360 cellOffsetsData[nOutputEdges] = 2 * nOutputEdges;
361
362 alignmentTree->SetCells(VTK_LINE, cellArray);
363
364 alignmentTree->GetCellData()->AddArray(arcIDs);
365
366 this->printMsg("Writing paraview/vtk output", 1);
367
368 if(!ExportJSON || ExportPath.length() < 1) {
369
370 //==================================================================================================================
371 // print status
372 this->printMsg("No JSON output.");
373
374 } else {
375
376 //==================================================================================================================
377 // print status
378 this->printMsg("Writing JSON alignment to \"" + ExportPath + "\"", 0,
379 debug::LineMode::REPLACE);
380
381 //==================================================================================================================
382 // output alignment tree as JSON file
383
384 std::ofstream fileJSON;
385 fileJSON.open(ExportPath + "/alignment.json");
386
387 std::vector<std::vector<int>> upEdges(nOutputVertices);
388 std::vector<std::vector<int>> downEdges(nOutputVertices);
389
390 std::vector<std::vector<int>> alignmentIDs;
391 for(size_t i = 0; i < n; i++) {
392 std::vector<int> const vertices_i(nVertices[i], -1);
393 alignmentIDs.push_back(vertices_i);
394 }
395
396 for(size_t i = 0; i < nOutputEdges; i++) {
397 int const id1 = outputEdges[i * 2];
398 int const id2 = outputEdges[i * 2 + 1];
399 float const v1 = scalar->GetValue(id1);
400 float const v2 = scalar->GetValue(id2);
401 if(v1 > v2) {
402 downEdges[id1].push_back(i);
403 upEdges[id2].push_back(i);
404 } else {
405 upEdges[id1].push_back(i);
406 downEdges[id2].push_back(i);
407 }
408 }
409
410 fileJSON << "{\n";
411
412 fileJSON << " \"nodes\": [\n";
413
414 for(size_t i = 0; i < nOutputVertices; i++) {
415 fileJSON << " {";
416 fileJSON << "\"scalar\": " << scalar->GetValue(i) << ", ";
417 fileJSON << "\"frequency\": " << freq->GetValue(i) << ", ";
418 for(size_t j = 0; j < n; j++) {
419 if(vertexIDs->GetComponent(i, j) >= 0)
420 alignmentIDs[j][vertexIDs->GetComponent(i, j)] = i;
421 }
422 fileJSON << "\"segmentationIDs\": [";
423 for(size_t j = 0; j < n; j++) {
424 fileJSON << segmentationIDs->GetComponent(i, j);
425 if(j < n - 1)
426 fileJSON << ",";
427 }
428 fileJSON << "], ";
429 fileJSON << "\"upEdgeIDs\": [";
430 for(size_t j = 0; j < upEdges[i].size(); j++) {
431 fileJSON << upEdges[i][j];
432 if(j < upEdges[i].size() - 1)
433 fileJSON << ",";
434 }
435 fileJSON << "], ";
436 fileJSON << "\"downEdgeIDs\": [";
437 for(size_t j = 0; j < downEdges[i].size(); j++) {
438 fileJSON << downEdges[i][j];
439 if(j < downEdges[i].size() - 1)
440 fileJSON << ",";
441 }
442 fileJSON << "]";
443 fileJSON << (i == nOutputVertices - 1 ? "}\n" : "},\n");
444 }
445
446 fileJSON << " ],\n";
447
448 fileJSON << " \"edges\": [\n";
449
450 for(size_t i = 0; i < nOutputEdges; i++) {
451 fileJSON << " {";
452 int const id1 = outputEdges[i * 2];
453 int const id2 = outputEdges[i * 2 + 1];
454 fileJSON << "\"node1\": " << id1 << ", \"node2\": " << id2;
455 fileJSON << (i == nOutputEdges - 1 ? "}\n" : "},\n");
456 }
457
458 fileJSON << " ]\n";
459
460 fileJSON << "}\n";
461
462 fileJSON.close();
463
464 //==================================================================================================================
465 // print status
466 this->printMsg("Writing JSON alignment to \"" + ExportPath + "\"", 1);
467 this->printMsg("Writing JSON input trees to \"" + ExportPath + "\"", 0,
468 debug::LineMode::REPLACE);
469
470 //==================================================================================================================
471 // output original trees as JSON
472
473 for(size_t t = 0; t < n; t++) {
474
475 fileJSON.open(ExportPath + "/tree" + std::to_string(t) + ".json");
476
477 upEdges = std::vector<std::vector<int>>(nVertices[t]);
478 downEdges = std::vector<std::vector<int>>(nVertices[t]);
479
480 for(size_t i = 0; i < nEdges[t]; i++) {
481 int const id1 = topologies[t][i * 2 + 0];
482 int const id2 = topologies[t][i * 2 + 1];
483 float const v1 = ((float *)scalars[t])[id1];
484 float const v2 = ((float *)scalars[t])[id2];
485 if(v1 > v2) {
486 downEdges[id1].push_back(i);
487 upEdges[id2].push_back(i);
488 } else {
489 upEdges[id1].push_back(i);
490 downEdges[id2].push_back(i);
491 }
492 }
493
494 fileJSON << "{\n";
495
496 fileJSON << " \"nodes\": [\n";
497
498 bool first = true;
499 for(size_t k = 0; k < nOutputVertices; k++) {
500 int const i = vertexIDs->GetComponent(k, t);
501 if(i < 0)
502 continue;
503 fileJSON << (first ? " {" : ",\n {");
504 fileJSON << "\"scalar\": " << ((float *)scalars[t])[i] << ", ";
505 fileJSON << "\"id\": " << alignmentIDs[t][i] << ", ";
506 fileJSON << "\"upEdgeIDs\": [";
507 for(size_t j = 0; j < upEdges[i].size(); j++) {
508 fileJSON << upEdges[i][j];
509 if(j < upEdges[i].size() - 1)
510 fileJSON << ",";
511 }
512 fileJSON << "], ";
513 fileJSON << "\"downEdgeIDs\": [";
514 for(size_t j = 0; j < downEdges[i].size(); j++) {
515 fileJSON << downEdges[i][j];
516 if(j < downEdges[i].size() - 1)
517 fileJSON << ",";
518 }
519 fileJSON << "]";
520 fileJSON << "}";
521 first = false;
522 }
523
524 fileJSON << "\n ],\n";
525
526 fileJSON << " \"edges\": [\n";
527
528 for(size_t i = 0; i < nEdges[t]; i++) {
529 fileJSON << " {";
530 int const id1 = alignmentIDs[t][topologies[t][i * 2 + 0]];
531 int const id2 = alignmentIDs[t][topologies[t][i * 2 + 1]];
532 fileJSON << "\"node1\": " << id1 << ", \"node2\": " << id2;
533 fileJSON << (i == nEdges[t] - 1 ? "}\n" : "},\n");
534 }
535
536 fileJSON << " ]\n";
537
538 fileJSON << "}\n";
539
540 fileJSON.close();
541 }
542 this->printMsg("Writing JSON input trees to \"" + ExportPath + "\"", 1);
543 }
544
546
547 return 1;
548}
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition BaseClass.h:47
TTK VTK-filter that computes an alignment for a multiblock of contourtrees.
int FillOutputPortInformation(int port, vtkInformation *info) override
int FillInputPortInformation(int port, vtkInformation *info) override
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
static void * GetVoidPointer(vtkDataArray *array, vtkIdType start=0)
Definition ttkUtils.cpp:226
virtual int setThreadNumber(const int threadNumber)
Definition BaseClass.h:80
void setWeightCombinatorialMatch(float weight)
void setWeightArcMatch(float weight)
void setWeightScalarValueMatch(float weight)
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
std::string to_string(__int128)
Definition ripserpy.cpp:99
The Topology ToolKit.
vtkStandardNewMacro(ttkContourTreeAlignment) ttkContourTreeAlignment
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)