From: Anthony Geay Date: Mon, 4 Jan 2016 07:31:30 +0000 (+0100) Subject: Addition of GhostCellsGenerator filter to avoid artefacts linked to // visualizations. X-Git-Tag: V7_8_0a1~7 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=2432a01b717bbf1aa27c9b9abeac727964601f3d;p=modules%2Fparavis.git Addition of GhostCellsGenerator filter to avoid artefacts linked to // visualizations. --- diff --git a/src/Plugins/CMakeLists.txt b/src/Plugins/CMakeLists.txt index ff1b52b3..8fca10f7 100755 --- a/src/Plugins/CMakeLists.txt +++ b/src/Plugins/CMakeLists.txt @@ -23,6 +23,7 @@ SET(_subdirs MEDReader # TableReader ElevationSurface + GhostCellsGenerator ScaleVector EllipseBuilder DifferenceTimesteps diff --git a/src/Plugins/GhostCellsGenerator/CMakeLists.txt b/src/Plugins/GhostCellsGenerator/CMakeLists.txt new file mode 100644 index 00000000..d66a9453 --- /dev/null +++ b/src/Plugins/GhostCellsGenerator/CMakeLists.txt @@ -0,0 +1,23 @@ +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + +PROJECT(GhostCellsGenerator) + +FIND_PACKAGE(ParaView REQUIRED) +INCLUDE(${PARAVIEW_USE_FILE}) + +IF(PARAVIEW_USE_MPI) +# Necessary while this class is not in VTK + SET(SOURCES vtkPUnstructuredGridGhostCellsGenerator.cxx) +ENDIF(PARAVIEW_USE_MPI) + +ADD_PARAVIEW_PLUGIN(GhostCellsGenerator "1.0" + SERVER_MANAGER_SOURCES vtkPVUnstructuredGridGhostCellsGenerator.cxx + SERVER_MANAGER_XML GhostCellsGenerator.xml + SOURCES ${SOURCES} + REQUIRED_ON_SERVER) + +INSTALL( TARGETS GhostCellsGenerator + RUNTIME DESTINATION lib/paraview + LIBRARY DESTINATION lib/paraview + ARCHIVE DESTINATION lib/paraview + ) diff --git a/src/Plugins/GhostCellsGenerator/GhostCellsGenerator.xml b/src/Plugins/GhostCellsGenerator/GhostCellsGenerator.xml new file mode 100644 index 00000000..f6990b55 --- /dev/null +++ b/src/Plugins/GhostCellsGenerator/GhostCellsGenerator.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + This property specifies the input to the ghost cells generator. + + + Specify if the filter must take benefit of global point ids if they exist or if + point coordinates should be used instead. + + + + This property provides a name for the input array + containing the global point ids if the GlobalIds array of the point data if not set. + + + + + + + + + diff --git a/src/Plugins/GhostCellsGenerator/vtkPUnstructuredGridGhostCellsGenerator.cxx b/src/Plugins/GhostCellsGenerator/vtkPUnstructuredGridGhostCellsGenerator.cxx new file mode 100644 index 00000000..7cfcf9e2 --- /dev/null +++ b/src/Plugins/GhostCellsGenerator/vtkPUnstructuredGridGhostCellsGenerator.cxx @@ -0,0 +1,581 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkPUnstructuredGridGhostCellsGenerator.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 "vtkPUnstructuredGridGhostCellsGenerator.h" + +#include "vtkCellArray.h" +#include "vtkCharArray.h" +#include "vtkDataSetSurfaceFilter.h" +#include "vtkExtractCells.h" +#include "vtkIdList.h" +#include "vtkIdTypeArray.h" +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkMergeCells.h" +#include "vtkMergePoints.h" +#include "vtkMPICommunicator.h" +#include "vtkMultiProcessController.h" +#include "vtkNew.h" +#include "vtkObjectFactory.h" +#include "vtkPointData.h" +#include "vtkPoints.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkUnstructuredGrid.h" + +#include +#include +#include + +//---------------------------------------------------------------------------- +// Helpers +namespace +{ +template +bool AllGatherV(vtkMultiProcessController* controller, + const T* localV, + vtkIdType localSize, + std::vector& globalV, + std::vector& sizes, + std::vector& offsets) +{ + int nbOfRanks = controller->GetNumberOfProcesses(); + sizes.resize(nbOfRanks); + int ret = controller->AllGather(&localSize, &sizes[0], 1); + if (ret == 0) + { + vtkErrorWithObjectMacro(controller, << "Communication error!"); + return false; + } + vtkIdType count = 0; + offsets.resize(nbOfRanks); + for (int i = 0; i < nbOfRanks; i++) + { + offsets[i] = count; + count += sizes[i]; + } + globalV.resize(count); + if (count > 0) + { + controller->AllGatherV(localSize > 0 ? localV : 0, + &globalV[0], localSize, &sizes[0], &offsets[0]); + } + return true; +} +} + +//---------------------------------------------------------------------------- +// Internal data structures + +// Class to hold asynchronous communication information +class CommDataInfo +{ +public: + CommDataInfo() : SendLen(-1), RecvLen(-1), CommStep(0) + { + this->SendBuffer = vtkCharArray::New(); + this->RecvBuffer = vtkCharArray::New(); + } + + CommDataInfo(const CommDataInfo& c) + { + *this = c; + if (this->SendBuffer) { this->SendBuffer->Register(0); } + if (this->RecvBuffer) { this->RecvBuffer->Register(0); } + } + + ~CommDataInfo() + { + if (this->SendBuffer) { this->SendBuffer->Delete(); } + if (this->RecvBuffer) { this->RecvBuffer->Delete(); } + } + + vtkMPICommunicator::Request SendReqs[2]; + vtkMPICommunicator::Request RecvReqs[2]; + vtkCharArray *SendBuffer; + vtkCharArray *RecvBuffer; + vtkIdType SendLen; + vtkIdType RecvLen; + int CommStep; +}; + +// Communication arrays +struct vtkPUnstructuredGridGhostCellsGenerator::vtkInternals +{ + // For global ids + std::map GlobalToLocalPointIdMap; + std::vector AllGlobalIdsOfSurfacePoints; + + // For point coordinates + vtkNew LocalPoints; + std::vector LocalPointsMap; + std::vector AllPointsOfSurfacePoints; + + std::vector AllSizes; + std::vector AllOffsets; + std::map > NeighborRanksCells; + std::map CommData; + vtkUnstructuredGridBase* Input; + + vtkDataArray* InputGlobalPointIds; + bool UseGlobalPointIds; +}; + +static const int UGGCG_SIZE_EXCHANGE_TAG = 9000; +static const int UGGCG_DATA_EXCHANGE_TAG = 9001; +static const char* UGGCG_GLOBAL_POINT_IDS = "GlobalNodeIds"; + +//---------------------------------------------------------------------------- + +vtkStandardNewMacro(vtkPUnstructuredGridGhostCellsGenerator) +vtkSetObjectImplementationMacro( + vtkPUnstructuredGridGhostCellsGenerator, Controller, vtkMultiProcessController); + +//---------------------------------------------------------------------------- +vtkPUnstructuredGridGhostCellsGenerator::vtkPUnstructuredGridGhostCellsGenerator() +{ + this->Controller = NULL; + this->SetController(vtkMultiProcessController::GetGlobalController()); + + this->Internals = NULL; + this->GlobalPointIdsArrayName = NULL; + this->UseGlobalPointIds = true; + this->SetGlobalPointIdsArrayName(UGGCG_GLOBAL_POINT_IDS); +} + +//---------------------------------------------------------------------------- +vtkPUnstructuredGridGhostCellsGenerator::~vtkPUnstructuredGridGhostCellsGenerator() +{ + this->SetController(NULL); + this->SetGlobalPointIdsArrayName(NULL); + + delete this->Internals; + this->Internals = 0; +} + +//----------------------------------------------------------------------------- +void vtkPUnstructuredGridGhostCellsGenerator::PrintSelf(ostream& os, vtkIndent indent) +{ + Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkPUnstructuredGridGhostCellsGenerator::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + // get the info objects + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + // get the input and output. Input may just have the UnstructuredGridBase + // interface, but output should be an unstructured grid. + vtkUnstructuredGridBase *input = vtkUnstructuredGridBase::SafeDownCast( + inInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); + + int ghostLevels = 1; + //ghostLevels = outInfo->Get( + // vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS()); + + if (!this->Controller) + { + this->Controller = vtkMultiProcessController::GetGlobalController(); + } + output->Reset(); + + this->NumRanks = this->Controller ? this->Controller->GetNumberOfProcesses() : 1; + this->RankId = this->Controller ? this->Controller->GetLocalProcessId() : 0; + if (ghostLevels == 0 || !this->Controller || this->NumRanks == 1) + { + // Ghost levels are not requested. Nothing to do but pass the dataset. + if (this->RankId == 0) + { + vtkWarningMacro(<< "Ghost cells not requested or not needed."); + } + output->ShallowCopy(input); + return 1; + } + + delete this->Internals; + this->Internals = new vtkPUnstructuredGridGhostCellsGenerator::vtkInternals(); + this->Internals->Input = input; + + vtkPointData *inputPD = input->GetPointData(); + this->Internals->InputGlobalPointIds = inputPD->GetGlobalIds(); + + if (!this->Internals->InputGlobalPointIds) + { + this->Internals->InputGlobalPointIds = + inputPD->GetArray(this->GlobalPointIdsArrayName); + inputPD->SetGlobalIds(this->Internals->InputGlobalPointIds); + } + + if (!this->UseGlobalPointIds) + { + this->Internals->InputGlobalPointIds = NULL; + } + + this->ExtractAndReduceSurfacePoints(); + this->UpdateProgress(0.3); + + this->ComputeSharedPoints(); + this->UpdateProgress(0.6); + + this->ExtractAndSendGhostCells(); + this->UpdateProgress(0.8); + + this->ReceiveAndMergeGhostCells(output); + this->UpdateProgress(1.0); + + output->GetInformation()->Set(vtkDataObject::DATA_NUMBER_OF_GHOST_LEVELS(), 1); + + this->Controller->Barrier(); + + delete this->Internals; + this->Internals = 0; + + return 1; +} + +//----------------------------------------------------------------------------- +// Step 1: Extract surface geometry and all reduce global ids of surface points +void vtkPUnstructuredGridGhostCellsGenerator::ExtractAndReduceSurfacePoints() +{ + // Extract boundary cells and points with the surface filter + vtkNew surfaceFilter; + surfaceFilter->SetInputData(this->Internals->Input); + surfaceFilter->PassThroughPointIdsOn(); + surfaceFilter->Update(); + + vtkPolyData* surface = surfaceFilter->GetOutput(); + vtkIdType nbSurfacePoints = surface->GetNumberOfPoints(); + vtkCellArray* surfaceCells = surface->GetPolys(); + surfaceCells->InitTraversal(); + vtkIdType npts, *pts; + + vtkIdTypeArray* surfaceOriginalPointIds = vtkIdTypeArray::SafeDownCast( + surface->GetPointData()->GetArray(surfaceFilter->GetOriginalPointIdsName())); + + if (this->Internals->InputGlobalPointIds) + { + std::vector globalIdsOfSurfacePoints; + globalIdsOfSurfacePoints.reserve(nbSurfacePoints); + + // Browse surface cells and save global and local ids of cell points + while (surfaceCells->GetNextCell(npts, pts)) + { + for (vtkIdType i = 0; i < npts; i++) + { + vtkIdType origPtId = surfaceOriginalPointIds->GetValue(pts[i]); + vtkIdType globalPtId = static_cast( + this->Internals->InputGlobalPointIds->GetTuple1(origPtId)); + + if (this->Internals->GlobalToLocalPointIdMap.find(globalPtId) == + this->Internals->GlobalToLocalPointIdMap.end()) + { + this->Internals->GlobalToLocalPointIdMap[globalPtId] = origPtId; + globalIdsOfSurfacePoints.push_back(globalPtId); + } + } + } + + // Now reduce surface point global ids on ALL ranks + ::AllGatherV(this->Controller, &globalIdsOfSurfacePoints[0], + globalIdsOfSurfacePoints.size(), + this->Internals->AllGlobalIdsOfSurfacePoints, + this->Internals->AllSizes, this->Internals->AllOffsets); + } + else + { + // We can't use global ids, so we will process point coordinates instead + vtkPoints* inputPoints = this->Internals->Input->GetPoints(); + vtkNew surfacePoints; + surfacePoints->SetDataTypeToDouble(); + surfacePoints->Allocate(nbSurfacePoints); + this->Internals->LocalPoints->InitPointInsertion( + surfacePoints.Get(), surface->GetPoints()->GetBounds()); + this->Internals->LocalPointsMap.reserve(nbSurfacePoints); + + // Browse surface cells and push point coordinates to the locator + while (surfaceCells->GetNextCell(npts, pts)) + { + for (vtkIdType i = 0; i < npts; i++) + { + vtkIdType origPtId = surfaceOriginalPointIds->GetValue(pts[i]); + double p[3]; + inputPoints->GetPoint(origPtId, p); + vtkIdType sid; + if (this->Internals->LocalPoints->InsertUniquePoint(p, sid)) + { + // New point, save the id of the original grid point id associated + // to this surface point + if (static_cast(this->Internals->LocalPointsMap.size()) <= sid) + { + this->Internals->LocalPointsMap.resize(sid + 1); + } + this->Internals->LocalPointsMap[sid] = origPtId; + } + } + } + + // Now reduce surface point coordinates on ALL ranks + ::AllGatherV(this->Controller, + (double*)surfacePoints->GetVoidPointer(0), + surfacePoints->GetNumberOfPoints() * 3, + this->Internals->AllPointsOfSurfacePoints, + this->Internals->AllSizes, this->Internals->AllOffsets); + } +} + +//--------------------------------------------------------------------------- +// Step 2: browse global ids/point coordinates of other ranks and check if some +// are duplicated locally. +// For each neighbor rank, save the ids of the cells adjacent to the surface +// points shared, those cells are the ghost cells we will send them. +void vtkPUnstructuredGridGhostCellsGenerator::ComputeSharedPoints() +{ + vtkNew cellIdsList; + for (int i = 0; i < this->NumRanks; i++) + { + if (i == this->RankId) + { + continue; + } + for (vtkIdType j = 0, idx = this->Internals->AllOffsets[i]; + j < this->Internals->AllSizes[i]; j++, idx++) + { + vtkIdType localPointId = -1; + if (this->Internals->InputGlobalPointIds) + { + // Check if this point exists locally from its global ids, if so + // get its local id. + vtkIdType gid = this->Internals->AllGlobalIdsOfSurfacePoints[idx]; + std::map::iterator iter = + this->Internals->GlobalToLocalPointIdMap.find(gid); + if (iter != this->Internals->GlobalToLocalPointIdMap.end()) + { + localPointId = iter->second; + } + } + else + { + // Check if this point exists locally from its coordinates, if so + // get its local id. + double *p = &this->Internals->AllPointsOfSurfacePoints[idx]; + localPointId = this->Internals->LocalPoints->IsInsertedPoint(p); + + if (localPointId != -1) + { + localPointId = this->Internals->LocalPointsMap[localPointId]; + } + idx += 2; // jump to next coordinates + j += 2; + } + + if (localPointId != -1) + { + // Current rank also has a copy of this global point + cellIdsList->Reset(); + // Get the cells connected to this point + this->Internals->Input->GetPointCells(localPointId, cellIdsList.Get()); + vtkIdType nbIds = cellIdsList->GetNumberOfIds(); + // Add those cells to the list of cells to send to this rank + for (vtkIdType k = 0; k < nbIds; k++) + { + this->Internals->NeighborRanksCells[i].insert(cellIdsList->GetId(k)); + } + } + } + } + + // Release memory of all reduced arrays + this->Internals->AllGlobalIdsOfSurfacePoints.resize(0); + this->Internals->AllPointsOfSurfacePoints.resize(0); + this->Internals->AllSizes.resize(0); + this->Internals->AllOffsets.resize(0); + // Now we know our neighbors and which points we have in common and the + // ghost cells to share. +} + +//----------------------------------------------------------------------------- +// Step 3: extract and send the ghost cells to the neighbor ranks +void vtkPUnstructuredGridGhostCellsGenerator::ExtractAndSendGhostCells() +{ + vtkNew cellIdsList; + vtkNew extractCells; + extractCells->SetInputData(this->Internals->Input); + std::map >::iterator iter = + this->Internals->NeighborRanksCells.begin(); + + vtkMPICommunicator* com = + vtkMPICommunicator::SafeDownCast(this->Controller->GetCommunicator()); + + // Browse all neighbor ranks and extract the cells connected to the points we share + for (; iter != this->Internals->NeighborRanksCells.end(); ++iter) + { + int toRank = iter->first; + std::set& cellsToShare = iter->second; + cellIdsList->SetNumberOfIds(cellsToShare.size()); + std::set::iterator sIter = cellsToShare.begin(); + for (vtkIdType i = 0; sIter != cellsToShare.end(); ++sIter, i++) + { + cellIdsList->SetId(i, *sIter); + } + extractCells->SetCellList(cellIdsList.Get()); + extractCells->Update(); + vtkUnstructuredGrid* extractGrid = extractCells->GetOutput(); + + // Send the extracted grid to the neighbor rank asynchronously + CommDataInfo& c = this->Internals->CommData[toRank]; + if (vtkCommunicator::MarshalDataObject(extractGrid, c.SendBuffer)) + { + c.SendLen = c.SendBuffer->GetNumberOfTuples(); + // Send data length + com->NoBlockSend(&c.SendLen, 1, toRank, UGGCG_SIZE_EXCHANGE_TAG, c.SendReqs[0]); + // Send raw data + com->NoBlockSend((char*)c.SendBuffer->GetVoidPointer(0), c.SendLen, toRank, + UGGCG_DATA_EXCHANGE_TAG, c.SendReqs[1]); + } + } +} + +//----------------------------------------------------------------------------- +// Step 4: receive the ghost cells from the neighbor ranks and merge them +// to the local grid. +void vtkPUnstructuredGridGhostCellsGenerator::ReceiveAndMergeGhostCells( + vtkUnstructuredGrid *output) +{ + // We need to compute a rough estimation of the total number of cells and + // points for vtkMergeCells + vtkIdType totalNbCells = this->Internals->Input->GetNumberOfCells(); + vtkIdType totalNbPoints = this->Internals->Input->GetNumberOfPoints(); + + vtkMPICommunicator* com = + vtkMPICommunicator::SafeDownCast(this->Controller->GetCommunicator()); + + // Browse all neighbor ranks and receive the mesh that contains cells + int nbNeighbors = static_cast(this->Internals->NeighborRanksCells.size()); + std::vector neighborGrids; + neighborGrids.reserve(nbNeighbors); + + // First create requests to receive the size of the mesh to receive + std::map >::iterator iter; + for (iter = this->Internals->NeighborRanksCells.begin(); + iter != this->Internals->NeighborRanksCells.end(); ++iter) + { + vtkIdType fromRank = iter->first; + CommDataInfo& c = this->Internals->CommData[fromRank]; + com->NoBlockReceive( + &c.RecvLen, 1, fromRank, UGGCG_SIZE_EXCHANGE_TAG, c.RecvReqs[0]); + } + + // Then, once the data length is received, create requests to receive the mesh data + int counter = 0; + while (counter != nbNeighbors) + { + for (iter = this->Internals->NeighborRanksCells.begin(); + iter != this->Internals->NeighborRanksCells.end(); ++iter) + { + vtkIdType fromRank = iter->first; + CommDataInfo& c = this->Internals->CommData[fromRank]; + if (!c.RecvReqs[0].Test() || c.CommStep != 0) + { + continue; + } + c.CommStep = 1; + c.RecvBuffer->SetNumberOfValues(c.RecvLen); + com->NoBlockReceive( + (char*)c.RecvBuffer->GetVoidPointer(0), c.RecvLen, fromRank, + UGGCG_DATA_EXCHANGE_TAG, c.RecvReqs[1]); + counter++; + } + } + + // Browse all neighbor ranks and receive the mesh that contains cells + // that are ghost cells for current rank. + counter = 0; + while (counter != nbNeighbors) + { + for (iter = this->Internals->NeighborRanksCells.begin(); + iter != this->Internals->NeighborRanksCells.end(); ++iter) + { + vtkIdType fromRank = iter->first; + CommDataInfo& c = this->Internals->CommData[fromRank]; + + if (!c.RecvReqs[1].Test() || c.CommStep != 1) + { + continue; + } + + c.CommStep = 2; + vtkUnstructuredGrid* grid = vtkUnstructuredGrid::New(); + vtkCommunicator::UnMarshalDataObject(c.RecvBuffer, grid); + c.RecvBuffer->Delete(); + c.RecvBuffer = NULL; + + // Flag the received grid elements as ghosts + grid->AllocatePointGhostArray(); + grid->AllocateCellGhostArray(); + grid->GetPointGhostArray()->FillComponent(0, 1); + grid->GetCellGhostArray()->FillComponent(0, 1); + + // Make sure the global point ids array is tagged accordingly + if (this->Internals->InputGlobalPointIds && + !grid->GetPointData()->GetGlobalIds()) + { + grid->GetPointData()->SetGlobalIds(grid->GetPointData()->GetArray( + this->Internals->InputGlobalPointIds->GetName())); + } + + totalNbCells += grid->GetNumberOfCells(); + totalNbPoints += grid->GetNumberOfPoints(); + + neighborGrids.push_back(grid); + + counter++; + } + } + + // Shallow copy the input grid and initialize the ghost arrays + vtkNew inputCopy; + inputCopy->ShallowCopy(this->Internals->Input); + inputCopy->AllocatePointGhostArray(); + inputCopy->AllocateCellGhostArray(); + + // MergeCells merge input + grids that contains ghost cells to the output grid + vtkNew mergeCells; + mergeCells->SetUnstructuredGrid(output); + mergeCells->SetTotalNumberOfCells(totalNbCells); + mergeCells->SetTotalNumberOfPoints(totalNbPoints); + mergeCells->SetTotalNumberOfDataSets( + 1 + static_cast(this->Internals->NeighborRanksCells.size())); + mergeCells->SetUseGlobalIds(this->Internals->InputGlobalPointIds != 0 ? 1 : 0); + mergeCells->SetPointMergeTolerance(0.0); + + // Merge input grid first + mergeCells->MergeDataSet(inputCopy.Get()); + + // Then merge ghost grid from neighbor rank + for (std::size_t i = 0; i < neighborGrids.size(); i++) + { + mergeCells->MergeDataSet(neighborGrids[i]); + neighborGrids[i]->Delete(); + } + + // Finalize the merged output + mergeCells->Finish(); +} diff --git a/src/Plugins/GhostCellsGenerator/vtkPUnstructuredGridGhostCellsGenerator.h b/src/Plugins/GhostCellsGenerator/vtkPUnstructuredGridGhostCellsGenerator.h new file mode 100644 index 00000000..8102d82e --- /dev/null +++ b/src/Plugins/GhostCellsGenerator/vtkPUnstructuredGridGhostCellsGenerator.h @@ -0,0 +1,104 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkPUnstructuredGridGhostCellsGenerator.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. + +=========================================================================*/ + +// .NAME vtkPUnstructuredGridGhostCellsGenerator - Builds ghost cells for a +// distributed unstructured grid dataset. +// +// .SECTION Description +// This filter generate ghost cells for distributed a unstructured grid in +// parallel - using MPI asynchronous communcations. +// The filter can take benefit of the input grid point global ids to perform. +// +// .SECTION Caveats +//
    +//
  • A step of 'all reduce' (each processor send/receive data to/from +// all other processors. +//
  • The code currently assumes one grid per rank.
  • +//
  • PointData and CellData must match across partitions/processes.
  • +//
+// +// .SECTION See Also +// vtkDistributedDataFilter vtkPUnstructuredGridGhostDataGenerator +// +// .SECTION Thanks +// This filter has been developed by Joachim Pouderoux, Kitware SAS 2015. + +#ifndef vtkPUnstructuredGridGhostCellsGenerator_h +#define vtkPUnstructuredGridGhostCellsGenerator_h + +#include "vtkUnstructuredGridAlgorithm.h" + +class vtkMultiProcessController; +class vtkUnstructuredGrid; + +class vtkPUnstructuredGridGhostCellsGenerator: + public vtkUnstructuredGridAlgorithm +{ + vtkTypeMacro(vtkPUnstructuredGridGhostCellsGenerator, vtkUnstructuredGridAlgorithm); + +public: + void PrintSelf(ostream& os, vtkIndent indent); + + static vtkPUnstructuredGridGhostCellsGenerator *New(); + + // Description: + // Set/Get the MPI multi process controller object. + void SetController(vtkMultiProcessController *c); + vtkGetObjectMacro(Controller, vtkMultiProcessController); + + // Description: + // Specify if the filter must take benefit of global point ids if they exist. + // If false, point coordinates are used. Default is TRUE. + vtkSetMacro(UseGlobalPointIds, bool); + vtkGetMacro(UseGlobalPointIds, bool); + vtkBooleanMacro(UseGlobalPointIds, bool); + + // Description: + // Specify the name of the global point ids data array if the GlobalIds + // attribute array is not set. Default is "GlobalNodeIds". + vtkSetStringMacro(GlobalPointIdsArrayName); + vtkGetStringMacro(GlobalPointIdsArrayName); + +protected: + vtkPUnstructuredGridGhostCellsGenerator(); + ~vtkPUnstructuredGridGhostCellsGenerator(); + + virtual int RequestData(vtkInformation *, vtkInformationVector **, + vtkInformationVector *); + + void ExtractAndReduceSurfacePoints(); + + void ComputeSharedPoints(); + + void ExtractAndSendGhostCells(); + + void ReceiveAndMergeGhostCells(vtkUnstructuredGrid*); + + vtkMultiProcessController *Controller; + + int NumRanks; + int RankId; + char* GlobalPointIdsArrayName; + bool UseGlobalPointIds; + +private: + struct vtkInternals; + vtkInternals* Internals; + + vtkPUnstructuredGridGhostCellsGenerator(const vtkPUnstructuredGridGhostCellsGenerator&); // Not implemented + void operator=(const vtkPUnstructuredGridGhostCellsGenerator&); // Not implemented +}; + +#endif diff --git a/src/Plugins/GhostCellsGenerator/vtkPVUnstructuredGridGhostCellsGenerator.cxx b/src/Plugins/GhostCellsGenerator/vtkPVUnstructuredGridGhostCellsGenerator.cxx new file mode 100644 index 00000000..b47aad61 --- /dev/null +++ b/src/Plugins/GhostCellsGenerator/vtkPVUnstructuredGridGhostCellsGenerator.cxx @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkPVUnstructuredGridGhostCellsGenerator.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 "vtkPVUnstructuredGridGhostCellsGenerator.h" +#include "vtkPVConfig.h" // need ParaView defines before MPI stuff + +#include "vtkInformation.h" +#include "vtkInformationVector.h" +#include "vtkMultiProcessController.h" +#include "vtkNew.h" +#include "vtkObjectFactory.h" +#include "vtkStreamingDemandDrivenPipeline.h" +#include "vtkUnstructuredGrid.h" + +#ifdef PARAVIEW_USE_MPI +# include "vtkPUnstructuredGridGhostCellsGenerator.h" +#endif + +static const char* PVUGGCG_GLOBAL_POINT_IDS = "GlobalNodeIds"; + +//---------------------------------------------------------------------------- + +vtkStandardNewMacro(vtkPVUnstructuredGridGhostCellsGenerator) +vtkSetObjectImplementationMacro( + vtkPVUnstructuredGridGhostCellsGenerator, Controller, vtkMultiProcessController); + +//---------------------------------------------------------------------------- +vtkPVUnstructuredGridGhostCellsGenerator::vtkPVUnstructuredGridGhostCellsGenerator() +{ + this->Controller = NULL; + this->SetController(vtkMultiProcessController::GetGlobalController()); + + this->GlobalPointIdsArrayName = NULL; + this->UseGlobalPointIds = true; + this->SetGlobalPointIdsArrayName(PVUGGCG_GLOBAL_POINT_IDS); +} + +//---------------------------------------------------------------------------- +vtkPVUnstructuredGridGhostCellsGenerator::~vtkPVUnstructuredGridGhostCellsGenerator() +{ + this->SetController(NULL); + this->SetGlobalPointIdsArrayName(NULL); +} + +//----------------------------------------------------------------------------- +void vtkPVUnstructuredGridGhostCellsGenerator::PrintSelf(ostream& os, vtkIndent indent) +{ + Superclass::PrintSelf(os, indent); +} + +//----------------------------------------------------------------------------- +int vtkPVUnstructuredGridGhostCellsGenerator::RequestData( + vtkInformation *vtkNotUsed(request), + vtkInformationVector **inputVector, + vtkInformationVector *outputVector) +{ + // get the info objects + vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + // get the input and output. Input may just have the UnstructuredGridBase + // interface, but output should be an unstructured grid. + vtkUnstructuredGridBase *input = vtkUnstructuredGridBase::SafeDownCast( + inInfo->Get(vtkDataObject::DATA_OBJECT())); + vtkUnstructuredGrid *output = vtkUnstructuredGrid::SafeDownCast( + outInfo->Get(vtkDataObject::DATA_OBJECT())); +#ifdef PARAVIEW_USE_MPI + vtkNew ghostGenerator; + ghostGenerator->SetInputData(input); + ghostGenerator->SetController(this->Controller); + ghostGenerator->SetUseGlobalPointIds(this->UseGlobalPointIds); + ghostGenerator->SetGlobalPointIdsArrayName(this->GlobalPointIdsArrayName); + ghostGenerator->Update(); + output->ShallowCopy(ghostGenerator->GetOutput()); +#else + output->ShallowCopy(input); +#endif + return 1; +} diff --git a/src/Plugins/GhostCellsGenerator/vtkPVUnstructuredGridGhostCellsGenerator.h b/src/Plugins/GhostCellsGenerator/vtkPVUnstructuredGridGhostCellsGenerator.h new file mode 100644 index 00000000..9ad1b20c --- /dev/null +++ b/src/Plugins/GhostCellsGenerator/vtkPVUnstructuredGridGhostCellsGenerator.h @@ -0,0 +1,91 @@ +/*========================================================================= + + Program: Visualization Toolkit + Module: vtkPVUnstructuredGridGhostCellsGenerator.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. + +=========================================================================*/ + +// .NAME vtkPVUnstructuredGridGhostCellsGenerator - Builds ghost cells for a +// distributed unstructured grid dataset. +// +// .SECTION Description +// This filter generate ghost cells for distributed a unstructured grid in +// parallel - using MPI asynchronous communcations. +// The filter can take benefit of the input grid point global ids to perform. +// +// .SECTION Caveats +//
    +//
  • A step of 'all reduce' (each processor send/receive data to/from +// all other processors. +//
  • The code currently assumes one grid per rank.
  • +//
  • PointData and CellData must match across partitions/processes.
  • +//
+// +// .SECTION See Also +// vtkDistributedDataFilter vtkPUnstructuredGridGhostDataGenerator +// +// .SECTION Thanks +// This filter has been developed by Joachim Pouderoux, Kitware SAS 2015. + +#ifndef vtkPVUnstructuredGridGhostCellsGenerator_h +#define vtkPVUnstructuredGridGhostCellsGenerator_h + +#include "vtkUnstructuredGridAlgorithm.h" + +class vtkMultiProcessController; +class vtkUnstructuredGrid; + +class vtkPVUnstructuredGridGhostCellsGenerator: + public vtkUnstructuredGridAlgorithm +{ + vtkTypeMacro(vtkPVUnstructuredGridGhostCellsGenerator, vtkUnstructuredGridAlgorithm); + +public: + void PrintSelf(ostream& os, vtkIndent indent); + + static vtkPVUnstructuredGridGhostCellsGenerator *New(); + + // Description: + // Set/Get the MPI multi process controller object. + void SetController(vtkMultiProcessController *c); + vtkGetObjectMacro(Controller, vtkMultiProcessController); + + // Description: + // Specify if the filter must take benefit of global point ids if they exist. + // If false, point coordinates are used. Default is TRUE. + vtkSetMacro(UseGlobalPointIds, bool); + vtkGetMacro(UseGlobalPointIds, bool); + vtkBooleanMacro(UseGlobalPointIds, bool); + + // Description: + // Specify the name of the global point ids data array if the GlobalIds + // attribute array is not set. Default is "GlobalNodeIds". + vtkSetStringMacro(GlobalPointIdsArrayName); + vtkGetStringMacro(GlobalPointIdsArrayName); + +protected: + vtkPVUnstructuredGridGhostCellsGenerator(); + ~vtkPVUnstructuredGridGhostCellsGenerator(); + + virtual int RequestData(vtkInformation *, vtkInformationVector **, + vtkInformationVector *); + + vtkMultiProcessController *Controller; + char* GlobalPointIdsArrayName; + bool UseGlobalPointIds; + +private: + + vtkPVUnstructuredGridGhostCellsGenerator(const vtkPVUnstructuredGridGhostCellsGenerator&); // Not implemented + void operator=(const vtkPVUnstructuredGridGhostCellsGenerator&); // Not implemented +}; + +#endif