Commit 620affe1 authored by Cory Quammen's avatar Cory Quammen Committed by Kitware Robot

Merge topic 'parallelize_connectivity'

2991bac0 Added documentation on parallel connectivity algorithm
c59912e6 Added parallel connectivity filter
08d60354 Fixed MPI tests specified with custom names
Acked-by: Kitware Robot's avatarKitware Robot <kwrobot@kitware.com>
Acked-by: David E. DeMarle's avatarDavid E. DeMarle <dave.demarle@kitware.com>
Merge-request: !3536
parents 3b090d7f 2991bac0
......@@ -182,7 +182,7 @@ function(vtk_add_test_mpi exename _tests)
${VTK_MPI_PRENUMPROC_FLAGS} ${VTK_MPI_NUMPROC_FLAG} ${numprocs}
${VTK_MPI_PREFLAGS}
$<TARGET_FILE:${exename}>
${name}
${test_file}
${_D} ${_T} ${_V}
${args}
${${vtk-module}_ARGS}
......
......@@ -11,6 +11,7 @@ set(Module_SRCS
vtkExtractUnstructuredGridPiece.cxx
vtkExtractUserDefinedPiece.cxx
vtkPCellDataToPointData.cxx
vtkPConnectivityFilter.cxx
vtkPExtractArraysOverTime.cxx
vtkPeriodicFilter.cxx
vtkPKdTree.cxx
......
......@@ -17,6 +17,12 @@ vtk_add_test_mpi(${vtk-module}CxxTests-MPI no_data_tests
ParallelResampling.cxx
UnitTestPMaskPoints.cxx
)
set(${vtk-module}CxxTests-MPI_NUMPROCS 1)
vtk_add_test_mpi(${vtk-module}CxxTests-MPI data_tests_1_proc
ParallelConnectivity1,ParallelConnectivity.cxx,TESTING_DATA,NO_VALID
)
# We want 4 processes to test the vtkAggregateDataSetFilter
# properly
set(${vtk-module}CxxTests-MPI_NUMPROCS 4)
......@@ -24,10 +30,16 @@ vtk_add_test_mpi(${vtk-module}CxxTests-MPI no_data_tests_4_procs
AggregateDataSet.cxx
)
vtk_add_test_mpi(${vtk-module}CxxTests-MPI data_tests_4_procs
ParallelConnectivity4,ParallelConnectivity.cxx,TESTING_DATA,NO_VALID
)
set(all_tests
${tests}
${data_tests_1_proc}
${no_data_tests}
${no_data_tests_4_procs}
${data_tests_4_procs}
)
vtk_test_mpi_executable(${vtk-module}CxxTests-MPI all_tests)
vtk_test_cxx_executable(${vtk-module}CxxTests testsStd)
/*=========================================================================
Program: Visualization Toolkit
Module: ParallelConnectivity.cxx
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
#include "vtkPConnectivityFilter.h"
#include "vtkContourFilter.h"
#include "vtkDataSetTriangleFilter.h"
#include "vtkDistributedDataFilter.h"
#include "vtkMPIController.h"
#include "vtkPUnstructuredGridGhostCellsGenerator.h"
#include "vtkPConnectivityFilter.h"
#include "vtkRemoveGhosts.h"
#include "vtkStructuredPoints.h"
#include "vtkStructuredPointsReader.h"
#include "vtkTestUtilities.h"
#include "vtkUnstructuredGrid.h"
#include <mpi.h>
int ParallelConnectivity(int argc, char* argv[])
{
int returnValue = EXIT_SUCCESS;
MPI_Init(&argc, &argv);
// Note that this will create a vtkMPIController if MPI
// is configured, vtkThreadedController otherwise.
vtkMPIController *contr = vtkMPIController::New();
contr->Initialize(&argc, &argv, 1);
vtkMultiProcessController::SetGlobalController(contr);
int me = contr->GetLocalProcessId();
vtkNew<vtkStructuredPointsReader> reader;
vtkDataSet* ds;
vtkSmartPointer<vtkUnstructuredGrid> ug = vtkSmartPointer<vtkUnstructuredGrid>::New();
if (me == 0)
{
char* fname =
vtkTestUtilities::ExpandDataFileName(argc, argv, "Data/ironProt.vtk");
std::cout << fname << std::endl;
reader->SetFileName(fname);
delete[] fname;
reader->Update();
ds = reader->GetOutput();
}
else
{
ds = ug;
}
vtkNew<vtkDistributedDataFilter> dd;
dd->SetInputData(ds);
dd->SetController(contr);
dd->UseMinimalMemoryOff();
dd->SetBoundaryModeToAssignToOneRegion();
vtkNew<vtkContourFilter> contour;
contour->SetInputConnection(dd->GetOutputPort());
contour->SetNumberOfContours(1);
contour->SetValue(0, 240.0);
vtkNew<vtkDataSetTriangleFilter> tetrahedralize;
tetrahedralize->SetInputConnection(contour->GetOutputPort());
vtkNew<vtkPUnstructuredGridGhostCellsGenerator> ghostCells;
ghostCells->SetController(contr);
ghostCells->SetBuildIfRequired(false);
ghostCells->SetMinimumNumberOfGhostLevels(1);
ghostCells->SetInputConnection(tetrahedralize->GetOutputPort());
vtkNew<vtkPConnectivityFilter> connectivity;
connectivity->SetInputConnection(ghostCells->GetOutputPort());
connectivity->Update();
// Remove ghost points/cells so that the cell count is the same regardless
// of the number of processes.
vtkNew<vtkRemoveGhosts> removeGhosts;
removeGhosts->SetInputConnection(connectivity->GetOutputPort());
// Check the number of regions
int numberOfRegions = connectivity->GetNumberOfExtractedRegions();
int expectedNumberOfRegions = 19;
if (numberOfRegions != expectedNumberOfRegions)
{
std::cerr << "Expected " << expectedNumberOfRegions << " regions but got "
<< numberOfRegions << std::endl;
returnValue = EXIT_FAILURE;
}
// Check the number of cells in the largest region when the extraction mode
// is set to largest region.
connectivity->SetExtractionModeToLargestRegion();
removeGhosts->Update();
int numberOfCells =
vtkPointSet::SafeDownCast(removeGhosts->GetOutput())->GetNumberOfCells();
int globalNumberOfCells = 0;
contr->AllReduce(&numberOfCells, &globalNumberOfCells, 1, vtkCommunicator::SUM_OP);
int expectedNumberOfCells = 2124;
if (globalNumberOfCells != expectedNumberOfCells)
{
std::cerr << "Expected " << expectedNumberOfCells << " cells in largest "
<< "region bug got " << globalNumberOfCells << std::endl;
returnValue = EXIT_FAILURE;
}
// Closest point region test
connectivity->SetExtractionModeToClosestPointRegion();
removeGhosts->Update();
numberOfCells =
vtkPointSet::SafeDownCast(removeGhosts->GetOutput())->GetNumberOfCells();
contr->AllReduce(&numberOfCells, &globalNumberOfCells, 1, vtkCommunicator::SUM_OP);
expectedNumberOfCells = 862; // point (0, 0, 0)
if (globalNumberOfCells != expectedNumberOfCells)
{
std::cerr << "Expected " << expectedNumberOfCells << " cells in closest "
<< "point extraction mode but got " << globalNumberOfCells << std::endl;
returnValue = EXIT_FAILURE;
}
contr->Finalize();
contr->Delete();
return returnValue;
}
......@@ -9,6 +9,7 @@ vtk_module(vtkFiltersParallel
vtkIOXML
vtkRendering${VTK_RENDERING_BACKEND}
vtkRenderingParallel
vtkFiltersParallelGeometry
vtkFiltersParallelMPI
vtkFiltersParallelImaging
vtkFiltersFlowPaths
......
This diff is collapsed.
/*=========================================================================
Program: Visualization Toolkit
Module: vtkPConnectivityFilter.h
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
All rights reserved.
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notice for more information.
=========================================================================*/
/**
* @class vtkPConnectivityFilter
* @brief Parallel version of vtkConnectivityFilter
*
* This class computes connectivity of a distributed data set in parallel.
*
* Problem
* =======
*
* Datasets are distributed among ranks in a distributed process (Figure 1).
* vtkConnectivityFilter already runs in parallel on each piece in a typical
* VTK application run with MPI, but it does not produce correct results. As
* Figure 2 shows, distributed pieces of each connected component may end up
* with different labels.
*
* ![Figure 1: Pieces in a distributed data set colored by processor
* rank.](vtkPConnectivityFilterFigure1.png)
*
* ![Figure 2: Left). Incorrect parallel labeling yields three regions instead of
* two, and contiguous regions have more than one region instead of one. Right).
* Desired correct labeling.](vtkPConnectivityFilterFigure2.png)
*
* The part missing from a fully parallel connectivity filter implementation is
* the identification of which pieces on different ranks are actually connected.
* This parallel filter provides that missing piece.
*
* Approach
* ========
*
* Run vtkConnectivityFilter on each rank’s piece and resolve the connected
* pieces afterwards. The implementation uses vtkMultiProcessController to
* communicate among processes.
*
* Input Requirements
* ==================
*
* The vtkPConnectivityFilter requires Ghost Points, which can be generated with
* the vtkPUnstructuredGridGhostCellsGenerator or vtkDistributedDataFilter.
*
* Steps in the vtkPConnectivityFilter
* -----------------------------------
*
* ### High-level steps
*
* + Run local connectivity algorithm.
*
* + Identify region connections across ranks and create a graph of these links.
*
* + Run a connected components algorithm on the graph created in the previous
* step to unify the regions across ranks.
*
* + Relabel cells and points with their “global” RegionIds.
*
* ### Low-level steps
*
* + In GenerateData(), invoke the superclass’s GenerateData() method. Make
* temporary changes to extract all connected regions - we’ll handle the
* different extraction modes at the end. Example results on 3 ranks are shown
* in Figure 3 where color indicates RegionId computed by vtkConnectivityFilter.
*
* + Check for errors in superclass GenerateData() on any rank and exit the
* algorithm if any encountered an error-indicating return code.
*
* ![Figure 3: Results after vtkConnectivityFilter superclass is called on each
* piece.](vtkPConnectivityFilterFigure3.png)
*
* + AllGather the number of connected RegionIds from each rank and AllGatherv
* the RegionIds themselves. (Optimization opportunity: We can skip the
* AllGatherv of RegionIds if they are guaranteed to be contiguous on each
* rank.)
*
* ![Figure 4: Ghost point and associated RegionId
* exchange.](vtkPConnectivityFilterFigure4.png)
*
* + Each rank gathers up ghost points and sends them to all other ranks as well
* as the RegionId assigned to each point. (Optimization opportunity: We can do
* a bounding box optimization to limit the sending of ghost points only to
* potential neighbors.)
*
* + Each rank runs through the ghost points and determines which points it owns
* using a locator object. If a point is found on the local rank, add the
* RegionId from the remote ghost point to a set associated with the local
* RegionId. This signifies that the local RegionId is connected to the remote
* RegionId associated with the ghost point (Optimization opportunity: Instead
* of using a locator object on the entire dataset piece on the rank, extract
* the surface and create a locator for the surface instead).
*
* + Each rank gathers the local-RegionId-to-remote-RegionId links from all
* other ranks.
*
* + From these links, each rank generates a graph structure of the global
* links. The graph structure is identical on all ranks. (Optimization
* opportunity: To reduce communication, this link exchange could be avoided and
* the graph could be made distributed. This is just more complicated to
* program, however).
*
* ![Figure 5: Connected region graph depicted by black line
* segments.](vtkPConnectivityFilterFigure5.png)
*
* + Run a connected components algorithm that relabels the RegionIds, yielding
* the full connectivity graph across ranks. Figure 6 shows an example result.
*
* + Relabel the remaining RegionIds by a contiguous set of RegionIds (e.g., go
* from [0, 5, 8, 9] to [0, 1, 2, 3]).
*
* ![Figure 6: Connected components of graph linking RegionIds across
* ranks.](vtkPConnectivityFilterFigure6.png)
*
* + From the RegionId graph, relabel points and cells in the output. The result
* is shown in Figure 7.
*
* ![Figure 7: Dataset relabeled with global connected
* RegionIds.](vtkPConnectivityFilterFigure7.png)
*
* + Handle ScalarConnectivy option and ExtractionMode after full region
* connectivity is determined by identifying the correct RegionId and extracting
* it by thresholding.
*
* Caveats
* =======
*
* This parallel implementation does not support a number of features that the
* vtkConnectivityFilter class supports, including:
*
* - ScalarConnectivity
* - VTK_EXTRACT_POINT_SEEDED_REGIONS extraction mode
* - VTK_EXTRACT_CELL_SEEDED_REGIONS extraction mode
* - VTK_EXTRACT_SPECIFIED_REGIONS extraction mode
*/
#ifndef vtkPConnectivityFilter_h
#define vtkPConnectivityFilter_h
#include "vtkFiltersParallelModule.h" // For export macro
#include "vtkConnectivityFilter.h"
class VTKFILTERSPARALLEL_EXPORT vtkPConnectivityFilter : public vtkConnectivityFilter
{
public:
vtkTypeMacro(vtkPConnectivityFilter,vtkConnectivityFilter);
void PrintSelf(ostream& os, vtkIndent indent) override;
static vtkPConnectivityFilter *New();
protected:
vtkPConnectivityFilter();
~vtkPConnectivityFilter() override;
int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *) override;
private:
vtkPConnectivityFilter(const vtkPConnectivityFilter&) = delete;
void operator=(const vtkPConnectivityFilter&) = delete;
};
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment