TTK
Loading...
Searching...
No Matches
ttkAlgorithm.cpp
Go to the documentation of this file.
1#include <ttkAlgorithm.h>
2#include <ttkMacros.h>
3#include <ttkUtils.h>
4
6#include <Triangulation.h>
8
9#include <vtkCellTypes.h>
10#include <vtkCommand.h>
11#include <vtkDataSet.h>
12
13#ifdef TTK_ENABLE_MPI
14#include <Identifiers.h>
15#include <vtkCellData.h>
16#include <vtkGhostCellsGenerator.h>
17#endif // TTK_ENABLE_MPI
18
19#include <vtkImageData.h>
20#include <vtkInformation.h>
21#include <vtkInformationIntegerKey.h>
22#include <vtkInformationVector.h>
23#include <vtkMultiBlockDataSet.h>
24#include <vtkPointData.h>
25#include <vtkPolyData.h>
26#include <vtkTable.h>
27#include <vtkUnstructuredGrid.h>
28
29#include <vtkCompositeDataPipeline.h>
30
31// Pass input type information key
32#include <vtkInformationKey.h>
33vtkInformationKeyMacro(ttkAlgorithm, SAME_DATA_TYPE_AS_INPUT_PORT, Integer);
34
35// Constructor / Destructor
39
41
42 this->printMsg("Requesting triangulation for '"
43 + std::string(dataSet->GetClassName()) + "'",
45#ifdef TTK_ENABLE_MPI
46 if(ttk::hasInitializedMPI()) {
47 if(!hasMPISupport_) {
49 "MPI is not supported for this filter, the results will be incorrect");
50 }
52 }
53#endif // TTK_ENABLE_MPI
54
56 this->debugLevel_, this->CompactTriangulationCacheSize, dataSet);
57
58#ifdef TTK_ENABLE_MPI
59 if(ttk::hasInitializedMPI()) {
60 std::vector<int> tmp{};
61 this->MPIPipelinePreconditioning(dataSet, tmp, triangulation);
62 this->MPITriangulationPreconditioning(triangulation, dataSet);
63 }
64#endif // TTK_ENABLE_MPI
65
66 if(triangulation)
67 return triangulation;
68
69 this->printErr("Unable to retrieve/initialize triangulation for '"
70 + std::string(dataSet->GetClassName()) + "'");
71
72 return nullptr;
73}
74
75vtkDataArray *ttkAlgorithm::GetOptionalArray(const bool &enforceArrayIndex,
76 const int &arrayIndex,
77 const std::string &arrayName,
78 vtkDataSet *const inputData,
79 const int &inputPort) {
80
81 vtkDataArray *optionalArray = nullptr;
82
83 if(enforceArrayIndex)
84 optionalArray = this->GetInputArrayToProcess(arrayIndex, inputData);
85
86 if(!optionalArray) {
87 this->SetInputArrayToProcess(arrayIndex, inputPort, 0, 0, arrayName.data());
88 optionalArray = this->GetInputArrayToProcess(arrayIndex, inputData);
89 }
90 return optionalArray;
91}
92
93std::string ttkAlgorithm::GetOrderArrayName(vtkDataArray *const array) {
94 return std::string(array->GetName()) + "_Order";
95}
96
97vtkDataArray *ttkAlgorithm::GetOrderArray(vtkDataSet *const inputData,
98 const int scalarArrayIdx,
99 const int orderArrayIdx,
100 const bool enforceOrderArrayIdx) {
101
102 auto isValidOrderArray = [](vtkDataArray *const array) {
103 if(!array)
104 return -4;
105
106 if(array->GetNumberOfComponents() != 1)
107 return -3;
108
110 if(array->GetDataType() != temp->GetDataType())
111 return -2;
112
113 const std::string name(array->GetName());
114 if(name.size() < 6 || (name.rfind("_Order") != (name.size() - 6)))
115 return -1;
116
117 return 1;
118 };
119
120 if(enforceOrderArrayIdx) {
121 auto orderArray = this->GetInputArrayToProcess(orderArrayIdx, inputData);
122 switch(isValidOrderArray(orderArray)) {
123 case -4: {
124 this->printErr("Unable to retrieve enforced order array at idx "
125 + std::to_string(orderArrayIdx) + ".");
126 return nullptr;
127 }
128 case -3: {
129 this->printErr("Retrieved enforced order array `"
130 + std::string(orderArray->GetName())
131 + "` has more than one component.");
132 return nullptr;
133 }
134 case -2: {
135 this->printErr("Enforced order array `"
136 + std::string(orderArray->GetName())
137 + "` is of incorrect type.");
139 this->printErr(" -> use `ttkArrayEditor` to convert data type to `"
140 + std::string(temp->GetDataTypeAsString()) + "`.");
141 return nullptr;
142 }
143 default: {
144 this->printMsg("Retrieved enforced order array `"
145 + std::string(orderArray->GetName()) + "`.",
147 return orderArray;
148 }
149 }
150 }
151
152 auto scalarArray = this->GetInputArrayToProcess(scalarArrayIdx, inputData);
153 if(!scalarArray) {
154 this->printErr("Unable to retrieve input scalar array for idx "
155 + std::to_string(scalarArrayIdx) + ".");
156 return nullptr;
157 } else if(isValidOrderArray(scalarArray) == 1) {
158 this->printMsg("Retrieved scalar array `"
159 + std::string(scalarArray->GetName())
160 + "` is already an order array.",
162 return scalarArray;
163 }
164
165 auto orderArray = inputData
166 ->GetAttributesAsFieldData(this->GetInputArrayAssociation(
167 scalarArrayIdx, inputData))
168 ->GetArray(this->GetOrderArrayName(scalarArray).data());
169
170 switch(isValidOrderArray(orderArray)) {
171 case -4: {
172 ttk::Timer timer;
173 this->printWrn("No pre-existing order for array:");
174 this->printWrn(" `" + std::string(scalarArray->GetName()) + "`.");
175
176 this->printMsg("Initializing order array.", 0, 0, this->threadNumber_,
178
179 auto nVertices = scalarArray->GetNumberOfTuples();
180 auto newOrderArray = vtkSmartPointer<ttkSimplexIdTypeArray>::New();
181 newOrderArray->SetName(this->GetOrderArrayName(scalarArray).data());
182 newOrderArray->SetNumberOfComponents(1);
183 newOrderArray->SetNumberOfTuples(nVertices);
184 std::vector<int> neighbors;
185#ifdef TTK_ENABLE_MPI
186 if(ttk::hasInitializedMPI()) {
187 this->MPIGhostPipelinePreconditioning(inputData);
188 this->MPIPipelinePreconditioning(inputData, neighbors, nullptr);
189 }
190#endif
191 switch(scalarArray->GetDataType()) {
192 vtkTemplateMacro(ttk::preconditionOrderArray(
193 nVertices,
194 static_cast<VTK_TT *>(ttkUtils::GetVoidPointer(scalarArray)),
195 static_cast<ttk::SimplexId *>(
196 ttkUtils::GetVoidPointer(newOrderArray)),
197 this->threadNumber_));
198 }
199
200 // append order array temporarily to input
201 inputData
202 ->GetAttributesAsFieldData(
203 this->GetInputArrayAssociation(scalarArrayIdx, inputData))
204 ->AddArray(newOrderArray);
205 this->printMsg("Initializing order array.", 1, timer.getElapsedTime(),
206 this->threadNumber_);
207
208 this->printWrn("TIP: run `ttkArrayPreconditioning` first");
209 this->printWrn("for improved performances :)");
210
211 return newOrderArray;
212 }
213
214 case -3: {
215 this->printErr(
216 "Retrieved order array `" + std::string(orderArray->GetName())
217 + "` for scalar array `" + std::string(scalarArray->GetName())
218 + "` has more than one component.");
219 return nullptr;
220 }
221
222 case -2: {
223 this->printErr(
224 "Retrieved order array `" + std::string(orderArray->GetName())
225 + "` for scalar array `" + std::string(scalarArray->GetName())
226 + "` is of incorrect type.");
228 this->printErr(" -> use `ttkArrayEditor` to convert data type to `"
229 + std::string(temp->GetDataTypeAsString()) + "`.");
230 return nullptr;
231 }
232
233 default: {
234 this->printMsg(
235 "Retrieved order array `" + std::string(orderArray->GetName())
236 + "` for scalar array `" + std::string(scalarArray->GetName()) + "`.",
238 return orderArray;
239 }
240 }
241}
242
244 ttkAlgorithm::GetIdentifierArrayPtr(const bool &enforceArrayIndex,
245 const int &arrayIndex,
246 const std::string &arrayName,
247 vtkDataSet *const inputData,
248 std::vector<ttk::SimplexId> &spareStorage,
249 const int inputPort,
250 const bool printErr) {
251
252 // fetch data array
253 const auto array = this->GetOptionalArray(
254 enforceArrayIndex, arrayIndex, arrayName, inputData, inputPort);
255 if(array == nullptr) {
256 if(printErr) {
257 this->printErr("Could not find the requested identifiers array");
258 }
259 return {};
260 }
261 if(array->GetNumberOfComponents() != 1) {
262 if(printErr) {
263 this->printErr("Identifiers field must have only one component!");
264 }
265 return {};
266 }
267
268#ifndef TTK_ENABLE_64BIT_IDS
269 if(array->GetDataType() == VTK_ID_TYPE
270 || array->GetDataType() == VTK_LONG_LONG) {
271 this->printMsg(
272 "Converting identifiers field from vtkIdType to SimplexId...");
273 const auto nItems = array->GetNumberOfTuples();
274
275 // fills the vector with the content of the data array converted to
276 // ttk::SimplexId
277 spareStorage.resize(nItems);
278 for(vtkIdType i = 0; i < nItems; ++i) {
279 spareStorage[i] = static_cast<ttk::SimplexId>(array->GetTuple1(i));
280 }
281
282 // return a pointer to the vector internal buffer
283 return spareStorage.data();
284 }
285#else
286 TTK_FORCE_USE(spareStorage);
287#endif // TTK_ENABLE_64BIT_IDS
288
289 // return a pointer to the data array internal buffer
290 return static_cast<ttk::SimplexId *>(ttkUtils::GetVoidPointer(array));
291}
292
293template <class vtkDataType>
294int prepOutput(vtkInformation *info, const std::string &className) {
295 auto output = vtkDataObject::GetData(info);
296 if(!output || !output->IsA(className.data())) {
297 auto newOutput = vtkSmartPointer<vtkDataType>::New();
298 info->Set(vtkDataObject::DATA_OBJECT(), newOutput);
299 }
300 return 1;
301}
302
304 return this->GetOutput(0);
305}
306
307vtkDataSet *ttkAlgorithm::GetOutput(int port) {
308 return vtkDataSet::SafeDownCast(this->GetOutputDataObject(port));
309}
310
311void ttkAlgorithm::SetInputData(vtkDataSet *input) {
312 this->SetInputData(0, input);
313}
314
315void ttkAlgorithm::SetInputData(int index, vtkDataSet *input) {
316 this->SetInputDataInternal(index, input);
317}
318
319void ttkAlgorithm::AddInputData(vtkDataSet *input) {
320 this->AddInputData(0, input);
321}
322
323void ttkAlgorithm::AddInputData(int index, vtkDataSet *input) {
324 this->AddInputDataInternal(index, input);
325}
326
327int ttkAlgorithm::RequestDataObject(vtkInformation *ttkNotUsed(request),
328 vtkInformationVector **inputVector,
329 vtkInformationVector *outputVector) {
330 // for each output
331 for(int i = 0; i < this->GetNumberOfOutputPorts(); ++i) {
332 auto outInfo = outputVector->GetInformationObject(i);
333 if(!outInfo) {
334 this->printErr("Unable to retrieve output vtkDataObject at port "
335 + std::to_string(i));
336 return 0;
337 }
338
339 auto outputPortInfo = this->GetOutputPortInformation(i);
340
341 // always request output type again for dynamic filter outputs
342 if(!this->FillOutputPortInformation(i, outputPortInfo)) {
343 this->printErr("Unable to fill output port information at port "
344 + std::to_string(i));
345 return 0;
346 }
347
348 if(outputPortInfo->Has(ttkAlgorithm::SAME_DATA_TYPE_AS_INPUT_PORT())) {
349 // Set output data type to input data type at specified port
350 auto inPortIndex
351 = outputPortInfo->Get(ttkAlgorithm::SAME_DATA_TYPE_AS_INPUT_PORT());
352 if(inPortIndex < 0 || inPortIndex >= this->GetNumberOfInputPorts()) {
353 this->printErr("Input port index " + std::to_string(inPortIndex)
354 + " specified by 'SAME_DATA_TYPE_AS_INPUT_PORT' key of "
355 "output port is out of range ("
356 + std::to_string(this->GetNumberOfInputPorts())
357 + " input ports).");
358 return 0;
359 }
360 auto inInfo = inputVector[inPortIndex]->GetInformationObject(0);
361 if(!inInfo) {
362 this->printErr(
363 "No information object at port " + std::to_string(inPortIndex)
364 + " specified by 'SAME_DATA_TYPE_AS_INPUT_PORT' key of output port.");
365 return 0;
366 }
367
368 auto input = vtkDataObject::GetData(inInfo);
369 auto output = vtkDataObject::GetData(outInfo);
370
371 if(!output || !output->IsA(input->GetClassName())) {
372 auto newOutput
373 = vtkSmartPointer<vtkDataObject>::Take(input->NewInstance());
374 outputPortInfo->Set(
375 vtkDataObject::DATA_TYPE_NAME(), input->GetClassName());
376 outInfo->Set(vtkDataObject::DATA_OBJECT(), newOutput);
377 }
378 } else {
379 // Explicitly create output by data type name
380 if(!outputPortInfo->Has(vtkDataObject::DATA_TYPE_NAME())) {
381 this->printErr("DATA_TYPE_NAME of output port " + std::to_string(i)
382 + " not specified");
383 return 0;
384 }
385 std::string outputType
386 = outputPortInfo->Get(vtkDataObject::DATA_TYPE_NAME());
387
388 if(outputType == "vtkUnstructuredGrid") {
389 prepOutput<vtkUnstructuredGrid>(outInfo, outputType);
390 } else if(outputType == "vtkPolyData") {
391 prepOutput<vtkPolyData>(outInfo, outputType);
392 } else if(outputType == "vtkMultiBlockDataSet") {
393 prepOutput<vtkMultiBlockDataSet>(outInfo, outputType);
394 } else if(outputType == "vtkTable") {
395 prepOutput<vtkTable>(outInfo, outputType);
396 } else if(outputType == "vtkImageData") {
397 prepOutput<vtkImageData>(outInfo, outputType);
398 } else {
399 this->printErr("Unsupported data type for output[" + std::to_string(i)
400 + "]: " + outputType);
401 return 0;
402 }
403 }
404
405 this->printMsg(
406 "Created '"
407 + std::string(outputPortInfo->Get(vtkDataObject::DATA_TYPE_NAME()))
408 + "' at output port " + std::to_string(i),
410 }
411
412 return 1;
413}
414
415#ifdef TTK_ENABLE_MPI
416
417int ttkAlgorithm::updateMPICommunicator(vtkDataSet *input) {
418 if(input == nullptr) {
419 return 0;
420 }
421 int isEmpty
422 = input->GetNumberOfCells() == 0 || input->GetNumberOfPoints() == 0;
423 int oldSize = ttk::MPIsize_;
424 int oldRank = ttk::MPIrank_;
425 MPI_Comm_split(MPI_COMM_WORLD, isEmpty, 0, &ttk::MPIcomm_);
426 MPI_Comm_rank(ttk::MPIcomm_, &ttk::MPIrank_);
427 MPI_Comm_size(ttk::MPIcomm_, &ttk::MPIsize_);
428 if(oldSize != ttk::MPIsize_) {
429 std::vector<int> newToOldRanks(ttk::MPIsize_);
430 MPI_Allgather(&oldRank, 1, MPI_INTEGER, newToOldRanks.data(), 1,
431 MPI_INTEGER, ttk::MPIcomm_);
432 std::map<int, int> oldToNewRanks;
433 for(int i = 0; i < ttk::MPIsize_; i++) {
434 oldToNewRanks[newToOldRanks[i]] = i;
435 }
436 int *vertexRankArray
437 = ttkUtils::GetPointer<int>(input->GetPointData()->GetArray("RankArray"));
438 if(vertexRankArray != nullptr) {
439 for(int i = 0; i < input->GetNumberOfPoints(); i++) {
440 vertexRankArray[i] = oldToNewRanks[vertexRankArray[i]];
441 }
442 }
443 int *cellRankArray
444 = ttkUtils::GetPointer<int>(input->GetCellData()->GetArray("RankArray"));
445 if(cellRankArray != nullptr) {
446 for(int i = 0; i < input->GetNumberOfCells(); i++) {
447 cellRankArray[i] = oldToNewRanks[cellRankArray[i]];
448 }
449 }
450 }
452 return isEmpty;
453}
454
456 ttk::SimplexId simplexNumber,
457 unsigned char *ghost,
458 int *rankArray) {
459 ttk::SimplexId ghostNumber = 0;
460 if(rankArray != nullptr) {
461#ifdef TTK_ENABLE_OPENMP
462#pragma omp parallel for reduction(+ : ghostNumber)
463#endif // TTK_ENABLE_OPENMP
464 for(ttk::SimplexId i = 0; i < simplexNumber; i++) {
465 if(rankArray[i] != ttk::MPIrank_) {
466 ghostNumber++;
467 }
468 }
469 } else {
470 if(ghost != nullptr) {
471#ifdef TTK_ENABLE_OPENMP
472#pragma omp parallel for reduction(+ : ghostNumber)
473#endif // TTK_ENABLE_OPENMP
474 for(ttk::SimplexId i = 0; i < simplexNumber; i++) {
475 if(ghost[i] == 1) {
476 ghostNumber++;
477 }
478 }
479 }
480 }
481
482 ttk::SimplexId realSimplexNumber = simplexNumber - ghostNumber;
483 auto minmax = std::minmax_element(globalIds, globalIds + simplexNumber);
484 ttk::LongSimplexId min = globalIds[minmax.first - globalIds];
485 ttk::LongSimplexId max = globalIds[minmax.second - globalIds];
486 ttk::SimplexId globalSimplexNumber;
487 ttk::LongSimplexId globalMin;
488 ttk::LongSimplexId globalMax;
489 MPI_Allreduce(&realSimplexNumber, &globalSimplexNumber, 1,
490 ttk::getMPIType(realSimplexNumber), MPI_SUM, ttk::MPIcomm_);
491 MPI_Allreduce(
492 &min, &globalMin, 1, ttk::getMPIType(min), MPI_MIN, ttk::MPIcomm_);
493 MPI_Allreduce(
494 &max, &globalMax, 1, ttk::getMPIType(max), MPI_MAX, ttk::MPIcomm_);
495
496 return (globalSimplexNumber == globalMax + 1 && globalMin == 0);
497};
498
500 vtkDataSet *input,
501 std::unordered_map<ttk::SimplexId, ttk::SimplexId> &vertGtoL,
502 std::vector<int> &neighborRanks) {
503
504 ttk::Identifiers identifiers;
505
506 vtkNew<vtkIdTypeArray> vtkVertexIdentifiers{};
507
508 vtkNew<vtkIdTypeArray> vtkCellIdentifiers{};
509 vtkVertexIdentifiers->SetName("GlobalPointIds");
510 vtkVertexIdentifiers->SetNumberOfComponents(1);
511 vtkVertexIdentifiers->SetNumberOfTuples(input->GetNumberOfPoints());
512 vtkVertexIdentifiers->Fill(-1);
513
514 identifiers.setVertexIdentifiers(
515 ttkUtils::GetPointer<ttk::LongSimplexId>(vtkVertexIdentifiers));
516
517 vtkCellIdentifiers->SetName("GlobalCellIds");
518 vtkCellIdentifiers->SetNumberOfComponents(1);
519 vtkCellIdentifiers->SetNumberOfTuples(input->GetNumberOfCells());
520 vtkCellIdentifiers->Fill(-1);
521
522 identifiers.setCellIdentifiers(
523 ttkUtils::GetPointer<ttk::LongSimplexId>(vtkCellIdentifiers));
524
525 int vertexNumber = input->GetNumberOfPoints();
526 identifiers.setVertexNumber(vertexNumber);
527 int cellNumber = input->GetNumberOfCells();
528 identifiers.setCellNumber(cellNumber);
529 int status = 0;
530
531 double *boundingBox = input->GetBounds();
532 identifiers.setBounds(boundingBox);
533 identifiers.initializeNeighbors(boundingBox, neighborRanks);
534 if(ttk::isRunningWithMPI()) {
535 switch(input->GetDataObjectType()) {
536 case VTK_UNSTRUCTURED_GRID:
537 case VTK_POLY_DATA: {
538
539 identifiers.setOutdatedGlobalPointIds(
540 ttkUtils::GetPointer<ttk::LongSimplexId>(
541 input->GetPointData()->GetGlobalIds()));
542 identifiers.setOutdatedGlobalCellIds(
543 ttkUtils::GetPointer<ttk::LongSimplexId>(
544 input->GetCellData()->GetGlobalIds()));
545 identifiers.setVertexRankArray(ttkUtils::GetPointer<int>(
546 input->GetPointData()->GetArray("RankArray")));
547 int *cellRankArray = ttkUtils::GetPointer<int>(
548 input->GetCellData()->GetArray("RankArray"));
549 identifiers.setCellRankArray(cellRankArray);
550 identifiers.setVertGhost(ttkUtils::GetPointer<unsigned char>(
551 input->GetPointData()->GetArray("vtkGhostType")));
552 unsigned char *cellGhost = ttkUtils::GetPointer<unsigned char>(
553 input->GetCellData()->GetArray("vtkGhostType"));
554 identifiers.setCellGhost(cellGhost);
555 vtkPointSet *pointSet = vtkPointSet::SafeDownCast(input);
556 identifiers.setPointSet(static_cast<float *>(
557 ttkUtils::GetVoidPointer(pointSet->GetPoints())));
558 vtkCellArray *cells = nullptr;
559 switch(input->GetDataObjectType()) {
560 case VTK_UNSTRUCTURED_GRID: {
561 auto dataSetAsUG = vtkUnstructuredGrid::SafeDownCast(input);
562 cells = dataSetAsUG->GetCells();
563 break;
564 }
565 case VTK_POLY_DATA: {
566 auto dataSetAsPD = vtkPolyData::SafeDownCast(input);
567 cells
568 = dataSetAsPD->GetNumberOfPolys() > 0 ? dataSetAsPD->GetPolys()
569 : dataSetAsPD->GetNumberOfLines() > 0 ? dataSetAsPD->GetLines()
570 : dataSetAsPD->GetVerts();
571 break;
572 }
573 default: {
574 this->printErr("Unable to get cells for `"
575 + std::string(input->GetClassName()) + "`");
576 }
577 }
578 if(cells == nullptr) {
579 return 0;
580 }
581 if(!cells->IsStorage64Bit()) {
582 if(cells->CanConvertTo64BitStorage()) {
583 this->printWrn("Converting the cell array to 64-bit storage");
584 bool success = cells->ConvertTo64BitStorage();
585 if(!success) {
586 this->printErr(
587 "Error converting the provided cell array to 64-bit storage");
588 return -1;
589 }
590 } else {
591 this->printErr(
592 "Cannot convert the provided cell array to 64-bit storage");
593 return -1;
594 }
595 }
596
597 identifiers.setConnectivity(ttkUtils::GetPointer<ttk::LongSimplexId>(
598 cells->GetConnectivityArray()));
599
600 std::vector<std::vector<ttk::SimplexId>> pointsToCells(vertexNumber);
601 vtkIdList *cellList = vtkIdList::New();
602 if(cellRankArray != nullptr) {
603 for(ttk::SimplexId i = 0; i < vertexNumber; i++) {
604 input->GetPointCells(i, cellList);
605 for(int j = 0; j < cellList->GetNumberOfIds(); j++) {
606 if(cellRankArray[cellList->GetId(j)] == ttk::MPIrank_) {
607 pointsToCells[i].push_back(cellList->GetId(j));
608 }
609 }
610 }
611 } else {
612 for(ttk::SimplexId i = 0; i < vertexNumber; i++) {
613 input->GetPointCells(i, cellList);
614 for(int j = 0; j < cellList->GetNumberOfIds(); j++) {
615 if(cellGhost[cellList->GetId(j)] == 0) {
616 pointsToCells[i].push_back(cellList->GetId(j));
617 }
618 }
619 }
620 }
621 identifiers.setPointsToCells(pointsToCells);
622
623 identifiers.initializeMPITypes();
624 identifiers.setVertGtoL(&vertGtoL);
625 vtkIdList *pointCell = vtkIdList::New();
626 input->GetCellPoints(0, pointCell);
627 int nbPoints = pointCell->GetNumberOfIds();
628 identifiers.setDomainDimension(nbPoints - 1);
629 identifiers.buildKDTree();
630 status = identifiers.executePolyData();
631 break;
632 }
633 case VTK_IMAGE_DATA: {
634 vtkImageData *data = vtkImageData::SafeDownCast(input);
635 identifiers.setDims(data->GetDimensions());
636 identifiers.setSpacing(data->GetSpacing());
637 status = identifiers.executeImageData();
638 break;
639 }
640 default: {
641 this->printErr("Unable to triangulate `"
642 + std::string(input->GetClassName()) + "`");
643 }
644 }
645 } else {
646 status = identifiers.executeSequential();
647 }
648
649 if(status < 1) {
650 printErr("Global identifier generation failed");
651 return -1;
652 }
653
654 // Add VTK objects to the data set
655
656 input->GetPointData()->SetGlobalIds(vtkVertexIdentifiers);
657 input->GetCellData()->SetGlobalIds(vtkCellIdentifiers);
658 return 0;
659}
660
661void ttkAlgorithm::MPIGhostPipelinePreconditioning(vtkDataSet *input) {
662
663 vtkNew<vtkGhostCellsGenerator> generator;
664 if(ttk::isRunningWithMPI()
665 && (!input->HasAnyGhostCells()
666 && ((input->GetPointData()->GetArray("RankArray") == nullptr)
667 || (input->GetCellData()->GetArray("RankArray") == nullptr)))) {
668 generator->SetInputData(input);
669 generator->BuildIfRequiredOff();
670 generator->SetNumberOfGhostLayers(1);
671 generator->Update();
672 input->ShallowCopy(generator->GetOutputDataObject(0));
673 input->GetPointData()->AddArray(
674 generator->GetOutputDataObject(0)->GetGhostArray(0));
675 input->GetCellData()->AddArray(
676 generator->GetOutputDataObject(0)->GetGhostArray(1));
677 }
678}
679
681 vtkDataSet *input,
682 std::vector<int> &neighbors,
683 ttk::Triangulation *triangulation) {
684
685 ttk::SimplexId vertexNumber = input->GetNumberOfPoints();
686 ttk::SimplexId cellNumber = input->GetNumberOfCells();
687 if((input->GetDataObjectType() == VTK_POLY_DATA
688 || input->GetDataObjectType() == VTK_UNSTRUCTURED_GRID)) {
689 if((input->GetCellData()->GetGlobalIds() == nullptr)
690 || (input->GetPointData()->GetGlobalIds() == nullptr)) {
691 printWrn("Up to Paraview 5.10.1, bugs have been found in VTK for the "
692 "distribution of Unstructured Grids and Poly Data");
693 printWrn("As a consequence, the generation of Global ids is "
694 "incorrect for those simplices");
695 printWrn(
696 "Beware when using TTK for such data set types, some results may "
697 "be false");
698 }
699 if((input->GetPointData()->GetArray("RankArray") == nullptr)
700 || (input->GetCellData()->GetArray("RankArray") == nullptr)) {
701 printWrn("Up to Paraview 5.10.1, bugs have been found in VTK for the "
702 "distribution of Unstructured Grids and Poly Data");
703 printWrn("As a consequence, the generation of RankArray is "
704 "incorrect for those simplices");
705 printWrn(
706 "Beware when using TTK for such data set types, some results may "
707 "be false");
708 }
709 }
710
711 // Get the neighbor ranks
712 std::vector<int> &neighborRanks{
713 triangulation != nullptr ? triangulation->getNeighborRanks() : neighbors};
714
715 double *boundingBox = input->GetBounds();
716 if(triangulation != nullptr) {
717 triangulation->createMetaGrid(boundingBox);
718 }
719
720 if(neighborRanks.empty()) {
721 ttk::preconditionNeighborsUsingBoundingBox(boundingBox, neighborRanks);
722 }
723
724 // Checks if global ids are valid
725 ttk::LongSimplexId *globalPointIds = ttkUtils::GetPointer<ttk::LongSimplexId>(
726 input->GetPointData()->GetGlobalIds());
727 ttk::LongSimplexId *globalCellIds = ttkUtils::GetPointer<ttk::LongSimplexId>(
728 input->GetCellData()->GetGlobalIds());
729
730 bool pointValidity{false};
731 bool cellValidity{false};
732 if((triangulation != nullptr
733 && (triangulation->getType() == ttk::Triangulation::Type::EXPLICIT
734 || triangulation->getType() == ttk::Triangulation::Type::COMPACT))
735 || triangulation == nullptr) {
736 if(globalPointIds != nullptr) {
737 unsigned char *ghostPoints = ttkUtils::GetPointer<unsigned char>(
738 input->GetPointData()->GetArray("vtkGhostType"));
739 int *vertexRankArray = ttkUtils::GetPointer<int>(
740 input->GetPointData()->GetArray("RankArray"));
741 pointValidity = checkGlobalIdValidity(
742 globalPointIds, vertexNumber, ghostPoints, vertexRankArray);
743 }
744 if(pointValidity && globalCellIds != nullptr) {
745
746 unsigned char *ghostCells = ttkUtils::GetPointer<unsigned char>(
747 input->GetCellData()->GetArray("vtkGhostType"));
748 int *cellRankArray = ttkUtils::GetPointer<int>(
749 input->GetCellData()->GetArray("RankArray"));
750 cellValidity = checkGlobalIdValidity(
751 globalCellIds, cellNumber, ghostCells, cellRankArray);
752 }
753 } else {
754 pointValidity = true;
755 cellValidity = true;
756 }
757
758 // If the global ids are not valid, they are computed again
759 if(!pointValidity || !cellValidity) {
760 if(triangulation != nullptr) {
761 if(triangulation->getType() == ttk::Triangulation::Type::EXPLICIT
762 || triangulation->getType() == ttk::Triangulation::Type::COMPACT) {
763 this->GenerateGlobalIds(
764 input, triangulation->getVertexGlobalIdMap(), neighborRanks);
765 }
766 } else {
767 std::unordered_map<ttk::SimplexId, ttk::SimplexId> vertGtoL{};
768 this->GenerateGlobalIds(input, vertGtoL, neighborRanks);
769 }
770 }
771}
772
774 ttk::Triangulation *triangulation, vtkDataSet *input) {
775
776 const auto pd{input->GetPointData()};
777 if(pd == nullptr) {
778 triangulation->printWrn("No point data on input object");
779 } else {
780 // provide "GlobalPointIds" & "vtkGhostType" point data arrays
781 // to the triangulation
782 triangulation->setVertsGlobalIds(
783 ttkUtils::GetPointer<ttk::LongSimplexId>(pd->GetGlobalIds()));
784 triangulation->setVertexGhostArray(
785 ttkUtils::GetPointer<unsigned char>(pd->GetArray("vtkGhostType")));
786 int *vertexRankArray = ttkUtils::GetPointer<int>(pd->GetArray("RankArray"));
787 if(vertexRankArray != nullptr) {
788 triangulation->setVertexRankArray(vertexRankArray);
789 }
790 triangulation->preconditionDistributedVertices();
791 }
792
793 const auto cd{input->GetCellData()};
794 if(cd == nullptr) {
795 triangulation->printWrn("No cell data on input object");
796 } else {
797 // provide "GlobalCellIds" & "vtkGhostType" cell data arrays to
798 // the triangulation
799 triangulation->setCellsGlobalIds(
800 ttkUtils::GetPointer<ttk::LongSimplexId>(cd->GetGlobalIds()));
801 triangulation->setCellGhostArray(
802 ttkUtils::GetPointer<unsigned char>(cd->GetArray("vtkGhostType")));
803 int *cellRankArray = ttkUtils::GetPointer<int>(cd->GetArray("RankArray"));
804 if(cellRankArray != nullptr) {
805 triangulation->setCellRankArray(cellRankArray);
806 }
807 triangulation->preconditionDistributedCells();
808 }
809}
810
811#endif // TTK_ENABLE_MPI
812
813//==============================================================================
814int ttkAlgorithm::ProcessRequest(vtkInformation *request,
815 vtkInformationVector **inputVector,
816 vtkInformationVector *outputVector) {
817 // 1. Pass
818 if(request->Has(vtkCompositeDataPipeline::REQUEST_DATA_OBJECT())) {
819 this->printMsg(
820 "Processing REQUEST_DATA_OBJECT", ttk::debug::Priority::VERBOSE);
821 return this->RequestDataObject(request, inputVector, outputVector);
822 }
823
824 // 2. Pass
825 if(request->Has(vtkCompositeDataPipeline::REQUEST_INFORMATION())) {
826 this->printMsg(
827 "Processing REQUEST_INFORMATION", ttk::debug::Priority::VERBOSE);
828 return this->RequestInformation(request, inputVector, outputVector);
829 }
830
831 // 3. Pass
832 if(request->Has(vtkCompositeDataPipeline::REQUEST_UPDATE_TIME())) {
833 this->printMsg(
834 "Processing REQUEST_UPDATE_TIME", ttk::debug::Priority::VERBOSE);
835 return this->RequestUpdateTime(request, inputVector, outputVector);
836 }
837
838 // 4. Pass
839 if(request->Has(
840 vtkCompositeDataPipeline::REQUEST_TIME_DEPENDENT_INFORMATION())) {
841 this->printMsg("Processing REQUEST_TIME_DEPENDENT_INFORMATION",
844 request, inputVector, outputVector);
845 }
846
847 // 5. Pass
848 if(request->Has(vtkCompositeDataPipeline::REQUEST_UPDATE_EXTENT())) {
849 this->printMsg(
850 "Processing REQUEST_UPDATE_EXTENT", ttk::debug::Priority::VERBOSE);
851 return this->RequestUpdateExtent(request, inputVector, outputVector);
852 }
853
854 // 6. Pass
855 if(request->Has(vtkCompositeDataPipeline::REQUEST_DATA_NOT_GENERATED())) {
856 this->printMsg(
857 "Processing REQUEST_DATA_NOT_GENERATED", ttk::debug::Priority::VERBOSE);
858 return this->RequestDataNotGenerated(request, inputVector, outputVector);
859 }
860
861 // 7. Pass
862 if(request->Has(vtkCompositeDataPipeline::REQUEST_DATA())) {
863 this->printMsg("Processing REQUEST_DATA", ttk::debug::Priority::VERBOSE);
865#ifdef TTK_ENABLE_MPI
866 if(ttk::hasInitializedMPI() && inputVector != nullptr) {
867 if(this->updateMPICommunicator(vtkDataSet::GetData(inputVector[0], 0))) {
868 return 1;
869 };
870 }
871#endif // TTK_ENABLE_MPI
872 return this->RequestData(request, inputVector, outputVector);
873 }
874
875 this->printErr("Unsupported pipeline pass:");
876 request->Print(cout);
877
878 return 0;
879}
#define TTK_FORCE_USE(x)
Force the compiler to use the function/method parameter.
Definition: BaseClass.h:57
#define ttkNotUsed(x)
Mark function/method parameters that are not used in the function body at all.
Definition: BaseClass.h:47
Baseclass of all VTK filters that wrap ttk modules.
Definition: ttkAlgorithm.h:34
void SetInputData(vtkDataSet *)
static vtkInformationIntegerKey * SAME_DATA_TYPE_AS_INPUT_PORT()
bool checkGlobalIdValidity(ttk::LongSimplexId *globalIds, ttk::SimplexId simplexNumber, unsigned char *ghost, int *rankArray)
ttk::SimplexId * GetIdentifierArrayPtr(const bool &enforceArrayIndex, const int &arrayIndex, const std::string &arrayName, vtkDataSet *const inputData, std::vector< ttk::SimplexId > &spareStorage, const int inputPort=0, const bool printErr=true)
void AddInputData(vtkDataSet *)
virtual int RequestUpdateTime(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
Definition: ttkAlgorithm.h:334
~ttkAlgorithm() override
virtual int RequestDataNotGenerated(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
Definition: ttkAlgorithm.h:376
float CompactTriangulationCacheSize
Definition: ttkAlgorithm.h:237
virtual int RequestData(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
Definition: ttkAlgorithm.h:390
void MPIGhostPipelinePreconditioning(vtkDataSet *input)
vtkDataArray * GetOrderArray(vtkDataSet *const inputData, const int scalarArrayIdx, const int orderArrayIdx=0, const bool enforceOrderArrayIdx=false)
virtual int RequestInformation(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
Definition: ttkAlgorithm.h:321
int ProcessRequest(vtkInformation *request, vtkInformationVector **inputVectors, vtkInformationVector *outputVector) override
virtual int RequestDataObject(vtkInformation *request, vtkInformationVector **inputVectors, vtkInformationVector *outputVector)
virtual int RequestUpdateTimeDependentInformation(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
Definition: ttkAlgorithm.h:346
ttk::Triangulation * GetTriangulation(vtkDataSet *dataSet)
virtual int RequestUpdateExtent(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
Definition: ttkAlgorithm.h:362
void MPITriangulationPreconditioning(ttk::Triangulation *triangulation, vtkDataSet *input)
vtkDataSet * GetOutput()
int GenerateGlobalIds(vtkDataSet *input, std::unordered_map< ttk::SimplexId, ttk::SimplexId > &vertGtoL, std::vector< int > &neighborRanks)
void MPIPipelinePreconditioning(vtkDataSet *input, std::vector< int > &neighbors, ttk::Triangulation *triangulation=nullptr)
int FillOutputPortInformation(int ttkNotUsed(port), vtkInformation *ttkNotUsed(info)) override
Definition: ttkAlgorithm.h:419
vtkDataArray * GetOptionalArray(const bool &enforceArrayIndex, const int &arrayIndex, const std::string &arrayName, vtkDataSet *const inputData, const int &inputPort=0)
static std::string GetOrderArrayName(vtkDataArray *const array)
static ttk::Triangulation * GetTriangulation(int debugLevel, float cacheRatio, vtkDataSet *object)
static void * GetVoidPointer(vtkDataArray *array, vtkIdType start=0)
Definition: ttkUtils.cpp:225
int threadNumber_
Definition: BaseClass.h:95
int debugLevel_
Definition: Debug.h:379
int printWrn(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition: Debug.h:159
std::string debugMsgNamePrefix_
Definition: Debug.h:384
void setDebugMsgPrefix(const std::string &prefix)
Definition: Debug.h:364
int printMsg(const std::string &msg, const debug::Priority &priority=debug::Priority::INFO, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cout) const
Definition: Debug.h:118
int printErr(const std::string &msg, const debug::LineMode &lineMode=debug::LineMode::NEW, std::ostream &stream=std::cerr) const
Definition: Debug.h:149
void setCellIdentifiers(ttk::LongSimplexId *cellIdentifiers)
Definition: Identifiers.h:97
void setVertexNumber(const SimplexId &vertexNumber)
Definition: Identifiers.h:85
void setCellNumber(const SimplexId &cellNumber)
Definition: Identifiers.h:89
int executeSequential()
Generates global ids for all data set type in sequential.
Definition: Identifiers.h:943
void setVertexIdentifiers(ttk::LongSimplexId *vertexIdentifiers)
Definition: Identifiers.h:93
double getElapsedTime()
Definition: Timer.h:15
Triangulation is a class that provides time and memory efficient traversal methods on triangulations ...
Definition: Triangulation.h:48
Triangulation::Type getType() const
COMMON_EXPORTS int MPIsize_
Definition: BaseClass.cpp:10
COMMON_EXPORTS int MPIrank_
Definition: BaseClass.cpp:9
void preconditionOrderArray(const size_t nVerts, const scalarType *const scalars, SimplexId *const order, const int nThreads=ttk::globalThreadNumber_)
Precondition an order array to be consumed by the base layer API.
long long int LongSimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:15
int SimplexId
Identifier type for simplices of any dimension.
Definition: DataTypes.h:22
vtkStandardNewMacro(ttkAlgorithm)
vtkInformationKeyMacro(ttkAlgorithm, SAME_DATA_TYPE_AS_INPUT_PORT, Integer)
int prepOutput(vtkInformation *info, const std::string &className)