/*========================================================================= Program: Visualization Toolkit Module: vtkStructuredAMRGridConnectivity.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 vtkStructuredAMRGridConnectivity * grid connectivity. * * * A concrete instance of vtkAbstractGridConnectivity that implements * functionality for computing the neighboring topology within a structured * AMR grid, as well as, generating ghost-layers. Support is provided for * 1-D, 2-D (XY,XZ,YZ) and 3-D cell-centered datasets. This implementation * does not have any support for distributed data. For the parallel * implementation see vtkPStructuredAMRGridConnectivity. * * @sa * vtkPStructuredAMRGridConnectivity vtkAbstractGridConnectivity */ #ifndef vtkStructuredAMRGridConnectivity_h #define vtkStructuredAMRGridConnectivity_h #include "vtkFiltersGeometryModule.h" // For export macro #include "vtkAbstractGridConnectivity.h" #include "vtkStructuredAMRNeighbor.h" // For vtkStructuredAMRNeighbor def. // C++ includes #include // For STL map #include // For STL stream #include // For STL set #include // For STL vector class VTKFILTERSGEOMETRY_EXPORT vtkStructuredAMRGridConnectivity : public vtkAbstractGridConnectivity { public: static vtkStructuredAMRGridConnectivity* New(); vtkTypeMacro(vtkStructuredAMRGridConnectivity, vtkAbstractGridConnectivity); void PrintSelf(ostream& os, vtkIndent indent ) override; /** * Initializes this instance of vtkStructuredAMRGridConnectivity where N * is the total number of grids in the AMR hierarchy. Optionally, if the * AMR dataset has a constant refinement, it should be specified during * initialization as the code optimizes for it. If a -1 or no refinement * ratio is specified a varying refinement ratio is assumed. */ void Initialize( const unsigned int NumberOfLevels, const unsigned int N, const int RefinementRatio=-1); /** * Computes neighboring information. */ void ComputeNeighbors() override; /** * Creates ghost layers. */ void CreateGhostLayers(const int N=1) override; /** * Registers the AMR grid with the given global linear grid ID (starting * numbering from 0) and level and refinement ratio. This method is to be * used when the refinement ratio is not constant. */ virtual void RegisterGrid( const int gridIdx, const int level, const int refinementRatio, int extents[6], vtkUnsignedCharArray* nodesGhostArray, vtkUnsignedCharArray* cellGhostArray, vtkPointData* pointData, vtkCellData* cellData, vtkPoints* gridNodes); /** * Registers the AMR grid with the given global linear grid ID (starting * numbering from 0) and level. The extents of the grid are expected to be * global node extents. */ virtual void RegisterGrid( const int gridIdx, const int level, int extents[6], vtkUnsignedCharArray* nodesGhostArray, vtkUnsignedCharArray* cellGhostArray, vtkPointData* pointData, vtkCellData* cellData, vtkPoints* gridNodes); //@{ /** * Get/Set macro for BalancedRefinement property, default is true. If the * refinement is balanced, then, adjacent grids in the AMR hierarchy can * only differ by one level. By default, a balanced refinement is assumed. */ vtkSetMacro(BalancedRefinement,bool); vtkGetMacro(BalancedRefinement,bool); //@} //@{ /** * Get/Set macro NodeCentered property which indicates if the data is * node-centered or cell-centered. By default, node-centered is set to false * since AMR datasets are primarily cell-centered. */ vtkSetMacro(NodeCentered,bool); vtkGetMacro(NodeCentered,bool); //@} //@{ /** * Get/Set CellCentered property which indicates if the data is cell-centered * By default, cell-centered is set to true. */ vtkSetMacro(CellCentered,bool); vtkGetMacro(CellCentered,bool); //@} /** * Returns the number of neighbors for the grid corresponding to the given * grid ID. */ int GetNumberOfNeighbors(const int gridID); /** * Returns the ghost extend for the grid corresponding to the given grid ID. */ void GetGhostedExtent(const int gridID, int ext[6]); /** * Returns the AMR neighbor for the patch with the corresponding grid ID. */ vtkStructuredAMRNeighbor GetNeighbor(const int gridID, const int nei); protected: vtkStructuredAMRGridConnectivity(); ~vtkStructuredAMRGridConnectivity() override; /** * Sets the total number of grids(blocks) in the AMR hierarchy */ void SetNumberOfGrids( const unsigned int N ) override; /** * Creates the ghosted mask arrays */ void CreateGhostedMaskArrays(const int gridID); /** * Creates the ghosted extent of the given grid */ void CreateGhostedExtent(const int gridID, const int N); /** * Sets the ghost extent for the grid corresponding to the given grid ID. */ void SetGhostedExtent(const int gridID, int ext[6]); /** * Gets the coarsened extent for the grid with the given grid index. */ void GetCoarsenedExtent( const int gridIdx, int fromLevel, int toLevel, int ext[6]); /** * Gets the refined extent for the grid with the given grid index. */ void GetRefinedExtent( const int gridIdx, int fromLevel, int toLevel, int ext[6]); /** * Refines the given extent. */ void RefineExtent( int orient[3], int ndim, int fromLevel, int toLevel, int ext[6]); /** * Given the global i,j,k index of a cell at a coarse level, fromLevel, this * method computes the range of cells on the refined grid. */ void GetCellRefinedExtent( int orient[3], int ndim, const int i, const int j, const int k, const int fromLevel, const int toLevel, int ext[6]); /** * Coarsens the given extent. */ void CoarsenExtent( int orient[3], int ndim, int fromLevel, int toLevel, int ext[6]); /** * Gets the grid extent for the grid with the given grid ID. */ void GetGridExtent( const int gridIdx, int ext[6] ); /** * Returns the level of the grid with the corresponding grid ID. */ int GetGridLevel( const int gridIdx ); /** * Checks if the given level has been registered */ bool LevelExists( const int level ); /** * Checks if the node is an interior node in the given extent. */ bool IsNodeInterior( const int i, const int j, const int k, int ext[6]); /** * Checks if the node is within the extent. */ bool IsNodeWithinExtent( const int i, const int j, const int k, int ext[6]); /** * Checks if the node is on a shared boundary. */ bool IsNodeOnSharedBoundary( const int i, const int j, const int k, const int gridId,int gridExt[6]); /** * Checks if the node is on the boundary of the given extent. */ bool IsNodeOnBoundaryOfExtent( const int i, const int j, const int k, int ext[6] ); /** * Inserts the grid corresponding to the given ID at the prescribed level. */ void InsertGridAtLevel( const int level, const int gridID); /** * Loops through the neighbors of this grid and computes the send and rcv * extents for the N requested ghost layers. */ void ComputeNeighborSendAndRcvExtent(const int gridID, const int N); /** * Computes the whole extent w.r.t. level 0 as well as the AMR dataset * description and dimension. */ void ComputeWholeExtent(); /** * Gets the whole extent with respect to the given level. * NOTE: This method assument that the whole extent has been computed. */ void GetWholeExtentAtLevel(const int level, int ext[6]); /** * Establishes neighboring relationship between grids i,j wheren i,j are * global indices. */ void EstablishNeighbors(const int i, const int j); /** * Computes the node orientation tuple for the given i,j,k node. */ void GetNodeOrientation( const int i, const int j, const int k, int gridExt[6], int nodeOrientation[3]); /** * Establishes the orientation vector and dimension based on the computed * data description. The orientation vector is a 3-tuple, which encodes the * dimensions that are used. For example, let's say that we want to define * the orientation to be in the XZ plane, then, the orient array would be * constructed as follows: {0,2 -1}, where -1 indicates a NIL value. */ void GetOrientationVector( const int dataDescription, int orient[3], int &ndim); /** * Checks if a constant refinement ratio has been specified. */ bool HasConstantRefinementRatio( ); /** * Sets the refinement ratio at the given level. */ void SetRefinementRatioAtLevel( const int level, const int r); /** * Returns the refinement ratio at the given level. */ int GetRefinementRatioAtLevel(const int level); /** * Checks if the extent ext1 and ext2 are equal. */ bool AreExtentsEqual(int ext1[6], int ext2[6] ); /** * Constructs the block topology for the given grid. */ void SetBlockTopology(const int gridID); /** * Returns the number of faces of the block corresponding to the given grid * ID that are adjacent to at least one other block. Note, this is not the * total number of neighbors for the block. This method simply checks how * many out of the 6 block faces have connections. Thus, the return value * has an upper-bound of 6. */ int GetNumberOfConnectingBlockFaces( const int gridID ); //@{ /** * Checks if the block corresponding to the given grid ID has a block * adjacent to it in the given block direction. * NOTE: The block direction is essentially one of the 6 faces of the * block defined as follows: *
    *
  • FRONT = 0 (+k diretion)
  • *
  • BACK = 1 (-k direction)
  • *
  • RIGHT = 2 (+i direction)
  • *
  • LEFT = 3 (-i direction)
  • *
  • TOP = 4 (+j direction)
  • *
  • BOTTOM = 5 (-j direction)
  • *
*/ bool HasBlockConnection(const int gridID, const int blockDirection) { // Sanity check assert("pre: gridID is out-of-bounds" && (gridID >=0) && (gridID < static_cast(this->NumberOfGrids))); assert("pre: BlockTopology has not been properly allocated" && (this->NumberOfGrids == this->BlockTopology.size())); assert("pre: blockDirection is out-of-bounds" && (blockDirection >= 0) && (blockDirection < 6) ); bool status = false; if( this->BlockTopology[ gridID ] & (1 << blockDirection) ) { status = true; } return( status ); } //@} /** * Removes a block connection along the given direction for the block * corresponding to the given gridID. * NOTE: The block direction is essentially one of the 6 faces of the * block defined as follows: *
    *
  • FRONT = 0 (+k diretion)
  • *
  • BACK = 1 (-k direction)
  • *
  • RIGHT = 2 (+i direction)
  • *
  • LEFT = 3 (-i direction)
  • *
  • TOP = 4 (+j direction)
  • *
  • BOTTOM = 5 (-j direction)
  • *
*/ void RemoveBlockConnection(const int gridID, const int blockDirection); /** * Adds a block connection along the given direction for the block * corresponding to the given gridID. * NOTE: The block direction is essentially one of the 6 faces of the * block defined as follows: *
    *
  • FRONT = 0 (+k diretion)
  • *
  • BACK = 1 (-k direction)
  • *
  • RIGHT = 2 (+i direction)
  • *
  • LEFT = 3 (-i direction)
  • *
  • TOP = 4 (+j direction)
  • *
  • BOTTOM = 5 (-j direction)
  • *
*/ void AddBlockConnection(const int gridID, const int blockDirection); /** * Clears all block connections for the block corresponding to the given * grid ID. */ void ClearBlockConnections( const int gridID ); /** * Marks the ghost property for the given node. */ virtual void MarkNodeProperty( const int gridId, const int i, const int j, const int k, int gridExt[6], int wholeExt[6], unsigned char &p); /** * Fills the node ghost arrays for the given grid */ virtual void FillNodesGhostArray( const int gridId, vtkUnsignedCharArray* nodesArray); /** * Fills the cell ghost arrays for the given grid */ virtual void FillCellsGhostArray( const int gridId, vtkUnsignedCharArray* cellArray); /** * Fills ghost arrays. */ void FillGhostArrays( const int gridId, vtkUnsignedCharArray* nodesArray, vtkUnsignedCharArray* cellsArray ) override; /** * Compute the AMR neighbor of grid "i" and its neighbor grid "j". * Given the structured neighbors computed in normalized space (i.e., at * the same level) between the two grids, this method computes the * corresponding AMR neighbor which essentially adds other bits of * information, such as level, relationship type, etc. * NOTE: * The extents next1 and next2 for each grid are the normalized extents */ vtkStructuredAMRNeighbor GetAMRNeighbor( const int i, const int iLevel, int next1[6], const int j, const int jLevel, int next2[6], const int normalizedLevel, const int levelDiff, vtkStructuredNeighbor &nei); /** * A Helper method to compute the AMR neighbor overlap extents. The method * coarsens/refines the gridOverlap and neiOverlap extents accordingly s.t. * they are w.r.t. to the level of the grid they refer to. */ void ComputeAMRNeighborOverlapExtents( const int iLevel, const int jLevel, const int normalizedLevel, const vtkStructuredNeighbor &nei, int orient[3], int ndim, int gridOverlapExtent[6], int neiOverlapExtent[6]); /** * Get 1-D orientation. */ int Get1DOrientation( const int idx, const int ExtentLo, const int ExtentHi, const int OnLo, const int OnHi, const int NotOnBoundary); /** * Prints the extent */ void PrintExtent(std::ostream& os, int ext[6]); /** * Initializes the ghost data-structures */ void InitializeGhostData( const int gridID ); /** * Transfers the data of the registered grid, to the ghosted data-structures. */ void TransferRegisteredDataToGhostedData( const int gridID ); /** * Transfers local node-centered neighbor data */ void TransferLocalNodeCenteredNeighborData( const int gridID, vtkStructuredAMRNeighbor &nei); /** * Copy cell center value from a coarser level by direct-injection, i.e., the * values within the coarse cell is assumed to be constant. */ void GetLocalCellCentersFromCoarserLevel( const int gridID, vtkStructuredAMRNeighbor &nei); /** * Copy cell center values from a finer level by cell averaging. */ void GetLocalCellCentersFromFinerLevel( const int gridID, vtkStructuredAMRNeighbor &nei); /** * Copy cell center values to fill in the ghost levels from a neighbor at * the same level as the grid corresponding to the given grid ID. */ void GetLocalCellCentersAtSameLevel( const int gridID, vtkStructuredAMRNeighbor &nei); /** * Transfers local cell-centered neighbor data */ void TransferLocalCellCenteredNeighborData( const int gridID, vtkStructuredAMRNeighbor &nei); /** * Transfers local neighbor data */ void TransferLocalNeighborData( const int gridID, vtkStructuredAMRNeighbor &nei); /** * Fills in the ghost data from the neighbors */ virtual void TransferGhostDataFromNeighbors(const int gridID); /** * Loops through all arrays and computes the average of the supplied source * indices and stores the corresponding average */ void AverageFieldData( vtkFieldData *source, vtkIdType *sourceIds, const int N, vtkFieldData *target, vtkIdType targetIdx); /** * Loops through all arrays in the source and for each array, it copies the * tuples from sourceIdx to the target at targetIdx. This method assumes * that the source and target have a one-to-one array correspondence, that * is array i in the source corresponds to array i in the target. */ void CopyFieldData( vtkFieldData *source, vtkIdType sourceIdx, vtkFieldData *target, vtkIdType targetIdx); unsigned int NumberOfLevels; // The total number of levels; int DataDimension; // The dimension of the data, i.e. 2 or 3 int DataDescription; // The data description, i.e., VTK_XY_PLANE, etc. int WholeExtent[6]; // The whole extent w.r.t. to the root level, level 0. int MaxLevel; // The max level of the AMR hierarchy int RefinementRatio; // The refinement ratio, set in the initialization,iff, // a constant refinement ratio is used. A value of -1 // indicates that the refinement ratio is not constant // and the RefinementRatios vector is used instead. bool NodeCentered; // Indicates if the data is node-centered bool CellCentered; // Indicates if the data is cell-centered bool BalancedRefinement; // If Balanced refinement is true, then adjacent // grids in the hierarchy can only differ by one // level. // AMRHierarchy stores the set of grid Ids in [0,N] for each level std::map< int, std::set > AMRHierarchy; // For each grid, [0,N] store the grid extents,level, and list of neighbors std::vector< int > GridExtents; // size of this vector is 6*N std::vector< int > GhostedExtents; // size of this vector is 6*N std::vector< unsigned char > BlockTopology; // size of this vector is N std::vector< int > GridLevels; // size of this vector is N std::vector< std::vector > Neighbors; // For each grid, [0,N], store the donor level,grid and cell information, a // DonorLevel of -1 indicates that the cell is not receiving any information // from a donor. std::vector< std::vector > CellCenteredDonorLevel; // RefinementRatios stores the refinement ratio at each level, this vector // is used only when the refinement ratio varies across levels std::vector< int > RefinementRatios; private: vtkStructuredAMRGridConnectivity(const vtkStructuredAMRGridConnectivity&) = delete; void operator=(const vtkStructuredAMRGridConnectivity&) = delete; }; //============================================================================= // INLINE METHODS //============================================================================= //------------------------------------------------------------------------------ inline int vtkStructuredAMRGridConnectivity::GetNumberOfNeighbors( const int gridID) { assert("pre: grid ID is out-of-bounds" && (gridID >= 0) && (gridID < static_cast(this->NumberOfGrids))); assert("pre: neighbors vector has not been properly allocated" && (this->Neighbors.size()==this->NumberOfGrids)); return( static_cast(this->Neighbors[gridID].size()) ); } //------------------------------------------------------------------------------ inline vtkStructuredAMRNeighbor vtkStructuredAMRGridConnectivity::GetNeighbor( const int gridID, const int nei) { assert("pre: grid ID is out-of-bounds" && (gridID >= 0) && (gridID < static_cast(this->NumberOfGrids))); assert("pre: neighbors vector has not been properly allocated" && (this->Neighbors.size()==this->NumberOfGrids)); assert("pre: nei index is out-of-bounds" && (nei >= 0) && (nei < static_cast(this->Neighbors[gridID].size()))); return( this->Neighbors[gridID][nei] ); } //------------------------------------------------------------------------------ inline int vtkStructuredAMRGridConnectivity::Get1DOrientation( const int idx, const int ExtentLo, const int ExtentHi, const int OnLo, const int OnHi, const int NotOnBoundary) { if( idx == ExtentLo ) { return OnLo; } else if( idx == ExtentHi ) { return OnHi; } return NotOnBoundary; } //------------------------------------------------------------------------------ inline int vtkStructuredAMRGridConnectivity::GetNumberOfConnectingBlockFaces( const int gridID ) { // Sanity check assert("pre: gridID is out-of-bounds" && (gridID >=0) && (gridID < static_cast(this->NumberOfGrids))); assert("pre: BlockTopology has not been properly allocated" && (this->NumberOfGrids == this->BlockTopology.size())); int count = 0; for( int i=0; i < 6; ++i ) { if( this->HasBlockConnection( gridID, i ) ) { ++count; } } assert( "post: count must be in [0,5]" && (count >=0 && count <= 6) ); return( count ); } //------------------------------------------------------------------------------ inline void vtkStructuredAMRGridConnectivity::RemoveBlockConnection( const int gridID, const int blockDirection ) { // Sanity check assert("pre: gridID is out-of-bounds" && (gridID >=0) && (gridID < static_cast(this->NumberOfGrids))); assert("pre: BlockTopology has not been properly allocated" && (this->NumberOfGrids == this->BlockTopology.size())); assert("pre: blockDirection is out-of-bounds" && (blockDirection >= 0) && (blockDirection < 6) ); this->BlockTopology[ gridID ] &= ~(1 << blockDirection); } //------------------------------------------------------------------------------ inline void vtkStructuredAMRGridConnectivity::AddBlockConnection( const int gridID, const int blockDirection ) { // Sanity check assert("pre: gridID is out-of-bounds" && (gridID >=0) && (gridID < static_cast(this->NumberOfGrids))); assert("pre: BlockTopology has not been properly allocated" && (this->NumberOfGrids == this->BlockTopology.size())); assert("pre: blockDirection is out-of-bounds" && (blockDirection >= 0) && (blockDirection < 6) ); this->BlockTopology[ gridID ] |= (1 << blockDirection); } //------------------------------------------------------------------------------ inline void vtkStructuredAMRGridConnectivity::ClearBlockConnections( const int gridID ) { // Sanity check assert("pre: gridID is out-of-bounds" && (gridID >=0) && (gridID < static_cast(this->NumberOfGrids))); assert("pre: BlockTopology has not been properly allocated" && (this->NumberOfGrids == this->BlockTopology.size())); for( int i=0; i < 6; ++i ) { this->RemoveBlockConnection( gridID, i ); } // END for all block directions } //------------------------------------------------------------------------------ inline bool vtkStructuredAMRGridConnectivity::AreExtentsEqual( int ext1[6], int ext2[6]) { for( int i=0; i < 6; ++i ) { if( ext1[i] != ext2[i] ) { return false; } } // END for return true; } //------------------------------------------------------------------------------ inline void vtkStructuredAMRGridConnectivity::PrintExtent( std::ostream& os, int ext[6]) { for( int i=0; i < 6; i+=2 ) { os << "["; os << ext[i] << " "; os << ext[i+1] << "] "; } // END for } //------------------------------------------------------------------------------ inline int vtkStructuredAMRGridConnectivity::GetGridLevel(const int gridIdx) { assert("pre: grid Index is out-of-bounds!" && (gridIdx < static_cast(this->NumberOfGrids))); assert("pre: grid levels vector has not been allocated" && (this->GridLevels.size()==this->NumberOfGrids) ); return( this->GridLevels[gridIdx] ); } //------------------------------------------------------------------------------ inline void vtkStructuredAMRGridConnectivity::SetRefinementRatioAtLevel( const int level, const int r) { assert("pre: RefinementRatios vector is not properly allocated" && this->RefinementRatios.size()==this->NumberOfLevels); assert("pre: leve is out-of-bounds!" && (level >= 0) && (level < static_cast(this->RefinementRatios.size())) ); assert("pre: invalid refinement ratio" && (r >= 2) ); this->RefinementRatios[ level ] = r; } //------------------------------------------------------------------------------ inline int vtkStructuredAMRGridConnectivity::GetRefinementRatioAtLevel( const int level) { assert( "pre: RefinementRatios vector is not properly allocated" && this->RefinementRatios.size()==this->NumberOfLevels); assert( "pre: leve is out-of-bounds!" && (level >= 0) && (level < static_cast(this->RefinementRatios.size()))); assert( "pre: refinement ratio for level has not been set" && (this->RefinementRatios[ level ] >= 2) ); return(this->RefinementRatios[level]); } //------------------------------------------------------------------------------ inline bool vtkStructuredAMRGridConnectivity::HasConstantRefinementRatio() { if( this->RefinementRatio < 2 ) { return false; } return true; } //------------------------------------------------------------------------------ inline void vtkStructuredAMRGridConnectivity::GetGridExtent( const int gridIdx, int ext[6]) { assert("pre: grid index is out-of-bounds" && ( (gridIdx >= 0) && (gridIdx < static_cast(this->GridExtents.size()) ) ) ); for( int i=0; i < 6; ++i ) { ext[ i ] = this->GridExtents[ gridIdx*6+i ]; } } //------------------------------------------------------------------------------ inline bool vtkStructuredAMRGridConnectivity::LevelExists( const int level ) { if( this->AMRHierarchy.find(level) != this->AMRHierarchy.end() ) { return true; } return false; } //------------------------------------------------------------------------------ inline void vtkStructuredAMRGridConnectivity::InsertGridAtLevel( const int level, const int gridID ) { if( this->LevelExists( level ) ) { this->AMRHierarchy[ level ].insert( gridID ); } else { std::set grids; grids.insert( gridID ); this->AMRHierarchy[ level ] = grids; } } #endif /* VTKSTRUCTUREDAMRGRIDCONNECTIVITY_H_ */