1018 lines
36 KiB
C++
1018 lines
36 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkDIYGhostUtilities.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 vtkDIYGhostUtilities
|
|
* @brief Utilities to produce ghost cells between a collection of data sets of same type.
|
|
*
|
|
* vtkDIYGhostUtilities is a set of utilities which produce ghost cells between
|
|
* a collection of data sets of same type, using DIY.
|
|
*
|
|
* Ghosts are computed from scratch, even if parts of the input already own ghosts. In such
|
|
* instance, ghosts are treated as if they didn't exist in the input.
|
|
*
|
|
* Mixed types in the input `vtkCompositeDataSet` are supported, in the sense that ghost cells are
|
|
* only exchanged between blocks of same type. Similarly, ghosts are exchanged between blocks that
|
|
* connect.
|
|
*
|
|
* Blocks connect with different criteria depending on their types:
|
|
*
|
|
* - `vtkImageData`: Blocks connect if they share face / edge / corner, if they share same
|
|
* dimension (1D / 2D / 3D), and if they have same orientation matrix and same spacing.
|
|
* - `vtkRectilinearGrid`: Blocks connect if the x, y, and z coordinate arrays match at their
|
|
* interfaces.
|
|
* - `vtkStructuredGrid`: Blocks connect if external faces of the grids are mangled together,
|
|
* regardless of relative inner orientation. In other words, if grid 1 is spanned by (i1, j1, k1)
|
|
* indexing, and grid 2 is spanned by (i2, j2, k2) indexing, if on one face, (j1, k1) connects
|
|
* with (-i2, -j2), those 2 grids are connected and will exchange ghosts. Two grids partially
|
|
* fitting are discarded. In order for 2 grids to fit, one corner from one face of one grid needs
|
|
* to be an existing point in one face of the second grid. Additionally, every points from this
|
|
* corner on both grids need to match until the opposite corner (opposite w.r.t. each dimension)
|
|
* is reached, and this opposite corner of the grid junction needs to be a corner of either grid.
|
|
* - `vtkUnstructuredGrid`: Blocks connect if the external surface of neighboring grids match.
|
|
* To do so, only points are looked at. If at least one point matches a point in a neighboring
|
|
* grid, then they are connected. If there are no point global ids in the input, the 3D position
|
|
* of the points is used to determine if grids match, up to floating point precision in the
|
|
* coordinates. Note that integer coordinates can be used with this pipeline. If global ids are
|
|
* present in the input point data, then the pipeline will only look at matching global ids, and
|
|
* ignore point positions.
|
|
* - `vtkPolyData`: Blocks connect if the boundary edges of neighboring poly data match. The filter
|
|
* behaves the same way it does with `vtkUnstructuredGrid`. Point positions are used to match
|
|
* points if point global ids are not present, and point global ids are used instead if they are
|
|
* present.
|
|
*
|
|
* Points at the interface between 2 partitions are edited depending on the ownership of the point
|
|
* after the ghost points are generated. One can keep track of which process owns a non-ghost copy
|
|
* of the point if an array associating each point with its process id is available in the input.
|
|
*
|
|
* @note Currently, only `vtkImageData`, `vtkRectilinearGrid`, `vtkStructuredGrid`,
|
|
* `vtkUnstructuredGrid` and `vtkPolyData` are
|
|
* implemented. Unless there is determining structural data added to subclasses of those classes,
|
|
* this filter should work well on subclasses of supported types.
|
|
*
|
|
* @warning This warning only applies for `vtkUnstructuredGrid` and `vtkPolyData` inputs. If
|
|
* there are duplicate points in the outer shell of an input partition, then this filter cannot
|
|
* decide on how to connect the cells properly when generating ghosts. The same phenomenon occurs
|
|
* when the outer shell of the partition has 2 points with the same global id. In such
|
|
* circumstances, use the `vtkStaticCleanUnstructuredGrid`
|
|
* or `vtkStaticCleanPolyData` filter first in order to have a clean input.
|
|
*/
|
|
#ifndef vtkDIYGhostUtilities_h
|
|
#define vtkDIYGhostUtilities_h
|
|
|
|
#include "vtkBoundingBox.h" // For ComputeLinkMap
|
|
#include "vtkDIYExplicitAssigner.h" // For DIY assigner
|
|
#include "vtkDIYUtilities.h" // For Block
|
|
#include "vtkObject.h"
|
|
#include "vtkParallelDIYModule.h" // For export macros
|
|
#include "vtkQuaternion.h" // For vtkImageData
|
|
#include "vtkSmartPointer.h" // For vtkSmartPointer
|
|
|
|
#include <array> // For VectorType and ExtentType
|
|
#include <map> // For BlockMapType
|
|
#include <set> // For Link
|
|
#include <vector> // For LinkMap
|
|
|
|
// clang-format off
|
|
#include "vtk_diy2.h" // Third party include
|
|
#include VTK_DIY2(diy/assigner.hpp)
|
|
#include VTK_DIY2(diy/master.hpp)
|
|
#include VTK_DIY2(diy/partners/all-reduce.hpp)
|
|
// clang-format on
|
|
|
|
class vtkAbstractPointLocator;
|
|
class vtkAlgorithm;
|
|
class vtkCellArray;
|
|
class vtkDataArray;
|
|
class vtkDataSet;
|
|
class vtkFieldData;
|
|
class vtkIdList;
|
|
class vtkIdTypeArray;
|
|
class vtkImageData;
|
|
class vtkMatrix3x3;
|
|
class vtkMultiProcessController;
|
|
class vtkPoints;
|
|
class vtkPointSet;
|
|
class vtkPolyData;
|
|
class vtkRectilinearGrid;
|
|
class vtkStructuredGrid;
|
|
class vtkUnsignedCharArray;
|
|
class vtkUnstructuredGrid;
|
|
|
|
class VTKPARALLELDIY_EXPORT vtkDIYGhostUtilities : public vtkObject
|
|
{
|
|
public:
|
|
vtkTypeMacro(vtkDIYGhostUtilities, vtkObject);
|
|
void PrintSelf(ostream& os, vtkIndent indent) override;
|
|
|
|
///@{
|
|
/**
|
|
* Convenient typedefs.
|
|
*/
|
|
using VectorType = std::array<double, 3>;
|
|
using QuaternionType = vtkQuaternion<double>;
|
|
using ExtentType = std::array<int, 6>;
|
|
template <class T>
|
|
using BlockMapType = std::map<int, T>;
|
|
using Links = std::set<int>;
|
|
using LinkMap = std::vector<Links>;
|
|
///@}
|
|
|
|
/**
|
|
* This helper structure owns a typedef to the block type of `DataSetT` used with diy to generate
|
|
* ghosts. This block type is defined as DataSetTypeToBlockTypeConverter<DataSetT>::BlockType.
|
|
*/
|
|
template <class DataSetT>
|
|
struct DataSetTypeToBlockTypeConverter;
|
|
|
|
protected:
|
|
/**
|
|
* Base block structure for data sets.
|
|
*/
|
|
struct DataSetBlockStructure
|
|
{
|
|
vtkSmartPointer<vtkFieldData> GhostCellData = nullptr;
|
|
vtkSmartPointer<vtkFieldData> GhostPointData = nullptr;
|
|
};
|
|
|
|
struct DataSetInformation
|
|
{
|
|
/**
|
|
* @warning This method does not work before the link map between blocks is computed.
|
|
*/
|
|
virtual bool InputNeedsGhostsPeeledOff() const = 0;
|
|
};
|
|
|
|
/**
|
|
* Structure to inherit from for data sets having a structured grid topology.
|
|
*/
|
|
struct GridBlockStructure : public DataSetBlockStructure
|
|
{
|
|
/**
|
|
* `GridBlockStructure` constructor. It takes the extent of a neighbor block as input.
|
|
*/
|
|
GridBlockStructure(const int* extent, int dim);
|
|
|
|
/**
|
|
* Extent of neighboring block with no ghosts.
|
|
*/
|
|
ExtentType Extent = ExtentType{ 1, -1, 1, -1, 1, -1 };
|
|
|
|
/**
|
|
* Extent of neighboring block that include ghost layers, shifted to match our mapping of the
|
|
* extent in the 3D world.
|
|
*/
|
|
ExtentType ShiftedExtentWithNewGhosts;
|
|
|
|
/**
|
|
* Extent of the neighboring block, shifted to match our mapping of the extent in the 3D world.
|
|
*/
|
|
ExtentType ShiftedExtent;
|
|
|
|
ExtentType ReceivedGhostExtent = ExtentType{ 1, -1, 1, -1, 1, -1 };
|
|
|
|
/**
|
|
* Binary mask encoding the adjacency of the neighboring block w.r.t. current block.
|
|
* This mask shall be written / read using Adjacency enumeration.
|
|
*/
|
|
unsigned char AdjacencyMask;
|
|
|
|
/**
|
|
* This stores the dimension of the grid (1D, 2D, or 3D).
|
|
*/
|
|
int DataDimension;
|
|
};
|
|
|
|
/**
|
|
* Structure storing information needed by a block on it's own grid structure.
|
|
*/
|
|
struct GridInformation : public DataSetInformation
|
|
{
|
|
bool InputNeedsGhostsPeeledOff() const override { return this->Extent != this->InputExtent; }
|
|
|
|
/**
|
|
* Extent without ghost layers.
|
|
*/
|
|
ExtentType Extent = ExtentType{ 1, -1, 1, -1, 1, -1 };
|
|
|
|
/**
|
|
* Input extent without any modification.
|
|
*/
|
|
ExtentType InputExtent = ExtentType{ 1, -1, 1, -1, 1, -1 };
|
|
|
|
ExtentType ExtentGhostThickness;
|
|
};
|
|
|
|
struct ImageDataInformation : public GridInformation
|
|
{
|
|
vtkImageData* Input;
|
|
};
|
|
|
|
/**
|
|
* Block structure storing information being communicated by neighboring blocks for
|
|
* `vtkImageData`.
|
|
*/
|
|
struct ImageDataBlockStructure : public GridBlockStructure
|
|
{
|
|
///@{
|
|
/**
|
|
* Constructor taking the extent (without ghosts) of the neighboring `vtkImageData`, as well
|
|
* as well as the image's origin, spacing, and orientation.
|
|
*/
|
|
ImageDataBlockStructure(const int extent[6], int dim, const double origin[3],
|
|
const double spacing[3], const double orientationQuaternion[4]);
|
|
ImageDataBlockStructure(const int extent[6], int dim, const double origin[3],
|
|
const double spacing[3], vtkMatrix3x3* directionMatrix);
|
|
///@}
|
|
|
|
/**
|
|
* Copy constructor.
|
|
*/
|
|
ImageDataBlockStructure(vtkImageData* image, const ImageDataInformation& info);
|
|
|
|
/**
|
|
* Origin of the neighboring `vtkImageData`.
|
|
*/
|
|
VectorType Origin;
|
|
|
|
/**
|
|
* Spacing of the neighboring `vtkImageData`.
|
|
*/
|
|
VectorType Spacing;
|
|
|
|
/**
|
|
* Orientation of the neighboring `vtkImageData`.
|
|
*/
|
|
QuaternionType OrientationQuaternion;
|
|
};
|
|
|
|
struct RectilinearGridInformation : public GridInformation
|
|
{
|
|
///@{
|
|
/**
|
|
* Point coordinates without ghosts.
|
|
*/
|
|
vtkSmartPointer<vtkDataArray> XCoordinates;
|
|
vtkSmartPointer<vtkDataArray> YCoordinates;
|
|
vtkSmartPointer<vtkDataArray> ZCoordinates;
|
|
///@}
|
|
|
|
/**
|
|
* Coordinates of ghosts copied from connected neighbors.
|
|
* This array maps to extents, i.e. the first element of this array stores the coordinates of
|
|
* the left side of the grid, the second the right side of the grid, and so on.
|
|
*/
|
|
vtkSmartPointer<vtkDataArray> CoordinateGhosts[6];
|
|
|
|
vtkRectilinearGrid* Input;
|
|
};
|
|
|
|
/**
|
|
* Block structure storing information being communicated by neighboring blocks for
|
|
* `vtkRectilinearGrid`.
|
|
*/
|
|
struct RectilinearGridBlockStructure : public GridBlockStructure
|
|
{
|
|
/**
|
|
* Constructor taking the extent (without ghosts) of the neighboring `vtkRectilinearGrid`,
|
|
* as well as its point coordinates.
|
|
*/
|
|
RectilinearGridBlockStructure(const int extent[6], int dim, vtkDataArray* xCoordinates,
|
|
vtkDataArray* yCoordinates, vtkDataArray* zCoordinates);
|
|
|
|
/**
|
|
* Copy constructor.
|
|
*/
|
|
RectilinearGridBlockStructure(vtkRectilinearGrid* grid, const RectilinearGridInformation& info);
|
|
|
|
///@{
|
|
/**
|
|
* Point coordinate arrays of the rectilinear grid.
|
|
*/
|
|
vtkSmartPointer<vtkDataArray> XCoordinates;
|
|
vtkSmartPointer<vtkDataArray> YCoordinates;
|
|
vtkSmartPointer<vtkDataArray> ZCoordinates;
|
|
///@}
|
|
};
|
|
|
|
struct StructuredGridInformation : public GridInformation
|
|
{
|
|
/**
|
|
* This structure represents the set of points and their corresponding extent
|
|
* of an external face of the structured grid.
|
|
*/
|
|
struct OuterPointLayersType
|
|
{
|
|
/**
|
|
* Points of an external face.
|
|
*/
|
|
vtkSmartPointer<vtkPoints> Points;
|
|
|
|
/**
|
|
* Extent (which represents a 2D, 1D, or 0D grid), of an external face.
|
|
*/
|
|
ExtentType Extent;
|
|
};
|
|
|
|
/**
|
|
* Array of 6 external faces. Each outer point layer holds a copy of the points of the external
|
|
* face, as well as its extent. This array is indexed in the same fashion as grid extents.
|
|
*/
|
|
OuterPointLayersType OuterPointLayers[6];
|
|
|
|
/**
|
|
* Handle on input points for current block.
|
|
*/
|
|
vtkPoints* InputPoints;
|
|
|
|
vtkStructuredGrid* Input;
|
|
};
|
|
|
|
/**
|
|
* Block structure storing information being communicated by neighboring blocks for
|
|
* `vtkStructuredGrid`.
|
|
*/
|
|
struct StructuredGridBlockStructure : public GridBlockStructure
|
|
{
|
|
/**
|
|
* Constructor taking the extent (without ghosts) of the neighboring `vtkStructuredGrid`,
|
|
* as well as its point array.
|
|
*/
|
|
StructuredGridBlockStructure(const int extent[6], int dim, vtkDataArray* points[6]);
|
|
|
|
/**
|
|
* Copy constructor.
|
|
*/
|
|
StructuredGridBlockStructure(vtkStructuredGrid* grid, const StructuredGridInformation& info);
|
|
|
|
/**
|
|
* Point coordinate arrays of the structured grid.
|
|
*/
|
|
vtkSmartPointer<vtkPoints> OuterPointLayers[6];
|
|
|
|
/**
|
|
* Grid interfacing with block's grid.
|
|
* This grid is a 2D grid and can be arbritrarely oriented depending on how grids connect.
|
|
*/
|
|
struct Grid2D
|
|
{
|
|
/**
|
|
* Start point extent coordinate in the x dimension
|
|
*/
|
|
int StartX = 0;
|
|
|
|
/**
|
|
* Start point extent coordinate in the y dimension
|
|
*/
|
|
int StartY = 0;
|
|
|
|
/**
|
|
* End point extent coordinate in the x dimension
|
|
*/
|
|
int EndX = 0;
|
|
|
|
/**
|
|
* End point extent coordinate in the y dimension
|
|
*/
|
|
int EndY = 0;
|
|
|
|
/**
|
|
* Orientation of the x dimension. (Either +1 or -1)
|
|
*/
|
|
int XOrientation = 0;
|
|
|
|
/**
|
|
* Orientation of the y dimension. (Either +1 or -1)
|
|
*/
|
|
int YOrientation = 0;
|
|
|
|
/**
|
|
* Index of the extent of the current grid. This is a value between 0 and 5, describing which
|
|
* external face of the structured grid this 2D grid represents.
|
|
*/
|
|
int ExtentId = -1;
|
|
};
|
|
|
|
/**
|
|
* 2D grid interfacing 2 blocks.
|
|
*
|
|
* @note This grid can be 1D or 0D.
|
|
*/
|
|
Grid2D GridInterface;
|
|
|
|
/**
|
|
* Buffer to store received ghost points from neighboring blocks.
|
|
*/
|
|
vtkNew<vtkPoints> GhostPoints;
|
|
};
|
|
|
|
struct UnstructuredDataInformation
|
|
{
|
|
bool InputNeedsGhostsPeeledOff() const
|
|
{
|
|
return this->OutputToInputCellIdRedirectionMap != nullptr;
|
|
};
|
|
|
|
/**
|
|
* Bounding box of input.
|
|
*/
|
|
vtkBoundingBox BoundingBox;
|
|
|
|
/**
|
|
* When the input has ghosts, this map is being used to copy input cells / cell data into
|
|
* the output (with input ghosts peeled off).
|
|
*/
|
|
vtkSmartPointer<vtkIdList> OutputToInputCellIdRedirectionMap = nullptr;
|
|
|
|
///@{
|
|
/**
|
|
* When the input has ghosts, this map is being used to copy input points / point data into
|
|
* the output (with input ghosts peeled off).
|
|
*/
|
|
vtkSmartPointer<vtkIdList> InputToOutputPointIdRedirectionMap = nullptr;
|
|
vtkSmartPointer<vtkIdList> OutputToInputPointIdRedirectionMap = nullptr;
|
|
///@}
|
|
|
|
/**
|
|
* Filter that is being used to extract the surface of the input.
|
|
* The surface is used to check how the interface of the input matches the ones of its
|
|
* neighboring blocks.
|
|
*/
|
|
vtkSmartPointer<vtkAlgorithm> InterfaceExtractor;
|
|
|
|
/**
|
|
* Handle to the local point ids of the surface of the input.
|
|
* Those point ids are being used to rapidly match points of the surface to their original
|
|
* location in the input.
|
|
*/
|
|
vtkIdTypeArray* InterfacePointIds;
|
|
|
|
/**
|
|
* Handle to the points of the surface of the input.
|
|
*/
|
|
vtkDataArray* InterfacePoints;
|
|
|
|
/**
|
|
* Handle to the point ids of the input surface, if present.
|
|
*/
|
|
vtkSmartPointer<vtkIdTypeArray> InterfaceGlobalPointIds;
|
|
|
|
///@{
|
|
/*
|
|
* This is a cursor telling the amount of points / cells information,
|
|
* that has
|
|
* already been added to the output. This variable is used at the very end of the pipeline.
|
|
*/
|
|
vtkIdType CurrentMaxPointId;
|
|
vtkIdType CurrentMaxCellId;
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* Number of input points / cell in the input when ghosts are removed.
|
|
*/
|
|
vtkIdType NumberOfInputPoints;
|
|
vtkIdType NumberOfInputCells;
|
|
///@}
|
|
};
|
|
|
|
struct UnstructuredDataBlockStructure : public DataSetBlockStructure
|
|
{
|
|
/**
|
|
* This lists the matching point ids to the interfacing points that are exchanged with current
|
|
* neighboring block. Those ids correspond to local point ordering as indexed in the input.
|
|
*/
|
|
vtkNew<vtkIdList> MatchingReceivedPointIds;
|
|
|
|
/**
|
|
* This array describes the same points as `MatchingReceivedPointIds`, but points are ordered
|
|
* like in the current neighboring block. Point ids stored in this array map to the output.
|
|
*/
|
|
vtkNew<vtkIdList> RemappedMatchingReceivedPointIdsSortedLikeTarget;
|
|
|
|
/**
|
|
* These are the interfacing points sent by the current neighboring block. They should match
|
|
* a subset of the output of the surface filter which is in `UnstructuredDataInformation`.
|
|
*/
|
|
vtkNew<vtkPoints> InterfacingPoints;
|
|
|
|
/**
|
|
* Point global ids of the interfacing surface sent to us by corresponding block, if present.
|
|
*/
|
|
vtkSmartPointer<vtkIdTypeArray> InterfacingGlobalPointIds = nullptr;
|
|
|
|
/**
|
|
* Point global ids sent to us by neighboring block, if present. This array has the same
|
|
* ordering as `GhostPoints`.
|
|
*/
|
|
vtkSmartPointer<vtkIdTypeArray> GhostGlobalPointIds = nullptr;
|
|
|
|
/**
|
|
* Ghost points sent by the current neighboring block.
|
|
*/
|
|
vtkNew<vtkPoints> GhostPoints;
|
|
|
|
/**
|
|
* This lists the ids of the points that we own and need to send to the current neighboring
|
|
* block.
|
|
*/
|
|
vtkNew<vtkIdList> PointIdsToSend;
|
|
|
|
///@{
|
|
/**
|
|
* It can happen that a point can be sent by multiple blocks. If those points are not carefully
|
|
* tracked down, we can end up instantiating multiple times a point that should be created only
|
|
* once. This array lists the potential duplicate point ids that are being send / received for
|
|
* the current neighboring block.
|
|
*/
|
|
vtkNew<vtkIdTypeArray> SharedPointIds;
|
|
vtkSmartPointer<vtkIdTypeArray> ReceivedSharedPointIds;
|
|
///@}
|
|
|
|
/**
|
|
* This is a mapping from points that have been sent by the current neighboring block and have
|
|
* already been added in the output points, to their location in the output point array.
|
|
*/
|
|
std::map<vtkIdType, vtkIdType> RedirectionMapForDuplicatePointIds;
|
|
|
|
/**
|
|
* This lists the ids of the cells that we own and need to send to the current neighboring
|
|
* block.
|
|
*/
|
|
vtkNew<vtkIdList> CellIdsToSend;
|
|
|
|
/**
|
|
* Point data at the interface sent by our neighbor. We only receive point data from neighbors
|
|
* of lower block id than us.
|
|
*/
|
|
vtkSmartPointer<vtkFieldData> InterfacingPointData;
|
|
};
|
|
|
|
struct UnstructuredGridInformation : public UnstructuredDataInformation
|
|
{
|
|
/**
|
|
* This is a cursor telling the amount of faces information, that has
|
|
* already been added to the output. This variable is used at the very end of the pipeline.
|
|
*/
|
|
vtkIdType CurrentFacesSize = 0;
|
|
|
|
/**
|
|
* This is a cursor telling how much the output connectivity array is filled.
|
|
* This is used at the very end of the pipeline.
|
|
*/
|
|
vtkIdType CurrentConnectivitySize = 0;
|
|
|
|
vtkIdTypeArray* Faces = nullptr;
|
|
vtkIdTypeArray* FaceLocations = nullptr;
|
|
|
|
vtkUnstructuredGrid* Input;
|
|
|
|
/**
|
|
* Cell connectivity array size of the input if the ghost cells are removed.
|
|
*/
|
|
vtkIdType InputConnectivitySize = 0;
|
|
|
|
/**
|
|
* Faces array size of the input if the ghost cells are removed.
|
|
*/
|
|
vtkIdType InputFacesSize = 0;
|
|
};
|
|
|
|
struct UnstructuredGridBlockStructure : public UnstructuredDataBlockStructure
|
|
{
|
|
/**
|
|
* Topology information for cells to be exchanged.
|
|
*/
|
|
struct TopologyBufferType
|
|
{
|
|
vtkSmartPointer<vtkUnsignedCharArray> Types = nullptr;
|
|
vtkSmartPointer<vtkIdTypeArray> Faces = nullptr;
|
|
vtkSmartPointer<vtkIdTypeArray> FaceLocations = nullptr;
|
|
vtkNew<vtkCellArray> CellArray;
|
|
};
|
|
|
|
TopologyBufferType SendBuffer;
|
|
TopologyBufferType ReceiveBuffer;
|
|
|
|
///@{
|
|
/**
|
|
* Handle to the faces / connectivity size that we have to send to the neighboring block.
|
|
*/
|
|
vtkIdType FacesSize = 0;
|
|
vtkIdType ConnectivitySize = 0;
|
|
///@}
|
|
};
|
|
|
|
struct PolyDataInformation : public UnstructuredDataInformation
|
|
{
|
|
vtkPolyData* Input;
|
|
|
|
///@{
|
|
/**
|
|
* This is a cursor telling how much the corresponding output connectivity array is filled.
|
|
* This is used at the very end of the pipeline.
|
|
*/
|
|
vtkIdType CurrentPolyConnectivitySize;
|
|
vtkIdType CurrentStripConnectivitySize;
|
|
vtkIdType CurrentLineConnectivitySize;
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* This is a cursor telling how many cells of corresponding types have been added so far.
|
|
* This is used at the very end of the pipeline.
|
|
*/
|
|
vtkIdType CurrentMaxPolyId = 0;
|
|
vtkIdType CurrentMaxStripId = 0;
|
|
vtkIdType CurrentMaxLineId = 0;
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* Number of cells of respective type when the input has its ghost cells removed
|
|
*/
|
|
vtkIdType NumberOfInputVerts;
|
|
vtkIdType NumberOfInputPolys;
|
|
vtkIdType NumberOfInputStrips;
|
|
vtkIdType NumberOfInputLines;
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* Cell connectivity array size of the input if ghost cells are removed.
|
|
*/
|
|
vtkIdType InputVertConnectivitySize;
|
|
vtkIdType InputPolyConnectivitySize;
|
|
vtkIdType InputStripConnectivitySize;
|
|
vtkIdType InputLineConnectivitySize;
|
|
///@{
|
|
|
|
///@{
|
|
/**
|
|
* In the event that the input has ghost cells, this maps the output cells (with input ghosts
|
|
* removed) to the input cells.
|
|
*/
|
|
vtkNew<vtkIdList> OutputToInputVertCellIdRedirectionMap;
|
|
vtkNew<vtkIdList> OutputToInputLineCellIdRedirectionMap;
|
|
vtkNew<vtkIdList> OutputToInputPolyCellIdRedirectionMap;
|
|
vtkNew<vtkIdList> OutputToInputStripCellIdRedirectionMap;
|
|
///@}
|
|
};
|
|
|
|
struct PolyDataBlockStructure : public UnstructuredDataBlockStructure
|
|
{
|
|
///@{
|
|
/**
|
|
* This lists the ids of the cells that we own and need to send to the current neighboring
|
|
* block.
|
|
*/
|
|
vtkNew<vtkIdList> PolyIdsToSend;
|
|
vtkNew<vtkIdList> StripIdsToSend;
|
|
vtkNew<vtkIdList> LineIdsToSend;
|
|
///@}
|
|
|
|
struct TopologyBufferType
|
|
{
|
|
vtkNew<vtkCellArray> Polys;
|
|
vtkNew<vtkCellArray> Strips;
|
|
vtkNew<vtkCellArray> Lines;
|
|
};
|
|
|
|
TopologyBufferType SendBuffer;
|
|
TopologyBufferType ReceiveBuffer;
|
|
|
|
///@{
|
|
/**
|
|
* Handle on the number of cells to send of the corresponding type.
|
|
*/
|
|
vtkIdType NumberOfPolysToSend = 0;
|
|
vtkIdType NumberOfStripsToSend = 0;
|
|
vtkIdType NumberOfLinesToSend = 0;
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* Handle on the number of cells of corresponding type to be sent to the neighbor block.
|
|
*/
|
|
vtkIdType PolyConnectivitySize = 0;
|
|
vtkIdType StripConnectivitySize = 0;
|
|
vtkIdType LineConnectivitySize = 0;
|
|
///@}
|
|
};
|
|
|
|
public:
|
|
/**
|
|
* Block structure to be used for diy communication.
|
|
* This is a generic structure split into 3 main components:
|
|
* - `BlockStructureType`: This holds all information sent by another block that are necessary
|
|
* to determine whether this block is to be connected with ourself.
|
|
* - `InformationType`: This holds all information from the input necessary to allocate the
|
|
* output for this block. This can include bounds, extent, etc.
|
|
*/
|
|
template <class BlockStructureT, class InformationT>
|
|
struct Block
|
|
{
|
|
///@{
|
|
/**
|
|
* Typedef handle on block structure and block information
|
|
*/
|
|
typedef BlockStructureT BlockStructureType;
|
|
typedef InformationT InformationType;
|
|
///@}
|
|
|
|
/**
|
|
* `BlockStructures` maps a neighboring block globald id to its block structure.
|
|
*/
|
|
BlockMapType<BlockStructureType> BlockStructures;
|
|
|
|
/**
|
|
* `InformationT` holds any information from the current block that is necessary to exchange
|
|
* ghosts. This is typically used when sending ghosts to neighboring blocks.
|
|
*/
|
|
InformationType Information;
|
|
|
|
BlockMapType<vtkBoundingBox> NeighborBoundingBoxes;
|
|
|
|
vtkBoundingBox BoundingBox;
|
|
|
|
vtkSmartPointer<vtkUnsignedCharArray> GhostCellArray;
|
|
vtkSmartPointer<vtkUnsignedCharArray> GhostPointArray;
|
|
};
|
|
|
|
///@{
|
|
/**
|
|
* Block typedefs.
|
|
*/
|
|
using ImageDataBlock = Block<ImageDataBlockStructure, ImageDataInformation>;
|
|
using RectilinearGridBlock = Block<RectilinearGridBlockStructure, RectilinearGridInformation>;
|
|
using StructuredGridBlock = Block<StructuredGridBlockStructure, StructuredGridInformation>;
|
|
using UnstructuredDataBlock = Block<UnstructuredDataBlockStructure, UnstructuredDataInformation>;
|
|
using UnstructuredGridBlock = Block<UnstructuredGridBlockStructure, UnstructuredGridInformation>;
|
|
using PolyDataBlock = Block<PolyDataBlockStructure, PolyDataInformation>;
|
|
//@}
|
|
|
|
/**
|
|
* Main pipeline generating ghosts. It takes as parameters a list of `DataSetT` for the `inputs`
|
|
* and the `outputs`.
|
|
* Please see `vtkGhostCellsGenerator` for a finer description of what this method does, as it is
|
|
* being used as a backend for this filter.
|
|
*
|
|
* `outputs` need to be already allocated and be of same size as `inputs`.
|
|
*/
|
|
template <class DataSetT>
|
|
static int GenerateGhostCells(std::vector<DataSetT*>& inputsDS, std::vector<DataSetT*>& outputsDS,
|
|
int outputGhostLevels, vtkMultiProcessController* controller);
|
|
|
|
///@{
|
|
/**
|
|
* Method that can be used to avoid the compile-time overhead of the templated method
|
|
* `GenerateGhostCells`. All this method does is call `GenerateGhostCells` with the appropriate
|
|
* template parameter.
|
|
*/
|
|
static int GenerateGhostCellsImageData(std::vector<vtkImageData*>& inputs,
|
|
std::vector<vtkImageData*>& outputs, int outputGhostLevels,
|
|
vtkMultiProcessController* controller);
|
|
static int GenerateGhostCellsRectilinearGrid(std::vector<vtkRectilinearGrid*>& inputs,
|
|
std::vector<vtkRectilinearGrid*>& outputs, int outputGhostLevels,
|
|
vtkMultiProcessController* controller);
|
|
static int GenerateGhostCellsStructuredGrid(std::vector<vtkStructuredGrid*>& inputs,
|
|
std::vector<vtkStructuredGrid*>& outputs, int outputGhostLevels,
|
|
vtkMultiProcessController* controller);
|
|
static int GenerateGhostCellsPolyData(std::vector<vtkPolyData*>& inputs,
|
|
std::vector<vtkPolyData*>& outputs, int outputGhostLevels,
|
|
vtkMultiProcessController* controller);
|
|
static int GenerateGhostCellsUnstructuredGrid(std::vector<vtkUnstructuredGrid*>& inputs,
|
|
std::vector<vtkUnstructuredGrid*>& outputs, int outputGhostLevels,
|
|
vtkMultiProcessController* controller);
|
|
///@}
|
|
|
|
protected:
|
|
vtkDIYGhostUtilities();
|
|
~vtkDIYGhostUtilities() override;
|
|
|
|
/**
|
|
* Reinitializes the bits that match the input bit mask in the input array to zero.
|
|
*/
|
|
static void ReinitializeSelectedBits(vtkUnsignedCharArray* ghosts, unsigned char mask);
|
|
|
|
/**
|
|
* This method will set all ghosts points in `output` to zero. It will also
|
|
* allocate a new ghost array if none is already present.
|
|
*/
|
|
template <class DataSetT>
|
|
static void InitializeGhostPointArray(
|
|
typename DataSetTypeToBlockTypeConverter<DataSetT>::BlockType* block, DataSetT* output);
|
|
|
|
/**
|
|
* This method will set all ghosts cells in `output` to zero. It will also
|
|
* allocate a new ghost array if none is already present.
|
|
*/
|
|
template <class DataSetT>
|
|
static void InitializeGhostCellArray(
|
|
typename DataSetTypeToBlockTypeConverter<DataSetT>::BlockType* block, DataSetT* output);
|
|
|
|
///@{
|
|
/**
|
|
*
|
|
*/
|
|
static void CloneGeometricStructures(
|
|
std::vector<vtkImageData*>& inputs, std::vector<vtkImageData*>& outputs);
|
|
static void CloneGeometricStructures(
|
|
std::vector<vtkRectilinearGrid*>& inputs, std::vector<vtkRectilinearGrid*>& outputs);
|
|
static void CloneGeometricStructures(
|
|
std::vector<vtkStructuredGrid*>& inputs, std::vector<vtkStructuredGrid*>& outputs);
|
|
static void CloneGeometricStructures(
|
|
std::vector<vtkUnstructuredGrid*>& inputs, std::vector<vtkUnstructuredGrid*>& outputs);
|
|
static void CloneGeometricStructures(
|
|
std::vector<vtkPolyData*>& inputs, std::vector<vtkPolyData*>& outputs);
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* Method to be overloaded for each supported type of input data set.
|
|
* In this method, given `BlockType` the block type for the data set type,
|
|
* `BlockType::InformationType` is filled with all information needed from the input to create the
|
|
* output.
|
|
*/
|
|
static void InitializeBlocks(diy::Master& master, std::vector<vtkImageData*>& inputs);
|
|
static void InitializeBlocks(diy::Master& master, std::vector<vtkRectilinearGrid*>& inputs);
|
|
static void InitializeBlocks(diy::Master& master, std::vector<vtkStructuredGrid*>& inputs);
|
|
static void InitializeBlocks(diy::Master& master, std::vector<vtkUnstructuredGrid*>& inputs);
|
|
static void InitializeBlocks(diy::Master& master, std::vector<vtkPolyData*>& inputs);
|
|
///@}
|
|
|
|
/**
|
|
* This method exchanges the bounding boxes among blocks.
|
|
*/
|
|
template <class DataSetT>
|
|
static void ExchangeBoundingBoxes(
|
|
diy::Master& master, const vtkDIYExplicitAssigner& assigner, std::vector<DataSetT*>& inputs);
|
|
|
|
template <class BlockT>
|
|
static LinkMap ComputeLinkMapUsingBoundingBoxes(const diy::Master& master);
|
|
|
|
///@{
|
|
/**
|
|
* Method to be overloaded for each supported type of input data set.
|
|
* This method is called in the pipeline right after diy environment
|
|
* has been set up. It exchanges between every information needed for the data set type `DataSetT`
|
|
* in order to be able to set link connections.
|
|
*/
|
|
static void ExchangeBlockStructures(diy::Master& master, std::vector<vtkImageData*>& inputs);
|
|
static void ExchangeBlockStructures(
|
|
diy::Master& master, std::vector<vtkRectilinearGrid*>& inputs);
|
|
static void ExchangeBlockStructures(diy::Master& master, std::vector<vtkStructuredGrid*>& inputs);
|
|
static void ExchangeBlockStructures(
|
|
diy::Master& master, std::vector<vtkUnstructuredGrid*>& inputs);
|
|
static void ExchangeBlockStructures(diy::Master& master, std::vector<vtkPolyData*>& inputs);
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* Method to be overloaded for each supported input data set type,
|
|
* that computes the minimal link map being necessary to exchange ghosts.
|
|
* This method is called after `master` has been relinked.
|
|
*/
|
|
static LinkMap ComputeLinkMap(
|
|
const diy::Master& master, std::vector<vtkImageData*>& inputs, int outputGhostLevels);
|
|
static LinkMap ComputeLinkMap(
|
|
const diy::Master& master, std::vector<vtkRectilinearGrid*>& inputs, int outputGhostLevels);
|
|
static LinkMap ComputeLinkMap(
|
|
const diy::Master& master, std::vector<vtkStructuredGrid*>& inputs, int outputGhostLevels);
|
|
static LinkMap ComputeLinkMap(
|
|
const diy::Master& master, std::vector<vtkUnstructuredGrid*>& inputs, int outputGhostLevels);
|
|
static LinkMap ComputeLinkMap(
|
|
const diy::Master& master, std::vector<vtkPolyData*>& inputs, int outputGhostLevels);
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* This method enqueues ghosts between communicating blocks. One version of this method
|
|
* is implemented per supported input types. It enqueues ghosts to block of id `blockId`.
|
|
*/
|
|
static void EnqueueGhosts(const diy::Master::ProxyWithLink& cp, const diy::BlockID& blockId,
|
|
vtkImageData* input, ImageDataBlock* block);
|
|
static void EnqueueGhosts(const diy::Master::ProxyWithLink& cp, const diy::BlockID& blockId,
|
|
vtkRectilinearGrid* input, RectilinearGridBlock* block);
|
|
static void EnqueueGhosts(const diy::Master::ProxyWithLink& cp, const diy::BlockID& blockId,
|
|
vtkStructuredGrid* input, StructuredGridBlock* block);
|
|
static void EnqueueGhosts(const diy::Master::ProxyWithLink& cp, const diy::BlockID& blockId,
|
|
vtkUnstructuredGrid* input, UnstructuredGridBlock* block);
|
|
static void EnqueueGhosts(const diy::Master::ProxyWithLink& cp, const diy::BlockID& blockId,
|
|
vtkPolyData* input, PolyDataBlock* block);
|
|
///@}
|
|
|
|
///@{
|
|
/**
|
|
* This method dequeues ghosts sent between communicating blocks. One version of this method
|
|
* is implemented per supported input types. It receives data from block of id `gid` and
|
|
* stores is inside `blockStructured`.
|
|
*/
|
|
static void DequeueGhosts(
|
|
const diy::Master::ProxyWithLink& cp, int gid, ImageDataBlockStructure& blockStructure);
|
|
static void DequeueGhosts(
|
|
const diy::Master::ProxyWithLink& cp, int gid, RectilinearGridBlockStructure& blockStructure);
|
|
static void DequeueGhosts(
|
|
const diy::Master::ProxyWithLink& cp, int gid, StructuredGridBlockStructure& blockStructure);
|
|
static void DequeueGhosts(
|
|
const diy::Master::ProxyWithLink& cp, int gid, UnstructuredGridBlockStructure& blockStructure);
|
|
static void DequeueGhosts(
|
|
const diy::Master::ProxyWithLink& cp, int gid, PolyDataBlockStructure& blockStructure);
|
|
///@}
|
|
|
|
/**
|
|
* Copy the inputs into the outputs. Shallow copying is performed if possible. If not,
|
|
* a deep copy is done.
|
|
*/
|
|
template <class DataSetT>
|
|
static void CopyInputsAndAllocateGhosts(diy::Master& master, diy::Assigner& assigner,
|
|
diy::RegularAllReducePartners& partners, std::vector<DataSetT*>& inputs,
|
|
std::vector<DataSetT*>& outputs, int outputGhostLevels);
|
|
|
|
///@{
|
|
/**
|
|
* Method to be overloaded for each supported input data set type,
|
|
* This method allocates ghosts in the output. At the point of calling this method,
|
|
* ghosts should have already been exchanged (see `ExchangeGhosts`).
|
|
*/
|
|
static void DeepCopyInputAndAllocateGhosts(
|
|
ImageDataBlock* block, vtkImageData* input, vtkImageData* outputs);
|
|
static void DeepCopyInputAndAllocateGhosts(
|
|
RectilinearGridBlock* block, vtkRectilinearGrid* input, vtkRectilinearGrid* outputs);
|
|
static void DeepCopyInputAndAllocateGhosts(
|
|
StructuredGridBlock* block, vtkStructuredGrid* input, vtkStructuredGrid* outputs);
|
|
static void DeepCopyInputAndAllocateGhosts(
|
|
UnstructuredGridBlock* block, vtkUnstructuredGrid* input, vtkUnstructuredGrid* outputs);
|
|
static void DeepCopyInputAndAllocateGhosts(
|
|
PolyDataBlock* block, vtkPolyData* input, vtkPolyData* outputs);
|
|
///@}
|
|
|
|
/**
|
|
* This method exchanges ghosts between connected blocks.
|
|
*/
|
|
template <class DataSetT>
|
|
static void ExchangeGhosts(diy::Master& master, std::vector<DataSetT*>& inputs);
|
|
|
|
/**
|
|
* This methods allocate a point and cell ghost array and fills it with 0.
|
|
*/
|
|
template <class DataSetT>
|
|
static void InitializeGhostArrays(
|
|
diy::Master& master, std::vector<DataSetT*>& outputs, int outputGhostLevels);
|
|
|
|
/**
|
|
* Adds ghost arrays, which are present in blocks of `master`, to `outputs` point and / or cell
|
|
* data.
|
|
*/
|
|
template <class DataSetT>
|
|
static void AddGhostArrays(diy::Master& master, std::vector<DataSetT*>& outputs);
|
|
|
|
///@{
|
|
/**
|
|
* This method sets the ghost arrays in the output. Ghosts have to be already allocated.
|
|
*/
|
|
static void FillGhostArrays(
|
|
const diy::Master& master, std::vector<vtkImageData*>& outputs, int outputGhostLevels);
|
|
static void FillGhostArrays(
|
|
const diy::Master& master, std::vector<vtkRectilinearGrid*>& outputs, int outputGhostLevels);
|
|
static void FillGhostArrays(
|
|
const diy::Master& master, std::vector<vtkStructuredGrid*>& outputs, int outputGhostLevels);
|
|
static void FillGhostArrays(
|
|
const diy::Master& master, std::vector<vtkUnstructuredGrid*>& outputs, int outputGhostLevels);
|
|
static void FillGhostArrays(
|
|
const diy::Master& master, std::vector<vtkPolyData*>& outputs, int outputGhostLevels);
|
|
///@}
|
|
|
|
private:
|
|
vtkDIYGhostUtilities(const vtkDIYGhostUtilities&) = delete;
|
|
void operator=(const vtkDIYGhostUtilities&) = delete;
|
|
|
|
///@{
|
|
/**
|
|
* Internal method that inflates exchanged bounding boxes to better treat floating point precision
|
|
* for points that are on the boundary of the bounding box.
|
|
*
|
|
* @note This method only does something for vtkUnstructuredGrid and vtkPolyData. The vtkDataSet
|
|
* version is empty;
|
|
*/
|
|
static void InflateBoundingBoxIfNecessary(
|
|
vtkDataSet* vtkNotUsed(input), vtkBoundingBox& vtkNotUsed(bb));
|
|
static void InflateBoundingBoxIfNecessary(vtkPointSet* input, vtkBoundingBox& bb);
|
|
///@}
|
|
};
|
|
|
|
#include "vtkDIYGhostUtilities.txx" // for template implementations
|
|
|
|
#endif
|