TTK
Loading...
Searching...
No Matches
ttkSeparatrixStability.cpp
Go to the documentation of this file.
2
3#include <vtkCellData.h>
4#include <vtkDataArray.h>
5#include <vtkDataSet.h>
6#include <vtkDoubleArray.h>
7#include <vtkFloatArray.h>
8#include <vtkInformation.h>
9#include <vtkInformationVector.h>
10#include <vtkObjectFactory.h>
11#include <vtkPointData.h>
12#include <vtkPolyData.h>
13#include <vtkSignedCharArray.h>
14#include <vtkSmartPointer.h>
15
16#include <ttkMacros.h>
17#include <ttkUtils.h>
18
19#include <Timer.h>
20#include <iomanip>
21#include <string>
22
24
26 this->SetNumberOfInputPorts(1);
27 this->SetNumberOfOutputPorts(1);
28}
29
31 vtkInformation *info) {
32 if(port == 0) {
33 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkMultiBlockDataSet");
34 return 1;
35 }
36 return 0;
37}
38
40 vtkInformation *info) {
41 if(port == 0) {
42 info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkMultiBlockDataSet");
43 return 1;
44 }
45 return 0;
46}
47
49 const int &globalId, std::vector<int> &localToGlobal, int &localId) {
50
51 for(unsigned int i = 0; i < localToGlobal.size(); i++) {
52 if(localToGlobal[i] == globalId) {
53 localId = i;
54 return true;
55 }
56 }
57 if(localId == -1) {
58 localId = localToGlobal.size();
59 localToGlobal.push_back(globalId);
60 }
61 return false;
62}
63
65 const int &sourceLocalId,
66 const int &destinationLocalId,
67 const int &separatrixLocalId,
68 GraphMatrixFull &adjacencyMatrix) {
69 int n_row = adjacencyMatrix.size();
70 int n_col = n_row == 0 ? 0 : adjacencyMatrix[0].size();
71 if(sourceLocalId < n_row) {
72 if(destinationLocalId < n_col) {
73 adjacencyMatrix[sourceLocalId][destinationLocalId] = separatrixLocalId;
74 } else {
75 for(int i = 0; i < n_row; i++) {
76 adjacencyMatrix[i].push_back(-1);
77 }
78 adjacencyMatrix[sourceLocalId][destinationLocalId] = separatrixLocalId;
79 }
80 } else {
81 if(destinationLocalId < n_col) {
82 std::vector<int> newRow(n_col, -1);
83 adjacencyMatrix.push_back(newRow);
84 adjacencyMatrix[sourceLocalId][destinationLocalId] = separatrixLocalId;
85 } else {
86 for(int i = 0; i < n_row; i++) {
87 adjacencyMatrix[i].push_back(-1);
88 }
89 std::vector<int> newRow(n_col + 1, -1);
90 adjacencyMatrix.push_back(newRow);
91 adjacencyMatrix[sourceLocalId][destinationLocalId] = separatrixLocalId;
92 }
93 }
94}
95
97 const int &cellId_2,
98 const int &sourceGlobalId,
99 const int &destinationGlobalId,
100 vtkDataSet *block,
101 vtkIdType &sourcePointId,
102 vtkIdType &destinationPointId) {
103
104 vtkIdList *pointIds = block->GetCell(cellId_1)->GetPointIds();
105 int id_0 = pointIds->GetId(0);
106 int id_1 = pointIds->GetId(1);
107 pointIds = block->GetCell(cellId_2)->GetPointIds();
108 int id_2 = pointIds->GetId(0);
109 int id_3 = pointIds->GetId(1);
110 ttkSimplexIdTypeArray *cellId = ttkSimplexIdTypeArray::SafeDownCast(
111 block->GetPointData()->GetArray(ttk::MorseSmaleCellIdName));
112
113 if((int)cellId->GetValue(id_0) == sourceGlobalId)
114 sourcePointId = id_0;
115 else if((int)cellId->GetValue(id_1) == sourceGlobalId)
116 sourcePointId = id_1;
117 else if((int)cellId->GetValue(id_2) == sourceGlobalId)
118 sourcePointId = id_2;
119 else if((int)cellId->GetValue(id_3) == sourceGlobalId)
120 sourcePointId = id_3;
121
122 if((int)cellId->GetValue(id_0) == destinationGlobalId)
123 destinationPointId = id_0;
124 else if((int)cellId->GetValue(id_1) == destinationGlobalId)
125 destinationPointId = id_1;
126 else if((int)cellId->GetValue(id_2) == destinationGlobalId)
127 destinationPointId = id_2;
128 else if((int)cellId->GetValue(id_3) == destinationGlobalId)
129 destinationPointId = id_3;
130}
131
133 vtkPoints *points,
134 const int &index,
135 const double &scalar,
136 std::vector<std::array<double, 3>> &coords,
137 std::vector<double> &scalars) {
138 std::array<double, 3> newCoords;
139 points->GetPoint(index, newCoords.data());
140 coords.push_back(newCoords);
141 scalars.push_back(scalar);
142}
143
145 vtkDataSet *block,
146 std::vector<int> &localToGlobal,
147 GraphMatrixFull &adjacencyMatrixFull,
148 std::vector<std::array<double, 3>> &coordsSource,
149 std::vector<std::array<double, 3>> &coordsDestination,
150 std::vector<double> &scalarsSource,
151 std::vector<double> &scalarsDestination,
152 int &n_separatrices,
153 std::vector<int> &globalSourcePointId,
154 std::vector<int> &globalDestinationPointId) {
155
156 vtkPoints *points = block->GetPoints();
157
158 vtkCellData *cellData = block->GetCellData();
159 vtkSignedCharArray *separatrixTypes = vtkSignedCharArray::SafeDownCast(
160 cellData->GetArray(ttk::MorseSmaleSeparatrixTypeName));
161 ttkSimplexIdTypeArray *separatrixIds = ttkSimplexIdTypeArray::SafeDownCast(
162 cellData->GetArray(ttk::MorseSmaleSeparatrixIdName));
163 ttkSimplexIdTypeArray *sourceIds = ttkSimplexIdTypeArray::SafeDownCast(
164 cellData->GetArray(ttk::MorseSmaleSourceIdName));
165 ttkSimplexIdTypeArray *destinationIds = ttkSimplexIdTypeArray::SafeDownCast(
166 cellData->GetArray(ttk::MorseSmaleDestinationIdName));
167 vtkDoubleArray *separatrixSourceScalars;
168 vtkDoubleArray *separatrixDestinationScalars;
169 if(*(separatrixTypes->GetTuple(0)) == 0) {
170 separatrixDestinationScalars = vtkDoubleArray::SafeDownCast(
171 cellData->GetArray(ttk::MorseSmaleSeparatrixMinimumName));
172 separatrixSourceScalars = vtkDoubleArray::SafeDownCast(
173 cellData->GetArray(ttk::MorseSmaleSeparatrixMaximumName));
174 } else {
175 separatrixDestinationScalars = vtkDoubleArray::SafeDownCast(
176 cellData->GetArray(ttk::MorseSmaleSeparatrixMaximumName));
177 separatrixSourceScalars = vtkDoubleArray::SafeDownCast(
178 cellData->GetArray(ttk::MorseSmaleSeparatrixMinimumName));
179 }
180
181 int n_cells = block->GetNumberOfCells();
182
183 std::vector<int> sourceLocalToGlobal;
184 std::vector<int> destinationLocalToGlobal;
185
186 int cellId_1 = 0;
187 int separatrixLocalId = -1;
188
189 while(cellId_1 < n_cells) {
190 int separatrixId = separatrixIds->GetValue(cellId_1);
191 int cellId_2 = cellId_1 + 1;
192 int nextSeparatrixId = separatrixIds->GetValue(cellId_2);
193 while(nextSeparatrixId == separatrixId && cellId_2 < n_cells) {
194 nextSeparatrixId = separatrixIds->GetValue(++cellId_2);
195 }
196 cellId_2--;
197 separatrixLocalId++;
198 int sourceGlobalId = sourceIds->GetValue(cellId_1);
199 int destinationGlobalId = destinationIds->GetValue(cellId_2);
200 int destinationLocalId = -1;
201 int sourceLocalId = -1;
202 vtkIdType sourcePointId;
203 vtkIdType destinationPointId;
204
205 computePointIds(cellId_1, cellId_2, sourceGlobalId, destinationGlobalId,
206 block, sourcePointId, destinationPointId);
207
208 bool foundSource = updateVisitedVertices(
209 sourceGlobalId, sourceLocalToGlobal, sourceLocalId);
210 bool foundDestination = updateVisitedVertices(
211 destinationGlobalId, destinationLocalToGlobal, destinationLocalId);
212 if(!foundDestination) {
213 double destinationScalar
214 = *(separatrixDestinationScalars->GetTuple(cellId_1));
215 appendPoint(points, destinationPointId, destinationScalar,
216 coordsDestination, scalarsDestination);
217 globalDestinationPointId.push_back(destinationPointId);
218 }
219 if(!foundSource && !MergeEdgesOnSaddles) {
220 double sourceScalar = *(separatrixSourceScalars->GetTuple(cellId_1));
222 points, sourcePointId, sourceScalar, coordsSource, scalarsSource);
223 globalSourcePointId.push_back(sourcePointId);
224 }
225 updateAdjacencyMatrix(sourceLocalId, destinationLocalId, separatrixLocalId,
226 adjacencyMatrixFull);
227 cellId_1 = cellId_2 + 1;
228 }
229
230 n_separatrices = separatrixLocalId + 1;
231 localToGlobal = std::move(destinationLocalToGlobal);
232
233 return 1;
234}
235
237 vtkMultiBlockDataSet *&multiBlock1_Separatrices,
238 vtkMultiBlockDataSet *&output1_Separatrices) {
239
240 int status;
241 int n_blocks = multiBlock1_Separatrices->GetNumberOfBlocks();
242 std::vector<std::vector<int>> LocalToGlobal(n_blocks);
243 std::vector<GraphMatrixFull> adjacencyMatricesFull(n_blocks);
244 std::vector<std::vector<std::array<double, 3>>> coordsDestination(n_blocks);
245 std::vector<std::vector<std::array<double, 3>>> coordsSource(n_blocks);
246 std::vector<std::vector<double>> scalarsDestination(n_blocks);
247 std::vector<std::vector<double>> scalarsSource(n_blocks);
248 std::vector<int> separatrixCountForEachBlock(n_blocks);
249 std::vector<std::vector<int>> edgeOccurrenceForEachBlock(n_blocks);
250 std::vector<std::vector<bool>> isomorphismsForEachBlock(n_blocks);
251 std::vector<std::vector<std::vector<int>>> matchingArrayForEachBlockSource(
252 n_blocks);
253 std::vector<std::vector<std::vector<int>>>
254 matchingArrayForEachBlockDestination(n_blocks);
255 std::vector<std::vector<std::vector<int>>>
256 matchingArraySeparatrixForEachBlock(n_blocks);
257 std::vector<std::vector<int>> globalSourcePointIdForEachBlock(n_blocks);
258 std::vector<std::vector<int>> globalDestinationPointIdForEachBlock(n_blocks);
259
260#ifdef TTK_ENABLE_OPENMP
261#pragma omp parallel for num_threads(threadNumber_)
262#endif // TTK_ENABLE_OPENMP
263 for(int i = 0; i < n_blocks; i++) {
264 vtkDataSet *block
265 = vtkDataSet::SafeDownCast(multiBlock1_Separatrices->GetBlock(i));
266
268 block, LocalToGlobal[i], adjacencyMatricesFull[i], coordsSource[i],
269 coordsDestination[i], scalarsSource[i], scalarsDestination[i],
270 separatrixCountForEachBlock[i], globalSourcePointIdForEachBlock[i],
271 globalDestinationPointIdForEachBlock[i]);
272 }
273
274 this->setEpsilon(CostDeathBirth);
275 this->setWeights(PX, PY, PZ, PF);
276
277 for(int i = 0; i < n_blocks; i++) {
278 std::string destinationSizeString
279 = std::to_string(globalDestinationPointIdForEachBlock[i].size());
280 std::string sourceSizeString
281 = std::to_string(globalSourcePointIdForEachBlock[i].size());
282 std::string blockIdString = std::to_string(i);
283
284 std::string msg1 = "Number of critical points (min-max) for block ";
285 msg1 += blockIdString;
286 msg1 += " : ";
287 msg1 += destinationSizeString;
288 this->printMsg(msg1);
289
290 if(!MergeEdgesOnSaddles) {
291 std::string msg2 = "Number of critical points (1sad-2sad) for block ";
292 msg2 += blockIdString;
293 msg2 += " : ";
294 msg2 += sourceSizeString;
295 this->printMsg(msg2);
296 }
297 }
298
299 status = this->buildOccurrenceArrays(
300 adjacencyMatricesFull, separatrixCountForEachBlock, coordsSource,
301 coordsDestination, scalarsSource, scalarsDestination, MergeEdgesOnSaddles,
302 edgeOccurrenceForEachBlock, isomorphismsForEachBlock,
303 matchingArrayForEachBlockSource, matchingArrayForEachBlockDestination,
304 matchingArraySeparatrixForEachBlock);
305
306 if(status == 0)
307 return status;
308
309 std::vector<int> classId(n_blocks, -1);
310 int idCount = 0;
311
312 for(int i = 0; i < n_blocks; i++) {
313 if(classId[i] != -1)
314 continue;
315 classId[i] = idCount;
316 for(int j = 0; j < n_blocks; j++) {
317 if(isomorphismsForEachBlock[i][j]) {
318 classId[j] = idCount;
319 }
320 }
321 idCount++;
322 }
323
324 for(int i = 0; i < n_blocks; i++) {
325 for(int j = 0; j < n_blocks; j++) {
326 assert(globalDestinationPointIdForEachBlock[i].size()
327 == matchingArrayForEachBlockDestination[j][i].size());
328 assert(globalSourcePointIdForEachBlock[i].size()
329 == matchingArrayForEachBlockSource[j][i].size());
330 }
331 }
332
333#ifdef TTK_ENABLE_OPENMP
334#pragma omp parallel for num_threads(threadNumber_)
335#endif // TTK_ENABLE_OPENMP
336 for(int i = 0; i < n_blocks; i++) {
337
338 vtkDataSet *block
339 = vtkDataSet::SafeDownCast(output1_Separatrices->GetBlock(i));
340 int cellNumber = block->GetNumberOfCells();
341 ttkSimplexIdTypeArray *separatrixIds = ttkSimplexIdTypeArray::SafeDownCast(
342 block->GetCellData()->GetArray(ttk::MorseSmaleSeparatrixIdName));
343
344 vtkNew<vtkFloatArray> occurrenceCount;
345 occurrenceCount->SetNumberOfComponents(1);
346 occurrenceCount->SetName(ttk::SeparatrixStabilityOccurrenceCount);
347
348 vtkNew<vtkIntArray> isomorphismClassId;
349 isomorphismClassId->SetNumberOfComponents(1);
350 isomorphismClassId->SetName(ttk::SeparatrixStabilityIsomorphismClassId);
351
352 vtkIdType currentCellId = 0;
353 int currentSeparatrixId = separatrixIds->GetValue(currentCellId);
354 int separatrixCount = 0;
355 float newValue
356 = (float)edgeOccurrenceForEachBlock[i][separatrixCount] / n_blocks;
357
358 occurrenceCount->InsertNextValue(newValue);
359
360 for(int j = 1; j < cellNumber; j++) {
361 if(separatrixIds->GetValue(j) != currentSeparatrixId) {
362 currentSeparatrixId = separatrixIds->GetValue(j);
363 separatrixCount++;
364 newValue
365 = (float)edgeOccurrenceForEachBlock[i][separatrixCount] / n_blocks;
366 }
367 occurrenceCount->InsertNextValue(newValue);
368 }
369
370 block->GetCellData()->AddArray(occurrenceCount);
371
372 isomorphismClassId->InsertNextValue(classId[i]);
373
374 block->GetFieldData()->AddArray(isomorphismClassId);
375
376 for(int j = 0; j < n_blocks; j++) {
377
378 vtkNew<vtkIntArray> matchingIdForSeparatrix_j;
379 matchingIdForSeparatrix_j->SetNumberOfComponents(1);
380 std::string tmp_string_1
382 + std::to_string(j);
383
384 const char *indexedArrayNameSeparatrix = tmp_string_1.c_str();
385 matchingIdForSeparatrix_j->SetName(indexedArrayNameSeparatrix);
386
387 int currentSeparatrixIdBis = separatrixIds->GetValue(0);
388 int separatrixCountBis = 0;
389 int newId = matchingArraySeparatrixForEachBlock[j][i][separatrixCountBis];
390 matchingIdForSeparatrix_j->InsertNextValue(newId);
391
392 for(int k = 1; k < cellNumber; k++) {
393 if(separatrixIds->GetValue(k) != currentSeparatrixIdBis) {
394 currentSeparatrixIdBis = separatrixIds->GetValue(k);
395 separatrixCountBis++;
396 newId = matchingArraySeparatrixForEachBlock[j][i][separatrixCountBis];
397 }
398 matchingIdForSeparatrix_j->InsertNextValue(newId);
399 }
400 block->GetCellData()->AddArray(matchingIdForSeparatrix_j);
401
402 vtkNew<vtkIntArray> matchingIdForCriticalPoints_j;
403 matchingIdForCriticalPoints_j->SetNumberOfComponents(1);
404 std::string tmp_string_2
406 + std::to_string(j);
407
408 const char *indexedArrayNameMatchingsId = tmp_string_2.c_str();
409 matchingIdForCriticalPoints_j->SetName(indexedArrayNameMatchingsId);
410 vtkPoints *points = block->GetPoints();
411
412 for(int k = 0; k < points->GetNumberOfPoints(); k++) {
413 matchingIdForCriticalPoints_j->InsertNextValue(-2);
414 }
415
416 for(unsigned int k = 0;
417 k < globalDestinationPointIdForEachBlock[i].size(); k++) {
418 int globalPointIdThisBlock = globalDestinationPointIdForEachBlock[i][k];
419 int matchingIdOtherBlock
420 = matchingArrayForEachBlockDestination[j][i][k];
421 matchingIdForCriticalPoints_j->SetValue(
422 globalPointIdThisBlock, matchingIdOtherBlock);
423 }
424 if(!MergeEdgesOnSaddles) {
425 for(unsigned int k = 0; k < globalSourcePointIdForEachBlock[i].size();
426 k++) {
427 int globalPointIdThisBlock = globalSourcePointIdForEachBlock[i][k];
428 int matchingIdOtherBlock = matchingArrayForEachBlockSource[j][i][k];
429 matchingIdForCriticalPoints_j->SetValue(
430 globalPointIdThisBlock, matchingIdOtherBlock);
431 }
432 }
433 block->GetPointData()->AddArray(matchingIdForCriticalPoints_j);
434 }
435 }
436 return status;
437}
438
440 vtkInformationVector **inputVector,
441 vtkInformationVector *outputVector) {
442 ttk::Timer t;
443 vtkMultiBlockDataSet *input1_Separatrices
444 = vtkMultiBlockDataSet::GetData(inputVector[0]);
445
446 if(input1_Separatrices == nullptr) {
447 this->printErr("No edges to perform calculation.");
448 return -1;
449 }
450
451 int status = 0;
452 vtkMultiBlockDataSet *output1_Separatrices
453 = vtkMultiBlockDataSet::GetData(outputVector, 0);
454 output1_Separatrices->ShallowCopy(input1_Separatrices);
455
456 if(input1_Separatrices->GetNumberOfBlocks() < 2) {
457 this->printErr(
458 "At least two datasets are required to perform calculations.");
459 return -1;
460 }
461
462 status = this->execute(input1_Separatrices, output1_Separatrices);
463
464 this->printMsg("Occurrence arrays calculated for "
465 + std::to_string(input1_Separatrices->GetNumberOfBlocks())
466 + " blocks",
467 1.0, t.getElapsedTime(), this->threadNumber_);
468
469 if(status != 1)
470 return 0;
471
472 return 1;
473}
#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::SeparatrixStability module.
int FillOutputPortInformation(int port, vtkInformation *info) override
int prepareData(vtkDataSet *block, std::vector< int > &localToGlobal, GraphMatrixFull &adjacencyMatrixFull, std::vector< std::array< double, 3 > > &coordsSource, std::vector< std::array< double, 3 > > &coordsDestination, std::vector< double > &scalarsSource, std::vector< double > &scalarsDestinatoin, int &n_separatrices, std::vector< int > &globalSourcePointId, std::vector< int > &globalDestinationPointId)
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
void computePointIds(const int &cellId_1, const int &cellId_2, const int &sourceGlobalId, const int &destinationGlobalId, vtkDataSet *block, vtkIdType &srcPointId, vtkIdType &destPointId)
void appendPoint(vtkPoints *points, const int &index, const double &scalar, std::vector< std::array< double, 3 > > &coords, std::vector< double > &scalars)
int execute(vtkMultiBlockDataSet *&multiBlock1_Separatrices, vtkMultiBlockDataSet *&output1_Separatrices)
int FillInputPortInformation(int port, vtkInformation *info) override
void updateAdjacencyMatrix(const int &sourceLocalId, const int &destinationLocalId, const int &separatrixLocalId, GraphMatrixFull &adjacencyMatrix)
bool updateVisitedVertices(const int &globalId, std::vector< int > &localToGlobal, int &localId)
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition Debug.h:149
void setWeights(const double &px, const double &py, const double &pz, const double &pf)
int buildOccurrenceArrays(const std::vector< GraphMatrixFull > &adjacencyMatrices, const std::vector< int > &separatrixCountForEachBlock, const std::vector< std::vector< std::array< double, 3 > > > &coordsSource, const std::vector< std::vector< std::array< double, 3 > > > &coordsDestination, const std::vector< std::vector< double > > &scalarsSource, const std::vector< std::vector< double > > &scalarsDestination, const bool &mergeEdgesOnSaddles, std::vector< std::vector< int > > &edgesOccurrencesForEachBlock, std::vector< std::vector< bool > > &isomorphismForEachBlock, std::vector< std::vector< std::vector< int > > > &matchingArrayForEachBlockSource, std::vector< std::vector< std::vector< int > > > &matchingArrayForEachBlockDestination, std::vector< std::vector< std::vector< int > > > &matchingArraySeparatrixForEachBlock)
std::vector< std::vector< int > > GraphMatrixFull
double getElapsedTime()
Definition Timer.h:15
const char MorseSmaleDestinationIdName[]
Definition DataTypes.h:53
const char SeparatrixStabilityMatchingIdName[]
Definition DataTypes.h:70
const char MorseSmaleSeparatrixMaximumName[]
Definition DataTypes.h:56
const char MorseSmaleSourceIdName[]
Definition DataTypes.h:52
const char SeparatrixStabilityIsomorphismClassId[]
Definition DataTypes.h:69
const char SeparatrixStabilityOccurrenceCount[]
Definition DataTypes.h:68
const char MorseSmaleCellIdName[]
Definition DataTypes.h:49
const char SeparatrixStabilityMatchingIdSeparatrixName[]
Definition DataTypes.h:72
const char MorseSmaleSeparatrixTypeName[]
Definition DataTypes.h:55
const char MorseSmaleSeparatrixMinimumName[]
Definition DataTypes.h:57
const char MorseSmaleSeparatrixIdName[]
Definition DataTypes.h:54
vtkIntArray ttkSimplexIdTypeArray
Definition ttkMacros.h:11
vtkStandardNewMacro(ttkSeparatrixStability)
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)