Commit 4dee0274 authored by Dan Lipsa's avatar Dan Lipsa
Browse files

Redesign "vtkGhostLevels" arrays and related ghost functionalties.


Co-authored-by: default avatarYuanxin Liu <leo.liu@kitware.com>
Co-authored-by: Berk Geveci's avatarBerk Geveci <berk.geveci@kitware.com>

 -The semantics of each unsigned char in the ghost arrays changes:
  Instead of storing a numeric value representing how far a cell is
  from the boundary, it is now a bit field specified by
  vtkDataSetAttributes::CellGhostTypes and
  vtkDataSetAttributes::PointGhostTypes.  The bit field is consistent
  with VisIt specs.

- Previously, filters strip all ghost cells they request from upstream
  before finalizing the output. This is no longer done.

- vtkUniform grids previously supported blanking through member arrays
  vtkUniformGrid::CellVisibility and
  vtkUniformGrid::PointVisibility. These arrays are removed and the
  blanking functionality are supported through the new ghost arrays
  instead.

- the "vtkGhostLevel" arrays for cell and point data are renamed to
  vtkDataSetAttributes::GhostArrayName() ("vtkGhostType").

- the version for VTK Legacy files is increased to 4.0 and the version for
  VTK XML files is increased to 2.0. When reading older files we
  convert vtkGhostLevels array to vtkGhostType.
parent 1424cab4
......@@ -161,7 +161,6 @@ set(Module_SRCS
vtkStructuredGrid.cxx
vtkStructuredPointsCollection.cxx
vtkStructuredPoints.cxx
vtkStructuredVisibilityConstraint.cxx
vtkSuperquadric.cxx
vtkTable.cxx
vtkTensor.cxx
......
......@@ -34,6 +34,72 @@
#define JMAX(ext) ext[3]
#define KMIN(ext) ext[4]
#define KMAX(ext) ext[5]
#define PRINT(x) cout<<"("<<myRank<<")"<<x<<endl;
namespace
{
void BlankGridsAtLevel(vtkOverlappingAMR* amr, int levelIdx, std::vector<std::vector<unsigned int> >& children,
const std::vector<int>& processMap)
{
unsigned int numDataSets = amr->GetNumberOfDataSets(levelIdx);
int N;
for( unsigned int dataSetIdx=0; dataSetIdx<numDataSets; dataSetIdx++)
{
const vtkAMRBox& box = amr->GetAMRBox(levelIdx, dataSetIdx);
vtkUniformGrid* grid = amr->GetDataSet(levelIdx, dataSetIdx);
if (grid == NULL )
{
continue;
}
N = grid->GetNumberOfCells();
vtkUnsignedCharArray *ghosts = vtkUnsignedCharArray::New();
ghosts->SetNumberOfTuples(N);
ghosts->FillComponent(0, 0);
ghosts->SetName(vtkDataSetAttributes::GhostArrayName());
if (children.size() > dataSetIdx)
{
std::vector<unsigned int>& dsChildren = children[dataSetIdx];
std::vector<unsigned int>::iterator iter;
// For each higher res box fill in the cells that
// it covers
for (iter=dsChildren.begin(); iter!=dsChildren.end(); iter++)
{
vtkAMRBox ibox;;
int childGridIndex = amr->GetCompositeIndex(levelIdx+1, *iter);
if(processMap[childGridIndex]<0)
{
continue;
}
if (amr->GetAMRInfo()->GetCoarsenedAMRBox(levelIdx+1, *iter, ibox))
{
ibox.Intersect(box);
const int *loCorner=ibox.GetLoCorner();
int hi[3];
ibox.GetValidHiCorner(hi);
for( int iz=loCorner[2]; iz<=hi[2]; iz++ )
{
for( int iy=loCorner[1]; iy<=hi[1]; iy++ )
{
for( int ix=loCorner[0]; ix<=hi[0]; ix++ )
{
vtkIdType id = vtkAMRBox::GetCellLinearIndex(box,ix, iy, iz, grid->GetDimensions());
ghosts->SetValue(id, ghosts->GetValue(id) | vtkDataSetAttributes::REFINEDCELL);
} // END for x
} // END for y
} // END for z
}
} // Processing all higher boxes for a specific coarse grid
}
grid->GetCellData()->AddArray(ghosts);
ghosts->Delete();
}
}
};
//------------------------------------------------------------------------------
void vtkAMRUtilities::PrintSelf( std::ostream& os, vtkIndent indent )
......@@ -408,47 +474,48 @@ void vtkAMRUtilities::BlankGridsAtLevel(vtkOverlappingAMR* amr, int levelIdx,
}
N = grid->GetNumberOfCells();
vtkUnsignedCharArray* vis = vtkUnsignedCharArray::New();
vis->SetName("visibility");
vis->SetNumberOfTuples( N );
vis->FillComponent(0,static_cast<char>(1));
grid->SetCellVisibilityArray(vis);
vis->Delete();
if (children.size() <= dataSetIdx)
continue;
std::vector<unsigned int>& dsChildren = children[dataSetIdx];
std::vector<unsigned int>::iterator iter;
vtkUnsignedCharArray *ghosts = vtkUnsignedCharArray::New();
ghosts->SetNumberOfTuples(N);
ghosts->FillComponent(0, 0);
ghosts->SetName(vtkDataSetAttributes::GhostArrayName());
// For each higher res box fill in the cells that
// it covers
for (iter=dsChildren.begin(); iter!=dsChildren.end(); iter++)
if (children.size() > dataSetIdx)
{
vtkAMRBox ibox;;
int childGridIndex = amr->GetCompositeIndex(levelIdx+1, *iter);
if(processMap[childGridIndex]<0)
{
continue;
}
if (amr->GetAMRInfo()->GetCoarsenedAMRBox(levelIdx+1, *iter, ibox))
std::vector<unsigned int>& dsChildren = children[dataSetIdx];
std::vector<unsigned int>::iterator iter;
// For each higher res box fill in the cells that
// it covers
for (iter=dsChildren.begin(); iter!=dsChildren.end(); iter++)
{
ibox.Intersect(box);
const int *loCorner=ibox.GetLoCorner();
int hi[3];
ibox.GetValidHiCorner(hi);
for( int iz=loCorner[2]; iz<=hi[2]; iz++ )
vtkAMRBox ibox;;
int childGridIndex = amr->GetCompositeIndex(levelIdx+1, *iter);
if(processMap[childGridIndex]<0)
{
continue;
}
if (amr->GetAMRInfo()->GetCoarsenedAMRBox(levelIdx+1, *iter, ibox))
{
for( int iy=loCorner[1]; iy<=hi[1]; iy++ )
ibox.Intersect(box);
const int *loCorner=ibox.GetLoCorner();
int hi[3];
ibox.GetValidHiCorner(hi);
for( int iz=loCorner[2]; iz<=hi[2]; iz++ )
{
for( int ix=loCorner[0]; ix<=hi[0]; ix++ )
for( int iy=loCorner[1]; iy<=hi[1]; iy++ )
{
vtkIdType id = vtkAMRBox::GetCellLinearIndex(box,ix, iy, iz, grid->GetDimensions());
vis->SetValue(id, 0);
} // END for x
} // END for y
} // END for z
}
} // Processing all higher boxes for a specific coarse grid
for( int ix=loCorner[0]; ix<=hi[0]; ix++ )
{
vtkIdType id = vtkAMRBox::GetCellLinearIndex(box,ix, iy, iz, grid->GetDimensions());
ghosts->SetValue(id, ghosts->GetValue(id) | vtkDataSetAttributes::REFINEDCELL);
} // END for x
} // END for y
} // END for z
}
} // Processing all higher boxes for a specific coarse grid
}
grid->GetCellData()->AddArray(ghosts);
ghosts->Delete();
}
}
......@@ -14,6 +14,7 @@
=========================================================================*/
#include "vtkDataSet.h"
#include "vtkCallbackCommand.h"
#include "vtkCell.h"
#include "vtkCellData.h"
#include "vtkCellTypes.h"
......@@ -33,9 +34,21 @@
vtkDataSet::vtkDataSet ()
{
vtkMath::UninitializeBounds(this->Bounds);
// Observer for updating the cell/point ghost arrays pointers
this->DataObserver = vtkCallbackCommand::New();
this->DataObserver->SetCallback(&vtkDataSet::OnDataModified);
this->DataObserver->SetClientData(this);
this->PointData = vtkPointData::New();
this->PointGhostArray = NULL;
// when point data is modified, we update the point data ghost array cache
this->PointData->AddObserver(vtkCommand::ModifiedEvent, this->DataObserver);
this->CellData = vtkCellData::New();
this->CellGhostArray = NULL;
// when cell data is modified, we update the cell data ghost array cache
this->CellData->AddObserver(vtkCommand::ModifiedEvent, this->DataObserver);
this->ScalarRange[0] = 0.0;
this->ScalarRange[1] = 1.0;
}
......@@ -43,8 +56,13 @@ vtkDataSet::vtkDataSet ()
//----------------------------------------------------------------------------
vtkDataSet::~vtkDataSet ()
{
this->PointData->RemoveObserver(this->DataObserver);
this->PointData->Delete();
this->CellData->RemoveObserver(this->DataObserver);
this->CellData->Delete();
this->DataObserver->Delete();
}
//----------------------------------------------------------------------------
......@@ -460,7 +478,7 @@ int vtkDataSet::CheckAttributes()
}
//----------------------------------------------------------------------------
void vtkDataSet::GenerateGhostLevelArray(int zeroExt[6])
void vtkDataSet::GenerateGhostArray(int zeroExt[6])
{
// Make sure this is a structured data set.
if(this->GetExtentType() != VTK_3D_EXTENT)
......@@ -469,28 +487,18 @@ void vtkDataSet::GenerateGhostLevelArray(int zeroExt[6])
}
// Avoid generating these if the producer has generated them.
if(!this->PointData->GetArray("vtkGhostLevels"))
{ // Create ghost levels for cells and points.
vtkUnsignedCharArray *levels;
if(!this->PointData->GetArray(vtkDataSetAttributes::GhostArrayName()))
{ // Set ghost types for cells and points.
vtkUnsignedCharArray *ghosts;
int extent[6];
int i, j, k, di, dj, dk, dist;
this->Information->Get(vtkDataObject::DATA_EXTENT(), extent);
/*
// Get the extent with ghost level 0.
translator->SetWholeExtent(whole_extent);
translator->SetPiece(update_piece);
translator->SetNumberOfPieces(update_num_pieces);
translator->SetGhostLevel(0);
translator->PieceToExtent();
translator->GetExtent(zeroExt);
*/
// ---- POINTS ----
// Allocate the appropriate number levels (number of points).
levels = vtkUnsignedCharArray::New();
levels->Allocate((extent[1]-extent[0] + 1) *
// Allocate the appropriate ghost types.
ghosts = vtkUnsignedCharArray::New();
ghosts->Allocate((extent[1]-extent[0] + 1) *
(extent[3]-extent[2] + 1) *
(extent[5]-extent[4] + 1));
......@@ -502,7 +510,7 @@ void vtkDataSet::GenerateGhostLevelArray(int zeroExt[6])
{
dk = zeroExt[4] - k;
}
if (k >= zeroExt[5])
if (k > zeroExt[5])
{ // Special case for last tile.
dk = k - zeroExt[5] + 1;
}
......@@ -513,7 +521,7 @@ void vtkDataSet::GenerateGhostLevelArray(int zeroExt[6])
{
dj = zeroExt[2] - j;
}
if (j >= zeroExt[3])
if (j > zeroExt[3])
{ // Special case for last tile.
dj = j - zeroExt[3] + 1;
}
......@@ -524,7 +532,7 @@ void vtkDataSet::GenerateGhostLevelArray(int zeroExt[6])
{
di = zeroExt[0] - i;
}
if (i >= zeroExt[1])
if (i > zeroExt[1])
{ // Special case for last tile.
di = i - zeroExt[1] + 1;
}
......@@ -538,23 +546,23 @@ void vtkDataSet::GenerateGhostLevelArray(int zeroExt[6])
{
dist = dk;
}
//cerr << " " << i << ", " << j << ", " << k << endl;
//cerr << " " << di << ", " << dj << ", " << dk << endl;
//cerr << dist << endl;
levels->InsertNextValue(static_cast<unsigned char>(dist));
unsigned char value = 0;
if(dist > 0)
{
value |= vtkDataSetAttributes::DUPLICATEPOINT;
}
ghosts->InsertNextValue(value);
}
}
}
levels->SetName("vtkGhostLevels");
this->PointData->AddArray(levels);
levels->Delete();
ghosts->SetName(vtkDataSetAttributes::GhostArrayName());
this->PointData->AddArray(ghosts);
ghosts->Delete();
// ---- CELLS ----
// Allocate the appropriate number levels (number of cells).
levels = vtkUnsignedCharArray::New();
levels->Allocate((extent[1]-extent[0]) *
// Allocate the appropriate ghost types.
ghosts = vtkUnsignedCharArray::New();
ghosts->Allocate((extent[1]-extent[0]) *
(extent[3]-extent[2]) *
(extent[5]-extent[4]));
......@@ -620,14 +628,18 @@ void vtkDataSet::GenerateGhostLevelArray(int zeroExt[6])
{
dist = dk;
}
levels->InsertNextValue(static_cast<unsigned char>(dist));
unsigned char value = 0;
if(dist > 0)
{
value |= vtkDataSetAttributes::DUPLICATECELL;
}
ghosts->InsertNextValue(value);
}
}
}
levels->SetName("vtkGhostLevels");
this->CellData->AddArray(levels);
levels->Delete();
ghosts->SetName(vtkDataSetAttributes::GhostArrayName());
this->CellData->AddArray(ghosts);
ghosts->Delete();
}
}
......@@ -694,3 +706,128 @@ void vtkDataSet::PrintSelf(ostream& os, vtkIndent indent)
os << indent << "Compute Time: " <<this->ComputeTime.GetMTime() << "\n";
}
//----------------------------------------------------------------------------
bool vtkDataSet::HasAnyGhostPoints()
{
return IsAnyBitSet(
this->GetPointGhostArray(), vtkDataSetAttributes::DUPLICATEPOINT);
}
//----------------------------------------------------------------------------
bool vtkDataSet::HasAnyGhostCells()
{
return IsAnyBitSet(this->GetCellGhostArray(),
vtkDataSetAttributes::DUPLICATECELL);
}
//----------------------------------------------------------------------------
vtkUnsignedCharArray* vtkDataSet::GetPointGhostArray()
{
if(!this->PointGhostArray)
{
this->PointGhostArray = vtkUnsignedCharArray::SafeDownCast(
this->GetPointData()->GetArray(vtkDataSetAttributes::GhostArrayName()));
}
assert (this->PointGhostArray ==
vtkUnsignedCharArray::SafeDownCast(
this->GetPointData()->GetArray(
vtkDataSetAttributes::GhostArrayName())));
return this->PointGhostArray;
}
//----------------------------------------------------------------------------
void vtkDataSet::UpdatePointGhostArrayCache()
{
this->PointGhostArray = vtkUnsignedCharArray::SafeDownCast(
this->GetPointData()->GetArray(vtkDataSetAttributes::GhostArrayName()));
}
//----------------------------------------------------------------------------
vtkUnsignedCharArray* vtkDataSet::AllocatePointGhostArray()
{
if(!this->GetPointGhostArray())
{
vtkUnsignedCharArray *ghosts = vtkUnsignedCharArray::New();
ghosts->SetName(vtkDataSetAttributes::GhostArrayName());
ghosts->SetNumberOfComponents(1);
ghosts->SetNumberOfTuples(this->GetNumberOfPoints());
ghosts->FillComponent(0, 0);
this->GetPointData()->AddArray(ghosts);
ghosts->Delete();
this->PointGhostArray = ghosts;
}
return this->PointGhostArray;
}
//----------------------------------------------------------------------------
vtkUnsignedCharArray* vtkDataSet::GetCellGhostArray()
{
if(!this->CellGhostArray)
{
this->CellGhostArray = vtkUnsignedCharArray::SafeDownCast(
this->GetCellData()->GetArray(vtkDataSetAttributes::GhostArrayName()));
}
assert (
this->CellGhostArray ==
vtkUnsignedCharArray::SafeDownCast(
this->GetCellData()->GetArray(vtkDataSetAttributes::GhostArrayName())));
return this->CellGhostArray;
}
//----------------------------------------------------------------------------
void vtkDataSet::UpdateCellGhostArrayCache()
{
this->CellGhostArray = vtkUnsignedCharArray::SafeDownCast(
this->GetCellData()->GetArray(vtkDataSetAttributes::GhostArrayName()));
}
//----------------------------------------------------------------------------
vtkUnsignedCharArray* vtkDataSet::AllocateCellGhostArray()
{
if(!this->GetCellGhostArray())
{
vtkUnsignedCharArray *ghosts = vtkUnsignedCharArray::New();
ghosts->SetName(vtkDataSetAttributes::GhostArrayName());
ghosts->SetNumberOfComponents(1);
ghosts->SetNumberOfTuples(this->GetNumberOfCells());
ghosts->FillComponent(0, 0);
this->GetCellData()->AddArray(ghosts);
ghosts->Delete();
this->CellGhostArray = ghosts;
}
return this->CellGhostArray;
}
//----------------------------------------------------------------------------
bool vtkDataSet::IsAnyBitSet(vtkUnsignedCharArray *a, int bitFlag)
{
if (a)
{
for (vtkIdType i = 0; i < a->GetNumberOfTuples(); ++i)
{
if (a->GetValue(i) & bitFlag)
{
return true;
}
}
}
return false;
}
//----------------------------------------------------------------------------
void vtkDataSet::OnDataModified(
vtkObject* source, unsigned long eid, void* clientdata, void *)
{
// update the point/cell pointers to ghost data arrays.
vtkDataSet* This = static_cast<vtkDataSet*>(clientdata);
if (source == This->GetPointData())
{
This->UpdatePointGhostArrayCache();
}
else
{
assert(source == This->GetCellData());
This->UpdateCellGhostArrayCache();
}
}
......@@ -47,6 +47,8 @@ class vtkCellTypes;
class vtkGenericCell;
class vtkIdList;
class vtkPointData;
class vtkUnsignedCharArray;
class vtkCallbackCommand;
class VTKCOMMONDATAMODEL_EXPORT vtkDataSet : public vtkDataObject
{
......@@ -330,10 +332,10 @@ public:
int CheckAttributes();
// Description:
// Normally called by pipeline executives or algoritgms only. This method
// Normally called by pipeline executives or algoritms only. This method
// computes the ghost arrays for a given dataset. The zeroExt argument
// specifies the extent of the region which ghost level = 0.
virtual void GenerateGhostLevelArray(int zeroExt[6]);
// specifies the extent of the region which ghost type = 0.
virtual void GenerateGhostArray(int zeroExt[6]);
//BTX
// Description:
......@@ -353,6 +355,55 @@ public:
// Get the number of elements for a specific attribute type (POINT, CELL, etc.).
virtual vtkIdType GetNumberOfElements(int type);
// Description:
// Returns 1 if there are any ghost cells
// 0 otherwise.
bool HasAnyGhostCells();
// Description:
// Returns 1 if there are any ghost points
// 0 otherwise.
bool HasAnyGhostPoints();
// Description:
// Returns 1 if there are any blanking cells
// 0 otherwise. Blanking is supported only for vtkStructuredGrid
// and vtkUniformGrid
virtual bool HasAnyBlankCells()
{
return 0;
}
// Description:
// Returns 1 if there are any blanking points
// 0 otherwise. Blanking is supported only for vtkStructuredGrid
// and vtkUniformGrid
virtual bool HasAnyBlankPoints()
{
return 0;
}
// Description:
// Gets the array that defines the ghost type of each point.
// We cache the pointer to the array to save a lookup involving string comparisons
vtkUnsignedCharArray* GetPointGhostArray();
// Description:
// Updates the pointer to the point ghost array.
void UpdatePointGhostArrayCache();
// Description:
// Allocate ghost array for points.
vtkUnsignedCharArray* AllocatePointGhostArray();
// Description:
// Get the array that defines the ghost type of each cell.
// We cache the pointer to the array to save a lookup involving string comparisons
vtkUnsignedCharArray* GetCellGhostArray();
// Description:
// Updates the pointer to the cell ghost array.
void UpdateCellGhostArrayCache();
// Description:
// Allocate ghost array for cells.
vtkUnsignedCharArray* AllocateCellGhostArray();
protected:
// Constructor with default bounds (0,1, 0,1, 0,1).
vtkDataSet();
......@@ -363,8 +414,14 @@ protected:
// only if the cache became invalid (ScalarRangeComputeTime).
virtual void ComputeScalarRange();
// Description:
// Helper function that tests if any of the values in 'a' have bitFlag set.
// The test performed is (value & bitFlag).
bool IsAnyBitSet(vtkUnsignedCharArray *a, int bitFlag);
vtkCellData *CellData; // Scalars, vectors, etc. associated w/ each cell
vtkPointData *PointData; // Scalars, vectors, etc. associated w/ each point
vtkCallbackCommand *DataObserver; // Observes changes to cell/point data
vtkTimeStamp ComputeTime; // Time at which bounds, center, etc. computed
double Bounds[6]; // (xmin,xmax, ymin,ymax, zmin,zmax) geometric bounds
double Center[3];
......@@ -375,8 +432,21 @@ protected:
// Time at which scalar range is computed
vtkTimeStamp ScalarRangeComputeTime;
// Description:
// These arrays pointers are caches used to avoid a string comparision (when
// getting ghost arrays using GetArray(name))
vtkUnsignedCharArray* PointGhostArray;
vtkUnsignedCharArray* CellGhostArray;
private:
void InternalDataSetCopy(vtkDataSet *src);
// Description:
// Called when point/cell data is modified
// Updates caches to point/cell ghost arrays.
static void OnDataModified(
vtkObject* source, unsigned long eid, void* clientdata, void *calldata);
//BTX
friend class vtkImageAlgorithmToDataSetFriendship;
//ETX
......
......@@ -103,6 +103,33 @@ public:
};
//ETX
// ----------- ghost points and ghost cells -------------------------------------------
//The following bit fields are consistent with VisIt ghost zones specification
//For details, see http://www.visitusers.org/index.php?title=Representing_ghost_data
enum CellGhostTypes
{
DUPLICATECELL = 1, //the cell is present on multiple processors
HIGHCONNECTIVITYCELL = 2, //the cell has more neighbors than in a regular mesh
LOWCONNECTIVITYCELL = 4, //the cell has less neighbors than in a regular mesh
REFINEDCELL = 8, //other cells are present that refines it.
EXTERIORCELL = 16, //the cell is on the exterior of the data set
HIDDENCELL = 32 //the cell is needed to maintain connectivity, but the data values should be ignored.
};
enum PointGhostTypes
{
DUPLICATEPOINT =1, //the cell is present on multiple processors