TTK
Loading...
Searching...
No Matches
ttkRipsComplex.cpp
Go to the documentation of this file.
1#include <ttkMacros.h>
2#include <ttkRipsComplex.h>
3#include <ttkUtils.h>
4
5#include <vtkAbstractArray.h>
6#include <vtkCellData.h>
7#include <vtkCellType.h>
8#include <vtkDoubleArray.h>
9#include <vtkInformation.h>
10#include <vtkNew.h>
11#include <vtkObjectFactory.h>
12#include <vtkPointData.h>
13#include <vtkTable.h>
14#include <vtkType.h>
15#include <vtkUnstructuredGrid.h>
16
17#include <array>
18#include <regex>
19
21
23 this->SetNumberOfInputPorts(1);
24 this->SetNumberOfOutputPorts(1);
25}
26
27int ttkRipsComplex::FillInputPortInformation(int port, vtkInformation *info) {
28 if(port == 0) {
29 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkTable");
30 return 1;
31 }
32 return 0;
33}
34
35int ttkRipsComplex::FillOutputPortInformation(int port, vtkInformation *info) {
36 if(port == 0) {
37 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkUnstructuredGrid");
38 return 1;
39 }
40 return 0;
41}
42
43int ttkRipsComplex::RequestData(vtkInformation *ttkNotUsed(request),
44 vtkInformationVector **inputVector,
45 vtkInformationVector *outputVector) {
46
47 using ttk::SimplexId;
48 ttk::Timer tm{};
49
50 auto *input = vtkTable::GetData(inputVector[0]);
51 auto *output = vtkUnstructuredGrid::GetData(outputVector);
52
53 if(SelectFieldsWithRegexp) {
54 // select all input columns whose name is matching the regexp
55 ScalarFields.clear();
56 const auto n = input->GetNumberOfColumns();
57 for(int i = 0; i < n; ++i) {
58 const auto &name = input->GetColumnName(i);
59 if(std::regex_match(name, std::regex(RegexpString))) {
60 ScalarFields.emplace_back(name);
61 }
62 }
63 }
64
65 const SimplexId numberOfRows = input->GetNumberOfRows();
66 const SimplexId numberOfColumns = ScalarFields.size();
67
68 if(numberOfRows <= 0 || numberOfColumns <= 0) {
69 this->printErr("Input matrix has invalid dimensions (rows: "
70 + std::to_string(numberOfRows)
71 + ", columns: " + std::to_string(numberOfColumns) + ")");
72 return 0;
73 }
74
75 if(numberOfColumns != numberOfRows) {
76 this->printErr("Input distance matrix is not square (rows: "
77 + std::to_string(numberOfRows)
78 + ", columns: " + std::to_string(numberOfColumns) + ")");
79 return 0;
80 }
81
82 std::array<vtkAbstractArray *, 3> components{
83 input->GetColumnByName(this->XColumn.data()),
84 input->GetColumnByName(this->YColumn.data()),
85 input->GetColumnByName(this->ZColumn.data()),
86 };
87
88 // points from components arrays
89 vtkNew<vtkPoints> points{};
90 const auto nPoints = components[0]->GetNumberOfTuples();
91 points->SetNumberOfPoints(nPoints);
92#ifdef TTK_ENABLE_OPENMP
93#pragma omp parallel for num_threads(this->threadNumber_)
94#endif // TTK_ENABLE_OPENMP
95 for(vtkIdType i = 0; i < nPoints; ++i) {
96 std::array<float, 3> coords{};
97 if(components[0] != nullptr) {
98 coords[0] = components[0]->GetVariantValue(i).ToFloat();
99 }
100 if(components[1] != nullptr && components[1] != components[0]) {
101 coords[1] = components[1]->GetVariantValue(i).ToFloat();
102 }
103 if(components[2] != nullptr && components[2] != components[0]
104 && components[2] != components[1]) {
105 coords[2] = components[2]->GetVariantValue(i).ToFloat();
106 }
107 points->SetPoint(i, coords.data());
108 }
109
110 std::vector<vtkAbstractArray *> arrays{};
111 arrays.reserve(ScalarFields.size());
112 for(const auto &s : ScalarFields) {
113 arrays.push_back(input->GetColumnByName(s.data()));
114 }
115
116 std::vector<std::vector<double>> inputMatrix(numberOfRows);
117#ifdef TTK_ENABLE_OPENMP
118#pragma omp parallel for num_threads(this->threadNumber_)
119#endif // TTK_ENABLE_OPENMP
120 for(SimplexId i = 0; i < numberOfRows; ++i) {
121 for(size_t j = 0; j < arrays.size(); ++j) {
122 inputMatrix[i].emplace_back(arrays[j]->GetVariantValue(i).ToDouble());
123 }
124 }
125
126 std::vector<ttk::SimplexId> vec_connectivity{};
127 std::vector<double> diameters{};
128 // PointData diameter statistics (min, mean, max)
129 vtkNew<vtkDoubleArray> diamMin{}, diamMean{}, diamMax{};
130 diamMin->SetName("MinDiameter");
131 diamMean->SetName("MeanDiameter");
132 diamMax->SetName("MaxDiameter");
133 diamMin->SetNumberOfTuples(numberOfRows);
134 diamMean->SetNumberOfTuples(numberOfRows);
135 diamMax->SetNumberOfTuples(numberOfRows);
136 vtkNew<vtkDoubleArray> gaussianDensity{};
137 gaussianDensity->SetName("GaussianDensity");
138 gaussianDensity->SetNumberOfTuples(numberOfRows);
139
140 const auto ret
141 = this->execute(vec_connectivity, diameters,
142 std::array<double *const, 3>{
143 ttkUtils::GetPointer<double>(diamMin),
144 ttkUtils::GetPointer<double>(diamMean),
145 ttkUtils::GetPointer<double>(diamMax),
146 },
147 inputMatrix, ttkUtils::GetPointer<double>(gaussianDensity));
148
149 if(ret != 0) {
150 return 0;
151 }
152
153 const auto nCells = vec_connectivity.size() / (this->OutputDimension + 1);
154 vtkNew<ttkSimplexIdTypeArray> offsets{}, connectivity{};
155 offsets->SetNumberOfComponents(1);
156 offsets->SetNumberOfTuples(nCells + 1);
157 connectivity->SetNumberOfComponents(1);
158 connectivity->SetNumberOfTuples(vec_connectivity.size());
159
160#ifdef TTK_ENABLE_OPENMP
161#pragma omp parallel for num_threads(this->threadNumber_)
162#endif // TTK_ENABLE_OPENMP
163 for(size_t i = 0; i < nCells + 1; ++i) {
164 offsets->SetTuple1(i, i * (this->OutputDimension + 1));
165 }
166
167#ifdef TTK_ENABLE_OPENMP
168#pragma omp parallel for num_threads(this->threadNumber_)
169#endif // TTK_ENABLE_OPENMP
170 for(size_t i = 0; i < vec_connectivity.size(); ++i) {
171 connectivity->SetTuple1(i, vec_connectivity[i]);
172 }
173
174 // gather arrays to make the UnstructuredGrid
175 vtkNew<vtkCellArray> cells{};
176#ifndef TTK_ENABLE_64BIT_IDS
177 cells->Use32BitStorage();
178#endif // TTK_ENABLE_64BIT_IDS
179 cells->SetData(offsets, connectivity);
180
181 const auto getCellType = [](const SimplexId dim) -> int {
182 if(dim == 3) {
183 return VTK_TETRA;
184 } else if(dim == 2) {
185 return VTK_TRIANGLE;
186 } else if(dim == 1) {
187 return VTK_LINE;
188 }
189 return VTK_VERTEX;
190 };
191
192 output->SetPoints(points);
193 output->SetCells(getCellType(this->OutputDimension), cells);
194
195 // compute cell diameters
196 vtkNew<vtkDoubleArray> cellDiameters{};
197 cellDiameters->SetNumberOfTuples(nCells);
198 cellDiameters->SetName("Diameter");
199
200#ifdef TTK_ENABLE_OPENMP
201#pragma omp parallel for num_threads(this->threadNumber_)
202#endif // TTK_ENABLE_OPENMP
203 for(size_t i = 0; i < nCells; ++i) {
204 cellDiameters->SetTuple1(i, diameters[i]);
205 }
206
207 output->GetPointData()->AddArray(diamMin);
208 output->GetPointData()->AddArray(diamMean);
209 output->GetPointData()->AddArray(diamMax);
210 if(this->ComputeGaussianDensity) {
211 output->GetPointData()->AddArray(gaussianDensity);
212 }
213 output->GetCellData()->AddArray(cellDiameters);
214
215 if(this->KeepAllDataArrays) {
216 auto pd = output->GetPointData();
217 if(pd != nullptr) {
218 for(vtkIdType i = 0; i < input->GetNumberOfColumns(); ++i) {
219 pd->AddArray(input->GetColumn(i));
220 }
221 }
222 }
223
224 this->printMsg("Produced " + std::to_string(nCells) + " cells of dimension "
225 + std::to_string(this->OutputDimension),
226 1.0, tm.getElapsedTime(), this->threadNumber_);
227
228 return 1;
229}
#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::RipsComplex processing package.
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
bool ComputeGaussianDensity
Definition RipsComplex.h:84
int execute(std::vector< SimplexId > &connectivity, std::vector< double > &diameters, std::array< double *const, 3 > diamStats, const std::vector< std::vector< double > > &distanceMatrix, double *const density=nullptr) const
Main entry point.
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
vtkStandardNewMacro(ttkRipsComplex)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)