TTK
Loading...
Searching...
No Matches
ttkRipsPersistenceDiagram.cpp
Go to the documentation of this file.
1#include <ttkMacros.h>
3#include <ttkUtils.h>
4
5#include <vtkCellData.h>
6#include <vtkDoubleArray.h>
7#include <vtkInformation.h>
8#include <vtkPointData.h>
9#include <vtkTable.h>
10
12
13int ttkRipsPersistenceDiagram::DiagramToVTU(
14 vtkUnstructuredGrid *vtu,
15 const std::vector<std::vector<ripser::pers_pair_t>> &diagram) {
16 const auto pd = vtu->GetPointData();
17 const auto cd = vtu->GetCellData();
18
19 int n_pairs = 0;
20 for(auto const &diagram_d : diagram)
21 n_pairs += diagram_d.size();
22
23 // point data arrays
24 vtkNew<ttkSimplexIdTypeArray> vertsId{};
25 vertsId->SetName(ttk::VertexScalarFieldName);
26 vertsId->SetNumberOfTuples(2 * n_pairs);
27 pd->AddArray(vertsId);
28
29 vtkNew<vtkIntArray> critType{};
30 critType->SetName(ttk::PersistenceCriticalTypeName);
31 critType->SetNumberOfTuples(2 * n_pairs);
32 pd->AddArray(critType);
33
34 // cell data arrays
35 vtkNew<ttkSimplexIdTypeArray> pairsId{};
36 pairsId->SetName(ttk::PersistencePairIdentifierName);
37 pairsId->SetNumberOfTuples(n_pairs);
38 cd->AddArray(pairsId);
39
40 vtkNew<vtkIntArray> pairsDim{};
41 pairsDim->SetName(ttk::PersistencePairTypeName);
42 pairsDim->SetNumberOfTuples(n_pairs);
43 cd->AddArray(pairsDim);
44
45 vtkNew<vtkDoubleArray> persistence{};
47 persistence->SetNumberOfTuples(n_pairs);
48 cd->AddArray(persistence);
49
50 vtkNew<vtkDoubleArray> birthScalars{};
51 birthScalars->SetName(ttk::PersistenceBirthName);
52 birthScalars->SetNumberOfTuples(n_pairs);
53 cd->AddArray(birthScalars);
54
55 vtkNew<vtkUnsignedCharArray> isFinite{};
56 isFinite->SetName(ttk::PersistenceIsFinite);
57 isFinite->SetNumberOfTuples(n_pairs);
58 cd->AddArray(isFinite);
59
60 // grid
61 vtkNew<vtkPoints> points{};
62 points->SetNumberOfPoints(2 * n_pairs);
63 vtkNew<vtkIdTypeArray> offsets{}, connectivity{};
64 offsets->SetNumberOfComponents(1);
65 offsets->SetNumberOfTuples(n_pairs + 1);
66 connectivity->SetNumberOfComponents(1);
67 connectivity->SetNumberOfTuples(2 * n_pairs);
68
69 unsigned i = 0;
70 unsigned i_max = 0;
71 double birth_max = 0.;
72 for(unsigned d = 0; d < diagram.size(); ++d) {
73 for(auto const &pair : diagram[d]) {
74 const unsigned i0 = 2 * i, i1 = 2 * i + 1;
75 pairsId->SetTuple1(i, i);
76 pairsDim->SetTuple1(i, d);
77
78 const double death = std::min(SimplexMaximumDiameter, pair.second.second);
79 isFinite->SetTuple1(
80 i,
81 pair.second.second < std::numeric_limits<ripser::value_t>::infinity());
82 persistence->SetTuple1(i, death - pair.first.second);
83 birthScalars->SetTuple1(i, pair.first.second);
84 points->SetPoint(i0, pair.first.second, pair.first.second, 0);
85 points->SetPoint(i1, pair.first.second, death, 0);
86
87 if(pair.first.second > birth_max) {
88 birth_max = pair.first.second;
89 i_max = i;
90 }
91
92 connectivity->SetTuple1(i0, i0);
93 connectivity->SetTuple1(i1, i1);
94 offsets->SetTuple1(i, 2 * i);
95
96 critType->SetTuple1(i0, d);
97 critType->SetTuple1(i1, d + 1);
98
99 vertsId->SetTuple1(i0, *std::max_element(pair.first.first.begin(),
100 pair.first.first.end()));
101 vertsId->SetTuple1(i1, *std::max_element(pair.second.first.begin(),
102 pair.second.first.end()));
103
104 ++i;
105 }
106 }
107
108 offsets->SetTuple1(n_pairs, connectivity->GetNumberOfTuples());
109
110 vtkNew<vtkCellArray> cells{};
111 cells->SetData(offsets, connectivity);
112 vtu->SetPoints(points);
113 vtu->SetCells(VTK_LINE, cells);
114
115 // add diagonal
116 std::array<vtkIdType, 2> diag{0, 2 * i_max};
117 vtu->InsertNextCell(VTK_LINE, 2, diag.data());
118 pairsId->InsertTuple1(n_pairs, -1);
119 pairsDim->InsertTuple1(n_pairs, -1);
120 isFinite->InsertTuple1(n_pairs, false);
121 persistence->InsertTuple1(n_pairs, 0.);
122 birthScalars->InsertTuple1(n_pairs, 0.);
123
124 return 1;
125}
126
128 this->SetNumberOfInputPorts(1);
129 this->SetNumberOfOutputPorts(1);
130}
131
133 vtkInformation *info) {
134 if(port == 0) {
135 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTable");
136 return 1;
137 }
138 return 0;
139}
140
142 vtkInformation *info) {
143 if(port == 0) {
144 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
145 return 1;
146 }
147 return 0;
148}
149
151 vtkInformationVector **inputVector,
152 vtkInformationVector *outputVector) {
153
154 ttk::Timer tm{};
155
156 vtkTable *input = vtkTable::GetData(inputVector[0]);
157 vtkUnstructuredGrid *outputPersistenceDiagram
158 = vtkUnstructuredGrid::GetData(outputVector);
159
160 if(!input)
161 return 0;
162
163 std::vector<std::vector<double>> points;
165 const int numberOfPoints = input->GetNumberOfRows();
166 const int dimension = input->GetNumberOfColumns();
167
168 points = std::vector<std::vector<double>>(numberOfPoints);
169 for(int i = 0; i < numberOfPoints; ++i) {
170 for(int j = 0; j < dimension; ++j)
171 points[i].push_back(input->GetValue(i, j).ToDouble());
172 }
173 this->printMsg("Ripser starts (#dim: " + std::to_string(dimension)
174 + ", #pts: " + std::to_string(numberOfPoints) + ")",
175 1.0, tm.getElapsedTime(), 1);
176 } else {
177 const int n
178 = std::min(input->GetNumberOfRows(), input->GetNumberOfColumns());
179 const int column_offset = input->GetNumberOfColumns() - n;
180
181 points = {std::vector<double>(n * (n - 1) / 2)};
182 for(int i = 1; i < n; ++i) {
183 for(int j = 0; j < i; ++j)
184 points[0][i * (i - 1) / 2 + j]
185 = input->GetValue(i, j + column_offset).ToDouble();
186 }
187 this->printMsg("Ripser starts (" + std::to_string(n) + "x"
188 + std::to_string(n) + " dist mat)",
189 1.0, tm.getElapsedTime(), 1);
190 }
191 this->printMsg(
192 "Simplex maximum dimension: " + std::to_string(SimplexMaximumDimension),
193 1.0, tm.getElapsedTime(), 1);
194 this->printMsg(
195 "Simplex maximum diameter: " + std::to_string(SimplexMaximumDiameter), 1.0,
196 tm.getElapsedTime(), 1);
197
198 std::vector<std::vector<ripser::pers_pair_t>> diagram(0);
199
200 const auto ret = this->execute(points, diagram);
201 if(ret != 0) {
202 return 0;
203 }
204
205 DiagramToVTU(outputPersistenceDiagram, diagram);
206 this->printMsg("Complete", 1.0, tm.getElapsedTime(), 1);
207
208 // shallow copy input Field Data
209 outputPersistenceDiagram->GetFieldData()->ShallowCopy(input->GetFieldData());
210
211 // return success
212 return 1;
213}
#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 wraps the ttk::RipsPersistenceDiagram module.
int FillInputPortInformation(int port, vtkInformation *info) override
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillOutputPortInformation(int port, vtkInformation *info) override
int execute(const std::vector< std::vector< double > > &points, std::vector< std::vector< ripser::pers_pair_t > > &ph) const
Main entry point.
const char PersistenceName[]
Definition DataTypes.h:72
const char PersistencePairTypeName[]
Definition DataTypes.h:73
const char PersistenceCriticalTypeName[]
Definition DataTypes.h:67
const char PersistenceIsFinite[]
Definition DataTypes.h:74
const char VertexScalarFieldName[]
default name for vertex scalar field
Definition DataTypes.h:35
const char PersistencePairIdentifierName[]
Definition DataTypes.h:71
const char PersistenceBirthName[]
Definition DataTypes.h:68
vtkStandardNewMacro(ttkRipsPersistenceDiagram)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)