TTK
Loading...
Searching...
No Matches
ttkStableManifoldPersistence.cpp
Go to the documentation of this file.
1#include <vtkCellData.h>
2#include <vtkDataArray.h>
3#include <vtkDataSet.h>
4#include <vtkDoubleArray.h>
5#include <vtkGenericCell.h>
6#include <vtkIdTypeArray.h>
7#include <vtkInformation.h>
8#include <vtkIntArray.h>
9#include <vtkNew.h>
10#include <vtkPointData.h>
11#include <vtkPointSet.h>
12#include <vtkPolyData.h>
13#include <vtkSmartPointer.h>
14#include <vtkUnstructuredGrid.h>
15
16#include <ttkMacros.h>
18#include <ttkUtils.h>
19
21
23
24 this->setDebugMsgPrefix("StableManifoldPersistence");
25 this->SetNumberOfInputPorts(3);
26 this->SetNumberOfOutputPorts(1);
27}
28
30 int port, vtkInformation *info) {
31 if(port == 0) {
32 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet");
33 return 1;
34 } else if(port == 1) {
35 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData");
36 return 1;
37 } else if(port == 2) {
38 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkUnstructuredGrid");
39 return 1;
40 }
41 return 0;
42}
43
45 int port, vtkInformation *info) {
46 if(port == 0) {
48 return 1;
49 }
50 return 0;
51}
52
53int ttkStableManifoldPersistence::AttachPersistence(vtkDataSet *output) const {
54
55 ttk::Timer t;
56
57 printMsg("Attaching persistence...", 0, 0, threadNumber_,
59
60 auto ascendingManifoldArray
61 = output->GetPointData()->GetArray(ttk::MorseSmaleAscendingName);
62 auto descendingManifoldArray
63 = output->GetPointData()->GetArray(ttk::MorseSmaleDescendingName);
64
65 auto sourceArray
66 = output->GetCellData()->GetArray(ttk::MorseSmaleSourceIdName);
67 auto destinationArray
68 = output->GetCellData()->GetArray(ttk::MorseSmaleDestinationIdName);
69
70 if((!ascendingManifoldArray) && (!descendingManifoldArray)
71 && (!sourceArray)) {
72 printErr("The input #0 is not a valid stable manifold.");
73 return -3;
74 }
75
76 bool isSegmentation = false;
77
78 if((ascendingManifoldArray) || (descendingManifoldArray))
79 isSegmentation = true;
80
81 vtkSmartPointer<vtkDoubleArray> const persistenceArray
83 persistenceArray->SetName(ttk::PersistenceName);
84
85 vtkSmartPointer<vtkIntArray> const pairTypeArray
87 pairTypeArray->SetName(ttk::PersistencePairTypeName);
88
89 if(!isSegmentation) {
90
91 int const cellNumber = output->GetNumberOfCells();
92
93 persistenceArray->SetNumberOfTuples(cellNumber);
94 pairTypeArray->SetNumberOfTuples(cellNumber);
95
96#ifdef TTK_ENABLE_OPENMP
97#pragma omp parallel for num_threads(threadNumber_)
98#endif
99 for(int i = 0; i < cellNumber; i++) {
100 double cellId = -1;
101 if((destinationArray) && (IsUnstable)) {
102 destinationArray->GetTuple(i, &cellId);
103 } else {
104 sourceArray->GetTuple(i, &cellId);
105 }
106 double const persistence = simplex2persistence_[(int)cellId];
107 double const pairType = simplex2pairType_[(int)cellId];
108 persistenceArray->SetTuple(i, &persistence);
109 pairTypeArray->SetTuple(i, &pairType);
110 }
111
112 output->GetCellData()->AddArray(persistenceArray);
113 output->GetCellData()->AddArray(pairTypeArray);
114 } else {
115
116 if((IsUnstable && descendingManifoldArray == nullptr)
117 || ascendingManifoldArray == nullptr) {
118 this->printErr("Missing array");
119 return -4;
120 }
121
122 int const vertexNumber = output->GetNumberOfPoints();
123
124 persistenceArray->SetNumberOfTuples(vertexNumber);
125 pairTypeArray->SetNumberOfTuples(vertexNumber);
126
127#ifdef TTK_ENABLE_OPENMP
128#pragma omp parallel for num_threads(threadNumber_)
129#endif
130 for(int i = 0; i < vertexNumber; i++) {
131 int cellId = -1;
132 double extremumId = -1;
133 if(IsUnstable) {
134 descendingManifoldArray->GetTuple(i, &extremumId);
135 cellId = min2simplex_[(int)extremumId];
136 } else {
137 ascendingManifoldArray->GetTuple(i, &extremumId);
138 cellId = max2simplex_[(int)extremumId];
139 }
140 double const persistence = simplex2persistence_[cellId];
141 double const pairType = simplex2pairType_[cellId];
142 persistenceArray->SetTuple(i, &persistence);
143 pairTypeArray->SetTuple(i, &pairType);
144 }
145
146 output->GetPointData()->AddArray(persistenceArray);
147 output->GetPointData()->AddArray(pairTypeArray);
148 }
149
150 printMsg("Persistence attached!", 1, t.getElapsedTime(), threadNumber_);
151
152 return 0;
153}
154
155int ttkStableManifoldPersistence::BuildSimplex2PersistenceMap(
156 vtkDataSet *stableManifold,
157 vtkPolyData *criticalPoints,
158 vtkUnstructuredGrid *persistenceDiagram) {
159
160 ttk::Timer t;
161
162 printMsg("Building critical persistence map.", 0, 0, threadNumber_,
164
165 vtkDataArray *criticalPointVertexIdArray
166 = criticalPoints->GetPointData()->GetArray(ttk::VertexScalarFieldName);
167 vtkDataArray *criticalCellIdArray
168 = criticalPoints->GetPointData()->GetArray(ttk::MorseSmaleCellIdName);
169 vtkDataArray *criticalCellDimensionArray
170 = criticalPoints->GetPointData()->GetArray(
172 if((!criticalPointVertexIdArray) || (!criticalCellIdArray)
173 || (!criticalCellDimensionArray)) {
174 printErr("The input #1 is not a valid set of critical points.");
175 return -1;
176 }
177
178 vtkDataArray *vertexIdArray
179 = persistenceDiagram->GetPointData()->GetArray(ttk::VertexScalarFieldName);
180 vtkDataArray *persistenceArray
181 = persistenceDiagram->GetCellData()->GetArray(ttk::PersistenceName);
182 vtkDataArray *persistencePairIdArray
183 = persistenceDiagram->GetCellData()->GetArray(
185 vtkDataArray *persistencePairTypeArray
186 = persistenceDiagram->GetCellData()->GetArray(ttk::PersistencePairTypeName);
187
188 if((!vertexIdArray) || (!persistenceArray) || (!persistencePairIdArray)
189 || (!persistencePairTypeArray)) {
190 printErr("The input #2 is not a valid persistence diagram.");
191 return -2;
192 }
193
194 int const maximumVertexId = vertexIdArray->GetMaxNorm();
195 std::vector<double> vertex2persistence(maximumVertexId + 1, -1);
196 std::vector<int> vertex2pairType(maximumVertexId + 1, -1);
197
198 int const cellNumber = persistenceDiagram->GetNumberOfCells();
199
200 // NOTE: multi-saddle prevent a parallel loop here.
201 for(int i = 0; i < cellNumber; i++) {
202
203 double pairId = -1;
204 persistencePairIdArray->GetTuple(i, &pairId);
205
206 if(pairId != -1) {
207 // not the diagonal
208
209 vtkNew<vtkGenericCell> c;
210 persistenceDiagram->GetCell(i, c);
211 int const pointId0 = c->GetPointId(0);
212 int const pointId1 = c->GetPointId(1);
213
214 double persistence = -1;
215 persistenceArray->GetTuple(i, &persistence);
216
217 double pairType = -1;
218 persistencePairTypeArray->GetTuple(i, &pairType);
219
220 double vertexId0 = -1, vertexId1 = -1;
221 vertexIdArray->GetTuple(pointId0, &vertexId0);
222 vertexIdArray->GetTuple(pointId1, &vertexId1);
223
224 if(vertex2persistence[(int)vertexId0] < persistence) {
225 vertex2persistence[(int)vertexId0] = persistence;
226 vertex2pairType[(int)vertexId0] = pairType;
227 }
228 if(vertex2persistence[(int)vertexId1] < persistence) {
229 vertex2persistence[(int)vertexId1] = persistence;
230 vertex2pairType[(int)vertexId1] = pairType;
231 }
232 }
233 }
234
235 int const maximumSimplexId = criticalCellIdArray->GetMaxNorm();
236 simplex2persistence_.resize(maximumSimplexId + 1, -1);
237 simplex2pairType_.resize(maximumSimplexId + 1, -1);
238
239 int const criticalPointNumber = criticalCellIdArray->GetNumberOfTuples();
240#ifdef TTK_ENABLE_OPENMP
241#pragma omp parallel for num_threads(threadNumber_)
242#endif
243 for(int i = 0; i < criticalPointNumber; i++) {
244 double cellId = -1;
245 criticalCellIdArray->GetTuple(i, &cellId);
246
247 double vertexId = -1;
248 criticalPointVertexIdArray->GetTuple(i, &vertexId);
249
250 simplex2persistence_[(int)cellId] = vertex2persistence[(int)vertexId];
251 simplex2pairType_[(int)cellId] = vertex2pairType[(int)vertexId];
252 }
253
254 // taking care of the maximum to simplex map
255 // get dimensionality from the stable manifold (the following maps are only
256 // useful if the module is called on the segmentation output of the
257 // morse-smale complex; then, we'll get the dimension right).
258 if(stableManifold->GetNumberOfCells()) {
259 int const cellType = stableManifold->GetCellType(0);
260 int dimension = -1;
261 if((cellType == VTK_TETRA) || (cellType == VTK_VOXEL))
262 dimension = 3;
263 else if((cellType == VTK_TRIANGLE) || (cellType == VTK_PIXEL))
264 dimension = 2;
265 else
266 dimension = 1;
267
268 min2simplex_.clear();
269 max2simplex_.clear();
270 for(int i = 0; i < criticalPointNumber; i++) {
271 double cellId = -1;
272 double criticalSimplexDimension = -1;
273 criticalCellDimensionArray->GetTuple(i, &criticalSimplexDimension);
274 criticalCellIdArray->GetTuple(i, &cellId);
275 if(criticalSimplexDimension == 0) {
276 // minimum
277 min2simplex_.push_back(cellId);
278 } else if(criticalSimplexDimension == dimension) {
279 // maximum
280 max2simplex_.push_back(cellId);
281 }
282 }
283 }
284
285 printMsg(
286 "Critical persistence map built!", 1, t.getElapsedTime(), threadNumber_);
287
288 return 0;
289}
290
292 vtkInformation *ttkNotUsed(request),
293 vtkInformationVector **inputVector,
294 vtkInformationVector *outputVector) {
295
296 ttk::Timer t;
297
298 const auto stableManifold = vtkDataSet::GetData(inputVector[0]);
299 const auto criticalPoints = vtkPolyData::GetData(inputVector[1]);
300 const auto persistenceDiagram = vtkUnstructuredGrid::GetData(inputVector[2]);
301
302 int ret = this->BuildSimplex2PersistenceMap(
303 stableManifold, criticalPoints, persistenceDiagram);
304
305 if(ret)
306 return ret;
307
308 auto output = vtkDataSet::GetData(outputVector);
309 output->ShallowCopy(stableManifold);
310
311 ret = this->AttachPersistence(output);
312
313 if(ret)
314 return ret;
315
316 // TODO: make an absolute version
317 // - color all separatrices on the path to the paired critical point
318
319 printMsg("Stable manifold total time", 1, t.getElapsedTime(), threadNumber_);
320
321 return 1;
322}
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition BaseClass.h:47
static vtkInformationIntegerKey * SAME_DATA_TYPE_AS_INPUT_PORT()
TTK VTK-filter for attaching to an input stable manifold (given by the Morse-Smale complex module) it...
int FillOutputPortInformation(int port, vtkInformation *info) override
int FillInputPortInformation(int port, vtkInformation *info) override
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
void setDebugMsgPrefix(const std::string &prefix)
Definition Debug.h:364
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
double getElapsedTime()
Definition Timer.h:15
const char MorseSmaleDestinationIdName[]
Definition DataTypes.h:53
const char PersistenceName[]
Definition DataTypes.h:72
const char MorseSmaleSourceIdName[]
Definition DataTypes.h:52
const char MorseSmaleAscendingName[]
Definition DataTypes.h:62
const char PersistencePairTypeName[]
Definition DataTypes.h:73
const char MorseSmaleCellDimensionName[]
Definition DataTypes.h:48
const char MorseSmaleDescendingName[]
Definition DataTypes.h:63
const char MorseSmaleCellIdName[]
Definition DataTypes.h:49
const char VertexScalarFieldName[]
default name for vertex scalar field
Definition DataTypes.h:35
const char PersistencePairIdentifierName[]
Definition DataTypes.h:71
vtkStandardNewMacro(ttkStableManifoldPersistence)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/|__ _|"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)