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
15#include <Identifiers.h>
16#include <vtkCellData.h>
17#include <vtkGhostCellsGenerator.h>
18#endif // TTK_ENABLE_MPI
19
20#include <vtkImageData.h>
21#include <vtkInformation.h>
22#include <vtkInformationIntegerKey.h>
23#include <vtkInformationVector.h>
24#include <vtkMultiBlockDataSet.h>
25#include <vtkPointData.h>
26#include <vtkPolyData.h>
27#include <vtkTable.h>
28#include <vtkUnstructuredGrid.h>
29
30#include <vtkCompositeDataPipeline.h>
31
32using namespace std;
33
34// Pass input type information key
35#include <vtkInformationKey.h>
36vtkInformationKeyMacro(ttkAlgorithm, SAME_DATA_TYPE_AS_INPUT_PORT, Integer);
37
38// Constructor / Destructor
42
44
45 this->printMsg("Requesting triangulation for '"
46 + std::string(dataSet->GetClassName()) + "'",
48#ifdef TTK_ENABLE_MPI
49 if((ttk::hasInitializedMPI()) && (ttk::isRunningWithMPI())) {
50 if(!hasMPISupport_) {
51 printErr("MPI is not formally supported for this filter :(");
52 printErr("The results are likely to be incorrect.");
53 }
55 }
56#endif // TTK_ENABLE_MPI
57
59 this->debugLevel_, this->CompactTriangulationCacheSize, dataSet);
60
61#ifdef TTK_ENABLE_MPI
62 if(ttk::hasInitializedMPI()) {
63 std::vector<int> tmp{};
64 std::map<int, int> tmpId{};
65 this->MPIPipelinePreconditioning(dataSet, tmp, tmpId, triangulation);
66 this->MPITriangulationPreconditioning(triangulation, dataSet);
67 }
68#endif // TTK_ENABLE_MPI
69
70 if(triangulation)
71 return triangulation;
72
73 this->printErr("Unable to retrieve/initialize triangulation for '"
74 + std::string(dataSet->GetClassName()) + "'");
75
76 return nullptr;
77}
78
79vtkDataArray *ttkAlgorithm::GetOptionalArray(const bool &enforceArrayIndex,
80 const int &arrayIndex,
81 const std::string &arrayName,
82 vtkDataSet *const inputData,
83 const int &inputPort) {
84
85 vtkDataArray *optionalArray = nullptr;
86
87 if(enforceArrayIndex)
88 optionalArray = this->GetInputArrayToProcess(arrayIndex, inputData);
89
90 if(!optionalArray) {
91 this->SetInputArrayToProcess(arrayIndex, inputPort, 0, 0, arrayName.data());
92 optionalArray = this->GetInputArrayToProcess(arrayIndex, inputData);
93 }
94 return optionalArray;
95}
96
97std::string ttkAlgorithm::GetOrderArrayName(vtkDataArray *const array) {
98 return std::string(array->GetName()) + "_Order";
99}
100
101vtkDataArray *
102 ttkAlgorithm::ComputeOrderArray(vtkDataSet *const inputData,
103 vtkDataArray *scalarArray,
104 const int scalarArrayIdx,
105 const bool getGlobalOrder,
106 vtkDataArray *oldOrderArray,
107 ttk::Triangulation *triangulation) {
108
110 auto nVertices = scalarArray->GetNumberOfTuples();
111 if(oldOrderArray != nullptr && getGlobalOrder) {
112 newOrderArray = ttkSimplexIdTypeArray::SafeDownCast(oldOrderArray);
113 } else {
115 newOrderArray->SetName(this->GetOrderArrayName(scalarArray).data());
116 newOrderArray->SetNumberOfComponents(1);
117 newOrderArray->SetNumberOfTuples(nVertices);
118 }
119
120 std::vector<int> neighbors;
121 std::map<int, int> neighborsToId;
122#ifdef TTK_ENABLE_MPI
123 if(ttk::hasInitializedMPI()) {
124 this->MPIGhostPipelinePreconditioning(inputData);
126 inputData, neighbors, neighborsToId, nullptr);
127 }
128 if(ttk::isRunningWithMPI() && getGlobalOrder) {
129 ttk::ArrayPreconditioning arrayPreconditioning
131 arrayPreconditioning.preconditionTriangulation(triangulation);
132 arrayPreconditioning.setGlobalOrder(getGlobalOrder);
133 ttkTypeMacroAT(scalarArray->GetDataType(), triangulation->getType(),
134 (arrayPreconditioning.processScalarArray<T0, T1>(
135 static_cast<const T1 *>(triangulation->getData()),
137 ttkUtils::GetPointer<T0>(scalarArray), nVertices)));
138 } else {
139 switch(scalarArray->GetDataType()) {
140 vtkTemplateMacro(ttk::preconditionOrderArray(
141 nVertices, static_cast<VTK_TT *>(ttkUtils::GetVoidPointer(scalarArray)),
142 static_cast<ttk::SimplexId *>(ttkUtils::GetVoidPointer(newOrderArray)),
143 this->threadNumber_));
144 }
145 }
146 if(oldOrderArray == nullptr || !getGlobalOrder) {
147 inputData
148 ->GetAttributesAsFieldData(
149 this->GetInputArrayAssociation(scalarArrayIdx, inputData))
150 ->AddArray(newOrderArray);
151 }
152#else
153
154 switch(scalarArray->GetDataType()) {
155 vtkTemplateMacro(ttk::preconditionOrderArray(
156 nVertices, static_cast<VTK_TT *>(ttkUtils::GetVoidPointer(scalarArray)),
157 static_cast<ttk::SimplexId *>(ttkUtils::GetVoidPointer(newOrderArray)),
158 this->threadNumber_));
159 }
160
161 inputData
162 ->GetAttributesAsFieldData(
163 this->GetInputArrayAssociation(scalarArrayIdx, inputData))
164 ->AddArray(newOrderArray);
165 TTK_FORCE_USE(triangulation);
166#endif
167 return newOrderArray;
168}
169
171 vtkDataSet *const inputData,
172 vtkDataArray *scalarArray,
173 const int scalarArrayIdx,
174 const bool getGlobalOrder,
175 vtkDataArray *orderArray,
176 ttk::Triangulation *triangulation,
177 const bool enforceOrderArrayIdx) {
178
179 std::string enforcedArray = "";
180 if(enforceOrderArrayIdx) {
181 enforcedArray = " enforced ";
182 }
183#ifdef TTK_ENABLE_MPI
184 if(getGlobalOrder) {
185 if(triangulation->isOrderArrayGlobal(
186 ttkUtils::GetVoidPointer(scalarArray))) {
187 this->printMsg("Retrieved " + enforcedArray + " order array `"
188 + std::string(orderArray->GetName()) + "`.",
190 return orderArray;
191 } else {
192 ttk::Timer timer;
194 this->printWrn("Order array `" + std::string(orderArray->GetName())
195 + "` is local, but a global order array is "
196 "required. Re-computing.");
197
198 this->printMsg("Initializing order array.", 0, 0, this->threadNumber_,
201
202 orderArray
203 = this->ComputeOrderArray(inputData, scalarArray, scalarArrayIdx,
204 getGlobalOrder, orderArray, triangulation);
205
206 triangulation->setIsOrderArrayGlobal(
207 ttkUtils::GetVoidPointer(scalarArray), true);
208
209 this->printMsg("Initializing order array.", 1, timer.getElapsedTime(),
210 this->threadNumber_);
211
213 this->printWrn("TIP: run `ttkArrayPreconditioning` first with "
214 "GlobalOrder enabled");
215 this->printWrn("for improved performances :)");
217 return orderArray;
218 }
219 } else {
220#else
221 TTK_FORCE_USE(inputData);
222 TTK_FORCE_USE(scalarArray);
223 TTK_FORCE_USE(scalarArrayIdx);
224 TTK_FORCE_USE(getGlobalOrder);
225 TTK_FORCE_USE(triangulation);
226#endif // TTK_ENABLE_MPI
227 this->printMsg("Retrieved " + enforcedArray + " order array `"
228 + std::string(orderArray->GetName()) + "`.",
230 return orderArray;
231#ifdef TTK_ENABLE_MPI
232 }
233#endif
234}
235
236vtkDataArray *ttkAlgorithm::GetOrderArray(vtkDataSet *const inputData,
237 const int scalarArrayIdx,
238 ttk::Triangulation *triangulation,
239 const bool getGlobalOrder,
240 const int orderArrayIdx,
241 const bool enforceOrderArrayIdx) {
242
243 auto isValidOrderArray = [](vtkDataArray *const array) {
244 if(!array)
245 return -4;
246
247 if(array->GetNumberOfComponents() != 1)
248 return -3;
249
251 if(array->GetDataType() != temp->GetDataType())
252 return -2;
253
254 const std::string name(array->GetName());
255 if(name.size() < 6 || (name.rfind("_Order") != (name.size() - 6)))
256 return -1;
257
258 return 1;
259 };
260 auto scalarArray = this->GetInputArrayToProcess(scalarArrayIdx, inputData);
261 if(enforceOrderArrayIdx) {
262 auto orderArray = this->GetInputArrayToProcess(orderArrayIdx, inputData);
263 switch(isValidOrderArray(orderArray)) {
264 case -4: {
265 this->printErr("Unable to retrieve enforced order array at idx "
266 + std::to_string(orderArrayIdx) + ".");
267 return nullptr;
268 }
269 case -3: {
270 this->printErr("Retrieved enforced order array `"
271 + std::string(orderArray->GetName())
272 + "` has more than one component.");
273 return nullptr;
274 }
275 case -2: {
276 this->printErr("Enforced order array `"
277 + std::string(orderArray->GetName())
278 + "` is of incorrect type.");
280 this->printErr(" -> use `ttkArrayEditor` to convert data type to `"
281 + std::string(temp->GetDataTypeAsString()) + "`.");
282 return nullptr;
283 }
284 default: {
286 inputData, scalarArray, scalarArrayIdx, getGlobalOrder, orderArray,
287 triangulation, enforceOrderArrayIdx);
288 }
289 }
290 }
291
292 if(!scalarArray) {
293 this->printErr("Unable to retrieve input scalar array for idx "
294 + std::to_string(scalarArrayIdx) + ".");
295 return nullptr;
296 } else if(isValidOrderArray(scalarArray) == 1) {
297 this->printMsg("Retrieved scalar array `"
298 + std::string(scalarArray->GetName())
299 + "` is already an order array.",
301 return scalarArray;
302 }
303
304 auto orderArray = inputData
305 ->GetAttributesAsFieldData(this->GetInputArrayAssociation(
306 scalarArrayIdx, inputData))
307 ->GetArray(this->GetOrderArrayName(scalarArray).data());
308
309 switch(isValidOrderArray(orderArray)) {
310 case -4: {
311 ttk::Timer timer;
313 this->printWrn("No pre-existing order for array:");
314 this->printWrn(" `" + std::string(scalarArray->GetName()) + "`.");
315
316 this->printMsg("Initializing order array.", 0, 0, this->threadNumber_,
319
320 orderArray
321 = this->ComputeOrderArray(inputData, scalarArray, scalarArrayIdx,
322 getGlobalOrder, orderArray, triangulation);
323
324 std::string optionOn = "";
325#ifdef TTK_ENABLE_MPI
326 if(getGlobalOrder) {
327 optionOn = "with GlobalOrder enabled ";
328 }
329 bool isGlobalOrder = getGlobalOrder || (!ttk::isRunningWithMPI());
330 triangulation->setIsOrderArrayGlobal(
331 ttkUtils::GetVoidPointer(scalarArray), isGlobalOrder);
332#endif // TTK_ENABLE_MPI
333 this->printMsg("Initializing order array.", 1, timer.getElapsedTime(),
334 this->threadNumber_);
335
337 this->printWrn("TIP: run `ttkArrayPreconditioning` first");
338 this->printWrn(optionOn + "for improved performances :)");
340
341 return orderArray;
342 }
343
344 case -3: {
345 this->printErr(
346 "Retrieved order array `" + std::string(orderArray->GetName())
347 + "` for scalar array `" + std::string(scalarArray->GetName())
348 + "` has more than one component.");
349 return nullptr;
350 }
351
352 case -2: {
353 this->printErr(
354 "Retrieved order array `" + std::string(orderArray->GetName())
355 + "` for scalar array `" + std::string(scalarArray->GetName())
356 + "` is of incorrect type.");
358 this->printErr(" -> use `ttkArrayEditor` to convert data type to `"
359 + std::string(temp->GetDataTypeAsString()) + "`.");
360 return nullptr;
361 }
362
363 default: {
364#ifdef TTK_ENABLE_MPI
365 if(!ttk::isRunningWithMPI()) {
366#endif
367 this->printMsg("Retrieved order array `"
368 + std::string(orderArray->GetName())
369 + "` for scalar array `"
370 + std::string(scalarArray->GetName()) + "`.",
372 return orderArray;
373#ifdef TTK_ENABLE_MPI
374 }
376 inputData, scalarArray, scalarArrayIdx, getGlobalOrder, orderArray,
377 triangulation, enforceOrderArrayIdx);
378#endif
379 }
380 }
381}
382
384 ttkAlgorithm::GetIdentifierArrayPtr(const bool &enforceArrayIndex,
385 const int &arrayIndex,
386 const std::string &arrayName,
387 vtkDataSet *const inputData,
388 std::vector<ttk::SimplexId> &spareStorage,
389 const int inputPort,
390 const bool printErr) {
391
392 // fetch data array
393 const auto array = this->GetOptionalArray(
394 enforceArrayIndex, arrayIndex, arrayName, inputData, inputPort);
395 if(array == nullptr) {
396 if(printErr) {
397 this->printErr("Could not find the requested identifiers array");
398 }
399 return {};
400 }
401 if(array->GetNumberOfComponents() != 1) {
402 if(printErr) {
403 this->printErr("Identifiers field must have only one component!");
404 }
405 return {};
406 }
407
408#ifndef TTK_ENABLE_64BIT_IDS
409 if(array->GetDataType() == VTK_ID_TYPE
410 || array->GetDataType() == VTK_LONG_LONG) {
411 this->printMsg(
412 "Converting identifiers field from vtkIdType to SimplexId...");
413 const auto nItems = array->GetNumberOfTuples();
414
415 // fills the vector with the content of the data array converted to
416 // ttk::SimplexId
417 spareStorage.resize(nItems);
418 for(vtkIdType i = 0; i < nItems; ++i) {
419 spareStorage[i] = static_cast<ttk::SimplexId>(array->GetTuple1(i));
420 }
421
422 // return a pointer to the vector internal buffer
423 return spareStorage.data();
424 }
425#else
426 TTK_FORCE_USE(spareStorage);
427#endif // TTK_ENABLE_64BIT_IDS
428
429 // return a pointer to the data array internal buffer
430 return static_cast<ttk::SimplexId *>(ttkUtils::GetVoidPointer(array));
431}
432
433template <class vtkDataType>
434int prepOutput(vtkInformation *info, const std::string &className) {
435 auto output = vtkDataObject::GetData(info);
436 if(!output || !output->IsA(className.data())) {
437 auto newOutput = vtkSmartPointer<vtkDataType>::New();
438 info->Set(vtkDataObject::DATA_OBJECT(), newOutput);
439 }
440 return 1;
441}
442
444 return this->GetOutput(0);
445}
446
447vtkDataSet *ttkAlgorithm::GetOutput(int port) {
448 return vtkDataSet::SafeDownCast(this->GetOutputDataObject(port));
449}
450
451void ttkAlgorithm::SetInputData(vtkDataSet *input) {
452 this->SetInputData(0, input);
453}
454
455void ttkAlgorithm::SetInputData(int index, vtkDataSet *input) {
456 this->SetInputDataInternal(index, input);
457}
458
459void ttkAlgorithm::AddInputData(vtkDataSet *input) {
460 this->AddInputData(0, input);
461}
462
463void ttkAlgorithm::AddInputData(int index, vtkDataSet *input) {
464 this->AddInputDataInternal(index, input);
465}
466
467int ttkAlgorithm::RequestDataObject(vtkInformation *ttkNotUsed(request),
468 vtkInformationVector **inputVector,
469 vtkInformationVector *outputVector) {
470 // for each output
471 for(int i = 0; i < this->GetNumberOfOutputPorts(); ++i) {
472 auto outInfo = outputVector->GetInformationObject(i);
473 if(!outInfo) {
474 this->printErr("Unable to retrieve output vtkDataObject at port "
475 + std::to_string(i));
476 return 0;
477 }
478
479 auto outputPortInfo = this->GetOutputPortInformation(i);
480
481 // always request output type again for dynamic filter outputs
482 if(!this->FillOutputPortInformation(i, outputPortInfo)) {
483 this->printErr("Unable to fill output port information at port "
484 + std::to_string(i));
485 return 0;
486 }
487
488 if(outputPortInfo->Has(ttkAlgorithm::SAME_DATA_TYPE_AS_INPUT_PORT())) {
489 // Set output data type to input data type at specified port
490 auto inPortIndex
491 = outputPortInfo->Get(ttkAlgorithm::SAME_DATA_TYPE_AS_INPUT_PORT());
492 if(inPortIndex < 0 || inPortIndex >= this->GetNumberOfInputPorts()) {
493 this->printErr("Input port index " + std::to_string(inPortIndex)
494 + " specified by 'SAME_DATA_TYPE_AS_INPUT_PORT' key of "
495 "output port is out of range ("
496 + std::to_string(this->GetNumberOfInputPorts())
497 + " input ports).");
498 return 0;
499 }
500 auto inInfo = inputVector[inPortIndex]->GetInformationObject(0);
501 if(!inInfo) {
502 this->printErr(
503 "No information object at port " + std::to_string(inPortIndex)
504 + " specified by 'SAME_DATA_TYPE_AS_INPUT_PORT' key of output port.");
505 return 0;
506 }
507
508 auto input = vtkDataObject::GetData(inInfo);
509 auto output = vtkDataObject::GetData(outInfo);
510
511 if(!output || !output->IsA(input->GetClassName())) {
512 auto newOutput
513 = vtkSmartPointer<vtkDataObject>::Take(input->NewInstance());
514 outputPortInfo->Set(
515 vtkDataObject::DATA_TYPE_NAME(), input->GetClassName());
516 outInfo->Set(vtkDataObject::DATA_OBJECT(), newOutput);
517 }
518 } else {
519 // Explicitly create output by data type name
520 if(!outputPortInfo->Has(vtkDataObject::DATA_TYPE_NAME())) {
521 this->printErr("DATA_TYPE_NAME of output port " + std::to_string(i)
522 + " not specified");
523 return 0;
524 }
525 std::string const outputType
526 = outputPortInfo->Get(vtkDataObject::DATA_TYPE_NAME());
527
528 if(outputType == "vtkUnstructuredGrid") {
529 prepOutput<vtkUnstructuredGrid>(outInfo, outputType);
530 } else if(outputType == "vtkPolyData") {
531 prepOutput<vtkPolyData>(outInfo, outputType);
532 } else if(outputType == "vtkMultiBlockDataSet") {
533 prepOutput<vtkMultiBlockDataSet>(outInfo, outputType);
534 } else if(outputType == "vtkTable") {
535 prepOutput<vtkTable>(outInfo, outputType);
536 } else if(outputType == "vtkImageData") {
537 prepOutput<vtkImageData>(outInfo, outputType);
538 } else {
539 this->printErr("Unsupported data type for output[" + std::to_string(i)
540 + "]: " + outputType);
541 return 0;
542 }
543 }
544
545 this->printMsg(
546 "Created '"
547 + std::string(outputPortInfo->Get(vtkDataObject::DATA_TYPE_NAME()))
548 + "' at output port " + std::to_string(i),
550 }
551
552 return 1;
553}
554
555#ifdef TTK_ENABLE_MPI
556
557int ttkAlgorithm::updateMPICommunicator(vtkDataSet *input) {
558 if(input == nullptr) {
559 return 0;
560 }
561 int isEmpty
562 = input->GetNumberOfCells() == 0 || input->GetNumberOfPoints() == 0;
563 int oldSize = ttk::MPIsize_;
564 int oldRank = ttk::MPIrank_;
565 MPI_Comm_split(MPI_COMM_WORLD, isEmpty, 0, &ttk::MPIcomm_);
566 MPI_Comm_rank(ttk::MPIcomm_, &ttk::MPIrank_);
567 MPI_Comm_size(ttk::MPIcomm_, &ttk::MPIsize_);
568 if(oldSize != ttk::MPIsize_) {
569 std::vector<int> newToOldRanks(ttk::MPIsize_);
570 MPI_Allgather(&oldRank, 1, MPI_INTEGER, newToOldRanks.data(), 1,
571 MPI_INTEGER, ttk::MPIcomm_);
572 std::map<int, int> oldToNewRanks;
573 for(int i = 0; i < ttk::MPIsize_; i++) {
574 oldToNewRanks[newToOldRanks[i]] = i;
575 }
576 int *vertexRankArray
577 = ttkUtils::GetPointer<int>(input->GetPointData()->GetArray("RankArray"));
578 if(vertexRankArray != nullptr) {
579 for(int i = 0; i < input->GetNumberOfPoints(); i++) {
580 vertexRankArray[i] = oldToNewRanks[vertexRankArray[i]];
581 }
582 }
583 int *cellRankArray
584 = ttkUtils::GetPointer<int>(input->GetCellData()->GetArray("RankArray"));
585 if(cellRankArray != nullptr) {
586 for(int i = 0; i < input->GetNumberOfCells(); i++) {
587 cellRankArray[i] = oldToNewRanks[cellRankArray[i]];
588 }
589 }
590 }
592 return isEmpty;
593}
594
596 ttk::SimplexId simplexNumber,
597 unsigned char *ghost,
598 int *rankArray) {
599 ttk::SimplexId ghostNumber = 0;
600 if(rankArray != nullptr) {
601#ifdef TTK_ENABLE_OPENMP
602#pragma omp parallel for reduction(+ : ghostNumber)
603#endif // TTK_ENABLE_OPENMP
604 for(ttk::SimplexId i = 0; i < simplexNumber; i++) {
605 if(rankArray[i] != ttk::MPIrank_) {
606 ghostNumber++;
607 }
608 }
609 } else {
610 if(ghost != nullptr) {
611#ifdef TTK_ENABLE_OPENMP
612#pragma omp parallel for reduction(+ : ghostNumber)
613#endif // TTK_ENABLE_OPENMP
614 for(ttk::SimplexId i = 0; i < simplexNumber; i++) {
615 if(ghost[i] == 1) {
616 ghostNumber++;
617 }
618 }
619 }
620 }
621
622 ttk::SimplexId realSimplexNumber = simplexNumber - ghostNumber;
623 auto minmax = std::minmax_element(globalIds, globalIds + simplexNumber);
624 ttk::LongSimplexId min = globalIds[minmax.first - globalIds];
625 ttk::LongSimplexId max = globalIds[minmax.second - globalIds];
626 ttk::SimplexId globalSimplexNumber;
627 ttk::LongSimplexId globalMin;
628 ttk::LongSimplexId globalMax;
629 MPI_Allreduce(&realSimplexNumber, &globalSimplexNumber, 1,
630 ttk::getMPIType(realSimplexNumber), MPI_SUM, ttk::MPIcomm_);
631 MPI_Allreduce(
632 &min, &globalMin, 1, ttk::getMPIType(min), MPI_MIN, ttk::MPIcomm_);
633 MPI_Allreduce(
634 &max, &globalMax, 1, ttk::getMPIType(max), MPI_MAX, ttk::MPIcomm_);
635
636 return (globalSimplexNumber == globalMax + 1 && globalMin == 0);
637};
638
640 vtkDataSet *input,
641 std::unordered_map<ttk::SimplexId, ttk::SimplexId> &vertGtoL,
642 std::vector<int> &neighborRanks,
643 std::map<int, int> &neighborsToId) {
644
645 ttk::Identifiers identifiers;
646
647 vtkNew<vtkIdTypeArray> vtkVertexIdentifiers{};
648
649 vtkNew<vtkIdTypeArray> vtkCellIdentifiers{};
650 vtkVertexIdentifiers->SetName("GlobalPointIds");
651 vtkVertexIdentifiers->SetNumberOfComponents(1);
652 vtkVertexIdentifiers->SetNumberOfTuples(input->GetNumberOfPoints());
653 vtkVertexIdentifiers->Fill(-1);
654
655 identifiers.setVertexIdentifiers(
656 ttkUtils::GetPointer<ttk::LongSimplexId>(vtkVertexIdentifiers));
657
658 vtkCellIdentifiers->SetName("GlobalCellIds");
659 vtkCellIdentifiers->SetNumberOfComponents(1);
660 vtkCellIdentifiers->SetNumberOfTuples(input->GetNumberOfCells());
661 vtkCellIdentifiers->Fill(-1);
662
663 identifiers.setCellIdentifiers(
664 ttkUtils::GetPointer<ttk::LongSimplexId>(vtkCellIdentifiers));
665
666 int vertexNumber = input->GetNumberOfPoints();
667 identifiers.setVertexNumber(vertexNumber);
668 int cellNumber = input->GetNumberOfCells();
669 identifiers.setCellNumber(cellNumber);
670 int status = 0;
671
672 double *boundingBox = input->GetBounds();
673 identifiers.setBounds(boundingBox);
674 identifiers.initializeNeighbors(boundingBox, neighborRanks, neighborsToId);
675 if(ttk::isRunningWithMPI()) {
676 switch(input->GetDataObjectType()) {
677 case VTK_UNSTRUCTURED_GRID:
678 case VTK_POLY_DATA: {
679
680 identifiers.setOutdatedGlobalPointIds(
682 input->GetPointData()->GetGlobalIds()));
683 identifiers.setOutdatedGlobalCellIds(
685 input->GetCellData()->GetGlobalIds()));
686 identifiers.setVertexRankArray(ttkUtils::GetPointer<int>(
687 input->GetPointData()->GetArray("RankArray")));
688 int *cellRankArray = ttkUtils::GetPointer<int>(
689 input->GetCellData()->GetArray("RankArray"));
690 identifiers.setCellRankArray(cellRankArray);
691 identifiers.setVertGhost(ttkUtils::GetPointer<unsigned char>(
692 input->GetPointData()->GetArray("vtkGhostType")));
693 unsigned char *cellGhost = ttkUtils::GetPointer<unsigned char>(
694 input->GetCellData()->GetArray("vtkGhostType"));
695 identifiers.setCellGhost(cellGhost);
696 vtkPointSet *pointSet = vtkPointSet::SafeDownCast(input);
697 identifiers.setPointSet(static_cast<float *>(
698 ttkUtils::GetVoidPointer(pointSet->GetPoints())));
699 vtkCellArray *cells = nullptr;
700 switch(input->GetDataObjectType()) {
701 case VTK_UNSTRUCTURED_GRID: {
702 auto dataSetAsUG = vtkUnstructuredGrid::SafeDownCast(input);
703 cells = dataSetAsUG->GetCells();
704 break;
705 }
706 case VTK_POLY_DATA: {
707 auto dataSetAsPD = vtkPolyData::SafeDownCast(input);
708 cells
709 = dataSetAsPD->GetNumberOfPolys() > 0 ? dataSetAsPD->GetPolys()
710 : dataSetAsPD->GetNumberOfLines() > 0 ? dataSetAsPD->GetLines()
711 : dataSetAsPD->GetVerts();
712 break;
713 }
714 default: {
715 this->printErr("Unable to get cells for `"
716 + std::string(input->GetClassName()) + "`");
717 }
718 }
719 if(cells == nullptr) {
720 return 0;
721 }
722 if(!cells->IsStorage64Bit()) {
723 if(cells->CanConvertTo64BitStorage()) {
724 this->printWrn("Converting the cell array to 64-bit storage");
725 bool success = cells->ConvertTo64BitStorage();
726 if(!success) {
727 this->printErr(
728 "Error converting the provided cell array to 64-bit storage");
729 return -1;
730 }
731 } else {
732 this->printErr(
733 "Cannot convert the provided cell array to 64-bit storage");
734 return -1;
735 }
736 }
737
738 identifiers.setConnectivity(ttkUtils::GetPointer<ttk::LongSimplexId>(
739 cells->GetConnectivityArray()));
740
741 std::vector<std::vector<ttk::SimplexId>> pointsToCells(vertexNumber);
742 vtkIdList *cellList = vtkIdList::New();
743 if(cellRankArray != nullptr) {
744 for(ttk::SimplexId i = 0; i < vertexNumber; i++) {
745 input->GetPointCells(i, cellList);
746 for(int j = 0; j < cellList->GetNumberOfIds(); j++) {
747 if(cellRankArray[cellList->GetId(j)] == ttk::MPIrank_) {
748 pointsToCells[i].push_back(cellList->GetId(j));
749 }
750 }
751 }
752 } else {
753 for(ttk::SimplexId i = 0; i < vertexNumber; i++) {
754 input->GetPointCells(i, cellList);
755 for(int j = 0; j < cellList->GetNumberOfIds(); j++) {
756 if(cellGhost[cellList->GetId(j)] == 0) {
757 pointsToCells[i].push_back(cellList->GetId(j));
758 }
759 }
760 }
761 }
762 identifiers.setPointsToCells(pointsToCells);
763
764 identifiers.initializeMPITypes();
765 identifiers.setVertGtoL(&vertGtoL);
766 vtkIdList *pointCell = vtkIdList::New();
767 input->GetCellPoints(0, pointCell);
768 int nbPoints = pointCell->GetNumberOfIds();
769 identifiers.setDomainDimension(nbPoints - 1);
770 identifiers.buildKDTree();
771 status = identifiers.executePolyData();
772 break;
773 }
774 case VTK_IMAGE_DATA: {
775 vtkImageData *data = vtkImageData::SafeDownCast(input);
776 identifiers.setDims(data->GetDimensions());
777 identifiers.setSpacing(data->GetSpacing());
778 status = identifiers.executeImageData();
779 break;
780 }
781 default: {
782 this->printErr("Unable to triangulate `"
783 + std::string(input->GetClassName()) + "`");
784 }
785 }
786 } else {
787 status = identifiers.executeSequential();
788 }
789
790 if(status < 1) {
791 printErr("Global identifier generation failed");
792 return -1;
793 }
794
795 // Add VTK objects to the data set
796
797 input->GetPointData()->SetGlobalIds(vtkVertexIdentifiers);
798 input->GetCellData()->SetGlobalIds(vtkCellIdentifiers);
799 return 0;
800}
801
802void ttkAlgorithm::MPIGhostPipelinePreconditioning(vtkDataSet *input) {
803
804 vtkNew<vtkGhostCellsGenerator> generator;
805 if(ttk::isRunningWithMPI()
806 && (!input->HasAnyGhostCells()
807 && ((input->GetPointData()->GetArray("RankArray") == nullptr)
808 || (input->GetCellData()->GetArray("RankArray") == nullptr)))) {
809 generator->SetInputData(input);
810 generator->BuildIfRequiredOff();
811 generator->SetNumberOfGhostLayers(1);
812 generator->Update();
813 input->ShallowCopy(generator->GetOutputDataObject(0));
814 input->GetPointData()->AddArray(
815 generator->GetOutputDataObject(0)->GetGhostArray(0));
816 input->GetCellData()->AddArray(
817 generator->GetOutputDataObject(0)->GetGhostArray(1));
818 }
819}
820
822 vtkDataSet *input,
823 std::vector<int> &neighbors,
824 std::map<int, int> &neighToId,
825 ttk::Triangulation *triangulation) {
826
827 ttk::SimplexId vertexNumber = input->GetNumberOfPoints();
828 ttk::SimplexId cellNumber = input->GetNumberOfCells();
829
830 if((input->GetDataObjectType() == VTK_POLY_DATA
831 || input->GetDataObjectType() == VTK_UNSTRUCTURED_GRID)) {
832
833 if((ttk::hasInitializedMPI()) && (ttk::isRunningWithMPI())) {
835 printWrn("The distribution by VTK of Unstructured");
836 printWrn("Grids and Poly Data has been reported");
837 printWrn("to be affected by bugs (at least up");
838 printWrn("to ParaView 5.10.1).");
839
840 if((input->GetCellData()->GetGlobalIds() == nullptr)
841 || (input->GetPointData()->GetGlobalIds() == nullptr)) {
842
843 printWrn("=> Global identifiers may be incorrect.");
844 }
845 if((input->GetPointData()->GetArray("RankArray") == nullptr)
846 || (input->GetCellData()->GetArray("RankArray") == nullptr)) {
847 printWrn("=> Rank arrays may be incorrect.");
848 }
850 }
851 }
852
853 // Get the neighbor ranks
854 std::vector<int> &neighborRanks{
855 triangulation != nullptr ? triangulation->getNeighborRanks() : neighbors};
856 std::map<int, int> &neighborsToId{
857 triangulation != nullptr ? triangulation->getNeighborsToId() : neighToId};
858
859 double *boundingBox = input->GetBounds();
860 if(triangulation != nullptr) {
861 triangulation->createMetaGrid(boundingBox);
862 }
863
864 if(neighborRanks.empty()) {
865 ttk::preconditionNeighborsUsingBoundingBox(
866 boundingBox, neighborRanks, neighborsToId);
867 }
868
869 // Checks if global ids are valid
871 input->GetPointData()->GetGlobalIds());
873 input->GetCellData()->GetGlobalIds());
874
875 bool pointValidity{false};
876 bool cellValidity{false};
877 if((triangulation != nullptr
878 && (triangulation->getType() == ttk::Triangulation::Type::EXPLICIT
879 || triangulation->getType() == ttk::Triangulation::Type::COMPACT))
880 || triangulation == nullptr) {
881 if(globalPointIds != nullptr) {
882 unsigned char *ghostPoints = ttkUtils::GetPointer<unsigned char>(
883 input->GetPointData()->GetArray("vtkGhostType"));
884 int *vertexRankArray = ttkUtils::GetPointer<int>(
885 input->GetPointData()->GetArray("RankArray"));
886 pointValidity = checkGlobalIdValidity(
887 globalPointIds, vertexNumber, ghostPoints, vertexRankArray);
888 }
889 if(pointValidity && globalCellIds != nullptr) {
890
891 unsigned char *ghostCells = ttkUtils::GetPointer<unsigned char>(
892 input->GetCellData()->GetArray("vtkGhostType"));
893 int *cellRankArray = ttkUtils::GetPointer<int>(
894 input->GetCellData()->GetArray("RankArray"));
895 cellValidity = checkGlobalIdValidity(
896 globalCellIds, cellNumber, ghostCells, cellRankArray);
897 }
898 } else {
899 pointValidity = true;
900 cellValidity = true;
901 }
902
903 // If the global ids are not valid, they are computed again
904 if(!pointValidity || !cellValidity) {
905 if(triangulation != nullptr) {
906 if(triangulation->getType() == ttk::Triangulation::Type::EXPLICIT
907 || triangulation->getType() == ttk::Triangulation::Type::COMPACT) {
908 this->GenerateGlobalIds(input, triangulation->getVertexGlobalIdMap(),
909 neighborRanks, neighborsToId);
910 }
911 } else {
912 std::unordered_map<ttk::SimplexId, ttk::SimplexId> vertGtoL{};
913 this->GenerateGlobalIds(input, vertGtoL, neighborRanks, neighborsToId);
914 }
915 }
916}
917
919 ttk::Triangulation *triangulation, vtkDataSet *input) {
920
921 const auto pd{input->GetPointData()};
922 if(pd == nullptr) {
923 triangulation->printWrn("No point data on input object");
924 } else {
925 // provide "GlobalPointIds" & "vtkGhostType" point data arrays
926 // to the triangulation
927 triangulation->setVertsGlobalIds(
928 ttkUtils::GetPointer<ttk::LongSimplexId>(pd->GetGlobalIds()));
929 triangulation->setVertexGhostArray(
930 ttkUtils::GetPointer<unsigned char>(pd->GetArray("vtkGhostType")));
931 int *vertexRankArray = ttkUtils::GetPointer<int>(pd->GetArray("RankArray"));
932 if(vertexRankArray != nullptr) {
933 triangulation->setVertexRankArray(vertexRankArray);
934 }
935 triangulation->preconditionDistributedVertices();
936 }
937
938 const auto cd{input->GetCellData()};
939 if(cd == nullptr) {
940 triangulation->printWrn("No cell data on input object");
941 } else {
942 // provide "GlobalCellIds" & "vtkGhostType" cell data arrays to
943 // the triangulation
944 triangulation->setCellsGlobalIds(
945 ttkUtils::GetPointer<ttk::LongSimplexId>(cd->GetGlobalIds()));
946 triangulation->setCellGhostArray(
947 ttkUtils::GetPointer<unsigned char>(cd->GetArray("vtkGhostType")));
948 int *cellRankArray = ttkUtils::GetPointer<int>(cd->GetArray("RankArray"));
949 if(cellRankArray != nullptr) {
950 triangulation->setCellRankArray(cellRankArray);
951 }
952 triangulation->preconditionDistributedCells();
953 }
954}
955
956#endif // TTK_ENABLE_MPI
957
958//==============================================================================
959int ttkAlgorithm::ProcessRequest(vtkInformation *request,
960 vtkInformationVector **inputVector,
961 vtkInformationVector *outputVector) {
962 // 1. Pass
963 if(request->Has(vtkCompositeDataPipeline::REQUEST_DATA_OBJECT())) {
964 this->printMsg(
965 "Processing REQUEST_DATA_OBJECT", ttk::debug::Priority::VERBOSE);
966 return this->RequestDataObject(request, inputVector, outputVector);
967 }
968
969 // 2. Pass
970 if(request->Has(vtkCompositeDataPipeline::REQUEST_INFORMATION())) {
971 this->printMsg(
972 "Processing REQUEST_INFORMATION", ttk::debug::Priority::VERBOSE);
973 return this->RequestInformation(request, inputVector, outputVector);
974 }
975
976 // 3. Pass
977 if(request->Has(vtkCompositeDataPipeline::REQUEST_UPDATE_TIME())) {
978 this->printMsg(
979 "Processing REQUEST_UPDATE_TIME", ttk::debug::Priority::VERBOSE);
980 return this->RequestUpdateTime(request, inputVector, outputVector);
981 }
982
983 // 4. Pass
984 if(request->Has(
985 vtkCompositeDataPipeline::REQUEST_TIME_DEPENDENT_INFORMATION())) {
986 this->printMsg("Processing REQUEST_TIME_DEPENDENT_INFORMATION",
989 request, inputVector, outputVector);
990 }
991
992 // 5. Pass
993 if(request->Has(vtkCompositeDataPipeline::REQUEST_UPDATE_EXTENT())) {
994 this->printMsg(
995 "Processing REQUEST_UPDATE_EXTENT", ttk::debug::Priority::VERBOSE);
996 return this->RequestUpdateExtent(request, inputVector, outputVector);
997 }
998
999 // 6. Pass
1000 if(request->Has(vtkCompositeDataPipeline::REQUEST_DATA_NOT_GENERATED())) {
1001 this->printMsg(
1002 "Processing REQUEST_DATA_NOT_GENERATED", ttk::debug::Priority::VERBOSE);
1003 return this->RequestDataNotGenerated(request, inputVector, outputVector);
1004 }
1005
1006 // 7. Pass
1007 if(request->Has(vtkCompositeDataPipeline::REQUEST_DATA())) {
1008 this->printMsg("Processing REQUEST_DATA", ttk::debug::Priority::VERBOSE);
1010#ifdef TTK_ENABLE_MPI
1011 if(ttk::hasInitializedMPI() && inputVector != nullptr) {
1012 if(this->updateMPICommunicator(vtkDataSet::GetData(inputVector[0], 0))) {
1013 return 1;
1014 };
1015 }
1016#endif // TTK_ENABLE_MPI
1017 return this->RequestData(request, inputVector, outputVector);
1018 }
1019
1020 this->printErr("Unsupported pipeline pass:");
1021 request->Print(cout);
1022
1023 return 0;
1024}
#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.
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))
~ttkAlgorithm() override
virtual int RequestDataNotGenerated(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
float CompactTriangulationCacheSize
virtual int RequestData(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
void MPIGhostPipelinePreconditioning(vtkDataSet *input)
virtual int RequestInformation(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
int ProcessRequest(vtkInformation *request, vtkInformationVector **inputVectors, vtkInformationVector *outputVector) override
int GenerateGlobalIds(vtkDataSet *input, std::unordered_map< ttk::SimplexId, ttk::SimplexId > &vertGtoL, std::vector< int > &neighborRanks, std::map< int, int > &neighborsToId)
vtkDataArray * checkForGlobalAndComputeOrderArray(vtkDataSet *const inputData, vtkDataArray *scalarArray, const int scalarArrayIdx, const bool getGlobalOrder, vtkDataArray *orderArray, ttk::Triangulation *triangulation, const bool enforceOrderArrayIdx)
virtual int RequestDataObject(vtkInformation *request, vtkInformationVector **inputVectors, vtkInformationVector *outputVector)
virtual int RequestUpdateTimeDependentInformation(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
ttk::Triangulation * GetTriangulation(vtkDataSet *dataSet)
virtual int RequestUpdateExtent(vtkInformation *ttkNotUsed(request), vtkInformationVector **ttkNotUsed(inputVectors), vtkInformationVector *ttkNotUsed(outputVector))
void MPITriangulationPreconditioning(ttk::Triangulation *triangulation, vtkDataSet *input)
vtkDataSet * GetOutput()
vtkDataArray * GetOrderArray(vtkDataSet *const inputData, const int scalarArrayIdx, ttk::Triangulation *triangulation, const bool getGlobalOrder=false, const int orderArrayIdx=0, const bool enforceOrderArrayIdx=false)
void MPIPipelinePreconditioning(vtkDataSet *input, std::vector< int > &neighbors, std::map< int, int > &neighToId, ttk::Triangulation *triangulation=nullptr)
int FillOutputPortInformation(int ttkNotUsed(port), vtkInformation *ttkNotUsed(info)) override
vtkDataArray * ComputeOrderArray(vtkDataSet *const inputData, vtkDataArray *scalarArray, const int scalarArrayIdx, const bool getGlobalOrder, vtkDataArray *oldOrderArray, ttk::Triangulation *triangulation)
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:228
static DT * GetPointer(vtkDataArray *array, vtkIdType start=0)
Definition ttkUtils.h:59
int preconditionTriangulation(AbstractTriangulation *triangulation)
int processScalarArray(const triangulationType *triangulation, ttk::SimplexId *orderArray, const DT *scalarArray, const size_t nVerts) const
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 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.
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 ...
AbstractTriangulation * getData()
Triangulation::Type getType() const
FiltratedEdge max(const FiltratedEdge &a, const FiltratedEdge &b)
COMMON_EXPORTS int MPIsize_
Definition BaseClass.cpp:10
int SimplexId
Identifier type for simplices of any dimension.
Definition DataTypes.h:22
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
vtkStandardNewMacro(ttkAlgorithm)
vtkInformationKeyMacro(ttkAlgorithm, SAME_DATA_TYPE_AS_INPUT_PORT, Integer)
int prepOutput(vtkInformation *info, const std::string &className)
#define ttkTypeMacroAT(group0, group1, call)
Definition ttkMacros.h:272
printMsg(debug::output::BOLD+" | | | | | . \\ | | (__| | / __/| |_| / __/| (_) |"+debug::output::ENDCOLOR, debug::Priority::PERFORMANCE, debug::LineMode::NEW, stream)