TTK
Loading...
Searching...
No Matches
ttkRipsPersistenceGenerators.cpp
Go to the documentation of this file.
3
4#include <vtkCellData.h>
5#include <vtkDoubleArray.h>
6#include <vtkInformation.h>
7#include <vtkTable.h>
8
9#include <regex>
10
12
14 = std::unordered_map<ttk::rpd::Edge, double, boost::hash<ttk::rpd::Edge>>;
15static void ParametrizeGenerator(EdgeParametrization &parametrization,
16 const ttk::rpd::Generator1 &generator) {
17
18 const int n = generator.first.size();
19 int id_a = generator.first[0].first;
20 int id_b = generator.first[0].second;
21 parametrization[generator.first[0]] = 0.;
22 for(int i = 1; i < n; ++i) {
23 for(const ttk::rpd::Edge &e : generator.first) {
24 if(e.first == id_b && e.second != id_a) {
25 parametrization[e] = double(i) / n;
26 id_a = id_b;
27 id_b = e.second;
28 break;
29 }
30 if(e.second == id_b && e.first != id_a) {
31 parametrization[e] = double(i) / n;
32 id_a = id_b;
33 id_b = e.first;
34 break;
35 }
36 }
37 }
38}
40void GeneratorsToVTU(vtkUnstructuredGrid *vtu,
41 vtkPoints *inputPoints,
42 const std::vector<ttk::rpd::Generator1> &generators1,
43 bool parametrize) {
44
45 const auto cd = vtu->GetCellData();
46
47 int n_edges = 0;
48 for(auto const &g : generators1)
49 n_edges += g.first.size();
50
51 // cell data arrays
52 vtkNew<vtkIntArray> simplexId{};
53 simplexId->SetName("simplexIdentifier");
54 simplexId->SetNumberOfTuples(n_edges);
55 cd->AddArray(simplexId);
56
57 vtkNew<vtkIntArray> classId{};
58 classId->SetName("ClassIdentifier");
59 classId->SetNumberOfTuples(n_edges);
60 cd->AddArray(classId);
61
62 vtkNew<vtkDoubleArray> classBirth{};
63 classBirth->SetName("ClassBirth");
64 classBirth->SetNumberOfTuples(n_edges);
65 cd->AddArray(classBirth);
66
67 vtkNew<vtkDoubleArray> classDeath{};
68 classDeath->SetName("ClassDeath");
69 classDeath->SetNumberOfTuples(n_edges);
70 cd->AddArray(classDeath);
71
72 vtkNew<vtkDoubleArray> classPersistence{};
73 classPersistence->SetName("ClassPersistence");
74 classPersistence->SetNumberOfTuples(n_edges);
75 cd->AddArray(classPersistence);
76
77 vtkNew<vtkIntArray> classDimension{};
78 classDimension->SetName("ClassDimension");
79 classDimension->SetNumberOfTuples(n_edges);
80 cd->AddArray(classDimension);
81
82 vtkNew<vtkDoubleArray> generatorParametrization{};
83 generatorParametrization->SetName("GeneratorParametrization");
84 generatorParametrization->SetNumberOfTuples(n_edges);
85 cd->AddArray(generatorParametrization);
86
87 // grid
88 vtkNew<vtkIdTypeArray> offsets{}, connectivity{};
89 offsets->SetNumberOfComponents(1);
90 offsets->SetNumberOfTuples(n_edges + 1);
91 connectivity->SetNumberOfComponents(1);
92 connectivity->SetNumberOfTuples(2 * n_edges);
93
94 unsigned i = 0;
95 for(unsigned j = 0; j < generators1.size(); ++j) {
96 const ttk::rpd::Generator1 &g = generators1[j];
97 EdgeParametrization parametrization;
98 if(parametrize)
99 ParametrizeGenerator(parametrization, g);
100 for(auto const &e : g.first) {
101 const unsigned i0 = 2 * i, i1 = 2 * i + 1;
102 simplexId->SetTuple1(i, i);
103 classId->SetTuple1(i, j);
104 classBirth->SetTuple1(i, g.second.first);
105 classDeath->SetTuple1(i, g.second.second);
106 classPersistence->SetTuple1(i, g.second.second - g.second.first);
107 classDimension->SetTuple1(i, 1);
108 if(parametrize)
109 generatorParametrization->SetTuple1(i, parametrization[e]);
110 else
111 generatorParametrization->SetTuple1(i, 0.);
112
113 connectivity->SetTuple1(i0, e.first);
114 connectivity->SetTuple1(i1, e.second);
115 offsets->SetTuple1(i, 2 * i);
116
117 ++i;
118 }
119 }
120 offsets->SetTuple1(n_edges, connectivity->GetNumberOfTuples());
121
122 vtkNew<vtkCellArray> cells{};
123 cells->SetData(offsets, connectivity);
124 vtu->SetPoints(inputPoints);
125 vtu->SetCells(VTK_LINE, cells);
126}
129 this->SetNumberOfInputPorts(2);
130 this->SetNumberOfOutputPorts(2);
131}
134 int port, vtkInformation *info) {
135 if(port == 0) {
136 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTable");
137 return 1;
138 } else if(port == 1) {
139 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPointSet");
140 return 1;
141 }
142 return 0;
143}
146 int port, vtkInformation *info) {
147 if(port == 0 || port == 1) {
148 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
149 return 1;
150 }
151 return 0;
152}
155 vtkInformation *ttkNotUsed(request),
156 vtkInformationVector **inputVector,
157 vtkInformationVector *outputVector) {
158
159 ttk::Timer tm{};
160
161 vtkTable *input = vtkTable::GetData(inputVector[0]);
162 vtkPointSet *pointSet = vtkPointSet::GetData(inputVector[1]);
163 vtkUnstructuredGrid *outputGenerators
164 = vtkUnstructuredGrid::GetData(outputVector, 0);
165 vtkUnstructuredGrid *outputPersistenceDiagram
166 = vtkUnstructuredGrid::GetData(outputVector, 1);
167
168 if(!input || !pointSet)
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 } else if(input->GetNumberOfRows() != pointSet->GetNumberOfPoints()) {
189 this->printErr("Input and 3D representation have different");
190 this->printErr("numbers of points: resp. "
191 + std::to_string(input->GetNumberOfRows()) + " and "
192 + std::to_string(pointSet->GetNumberOfPoints()));
193 return 0;
194 }
195
196 std::vector<vtkAbstractArray *> arrays;
197 arrays.reserve(ScalarFields.size());
198 for(const auto &s : ScalarFields)
199 arrays.push_back(input->GetColumnByName(s.data()));
200
201 std::vector<std::vector<double>> points;
202
204 const int numberOfPoints = input->GetNumberOfRows();
205 const int dimension = ScalarFields.size();
206 points.resize(numberOfPoints);
207 for(int i = 0; i < numberOfPoints; ++i) {
208 for(int j = 0; j < dimension; ++j)
209 points[i].push_back(arrays[j]->GetVariantValue(i).ToDouble());
210 }
211 this->printMsg(
212 "Computing Rips pers. generators", 0.0, tm.getElapsedTime(), 1);
213 this->printMsg("#dimensions: " + std::to_string(dimension)
214 + ", #points: " + std::to_string(numberOfPoints),
215 0.0, tm.getElapsedTime(), 1);
216 }
217
218 else {
219 const unsigned n = input->GetNumberOfRows();
220 if(n != ScalarFields.size()) {
221 this->printErr("Input distance matrix is not squared.");
222 this->printErr("(rows: " + std::to_string(input->GetNumberOfRows())
223 + ", columns: " + std::to_string(ScalarFields.size())
224 + ")");
225 return 0;
226 }
227
228 points = {std::vector<double>(n * (n - 1) / 2)};
229 for(unsigned i = 1; i < n; ++i) {
230 for(unsigned j = 0; j < i; ++j)
231 points[0][i * (i - 1) / 2 + j]
232 = arrays[j]->GetVariantValue(i).ToDouble();
233 }
234 this->printMsg(
235 "Computing Rips pers. generators", 0.0, tm.getElapsedTime(), 1);
236 this->printMsg(
237 "(" + std::to_string(n) + "x" + std::to_string(n) + " distance matrix)",
238 0.0, tm.getElapsedTime(), 1);
239 }
240
241 std::vector<ttk::rpd::Diagram> diagram(0);
242 std::vector<ttk::rpd::Generator1> generators(0);
243 this->execute(points, diagram, generators);
244
246 outputGenerators, pointSet->GetPoints(), generators, !OutputCascade);
247 DiagramToVTU(outputPersistenceDiagram, diagram, SimplexMaximumDiameter);
248
249 this->printMsg("Complete", 1.0, tm.getElapsedTime(), 1);
250
251 // shallow copy input Field Data
252 outputPersistenceDiagram->GetFieldData()->ShallowCopy(input->GetFieldData());
253
254 // return success
255 return 1;
256}
#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::RipsPersistenceGenerators module.
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
int FillOutputPortInformation(int port, vtkInformation *info) override
int FillInputPortInformation(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
void execute(const std::vector< std::vector< double > > &points, rpd::MultidimensionalDiagram &diagrams, std::vector< rpd::Generator1 > &generators) const
std::pair< id_t, id_t > Edge
std::pair< std::vector< Edge >, std::pair< value_t, value_t > > Generator1
int DiagramToVTU(vtkUnstructuredGrid *vtu, const ttk::DiagramType &diagram, vtkDataArray *const inputScalars, const ttk::Debug &dbg, const int dim, const bool embedInDomain)
Converts a Persistence Diagram in the ttk::DiagramType format to the VTK Unstructured Grid format (as...
std::unordered_map< ttk::rpd::Edge, double, boost::hash< ttk::rpd::Edge > > EdgeParametrization
vtkStandardNewMacro(ttkRipsPersistenceGenerators)
void GeneratorsToVTU(vtkUnstructuredGrid *vtu, vtkPoints *inputPoints, const std::vector< ttk::rpd::Generator1 > &generators1, bool parametrize)
Converts a vector of 1-dimensional persistent generators in the ttk::rpd::Generator format to the VTK...
TTKRIPSPERSISTENCEGENERATORS_EXPORT void GeneratorsToVTU(vtkUnstructuredGrid *vtu, vtkPoints *inputPoints, const std::vector< ttk::rpd::Generator1 > &generators1, bool parametrize=true)
Converts a vector of 1-dimensional persistent generators in the ttk::rpd::Generator format to the VTK...
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)