TTK
Loading...
Searching...
No Matches
ttkPersistenceDiagramDistanceMatrix.cpp
Go to the documentation of this file.
3
4#include <vtkCellData.h>
5#include <vtkCharArray.h>
6#include <vtkDataArray.h>
7#include <vtkDataSet.h>
8#include <vtkDoubleArray.h>
9#include <vtkFiltersCoreModule.h>
10#include <vtkFloatArray.h>
11#include <vtkIntArray.h>
12#include <vtkMultiBlockDataSet.h>
13#include <vtkNew.h>
14#include <vtkObjectFactory.h>
15#include <vtkPointData.h>
16#include <vtkStringArray.h>
17#include <vtkTable.h>
18#include <vtkUnstructuredGrid.h>
19
21
23 SetNumberOfInputPorts(1);
24 SetNumberOfOutputPorts(1);
25}
26
28 int port, vtkInformation *info) {
29 if(port == 0) {
30 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
31 info->Set(vtkAlgorithm::INPUT_IS_REPEATABLE(), 1);
32 return 1;
33 }
34 return 0;
35}
36
38 int port, vtkInformation *info) {
39 if(port == 0) {
40 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkTable");
41 return 1;
42 }
43 return 0;
44}
45
46// to adapt if your wrapper does not inherit from vtkDataSetAlgorithm
48 vtkInformation * /*request*/,
49 vtkInformationVector **inputVector,
50 vtkInformationVector *outputVector) {
51 ttk::Memory const m;
52
53 // Get input data
54 std::vector<vtkUnstructuredGrid *> inputDiagrams;
55
56 auto nBlocks = inputVector[0]->GetNumberOfInformationObjects();
57 std::vector<vtkMultiBlockDataSet *> blocks(nBlocks);
58
59 if(nBlocks > 2) {
60 this->printWrn("Only dealing with the first two MultiBlockDataSets");
61 nBlocks = 2;
62 }
63
64 // number of diagrams per input block
65 std::array<size_t, 2> nInputs{0, 0};
66
67 for(int i = 0; i < nBlocks; ++i) {
68 blocks[i] = vtkMultiBlockDataSet::GetData(inputVector[0], i);
69 if(blocks[i] != nullptr) {
70 nInputs[i] = blocks[i]->GetNumberOfBlocks();
71 for(size_t j = 0; j < nInputs[i]; ++j) {
72 inputDiagrams.emplace_back(
73 vtkUnstructuredGrid::SafeDownCast(blocks[i]->GetBlock(j)));
74 }
75 }
76 }
77
78 if(nInputs[0] + nInputs[1] == 0) {
79 this->printErr("No input detected");
80 return 0;
81 }
82
83 // total number of diagrams
84 const int nDiags = inputDiagrams.size();
85
86 // Sanity check
87 for(const auto vtu : inputDiagrams) {
88 if(vtu == nullptr) {
89 this->printErr("Input diagrams are not all vtkUnstructuredGrid");
90 return 0;
91 }
92 }
93
94 // Set output
95 auto diagramsDistTable = vtkTable::GetData(outputVector);
96
97 std::vector<ttk::DiagramType> intermediateDiagrams(nDiags);
98
99 for(int i = 0; i < nDiags; i++) {
100 auto &diag{intermediateDiagrams[i]};
101 const auto ret = VTUToDiagram(diag, inputDiagrams[i], *this);
102 if(ret < 0) {
103 this->printErr("Could not read Persistence Diagram");
104 return 0;
105 }
106 }
107
108 const auto diagramsDistMat = this->execute(intermediateDiagrams, nInputs);
109
110 // zero-padd column name to keep Row Data columns ordered
111 const auto zeroPad
112 = [](std::string &colName, const size_t numberCols, const size_t colIdx) {
113 std::string const max{std::to_string(numberCols - 1)};
114 std::string const cur{std::to_string(colIdx)};
115 std::string const zer(max.size() - cur.size(), '0');
116 colName.append(zer).append(cur);
117 };
118
119 const auto nTuples = nInputs[1] == 0 ? nInputs[0] : nInputs[1];
120
121 // copy diagrams distance matrix to output
122 for(size_t i = 0; i < diagramsDistMat.size(); ++i) {
123 std::string name{"Diagram"};
124 zeroPad(name, diagramsDistMat.size(), i);
125
126 vtkNew<vtkDoubleArray> col{};
127 col->SetNumberOfTuples(nTuples);
128 col->SetName(name.c_str());
129 for(size_t j = 0; j < diagramsDistMat[i].size(); ++j) {
130 col->SetTuple1(j, diagramsDistMat[i][j]);
131 }
132 diagramsDistTable->AddColumn(col);
133 }
134
135 // aggregate the field data arrays from all input diagrams
136 vtkNew<vtkFieldData> inputFdA{};
137
138 for(const auto diag : inputDiagrams) {
139 const auto fd{diag->GetFieldData()};
140 for(int i = 0; i < fd->GetNumberOfArrays(); ++i) {
141 const auto array{fd->GetAbstractArray(i)};
142 if(array->IsA("vtkDataArray") || array->IsA("vtkStringArray")) {
143 inputFdA->AddArray(array);
144 }
145 }
146 }
147
148 // avoid modifying input field data
149 vtkNew<vtkFieldData> outputFda{};
150 outputFda->DeepCopy(inputFdA);
151
152 for(int i = 0; i < outputFda->GetNumberOfArrays(); ++i) {
153 const auto array{outputFda->GetAbstractArray(i)};
154 array->SetNumberOfTuples(inputDiagrams.size());
155 const auto name{array->GetName()};
156 for(size_t j = 0; j < inputDiagrams.size(); ++j) {
157 const auto fd{inputDiagrams[j]->GetFieldData()};
158 const auto inputArray{fd->GetAbstractArray(name)};
159 if(inputArray != nullptr) {
160 array->SetTuple(j, 0, inputArray);
161 } else {
162 if(array->IsA("vtkDataArray")) {
163 vtkDataArray::SafeDownCast(array)->SetTuple1(j, NAN);
164 } else if(array->IsA("vtkStringArray")) {
165 vtkStringArray::SafeDownCast(array)->SetValue(j, "");
166 }
167 }
168 }
169 // copy "extended" input field data array to output row data
170 diagramsDistTable->AddColumn(array);
171 }
172
173 return 1;
174}
TTK processing package for the computation of a matrix of Wasserstein distances between persistence d...
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillInputPortInformation(int port, vtkInformation *info) override
int FillOutputPortInformation(int port, vtkInformation *info) override
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:159
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
std::vector< std::vector< double > > execute(const std::vector< DiagramType > &intermediateDiagrams, const std::array< size_t, 2 > &nInputs) const
vtkStandardNewMacro(ttkPersistenceDiagramDistanceMatrix)
int VTUToDiagram(ttk::DiagramType &diagram, vtkUnstructuredGrid *vtu, const ttk::Debug &dbg)
Converts a Persistence Diagram in the VTK Unstructured Grid format (as generated by the ttkPersistenc...