1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
// SPDX-License-Identifier: BSD-3-Clause
#include "vtkBoundingBox.h"
#include "vtkDistributedPointCloudFilter.h"
#include "vtkDoubleArray.h"
#include "vtkGenerateIds.h"
#include "vtkGenerateProcessIds.h"
#include "vtkMPICommunicator.h"
#include "vtkMPIController.h"
#include "vtkMinimalStandardRandomSequence.h"
#include "vtkNew.h"
#include "vtkPointData.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkStringArray.h"
#ifdef DEBUG_ON
#include "vtkXMLPPolyDataWriter.h"
#endif
#include <sstream>
int TestDistributedPointCloudFilter(int argc, char* argv[])
{
vtkNew<vtkMPIController> controller;
controller->Initialize(&argc, &argv, 0);
assert("pre: Controller should not be nullptr" && (controller != nullptr));
vtkMultiProcessController::SetGlobalController(controller);
const int rank = controller->GetLocalProcessId();
const int numberOfProcessors = controller->GetNumberOfProcesses();
assert("pre: NumberOfProcessors >= 1" && (numberOfProcessors >= 1));
assert("pre: Rank is out-of-bounds" && (rank >= 0));
const int finalNumberOfPointsPerRank = 40;
const int totalNumberOfPoints = numberOfProcessors * finalNumberOfPointsPerRank;
const int initialNumberOfPoints = totalNumberOfPoints / (numberOfProcessors > 1 ? 2 : 1);
vtkNew<vtkPolyData> inputPoly;
// Create random set of points on the two first ranks only
if (rank == 0 || rank == 1)
{
vtkNew<vtkMinimalStandardRandomSequence> random;
random->Initialize(rank);
vtkNew<vtkPoints> points;
points->SetNumberOfPoints(initialNumberOfPoints);
inputPoly->SetPoints(points);
vtkNew<vtkDoubleArray> data;
data->SetNumberOfValues(initialNumberOfPoints);
data->SetName("ReverseOrder");
inputPoly->GetPointData()->AddArray(data);
vtkNew<vtkStringArray> sdata;
sdata->SetNumberOfValues(initialNumberOfPoints);
sdata->SetName("RankString");
inputPoly->GetPointData()->AddArray(sdata);
std::stringstream ss;
ss << "Rank_" << rank;
for (vtkIdType i = 0; i < initialNumberOfPoints; i++)
{
double coords[3];
coords[0] = random->GetValue();
random->Next();
coords[1] = random->GetValue();
random->Next();
coords[2] = random->GetValue();
random->Next();
points->SetPoint(i, coords);
data->SetValue(i, totalNumberOfPoints - i - 1);
sdata->SetValue(i, ss.str());
}
}
// attach initial ids and process ids
vtkNew<vtkGenerateIds> idFilter;
idFilter->SetInputData(inputPoly);
idFilter->SetPointIdsArrayName("OriginalId");
idFilter->SetCellIdsArrayName("OriginalId");
vtkNew<vtkGenerateProcessIds> procIdScalars;
procIdScalars->SetInputConnection(idFilter->GetOutputPort());
procIdScalars->Update();
procIdScalars->GetPolyDataOutput()->GetPointData()->GetProcessIds()->SetName(
"OriginalProcessIds");
procIdScalars->GetPolyDataOutput()->GetPointData()->SetActiveAttribute(
-1, vtkDataSetAttributes::PROCESSIDS);
// distribute the points over the processors
vtkNew<vtkDistributedPointCloudFilter> filter;
filter->SetInputConnection(procIdScalars->GetOutputPort());
// attach new process ids
vtkNew<vtkGenerateProcessIds> outProcIdScalars;
outProcIdScalars->SetInputConnection(filter->GetOutputPort());
outProcIdScalars->Update();
vtkPolyData* outputPoly = vtkPolyData::SafeDownCast(outProcIdScalars->GetOutput());
bool error = false;
int nbOfLocallyReceivedPoints = outputPoly->GetNumberOfPoints();
if (nbOfLocallyReceivedPoints != finalNumberOfPointsPerRank)
{
cerr << "No point on the node " << rank << "\n";
// do not exit here so MPI can end correctly
error = true;
}
if (outputPoly->GetPointData()->GetNumberOfArrays() != 5)
{
cerr << "Incorrect number of point data arrays on rank " << rank << "\n";
error = true;
}
double bounds[6];
outputPoly->GetBounds(bounds);
vtkBoundingBox bbox(bounds);
if (!bbox.IsValid() || bbox.GetLength(0) == 0. || bbox.GetLength(1) == 0. ||
bbox.GetLength(2) == 0.)
{
cerr << "Incorrect bounding box of output points on rank " << rank << "\n";
error = true;
}
vtkMPICommunicator* com = vtkMPICommunicator::SafeDownCast(controller->GetCommunicator());
std::vector<int> nbOfReceivedPoints(numberOfProcessors);
com->AllGather(&nbOfLocallyReceivedPoints, nbOfReceivedPoints.data(), 1);
int totalNumberOfReceivedPoints = 0;
for (vtkIdType i = 0; i < numberOfProcessors; i++)
{
totalNumberOfReceivedPoints += nbOfReceivedPoints[i];
}
if (totalNumberOfReceivedPoints != totalNumberOfPoints)
{
cerr << "Wrong total of points: " << totalNumberOfReceivedPoints << " instead of "
<< totalNumberOfPoints << "\n";
cerr << "Rank " << rank << ":";
for (int i = 0; i < nbOfLocallyReceivedPoints; i++)
{
cout << " " << outputPoly->GetPoints()->GetPoint(i)[0];
}
cerr << endl;
error = true;
}
controller->Finalize();
return error ? EXIT_FAILURE : EXIT_SUCCESS;
}
|