TTK
Loading...
Searching...
No Matches
ttkRipsPersistenceDiagram.cpp
Go to the documentation of this file.
2
3#include <vtkCellData.h>
4#include <vtkDoubleArray.h>
5#include <vtkInformation.h>
6#include <vtkPointData.h>
7#include <vtkTable.h>
8
9#include <regex>
10
12
13void DiagramToVTU(vtkUnstructuredGrid *vtu,
15 double SimplexMaximumDiameter) {
16
17 const auto pd = vtu->GetPointData();
18 const auto cd = vtu->GetCellData();
19
20 int n_pairs = 0;
21 for(auto const &diagram_d : diagram)
22 n_pairs += diagram_d.size();
23
24 if(SimplexMaximumDiameter == ttk::rpd::inf) {
25 double maxFiniteValue = 0.;
26 for(auto const &diag : diagram) {
27 for(auto const &[b, d] : diag) {
28 if(d.second < ttk::rpd::inf)
29 maxFiniteValue = std::max(maxFiniteValue, d.second);
30 }
31 }
32 SimplexMaximumDiameter = 1.5 * maxFiniteValue;
33 }
34
35 // point data arrays
36 vtkNew<ttkSimplexIdTypeArray> vertsId{};
37 vertsId->SetName(ttk::VertexScalarFieldName);
38 vertsId->SetNumberOfTuples(2 * n_pairs);
39 pd->AddArray(vertsId);
40
41 vtkNew<vtkIntArray> critType{};
42 critType->SetName(ttk::PersistenceCriticalTypeName);
43 critType->SetNumberOfTuples(2 * n_pairs);
44 pd->AddArray(critType);
45
46 // cell data arrays
47 vtkNew<ttkSimplexIdTypeArray> pairsId{};
48 pairsId->SetName(ttk::PersistencePairIdentifierName);
49 pairsId->SetNumberOfTuples(n_pairs);
50 cd->AddArray(pairsId);
51
52 vtkNew<vtkIntArray> pairsDim{};
53 pairsDim->SetName(ttk::PersistencePairTypeName);
54 pairsDim->SetNumberOfTuples(n_pairs);
55 cd->AddArray(pairsDim);
56
57 vtkNew<vtkDoubleArray> persistence{};
58 persistence->SetName(ttk::PersistenceName);
59 persistence->SetNumberOfTuples(n_pairs);
60 cd->AddArray(persistence);
61
62 vtkNew<vtkDoubleArray> birthScalars{};
63 birthScalars->SetName(ttk::PersistenceBirthName);
64 birthScalars->SetNumberOfTuples(n_pairs);
65 cd->AddArray(birthScalars);
66
67 vtkNew<vtkUnsignedCharArray> isFinite{};
68 isFinite->SetName(ttk::PersistenceIsFinite);
69 isFinite->SetNumberOfTuples(n_pairs);
70 cd->AddArray(isFinite);
71
72 // grid
73 vtkNew<vtkPoints> points{};
74 points->SetNumberOfPoints(2 * n_pairs);
75 vtkNew<vtkIdTypeArray> offsets{}, connectivity{};
76 offsets->SetNumberOfComponents(1);
77 offsets->SetNumberOfTuples(n_pairs + 1);
78 connectivity->SetNumberOfComponents(1);
79 connectivity->SetNumberOfTuples(2 * n_pairs);
80
81 unsigned i = 0;
82 unsigned i_max = 0;
83 double birth_max = 0.;
84 for(unsigned d = 0; d < diagram.size(); ++d) {
85 for(auto const &pair : diagram[d]) {
86 const unsigned i0 = 2 * i, i1 = 2 * i + 1;
87 pairsId->SetTuple1(i, i);
88 pairsDim->SetTuple1(i, d);
89
90 const double death = std::min(SimplexMaximumDiameter, pair.second.second);
91 isFinite->SetTuple1(i, pair.second.second < ttk::rpd::inf);
92 persistence->SetTuple1(i, death - pair.first.second);
93 birthScalars->SetTuple1(i, pair.first.second);
94 points->SetPoint(i0, pair.first.second, pair.first.second, 0);
95 points->SetPoint(i1, pair.first.second, death, 0);
96
97 if(pair.first.second > birth_max) {
98 birth_max = pair.first.second;
99 i_max = i;
100 }
101
102 connectivity->SetTuple1(i0, i0);
103 connectivity->SetTuple1(i1, i1);
104 offsets->SetTuple1(i, 2 * i);
105
106 critType->SetTuple1(i0, d);
107 critType->SetTuple1(i1, d + 1);
108
109 vertsId->SetTuple1(i0, *std::max_element(pair.first.first.begin(),
110 pair.first.first.end()));
111 vertsId->SetTuple1(i1, *std::max_element(pair.second.first.begin(),
112 pair.second.first.end()));
113
114 ++i;
115 }
116 }
117
118 offsets->SetTuple1(n_pairs, connectivity->GetNumberOfTuples());
119
120 vtkNew<vtkCellArray> cells{};
121 cells->SetData(offsets, connectivity);
122 vtu->SetPoints(points);
123 vtu->SetCells(VTK_LINE, cells);
124
125 // add diagonal
126 std::array<vtkIdType, 2> diag{0, 2 * i_max};
127 vtu->InsertNextCell(VTK_LINE, 2, diag.data());
128 pairsId->InsertTuple1(n_pairs, -1);
129 pairsDim->InsertTuple1(n_pairs, -1);
130 isFinite->InsertTuple1(n_pairs, false);
131 persistence->InsertTuple1(n_pairs, 0.);
132 birthScalars->InsertTuple1(n_pairs, 0.);
133}
134
136 this->SetNumberOfInputPorts(1);
137 this->SetNumberOfOutputPorts(1);
138}
139
141 vtkInformation *info) {
142 if(port == 0) {
143 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTable");
144 return 1;
145 }
146 return 0;
147}
148
150 vtkInformation *info) {
151 if(port == 0) {
152 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
153 return 1;
154 }
155 return 0;
156}
157
159 vtkInformationVector **inputVector,
160 vtkInformationVector *outputVector) {
161
162 ttk::Timer tm{};
163
164 vtkTable *input = vtkTable::GetData(inputVector[0]);
165 vtkUnstructuredGrid *outputPersistenceDiagram
166 = vtkUnstructuredGrid::GetData(outputVector);
167
168 if(!input)
169 return 0;
170
171 if(SelectFieldsWithRegexp) {
172 // select all input columns whose name is matching the regexp
173 ScalarFields.clear();
174 const auto n = input->GetNumberOfColumns();
175 for(int i = 0; i < n; ++i) {
176 const auto &name = input->GetColumnName(i);
177 if(std::regex_match(name, std::regex(RegexpString))) {
178 ScalarFields.emplace_back(name);
179 }
180 }
181 }
182
183 if(input->GetNumberOfRows() <= 0 || ScalarFields.size() <= 0) {
184 this->printErr("Input matrix has invalid dimensions (rows: "
185 + std::to_string(input->GetNumberOfRows())
186 + ", columns: " + std::to_string(ScalarFields.size()) + ")");
187 return 0;
188 }
189
190 std::vector<vtkAbstractArray *> arrays;
191 arrays.reserve(ScalarFields.size());
192 for(const auto &s : ScalarFields)
193 arrays.push_back(input->GetColumnByName(s.data()));
194
195 std::vector<std::vector<double>> points;
197 const int numberOfPoints = input->GetNumberOfRows();
198 const int dimension = ScalarFields.size();
199
200 points = std::vector<std::vector<double>>(numberOfPoints);
201 for(int i = 0; i < numberOfPoints; ++i) {
202 for(int j = 0; j < dimension; ++j)
203 points[i].push_back(arrays[j]->GetVariantValue(i).ToDouble());
204 }
205 this->printMsg(
206 "Computing Rips persistence diagram", 1.0, tm.getElapsedTime(), 1);
207 this->printMsg("#dimensions: " + std::to_string(dimension)
208 + ", #points: " + std::to_string(numberOfPoints),
209 0.0, tm.getElapsedTime(), 1);
210 } else {
211 const unsigned n = input->GetNumberOfRows();
212 if(n != ScalarFields.size()) {
213 this->printErr("Input distance matrix is not squared.");
214 this->printErr("(rows: " + std::to_string(input->GetNumberOfRows())
215 + ", columns: " + std::to_string(ScalarFields.size())
216 + ")");
217 return 0;
218 }
219
220 points = {std::vector<double>(n * (n - 1) / 2)};
221 for(unsigned i = 1; i < n; ++i) {
222 for(unsigned j = 0; j < i; ++j)
223 points[0][i * (i - 1) / 2 + j]
224 = arrays[j]->GetVariantValue(i).ToDouble();
225 }
226 this->printMsg(
227 "Computing Rips persistence diagram", 1.0, tm.getElapsedTime(), 1);
228 this->printMsg(
229 "(" + std::to_string(n) + "x" + std::to_string(n) + " distance matrix)",
230 0.0, tm.getElapsedTime(), 1);
231 }
232
233 this->printMsg(
234 "Homology maximum dimension: " + std::to_string(HomologyMaximumDimension),
235 0.0, tm.getElapsedTime(), 1);
236 this->printMsg(
237 "Simplex maximum diameter: " + std::to_string(SimplexMaximumDiameter), 0.0,
238 tm.getElapsedTime(), 1);
240 this->printMsg("Backend: Ripser", 0.0, tm.getElapsedTime(), 1);
241 else if(BackEnd == BACKEND::GEOMETRY)
242 this->printMsg("Backend: Geometric", 0.0, tm.getElapsedTime(), 1);
243
245
246 if(this->execute(points, diagram) != 0)
247 return 0;
248
250 outputPersistenceDiagram, diagram,
252
253 this->printMsg("Complete", 1.0, tm.getElapsedTime(), 1);
254
255 // shallow copy input Field Data
256 outputPersistenceDiagram->GetFieldData()->ShallowCopy(input->GetFieldData());
257
258 // return success
259 return 1;
260}
#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 printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
int execute(const rpd::PointCloud &points, rpd::MultidimensionalDiagram &ph) const
Main entry point.
constexpr value_t inf
std::vector< Diagram > MultidimensionalDiagram
const char PersistenceName[]
Definition DataTypes.h:80
const char PersistencePairTypeName[]
Definition DataTypes.h:81
const char PersistenceCriticalTypeName[]
Definition DataTypes.h:75
const char PersistenceIsFinite[]
Definition DataTypes.h:82
const char VertexScalarFieldName[]
default name for vertex scalar field
Definition DataTypes.h:35
const char PersistencePairIdentifierName[]
Definition DataTypes.h:79
const char PersistenceBirthName[]
Definition DataTypes.h:76
void DiagramToVTU(vtkUnstructuredGrid *vtu, const ttk::rpd::MultidimensionalDiagram &diagram, double SimplexMaximumDiameter)
Converts a Rips Persistence Diagram in the ttk::rpd::MultidimensionalDiagram format to the VTK Unstru...
vtkStandardNewMacro(ttkRipsPersistenceDiagram)
TTKRIPSPERSISTENCEDIAGRAM_EXPORT void DiagramToVTU(vtkUnstructuredGrid *vtu, const ttk::rpd::MultidimensionalDiagram &diagram, double SimplexMaximumDiameter)
Converts a Rips Persistence Diagram in the ttk::rpd::MultidimensionalDiagram format to the VTK Unstru...
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)